SemanticReleaseHex - Fully automated version management and release processes

Hello, Elixir community!

I’m excited to introduce a new tool that aims to streamline version management and release processes for Elixir projects: semantic-release-hex.

Disclaimers

Before we dive in, I want to clarify that semantic-release-hex is a JavaScript library designed to enhance version management and release processes in Elixir projects. While it’s not an Elixir library per se, its integration with Elixir projects can bring the power and simplicity of semantic-release to your workflow.

I also want to mention that although it’s only been two weeks, I’ve recently been invited to the semantic-release organization. The reason I’m developing this library is unrelated to my membership in the organization and is solely motivated by my complete trust and utter admiration for that project, which I’ve been using for more than 6 years in all of my projects, both personal and professional.*

Why?

In the course of developing a SaaS project with Elixir & Phoenix, I encountered the challenge of automating version management while adhering to best practices. Initially being a JavaScript developer, I turned to the reliable semantic-release tool but found it lacking in Elixir integration. This led me to create semantic-release-hex.

semantic-release features

  • Determining the next version number
  • Generating release notes & updating the changelog file
  • Creating a git tag
  • Publishing GitHub/GitLab releases
  • Commenting on released Pull Requests/Issues

semantic-release-hex features

  • Updating the version in mix.exs

semantic-release-hex roadmap

Benefits

  • Fully automated release
  • Enforce Semantic Versioning specification
  • New features and fixes are immediately available to users
  • Notify maintainers and users of new releases
  • Use formalized commit message convention to document changes in the codebase
  • Integrate with your continuous integration workflow
  • Avoid potential errors associated with manual releases
  • Simple and reusable configuration via shareable configurations

Trying it out

I’ve set up a demo repository to showcase what that would look like in an Elixir project: semantic-release-hex-demo. Feel free to explore its content, commit history, or even fork it to test things out, as it’s what it’s meant for.

You will also find detailed instructions on how to set it up in your own Elixir project on the main repository.

I’m eager to hear your thoughts, answer any questions, and discuss how semantic-release-hex can enhance your Elixir projects!

Also, if you’d like to share your views on features currently being specified/implemented, don’t hesitate to visit the Discussions/Issues for feature requests.

Thank you for reading :heart:

Acknowledgements

Special thanks to @Eiji and @D4no0 for their invaluable feedback!

6 Likes

Isn’t it easier to create a mix task which firstly guess based on configurable prefix (let’s say: "fix: ") and then asks for a type of version change giving the guessed one as default (to just press enter)?

config ::semantic_release, :prefix,
  major: ["…"],
  minor: ["…"],
  major: ["fix: ", "other: "],

Some projects would need to add node as extra environment dependency which is not always a good idea. If we are going to simplify one thing we shouldn’t complicate other one. For me it’s simple on my laptop, because I use asdf, but not everyone is in such case. Also obviously the documentation is not on hex with all of it’s side-effects which may be confusing especially for new developers.

$ mix semantic.release --log-level debug
[debug] Found "…" prefix in commit message which is configured for … version change
[debug] Found (…)
(…)
[info] The determined version change is …
Which version change should be applied?
1) Major
2) Minor
3) Bug fix (default)
Choose type of version change [1/2/3] _
[debug] The chosen type is …
[info] The new version is …
Are you ready to push changes [Y/n] _
[debug] Pushes commit(s)
Do you want to create a new git tag "v1.x.y"? [Y/n] _
[debug] Created git tag "v1.x.y"
Do you want to publish a release to hex? [Y/n] _
[debug] The release has been published
[debug] The documentation has been published
The version has been successfully changed from … to …

$ mix semantic.release --yes-all
Which version change should be applied?
1) Major
2) Minor (default)
3) Bug fix
Choose type of version change [1/2/3] _
The version has been successfully changed from … to …

$ mix semantic.release --yes-all --default
The version has been successfully changed from … to …

Does it have any strict format or it’s configurable somehow?

Does it creates a git tags automatically as well (git checkout v1.x.y or so)?

What is the comment content? Is it configurable? How about wiki?

For me the best documentation is:

  1. wiki as user perspective
  2. issue as developer perspective
  3. pull request as implementation details

How about Installation in README.md file? It should be easy to find in markdown as long as you know the project name and previous version.

Those links are relative, so browser searches it on this forum …

1 Like

Isn’t it easier to create a mix task which firstly guess based on configurable prefix (let’s say: "fix: ") and then asks for a type of version change giving the guessed one as default (to just press enter)?

I thought about making an actual Elixir library to solve the issue at hand.

However, semantic-release is the industry standard battle-tested tool (was created almost 10 years ago and is the 128th most depended upon package on NPM, ahead of jquery, underscore, babel and lots of other staples), packs in a lot of useful features (e.g. support for pre-release / maintenance branches) and is highly configurable to suit almost any workflow.

For these reasons, while it would be extremely instructive to try and create an Elixir equivalent, I don’t think reinventing the wheel is a good use of time, especially when there is virtually no downside to using (and extending) the already available tooling.

Some projects would need to add node as extra environment dependency which is not always a good idea.

Technically, because semantic-release is made with a CI-first approach in mind, it doesn’t have to ever be run locally. Because of this, the Node.js environment dependency is only in the release workflow file. Node.js is required locally only when initializing the tool, to install the packages and run the dry-run to check everything is working as expected.

Also obviously the documentation is not on hex with all of it’s side-effects which may be confusing especially for new developers.

I’m not sure what you mean by “side-effects”, but I don’t think not having the documentation on hex is an issue, since this isn’t an Elixir library per see, and the only place it will be referenced is in the release configuration. Similar to CI tools, where you wouldn’t expect GitHub Actions documentation to be on Hex, the relevant documentation is readily available where it’s most relevant.

Does it have any strict format or it’s configurable somehow?

This is fully configurable by choosing an existing conventional changelog preset, or creating your own by forking one of the existing presets and making adjustments as I did (to be exact it is a maintained fork) with @insurgent/conventional-changelog-preset (which includes all commit types and adds emojis before categories). You can take a look at the relevant source code in lib/commit-transform.js. But note that with all the available presets, you probably don’t have to create a new one.

Does it creates a git tags automatically as well (git checkout v1.x.y or so)?

Yes, I forgot to mention that in the post, but semantic-release tags the version to the release commit before creating a GitHub/GitLab release, as it actually relies heavily on tags (e.g. to determine the current version).

What is the comment content? Is it configurable? How about wiki ?

You can take a look at an example comment here: semantic-release/semantic-release#3062 (comment).

It is also fully configurable, please refer to the semantic-release/github options documentation if you’d like to know more.

Regarding the wiki, I’m not sure what you mean by that. Could you please expand on the use case(s) you have in mind?

How about Installation in README.md file? It should be easy to find in markdown as long as you know the project name and previous version.

That’s actually a very good idea, thank you so much! I’ll be adding it to the feature requests and will start working on it as soon as it is specified correctly (btw if you’d like to share your views on features currently being specified/implemented, don’t hesitate to visit the Discussions/Issues for feature requests).

Those links are relative, so browser searches it on this forum …

Sorry about that, thanks for pointing this out I’ll fix them immediately.

Thank you so much for responding to my post to share your views and concerns, and I hope I’ve addressed them as best as possible :heart:

1 Like

I’m also not a big fan of installing node and random JS packages either on dev or CI/CD, I am tired of redoing the CI script every few months because of some forced “deprecations” introduced in the ways to install node or other js packages.

If the implementation of the package is what matters, I think making a CLI and packaging it together with a elixir library, just like tailwind does is a much more sane approach and would make everyone happy by not caring about any implementation details.

1 Like

I’m also not a big fan of installing node and random JS packages either on dev or CI/CD, I am tired of redoing the CI script every few months because of some forced “deprecations” introduced in the ways to install node or other js packages.

Unrelated: superfluous defense of Node.js and NPM

As a JavaScript developer for more than 10 years, I’m not aware of any such “forced deprecations” requiring substantial changes to CI workflows.

For example, the official GitHub Action setup-node did not make changes to its interface between v1 and v4 (current version) other than renaming the version option to node-version in v3.0.0 (and adding a lot of non-breaking features, e.g. support for .tool-versions).

Similarly, the interface of a basic npm install command did not change between the (pre-v1) 2010 specification and today’s latest (v10) documentation. Of course, the way NPM handles the installation and optimization of packages changed a lot under the hood (thank god, because the early days were … something :sweat_smile:), but breaking changes never were an issue, at least for me. Searching through @npm/cli releases supports those claims.

It’s also worth mentioning that Node.js releases LTS versions, which “typically guarantees that critical bugs will be fixed for a total of 30 months”.

If the implementation of the package is what matters, I think making a CLI and packaging it together with a elixir library, just like tailwind does is a much more sane approach and would make everyone happy by not caring about any implementation details.

That being said, I can understand that one might not want to install a Node.js runtime and packages in an Elixir project, even if only on the CI.

I really like your idea of packaging the library in a hex package!

Unfortunately, there’s a major difference between tailwind and semantic-release, being that the former is a frontend library (hence it runs in the browser). If we were to try and do the same thing for semantic-release, I’m afraid we’d have to bundle a Node.js runtime inside the hex package, which I don’t think would be either a practical or good idea and might even not be possible at all.

EDIT: I realized you were mentioning that Elixir’s tailwind uses the Tailwind standalone CLI under the hood, and so does not require having Node.js installed. I wasn’t aware of that, and it definitely looks very interesting, I’ll be looking further into it!

Anyway, I’ll be looking into this idea further, even if that means installing the Node.js runtime on the CI separately. That would allow to simplify the installation process and also provide a mix task for running the release. Thanks for the great suggestion!

ex_doc as well as everything in Elixir environment is extremely powerful. As long as yo have it as a dependency you can easily link to every it’s module, function and so on. No matter how good or not is it, it would never support every possible source (not only npm). Therefore the developer who want to describe everything in details in a guide would need to use absolute urls. In my personal opinion Elixir’s documentation tool output looks brillant and I’m really used to it. Suddenly changing a look like feeling of documentation by clicking on “some url” is not … handy.

Since the documentation could not be found on hex or hexdocs page and Google uses a terrible algorithms it may be hard to find such tool. How much people are searching for a package here on forum? Keep in mind there is “hex” in the project name it’s of course correct on one side, but confusing on the other one as what developer expects is not what is provided.

I remember it was something about semantic versioning … What was it’s name? Weird … there is nothing about it on hex … Did I forgot some keyword?

That would be my first thoughts …

Having a tool outside of the ecosystem is of course your decision, but it’s rather a matter of time for a side-effects to come. It’s like a butterfly effect. If some (even small) % of developers would have trouble search for it then in long term it would not give anything good.

Of course I may be wrong here, because I’m writing it from my perspective. For example in many cases I already had a desired page on some nth results page. As above I’m not searching for a specific package/tool on forum, but rather on hex/hexdocs.

I’m really not sure what to recommend here. Maybe try to go a similar route in the Phoenix assets. Instead of using npm they are downloading some tools (esbuild and tailwind) and run them as watchers. Of course watchers here does not makes sense, but I don’t know … downloading a standalone node binary (if possible) to some directory and call your code (like install_and_run in watchers config). Therefore most of your code would stay on npm and you could keep documentation including guides for Elixir stuff on hexdocs making it’s easier to find. Does it makes sense for your case?

Edit: Oh, actually @D4no0 proposed it before me. :+1:

Not really … it’s like a … web service. I mean you do not care in which language Slack API was created. The API itself is not a part of environment, but it’s a 3rd-paty service to integrate. Also if such a web service is related to language environment then we have for example a Slack API client hex dependency which instead giving tons of links to Slack API documents everything on hex. As long as it works “nobody cares” how it works i.e. it could be a REST API or GraphQL one - the hex package gives it’s own Elixir’s API.

I had not idea how your code is working, so I was wondering if there was some AI-based text generators, so actually never mind :sweat_smile:

1 Like

That all makes total sense, I now understand your point about having the documentation on hexdocs, which would be even further solidified by the creation of an Elixir package abstracting the installation and release mechanisms associated with Node.js. I really like this solution and have already started looking into it.

I’m not aware of any mention of a standalone release of semantic-release-cli, but that will be a great addition to the tool that I’m sure the core team will welcome with enthusiasm! I’ll run the idea by them while working on a prototype.

Regarding the AI-based documentation generator, semantic-release indeed does not ship with that feature, but maybe someone will create a plugin for that in the future :sweat_smile:

Thank you for being so patient with me, your input is really valuable and highly appreciated!

2 Likes

I have used another lib called git_opts before, which is written in Elixir. Out of curiosity: did you find any specific functionality lacking in the ecosystem that prompted you to create another library?

1 Like

git_ops seems to be lacking the following:

  • Committing & pushing changes to the repository
  • Creating & pushing tags to the repository
  • Publishing GitHub/GitLab releases
  • Publishing to Hex
  • Commenting on released Pull Requests/Issues
  • CI Integration (ability to use GitHub/GitLab tokens for auth)
  • Support for a wide variety of workflows
  • Modularity (existing plugins)
  • Extensibility (ability to easily create a new plugin)
  • Customization (extensive configuration options)
  • Comprehensive documentation

Ultimately, its missing git & CI integrations make it unable to be fully automated easily.

I had noticed git_opts while researching the topic, but thought it was unmaintained due to misreading “Jun 21” for `“June 2021”. I now realize the package receives a bit of attention.

Though git_ops looks like a great project and would have the benefit of allowing any Elixir developer to contribute without knowing JavaScript, I think it is unfortunate that someone would invest their time in reconstructing a tool from scratch when there’s practically no drawback to utilizing and enhancing the existing tooling (as I stated before).

semantic-release is a mature and stable tool, with features that would take months (or even years) to develop in git_ops with a dedicated and active team. This is what led me to believe creating a bridge between Elixir and semantic-release to bring its capabilities to the ecosystem was the best solution.

Disclaimer: I haven’t mentioned that before as it did not seem relevant since it’s only been two weeks, but I’ve recently been invited to the semantic-release organization. The reason I’m developing this library is unrelated to my membership in the organization and is solely motivated by my complete trust and utter admiration for that tool, which I’ve been using for more than 6 years in all of my projects, both personal and professional.

1 Like

In case that’s of interest to anyone, here’s the GitHub Discussion I just created on semantic-release which will host the exchanges with the core team regarding this project:

I’ve mentioned the need for creating an official standalone executable, required to bundle everything as a hex package, and the possible approach to fulfill that requirement. I’m waiting for their preliminary feedback before beginning any work.

1 Like

Thanks for creating semantic-release-hex. I think it’s a great addition to the semantic-release ecosystem.

I think that the Elixir community is not so keen on using tools like semantic-release to continuously release libs and generate CHANGELOGs. I think the majority of us are publishing our libs manually to hex.

I’ve been using semantic-release in my plugins for Logseq (the open-source outliner note-taking app) since that’s the recommended way of releasing Logseq plugins. Although I admit it was a bit confusing to set up, I’m really enjoying committing stuff using feat: new feature here and that immediately triggering a new version and release.

I thought about creating something like semantic-release for Elixir, but as you said, there’s lots of functionality. I particularly enjoy all the PR comments when you release a new version.

I’m not maintaining any Elixir lib right now, but if I do, I’ll sure use semantic-release-hex. Thanks and congrats!

1 Like

Thank you so much for your kind words, George!

I also noticed the Elixir libraries are almost all released manually, but (maybe incorrectly) attributed that to the missing tooling for reliable release automation.

I’m a tremendous advocate for automating this workflow, as I truly believe it is an excellent enabler of good practices (always having the main branch deployable, providing bug fixes to maintenance versions, consistent versioning, maintaining a changelog, etc…).

My objective is to enable project maintainers to automate their release workflows if they ever want to, and I’d be delighted if my efforts bring value to even just one project!

I’m thrilled to know you’d be a semantic-release-hex user if you’d have to maintain an Elixir lib, thanks again for your message!

1 Like