diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 00000000..0a6bae1d --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,91 @@ +name: Release + +on: + workflow_dispatch: + inputs: + version: + type: string + description: New version number in X.Y.Z + required: true + +jobs: + update-master-branch: + runs-on: ubuntu-latest + steps: + - uses: everlytic/branch-merge@1.1.5 + with: + github_token: ${{ secrets.PAT }} + source_ref: 'develop' + target_branch: 'master' + commit_message_template: '[Automated] Merged {source_ref} into target {target_branch}' + + release: + needs: [ 'update-master-branch' ] + runs-on: ubuntu-latest + permissions: + contents: write + steps: + - name: Fetch repo + uses: actions/checkout@v4 + with: + ref: 'master' + fetch-depth: 0 + + - name: Get latest tag + id: latest_tag + shell: bash + run: | + echo "TAG_NAME=$(git describe --tags $(git rev-list --tags --max-count=1))" >> $GITHUB_OUTPUT + - name: Generate a changelog + uses: orhun/git-cliff-action@v2 + id: generate-changelog + with: + config: ./cliff-release.toml + args: ${{ steps.latest_tag.outputs.TAG_NAME }}..HEAD + + - name: Create release and upload build + uses: softprops/action-gh-release@v1 + id: create-release + with: + name: v${{ github.event.inputs.version }} + tag_name: v${{ github.event.inputs.version }} + token: ${{ secrets.GITHUB_TOKEN }} + body: ${{ steps.generate-changelog.outputs.content }} + + update-changelog: + needs: [ 'release' ] + name: Generate changelog + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + ref: 'master' + token: ${{ secrets.PAT }} + fetch-depth: 0 + + - name: Get latest tag + id: latest_tag + shell: bash + run: | + echo "TAG_NAME=$(git describe --tags $(git rev-list --tags --max-count=1))" >> $GITHUB_OUTPUT + - name: Generate a changelog + uses: orhun/git-cliff-action@v2 + id: git-cliff + with: + config: cliff.toml + args: v0.0.0..${{ steps.latest_tag.outputs.TAG_NAME }} + env: + OUTPUT: ${{ github.workspace }}/CHANGELOG.md + + - uses: stefanzweifel/git-auto-commit-action@v4 + with: + commit_message: 'docs(changelog): update changelog' + file_pattern: CHANGELOG.md + + - uses: everlytic/branch-merge@1.1.5 + with: + github_token: ${{ secrets.PAT }} + source_ref: 'master' + target_branch: 'develop' + commit_message_template: '[Automated] Merged {source_ref} into target {target_branch}' diff --git a/cliff-release.toml b/cliff-release.toml new file mode 100644 index 00000000..3975df70 --- /dev/null +++ b/cliff-release.toml @@ -0,0 +1,80 @@ +# configuration file for git-cliff (0.1.0) + +[changelog] +# changelog header +header = """ +# What's Changed +""" +# template for the changelog body +# https://tera.netlify.app/docs/#introduction +body = """ +{% for group, commits in commits | group_by(attribute="group") %}\ + ### {{ group | striptags | trim | upper_first }} + {% for commit in commits + | filter(attribute="scope") + | sort(attribute="scope") %} + - **{{commit.scope}}**: {{ commit.message | upper_first | trim }} | [{{ commit.id | truncate(length=7, end="") }}](/commit/{{ commit.id }})\ + {%- if commit.breaking %} + {% raw %} {% endraw %}- **BREAKING**: {{commit.breaking_description}} + {%- endif -%} + + {%- endfor -%} + {%- for commit in commits %} + {%- if commit.scope -%} + {% else -%} + {% raw %}\n{% endraw %}\ + - {{ commit.message | upper_first | trim }} | [{{ commit.id | truncate(length=7, end="") }}](/commit/{{ commit.id }})\ + {%- if commit.breaking %} + {% raw %} {% endraw %}- **BREAKING**: {{commit.breaking_description}} + {%- endif -%} + + {% endif -%} + {% endfor -%} + {% raw %}\n{% endraw %} +{% endfor %}\n\ +""" +# remove the leading and trailing whitespaces from the template +trim = true +# changelog footer +footer = """ +""" + +# postprocessors +postprocessors = [ + { pattern = '(\(/pull/[0-9]+\)\)) \| .+', replace = "${1}" }, + { pattern = '', replace = "https://github.com/mainsail-crew/crowsnest" }, # replace repository URL +] + +[git] +# allow only conventional commits +# https://www.conventionalcommits.org +conventional_commits = true +filter_unconventional = true +# regex for parsing and grouping commits +commit_parsers = [ + # Commits to skip + { message = "^docs\\(changelog\\):", group = "Changelog", skip = true}, # Old redundant commits + { message = "^chore: push version number to", group = "9$Other", skip = true}, # Old redundant commits + { message = "^chore\\(changelog\\): update changelog", group = "Changelog", skip = true}, # Old redundant commits + + # Commits to parse + { message = "^feat(\\(.*\\))?:", group = "Features"}, + { message = "^feature(\\(.*\\))?:", group = "Features"}, + { message = "^fix(\\(.*\\))?:", group = "Bug Fixes and Improvements"}, + { message = "^perf(\\(.*\\))?:", group = "Performance"}, + { message = "^refactor(\\(.*\\))?:", group = "Refactor"}, + { message = "^style(\\(.*\\))?:", group = "Styling"}, + { message = "^locale(\\(.*\\))?:", group = "Localization"}, + { message = "^docs(\\(.*\\))?:", group = "Documentation"}, + { message = "^test(\\(.*\\))?:", group = "Other"}, + { message = "^chore(\\(.*\\))?:", group = "Other"}, + { body = ".*security", group = "Security"}, +] +commit_preprocessors = [ + { pattern = '\((\w+\s)?#([0-9]+)\)', replace = "([#${2}](/pull/${2}))" }, +] +# filter out the commits that are not matched by commit parsers +filter_commits = true +ignore_tags="v*-(beta|rc)*" +# glob pattern for matching git tags +tag_pattern = "v[0-9]*" diff --git a/cliff.toml b/cliff.toml new file mode 100644 index 00000000..6aa1d8bb --- /dev/null +++ b/cliff.toml @@ -0,0 +1,86 @@ +# configuration file for git-cliff (0.1.0) + +[changelog] +# changelog header +header = """ + +# Changelog +All notable changes to Crowsnest will be documented in this file.\n +""" +# template for the changelog body +# https://tera.netlify.app/docs/#introduction +body = """ +{% if version %}\ + ## [{{ version | trim_start_matches(pat="v") }}](https://github.com/mainsail-crew/crowsnest/releases/tag/{{version}}) - {{ timestamp | date(format="%Y-%m-%d") }} +\ +{% else %}\ + ## [unreleased] +{% endif %}\ +{% for group, commits in commits | group_by(attribute="group") %}\ + ### {{ group | striptags | trim | upper_first }} + {% for commit in commits + | filter(attribute="scope") + | sort(attribute="scope") %} + - **{{commit.scope}}**: {{ commit.message | upper_first | trim }} | [{{ commit.id | truncate(length=7, end="") }}](/commit/{{ commit.id }})\ + {%- if commit.breaking %} + {% raw %} {% endraw %}- **BREAKING**: {{commit.breaking_description}} + {%- endif -%} + {%- endfor -%} + {%- for commit in commits %} + {%- if commit.scope -%} + {% else -%} + {% raw %}\n{% endraw %}\ + - {{ commit.message | upper_first | trim }} | [{{ commit.id | truncate(length=7, end="") }}](/commit/{{ commit.id }})\ + {%- if commit.breaking %} + {% raw %} {% endraw %}- **BREAKING**: {{commit.breaking_description}} + {%- endif -%} + {% endif -%} + {% endfor -%} + {% raw %}\n{% endraw %} +{% endfor %}\n\ +""" +# remove the leading and trailing whitespaces from the template +trim = true +# changelog footer +footer = """ +""" + +# postprocessors +postprocessors = [ + { pattern = '(\(/pull/[0-9]+\)\)) \| .+', replace = "${1}" }, + { pattern = '', replace = "https://github.com/mainsail-crew/crowsnest" }, # replace repository URL +] + +[git] +# allow only conventional commits +# https://www.conventionalcommits.org +conventional_commits = true +filter_unconventional = false +# regex for parsing and grouping commits +commit_parsers = [ + # Commits to skip + { message = "^docs\\(changelog\\):", group = "Changelog", skip = true}, # Old redundant commits + { message = "^chore: push version number to", group = "9$Other", skip = true}, # Old redundant commits + { message = "^chore\\(changelog\\): update changelog", group = "Changelog", skip = true}, # Old redundant commits + + # Commits to parse + { message = "^feat(\\(.*\\))?:", group = "Features"}, + { message = "^feature(\\(.*\\))?:", group = "Features"}, + { message = "^fix(\\(.*\\))?:", group = "Bug Fixes and Improvements"}, + { message = "^perf(\\(.*\\))?:", group = "Performance"}, + { message = "^refactor(\\(.*\\))?:", group = "Refactor"}, + { message = "^style(\\(.*\\))?:", group = "Styling"}, + { message = "^locale(\\(.*\\))?:", group = "Localization"}, + { message = "^docs(\\(.*\\))?:", group = "Documentation"}, + { message = "^test(\\(.*\\))?:", group = "Other"}, + { message = "^chore(\\(.*\\))?:", group = "Other"}, + { body = ".*security", group = "Security"}, +] +commit_preprocessors = [ + { pattern = '\((\w+\s)?#([0-9]+)\)', replace = "([#${2}](/pull/${2}))" }, +] +# filter out the commits that are not matched by commit parsers +filter_commits = true +ignore_tags="v*-(beta|rc)*" +# glob pattern for matching git tags +tag_pattern = "v[0-9]*"