# Semantic Release
We use semantic release nearly everywhere. Here is a short description on how to write commit messages.
## Commits matter!
We use semantic release (https://github.com/semantic-release/semantic-release) to automate releases.
**BEST PRACTICE:** Develop (larger changes) on a seperate branch and merge it if you are ready.
Either way, a commit body should have the following structure.
Refer to the following docs: https://github.com/angular/angular.js/blob/master/DEVELOPERS.md#-git-commit-guidelines
```
<type>(<scope>): <subject>
<BLANK LINE>
<body>
<BLANK LINE>
<footer>
```
### Revert
If the commit reverts a previous commit, it should begin with `revert: `, followed by the header of the reverted commit. In the body it should say: `This reverts commit hash`., where the hash is the SHA of the commit being reverted.
### Type
Must be one of the following:
- feat: A new feature
- fix: A bug fix
- docs: Documentation only changes
- style: Changes that do not affect the meaning of the code (white-space, formatting, missing semi-colons, etc)
- refactor: A code change that neither fixes a bug nor adds a feature
- perf: A code change that improves performance
- test: Adding missing or correcting existing tests
- chore: Changes to the build process or auxiliary tools and libraries such as documentation generation
### Scope
The scope could be anything specifying place of the commit change.
~~For example $location, $browser, $compile, $rootScope, ngHref, ngClick, ngView, etc...~~
In this case you could address the feature like `openservice` or `permission`.
You can use `*` when the change affects more than a single scope.
### Subject
The subject contains succinct description of the change:
use the imperative, present tense: "change" not "changed" nor "changes" don't capitalize first letter no dot (.) at the end
### Body
Just as in the subject, use the imperative, present tense: "change" not "changed" nor "changes".
The body should include the motivation for the change and contrast this with previous behavior.
### Footer
The footer should contain any information about Breaking Changes and is also the place to reference GitHub issues that this commit closes.
Breaking Changes should start with the word `BREAKING CHANGE:` with a space or two newlines. The rest of the commit message is then used for this.
## Sample GitHub Workflow configuration
```yml
name: Docker Image CI
on:
push:
branches: ["master"]
pull_request:
branches: ["master"]
env:
IMAGE_NAME: XXX
LATEST_TAG: latest
permissions:
contents: write
pages: write
id-token: write
jobs:
release:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
persist-credentials: false
- name: Set up Node.js
uses: actions/setup-node@v4
with:
node-version: 22
registry-url: "https://registry.npmjs.org/"
- uses: pnpm/action-setup@v4
- name: Install dependencies
run: pnpm install
- name: Build the project
run: pnpm run build
- name: Archive dist folder #Use this to create a zip file with the distribution. This can be appended to the release assets.
run: zip -r dist.zip dist
- name: Semantic Release 🚀
id: semantic
run: npx semantic-release --branches master
env:
GH_TOKEN: ${{ secrets.XXX }}
NODE_AUTH_TOKEN: ${{ secrets.XXX }}
outputs:
new-release-published: ${{ steps.semantic.outputs.new-release-published }}
new-release-version: ${{ steps.semantic.outputs.new-release-version }}
new-release-git-tag: ${{ steps.semantic.outputs.new-release-git-tag }}
publish:
runs-on: ubuntu-latest
needs: release
if: github.ref == 'refs/heads/master' && github.event_name == 'push' && needs.release.outputs.new-release-published == 'true'
steps:
- uses: actions/checkout@v4
- name: Log in to Docker Hub
uses: docker/login-action@v2
with:
username: ${{ secrets.XXX }}
password: ${{ secrets.XXX }}
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Extract metadata
id: meta
uses: docker/metadata-action@v5
with:
images: ${{ env.IMAGE_NAME }}
- name: Build and push the Docker image
uses: docker/build-push-action@v6
with:
context: .
file: ./Dockerfile
sbom: true
provenance: mode=max
push: true
tags: "${{env.IMAGE_NAME }}:${{ env.LATEST_TAG }},${{ env.IMAGE_NAME }}:${{ needs.release.outputs.new-release-version }}"
```
## Package.json configuration
```json
{
...
"release": {
"branches": ["master"],
"repositoryUrl": "https://github.com/open-inc/xxx.git",
"plugins": [
"@semantic-release/commit-analyzer",
"@semantic-release/release-notes-generator",
"@semantic-release/changelog",
{
"path": "@semantic-release/github",
"assets": [
{
"path": "dist.zip",
"name": "xxx-distribution-v${nextRelease.version}.zip"
}
]
},
"semantic-release-export-data"
],
"prepare": [
"@semantic-release/changelog",
"@semantic-release/npm",
{
"path": "@semantic-release/git",
"assets": ["package.json", "pnpm-lock.json", "CHANGELOG.md"],
"message": "chore(release): Release ${nextRelease.version} \n\n${nextRelease.notes}"
}
]
},
"dependencies": {
...
"semantic-release": "^24.2.5"
},
"devDependencies": {
...
"@semantic-release/changelog": "^6.0.3",
"@semantic-release/commit-analyzer": "^13.0.1",
"@semantic-release/exec": "^7.1.0",
"@semantic-release/git": "^10.0.1",
"@semantic-release/npm": "^12.0.1",
"@semantic-release/github": "^11.0.3",
"@semantic-release/release-notes-generator": "^14.0.3",
"semantic-release-export-data": "^1.1.0",
}
}
```