Automating Tag and Release Generation with Semantic Release and GitHub Actions for Node.js Applications
Published: 2024-01-06 20:15:35

In an increasingly automation-focused software development landscape, streamlining repetitive processes is essential. A common practice involves creating tags and releases to mark different versions of an application. However, this process can become tedious and prone to human errors. It is in this context that tools like Semantic Release and GitHub Actions come into play, offering an automated and robust approach to managing your project's versions.

##What is Semantic Release?

Semantic Release is a tool that automates semantic versioning and release creation based on the content of changes made to the source code. By adopting this approach, the tool analyzes commits since the last version, automatically determines the version type (major, minor, or patch) based on the changes made, and then generates a new tag and release. This not only streamlines the process but also ensures consistency and accuracy in your software versions. See [default release rules](https://github.com/semantic-release/commit-analyzer/blob/HEAD/lib/default-release-rules.js).

##The Importance of Conventional Commits

Central to this process is the use of [Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0/#specification), a standardized commit message convention. Conventional Commits enable Semantic Release to accurately determine the type of version change based on commit messages. By following this convention, you ensure that your commits provide clear and consistent information for automated versioning.

##Get started
Let's install the libs with the necessary plugins to use semantic release with github.
`npm i @semantic-release/commit-analyzer @semantic-release/git @semantic-release/github @semantic-release/release-notes-generator @semantic-release/npm --save-dev`

Update **package.json** with 
```
"release": {
    "branches": [
      "main"
    ],
    "repositoryUrl": "https://github.com/your_user/your_repository.git",
    "plugins": [
      "@semantic-release/commit-analyzer",
      "@semantic-release/release-notes-generator",
      "@semantic-release/npm",
      [
        "@semantic-release/git",
        {
          "message": "chore(release): ${nextRelease.version} \n\n${nextRelease.notes}"
        }
      ],
      "@semantic-release/github"
    ]
  }
```

Update your permissions for GITHUB_TOKEN to **Read and write**
![Github permissions](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/s3dt8zbusau854cgl5if.png)

Add the repository secrets NPM_TOKEN; it is essential for the @semantic-release/npm plugin to update your package.json version.


![NPM_TOKEN](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/t9kgy9nh1zf0fto9keum.png)

Create file **release.yml** in folder .github/workflows

```
name: Release
on:
  push:
    branches:
      - main
jobs:
  release:
    name: Release
    runs-on: ubuntu-latest
    steps:
      - name: Checkout
        uses: actions/checkout@v3
        with:
          fetch-depth: 0
      - name: Setup Node.js
        uses: actions/setup-node@v3
        with:
          node-version: "lts/*"
      - name: Install dependencies
        run: npm install
      - name: Release
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
          NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
        run: npx semantic-release

```
Now I'm going to add a feature to my application that implements an endpoint for health check.

`$ git commit -m "feat: add health check endpoint"`
`$ git push origin main`

![pipeline](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/gm5z6tz7xdpzdrjj360v.png)

![V1.0.0](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ay8ckxff53j4bmue8u7x.png)

We can see that the first version of the application was generated.
Now, I'm going to add one more feature, an endpoint to return a list of users.

`$ git commit -m "feat: add endpoint to list all users"`
`$ git push origin main`

![pipeline](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7jodtfa3nl4fxfcjw5c4.png)

We can see that a new tag was generated with a minor change.

![v1.1.0](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/junxko54vtko7ugai0lh.png)

Now I'm going to do a bug fix.
`$ git commit -m "fix: bug fix example"`
`$ git push origin main`

We can see that a new tag was generated with a patch change.

![v1.1.1](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/lmj0jmid288ukw0haas8.png)

To conclude, I will implement a feature that includes breaking changes, resulting in the generation of a tag reflecting a major version update.
```
$ git commit -m "feat: add authentication for get users route

BREAKING CHANGE: route /users needs authentication"
```

![v2.0.0](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1g0m0o6mqv0xzm8w88j7.png)

repository: [semantic-release-example](https://github.com/eduardoconti/semantic-release-example)

links: 

- [semantic-release.gitbook](https://semantic-release.gitbook.io/semantic-release/)

- [conventional commits](https://www.conventionalcommits.org/en/v1.0.0/#specification)

- [NPM creating-and-viewing-access-tokens](https://docs.npmjs.com/creating-and-viewing-access-tokens)