From b920b6b45e580c6d6a0660145fb38c8cfca97218 Mon Sep 17 00:00:00 2001 From: Daniel Atanasovski Date: Wed, 20 Mar 2024 15:38:23 +1100 Subject: [PATCH 1/8] feat: shellcheck config for simplicity --- .shellcheckrc | 1 + 1 file changed, 1 insertion(+) create mode 100644 .shellcheckrc diff --git a/.shellcheckrc b/.shellcheckrc new file mode 100644 index 0000000..8226afb --- /dev/null +++ b/.shellcheckrc @@ -0,0 +1 @@ +external-sources=true From 0c4ebd1e559dc12472d53e2df4187af95660ec75 Mon Sep 17 00:00:00 2001 From: Daniel Atanasovski Date: Wed, 20 Mar 2024 15:39:13 +1100 Subject: [PATCH 2/8] fix: strip leading 0 in date command for CI workflow --- .github/workflows/test-and-release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test-and-release.yml b/.github/workflows/test-and-release.yml index 95e4963..a8758fa 100644 --- a/.github/workflows/test-and-release.yml +++ b/.github/workflows/test-and-release.yml @@ -65,7 +65,7 @@ jobs: - name: Check increment result shell: bash - run: '[[ "$(date +%Y.%m)" == "$(echo "${{ steps.version-increment.outputs.VERSION }}" | cut -d "." -f 1-2)" ]]' + run: '[[ "$(date +%Y.%-m)" == "$(echo "${{ steps.version-increment.outputs.VERSION }}" | cut -d "." -f 1-2)" ]]' test-action-yml: # integration testing needs: From 0df84379a916a0eec45b5e362eeb80784b0bc330 Mon Sep 17 00:00:00 2001 From: Daniel Atanasovski Date: Wed, 20 Mar 2024 15:41:06 +1100 Subject: [PATCH 3/8] feat: add new scheme `conventional_commits` --- action.yml | 13 ++++++++++--- shared.sh | 13 ++++++++++--- version-increment.sh | 31 +++++++++++++++++++++++++++++-- version-lookup.sh | 2 +- 4 files changed, 50 insertions(+), 9 deletions(-) diff --git a/action.yml b/action.yml index b4a1e60..268e5b0 100644 --- a/action.yml +++ b/action.yml @@ -8,7 +8,14 @@ branding: inputs: scheme: - description: 'Versioning scheme - semver, or, calver (defaults to semver)' + description: | + Versioning scheme - semver, calver or conventional_commits (defaults to semver). + + `conventional_commits` Will parse the last commit message to determine the increment type. + Supports the following increment types: + - patch (build, chore, ci, docs, fix, perf, refactor, revert, style, test) + - minor (feat) + - Major (any of the above types with an '!' or 'BREAKING CHANGE:' in commit body) required: false default: 'semver' pep440: @@ -36,14 +43,14 @@ outputs: description: 'Current normal version detected' value: ${{ steps.version-lookup.outputs.CURRENT_VERSION }} current-v-version: - description: 'Current normal version detected, prefixed with a `v` charatcter' + description: 'Current normal version detected, prefixed with a `v` character' value: ${{ steps.version-lookup.outputs.CURRENT_V_VERSION }} version: description: 'Incremented version calculated' value: ${{ steps.version-increment.outputs.VERSION }} v-version: description: 'Incremented version calculated, prefixed with a `v` charatcter' - value: ${{ steps.version-increment.outputs.V_VERSION }} + value: ${{ steps.version-increment.outputs.V_VERSION }} major-version: description: 'Major number of the incremented version' value: ${{ steps.version-increment.outputs.MAJOR_VERSION }} diff --git a/shared.sh b/shared.sh index e1c97e6..d9f529f 100644 --- a/shared.sh +++ b/shared.sh @@ -11,13 +11,21 @@ pcre_master_ver='^(?P0|[1-9]\d*)\.(?P0|[1-9]\d*)\.(?P0|[1-9 pcre_allow_vprefix="^v{0,1}${pcre_master_ver:1}" pcre_old_calver='^(?P0|[1-9]\d*)-0{0,1}(?P0|[0-9]\d*)-R(?P0|[1-9]\d*)$' +##==---------------------------------------------------------------------------- +## Conventional commit regexes +## see: https://www.conventionalcommits.org/en/v1.0.0/ + +pcre_conventional_commit_patch='^(build|chore|ci|docs|fix|perf|refactor|revert|style|test)(\([a-zA-Z0-9-]+\))?:\s.*' +pcre_conventional_commit_minor='^(feat)(\([a-zA-Z0-9-]+\))?:\s.*' +pcre_conventional_commit_breaking='^(build|chore|ci|docs|feat|fix|perf|refactor|revert|style|test)(\([a-zA-Z0-9-]+\))?!:.*|BREAKING CHANGE:' + ##==---------------------------------------------------------------------------- ## Input validation input_errors='false' scheme="${scheme:-semver}" -if [[ "${scheme}" != 'semver' && "${scheme}" != 'calver' ]] ; then - echo "🛑 Value of 'scheme' is not valid, choose from 'semver' or 'calver'" 1>&2 +if [[ "${scheme}" != 'semver' && "${scheme}" != 'calver' && "${scheme}" != 'conventional_commits' ]] ; then + echo "🛑 Value of 'scheme' is not valid, choose from 'semver', 'calver' or 'conventional_commits" 1>&2 input_errors='true' fi @@ -40,7 +48,6 @@ if [[ "${use_api}" == 'true' ]] ; then fi fi - ##==---------------------------------------------------------------------------- ## MacOS compatibility - for local testing diff --git a/version-increment.sh b/version-increment.sh index 7036524..66e8c06 100755 --- a/version-increment.sh +++ b/version-increment.sh @@ -30,7 +30,7 @@ fi default_branch='main' # use release_branch if not empty if [[ -n "${release_branch:-}" ]] ; then - default_branch="${release_branch}" + default_branch="${release_branch}" elif [[ -z "${BATS_VERSION:-}" ]] ; then # if we're _not_ testing, then _actually_ check the origin if [[ "${use_api:-}" == 'true' ]] ; then @@ -48,6 +48,7 @@ elif [[ -z "${BATS_VERSION:-}" ]] ; then fi current_ref="${GITHUB_REF:-}" +git_commit_sha=${GITHUB_SHA:-} if [[ "${use_api:-}" == 'true' ]] ; then # because we cannot use `rev-parse` with the API, we'll take a punt that 9 characters is enough for uniqueness @@ -55,7 +56,33 @@ if [[ "${use_api:-}" == 'true' ]] ; then git_commit="$(echo "${GITHUB_SHA:0:9}" | sed 's/0*//')" # Also, trim leading zeros, because semver doesn't allow that in else # the 'pre-release version' part, but we can't use the + char git_commit="$(git rev-parse --short HEAD | sed 's/0*//')" # to make it 'build metadata' as that's not supported in K8s -fi # labels + git_commit_sha="$(git rev-parse --short HEAD)" # labels +fi + +##==---------------------------------------------------------------------------- +## Conventional commits +# If calver is set, raise a warning +if [[ "${scheme}" == 'conventional_commits' ]] ; then + # Get message from given commit + commit_message=$(git log -1 --pretty=format:%B "${git_commit_sha}") + + # Check commit message header + found_match='false' + if [[ -n "$(echo "${commit_message}" | ${grep} -P "${pcre_conventional_commit_breaking}")" ]] ; then + increment='major' + found_match='true' + elif [[ -n "$(echo "${commit_message}" | ${grep} -P "${pcre_conventional_commit_minor}")" ]] ; then + increment='minor' + found_match='true' + elif [[ -n "$(echo "${commit_message}" | ${grep} -P "${pcre_conventional_commit_patch}")" ]] ; then + increment='patch' + found_match='true' + fi + + if [[ "${found_match}" == 'false' ]] ; then + echo "⚠️ No conventional commit found, defaulting to ${increment} increment" 1>&2 + fi +fi ##==---------------------------------------------------------------------------- ## Version increment diff --git a/version-lookup.sh b/version-lookup.sh index 130ca89..3957688 100755 --- a/version-lookup.sh +++ b/version-lookup.sh @@ -46,7 +46,7 @@ if [[ -z "${current_version:-}" ]] ; then echo "⚠️ No previous release version identified in git tags" # brand new repo! (probably) case "${scheme}" in - semver) + semver | conventional_commits) current_version="0.0.0" ;; calver) From a449b7584857f9dcf45ae8dac92b6addfceb91ad Mon Sep 17 00:00:00 2001 From: Daniel Atanasovski Date: Wed, 20 Mar 2024 15:41:30 +1100 Subject: [PATCH 4/8] test: add tests for new `conventional_commits` scheme --- tests/test_version-increment.bats | 128 ++++++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) diff --git a/tests/test_version-increment.bats b/tests/test_version-increment.bats index f2da4d7..bdb4834 100644 --- a/tests/test_version-increment.bats +++ b/tests/test_version-increment.bats @@ -272,3 +272,131 @@ function init_repo { [[ "$output" = *"PRE_RELEASE_LABEL=pre.${short_ref}"* ]] && [[ "$output" = *"VERSION=$(date +%Y.%-m.1)+pre.${short_ref}"* ]] } + +@test "increments the patch version after a fix commit (conventional commits)" { + init_repo + + export current_version=1.2.3 + export scheme="conventional_commits" + + echo "fix: something" > fix.txt + git add fix.txt + git commit -m "fix: something" + + run ../../version-increment.sh + + print_run_info + [ "$status" -eq 0 ] && + [[ "$output" = *"VERSION=1.2.4"* ]] + [[ "$output" != *"No conventional commit found"* ]] +} + + +@test "increments the patch version after a scoped fix commit (conventional commits)" { + init_repo + + export current_version=1.2.3 + export scheme="conventional_commits" + + echo "fix: something" > fix.txt + git add fix.txt + git commit -m "fix(api): something" + + run ../../version-increment.sh + + print_run_info + [ "$status" -eq 0 ] && + [[ "$output" = *"VERSION=1.2.4"* ]] + [[ "$output" != *"No conventional commit found"* ]] +} + +@test "increments the major version after a breaking fix commit (conventional commits)" { + init_repo + + export current_version=1.2.3 + export scheme="conventional_commits" + + echo "fix: breaking something" > fix.txt + git add fix.txt + git commit -m "fix!: something" + + run ../../version-increment.sh + + print_run_info + [ "$status" -eq 0 ] && + [[ "$output" = *"VERSION=2.0.0"* ]] + [[ "$output" != *"No conventional commit found"* ]] +} + +@test "increments the minor version after a feat commit (conventional commits)" { + init_repo + + export current_version=1.2.3 + export scheme="conventional_commits" + + echo "new feature" > feat.txt + git add feat.txt + git commit -m "feat: something" + + run ../../version-increment.sh + + print_run_info + [ "$status" -eq 0 ] && + [[ "$output" = *"VERSION=1.3.0"* ]] + [[ "$output" != *"No conventional commit found"* ]] +} + +@test "increments the major version after a breaking feat commit (conventional commits)" { + init_repo + + export current_version=1.2.3 + export scheme="conventional_commits" + + echo "breaking new feature" > feat.txt + git add feat.txt + git commit -m "feat!: something" + + run ../../version-increment.sh + + print_run_info + [ "$status" -eq 0 ] && + [[ "$output" = *"VERSION=2.0.0"* ]] + [[ "$output" != *"No conventional commit found"* ]] +} + +@test "increments the major version after a breaking change in the commit body (conventional commits)" { + init_repo + + export current_version=1.2.3 + export scheme="conventional_commits" + + echo "breaking new fix" > feat.txt + git add feat.txt + git commit -m "Fix: something + BREAKING CHANGE: really important" + + run ../../version-increment.sh + + print_run_info + [ "$status" -eq 0 ] && + [[ "$output" = *"VERSION=2.0.0"* ]] + [[ "$output" != *"No conventional commit found"* ]] +} + +@test "increments the patch version by default if no conventional commits found and enabled (conventional commits)" { + init_repo + + export current_version=1.2.3 + export scheme="conventional_commits" + + echo "some new change" > feat.txt + git add feat.txt + git commit -m "new change" + + run ../../version-increment.sh + + print_run_info + [ "$status" -eq 0 ] && + [[ "$output" = *"VERSION=1.2.4"* ]] + [[ "$output" = *"No conventional commit found"* ]] +} From 352a9961c852fdfb3478f31a9d59afa6c23568c6 Mon Sep 17 00:00:00 2001 From: Phil Jay Date: Tue, 23 Apr 2024 17:13:22 +1000 Subject: [PATCH 5/8] Update action.yml for README --- action.yml | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/action.yml b/action.yml index 268e5b0..6fcbc22 100644 --- a/action.yml +++ b/action.yml @@ -11,11 +11,11 @@ inputs: description: | Versioning scheme - semver, calver or conventional_commits (defaults to semver). - `conventional_commits` Will parse the last commit message to determine the increment type. - Supports the following increment types: + `conventional_commits` Will parse the last commit message (e.g. the merge commit) to + determine the increment type, and supports the following increment types by keyword: - patch (build, chore, ci, docs, fix, perf, refactor, revert, style, test) - minor (feat) - - Major (any of the above types with an '!' or 'BREAKING CHANGE:' in commit body) + - major (any of the above keywords followed by a '!' character, or 'BREAKING CHANGE:' in commit body) required: false default: 'semver' pep440: @@ -26,6 +26,9 @@ inputs: description: | Field to increment - major, minor, or, patch (defaults to patch) + If using the `conventional_commits` scheme, this is the default increment if the parsing of the merge commit fails to + find conventional commits information + Not applicable to `calver` scheme required: false default: 'patch' From 73ade5516c4c6327a12b7981b2f554c05316c6a2 Mon Sep 17 00:00:00 2001 From: Phil Jay Date: Tue, 23 Apr 2024 17:17:01 +1000 Subject: [PATCH 6/8] Update version-increment.sh for old comment --- version-increment.sh | 1 - 1 file changed, 1 deletion(-) diff --git a/version-increment.sh b/version-increment.sh index 66e8c06..e76c091 100755 --- a/version-increment.sh +++ b/version-increment.sh @@ -61,7 +61,6 @@ fi ##==---------------------------------------------------------------------------- ## Conventional commits -# If calver is set, raise a warning if [[ "${scheme}" == 'conventional_commits' ]] ; then # Get message from given commit commit_message=$(git log -1 --pretty=format:%B "${git_commit_sha}") From c6ea11748a1406b148ee69c7642180d9a40fa0c3 Mon Sep 17 00:00:00 2001 From: Phil Jay Date: Tue, 23 Apr 2024 17:34:47 +1000 Subject: [PATCH 7/8] Update README.md for conventional commits --- README.md | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 82988f2..90707cb 100644 --- a/README.md +++ b/README.md @@ -70,6 +70,22 @@ If the current latest normal version is not the current year and month, then the year and month digits will be set to the current year and month, and the release digit will be reset to 1. +### Conventional Commits (semver with smarts) 💡 + +If you choose the conventional commits scheme, the action will parse the last commit message _(usually the merge commit)_ to determine +the increment type for a `semver` version. + +The following increment types by keyword are supported: + - patch: build, chore, ci, docs, fix, perf, refactor, revert, style, test + - minor: feat + - major: any of the above keywords followed by a '!' character, or 'BREAKING CHANGE:' in commit body + +If none of the keywords are detected, then the increment specified by the `increment` input will be used (defaults to patch). + +> [!TIP] +> You might like to _enforce_ conventional commits in the title of your pull requests to ensure that the merge commit has the correct +> information. Something like this action might be handy: https://github.com/marketplace/actions/conventional-commit-in-pull-requests + ### Default branch vs. any other branch 🎋 **Default branch** @@ -107,7 +123,7 @@ Examples: | name | description | required | default | | :--- | :--- | :--- | :--- | -| scheme | The versioning scheme in-use, either `semver` or `calver` | No | `semver` | +| scheme | The versioning scheme in-use, either `semver`, `calver` or `conventional_commits` | No | `semver` | | pep440 | Set to `true` for PEP440 compatibility of _pre-release_ versions by making use of the build metadata segment of semver, which maps to local version identifier in PEP440 | No | `false` | | increment | The digit to increment, either `major`, `minor` or `patch`, ignored if `scheme` == `calver` | No | `patch` | | release_branch | Specify a non-default branch to use for the release tag (the one without -pre) | No | | From 81805365e19ee23f3eaa815e4662c86ade1e2825 Mon Sep 17 00:00:00 2001 From: Phil Jay Date: Tue, 23 Apr 2024 17:37:34 +1000 Subject: [PATCH 8/8] Update README.md for version bump --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 90707cb..36e23e1 100644 --- a/README.md +++ b/README.md @@ -30,7 +30,7 @@ use the API mode: ```yaml - name: Get next version - uses: reecetech/version-increment@2023.10.1 + uses: reecetech/version-increment@2024.4.1 id: version with: use_api: true