diff --git a/.github/workflows/test-and-release.yml b/.github/workflows/test-and-release.yml index 1a2bc92..95e4963 100644 --- a/.github/workflows/test-and-release.yml +++ b/.github/workflows/test-and-release.yml @@ -13,7 +13,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout code - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Run ShellCheck uses: ludeeus/action-shellcheck@2.0.0 @@ -24,7 +24,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout code - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Setup bats uses: mig4/setup-bats@af9a00deb21b5d795cabfeaa8d9060410377686d # v1.2.0 @@ -34,14 +34,85 @@ jobs: - name: Test run: bats tests/*.bats - release: + test-api-mode: # requires github API, didn't want to mock it + runs-on: ubuntu-latest + env: + github_token: ${{ github.token }} + steps: + - name: Checkout code # have to checkout to have the source code available + uses: actions/checkout@v4 + + - name: Remove .git directory # remove the git directory to make the testing valid + run: rm -rf .git/ + + - name: Test lookup version (with API) + id: version-lookup + env: + use_api: 'true' + run: ./version-lookup.sh + + - name: Check lookup result + shell: bash + run: '[[ -n "${{ steps.version-lookup.outputs.CURRENT_VERSION }}" ]]' + + - name: Test increment version (with API) + id: version-increment + run: ./version-increment.sh + env: + current_version: ${{ steps.version-lookup.outputs.CURRENT_VERSION }} + scheme: calver + use_api: 'true' + + - name: Check increment result + shell: bash + run: '[[ "$(date +%Y.%m)" == "$(echo "${{ steps.version-increment.outputs.VERSION }}" | cut -d "." -f 1-2)" ]]' + + test-action-yml: # integration testing needs: - lint - test + - test-api-mode + runs-on: ubuntu-latest + steps: + - name: Checkout code # have to checkout to have the source code available + uses: actions/checkout@v4 + + - name: Remove .git directory # remove the git directory to make the testing valid + run: rm -rf .git/ + + - name: Get next version via API + uses: ./ + id: version-via-api + with: + scheme: 'calver' + use_api: true + + - name: Checkout code + uses: actions/checkout@v4 + + - name: Get next version via Git + uses: ./ + id: version-via-git + with: + scheme: 'calver' + use_api: false + + - name: Check results agree + shell: bash + run: | + [[ "${{ steps.version-via-api.outputs.current-version }}" == "${{ steps.version-via-git.outputs.current-version }}" ]] + [[ "${{ steps.version-via-api.outputs.major-version }}" == "${{ steps.version-via-git.outputs.major-version }}" ]] + [[ "${{ steps.version-via-api.outputs.minor-version }}" == "${{ steps.version-via-git.outputs.minor-version }}" ]] + [[ "${{ steps.version-via-api.outputs.patch-version }}" == "${{ steps.version-via-git.outputs.patch-version }}" ]] + # Don't test the full version or pre-version, since the number of digits is likely to be different (9 via api vs. 7 via git) + + release: + needs: + - test-action-yml runs-on: ubuntu-latest steps: - name: Checkout code - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Lookup version id: version-lookup diff --git a/README.md b/README.md index 4fadaea..82988f2 100644 --- a/README.md +++ b/README.md @@ -1,12 +1,12 @@ -# ➕ Version Increment +# Version Increment ➕ -## 📄 Use +## Use 📄 -### ⌨️ Example +### Example ⌨️ ```yaml - name: Checkout code - uses: actions/checkout@v2 + uses: actions/checkout@v4 - name: Get next version uses: reecetech/version-increment@2023.9.3 @@ -23,7 +23,20 @@ context: . ``` -### 🔖 semver +#### API mode 🔗 + +Maybe you don't want to checkout your code in the job that calculates the version number. That's okay, you can +use the API mode: + +```yaml + - name: Get next version + uses: reecetech/version-increment@2023.10.1 + id: version + with: + use_api: true +``` + +### semver 🔖 This action will detect the current latest _normal_ semantic version (semver) from the tags in a git repository. It will increment the version as directed (by default: +1 to @@ -37,7 +50,7 @@ e.g. `1.2.7` See: https://semver.org/spec/v2.0.0.html -### 📅 calver (semver compliant) +### calver (semver compliant) 📅 Optionally, this action can provide semver compliant calendar versions (calver). In this calver scheme, the semver major, minor and patch digits map to year, @@ -57,7 +70,7 @@ 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. -### 🎋 Default branch vs. any other branch +### Default branch vs. any other branch 🎋 **Default branch** @@ -68,6 +81,17 @@ Examples: * `1.2.7` * `2021.6.2` +You may override the branch to consider the release branch if it is not the default branch, by providing a specific +release branch name as an input. For example: + +```yaml + - name: Get next version + uses: reecetech/version-increment@2023.10.1 + id: version + with: + release_branch: publish +``` + **Any other branch** The action will return a _pre-release_ version if any other branch is detected @@ -79,7 +103,7 @@ Examples: * `1.2.7-pre.41218aa78` * `2021.6.2-pre.32fd19841` -### 📥 Inputs +### Inputs 📥 | name | description | required | default | | :--- | :--- | :--- | :--- | @@ -87,8 +111,9 @@ Examples: | 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 | | +| use_api | Use the GitHub API to discover current tags, which avoids the need for a git checkout, but requires `curl` and `jq` | No | `false` | -### 📤 Outputs +### Outputs 📤 | name | description | | :--- | :--- | @@ -104,7 +129,7 @@ Examples: | minor-v-version | Minor number of the incremented version, prefixed with a `v` character | | patch-v-version | Patch number of the incremented version, prefixed with a `v` character | -## 💕 Contributing +## Contributing 💕 Please raise a pull request, but note the testing tools below diff --git a/action.yml b/action.yml index 7b51a8f..b4a1e60 100644 --- a/action.yml +++ b/action.yml @@ -26,6 +26,10 @@ inputs: description: 'Specify a non-default branch to use for the release tag (the one without -pre)' required: false type: string + use_api: + description: 'Use the GitHub API to discover current tags, which avoids the need for a git checkout, but requires `curl` and `jq`' + required: false + default: false outputs: current-version: @@ -69,7 +73,9 @@ runs: run: ${{ github.action_path }}/version-lookup.sh shell: bash env: + github_token: ${{ github.token }} scheme: ${{ inputs.scheme }} + use_api: ${{ inputs.use_api }} - id: version-increment run: ${{ github.action_path }}/version-increment.sh @@ -77,6 +83,8 @@ runs: env: current_version: ${{ steps.version-lookup.outputs.CURRENT_VERSION }} increment: ${{ inputs.increment }} + github_token: ${{ github.token }} pep440: ${{ inputs.pep440 }} scheme: ${{ inputs.scheme }} release_branch: ${{ inputs.release_branch }} + use_api: ${{ inputs.use_api }} diff --git a/shared.sh b/shared.sh index ee14092..e1c97e6 100644 --- a/shared.sh +++ b/shared.sh @@ -27,6 +27,20 @@ if [[ "${pep440}" != 'false' && "${pep440}" != 'true' ]] ; then input_errors='true' fi +use_api="${use_api:-false}" +if [[ "${use_api}" != 'false' && "${use_api}" != 'true' ]] ; then + echo "🛑 Value of 'use_api' is not valid, choose from 'false' or 'true'" 1>&2 + input_errors='true' +fi + +if [[ "${use_api}" == 'true' ]] ; then + if [[ -z "${github_token:-}" ]] ; then + echo "🛑 'use_api' is true, but environment variable 'github_token' is not set" 1>&2 + input_errors='true' + fi +fi + + ##==---------------------------------------------------------------------------- ## MacOS compatibility - for local testing diff --git a/version-increment.sh b/version-increment.sh index db956e6..7036524 100755 --- a/version-increment.sh +++ b/version-increment.sh @@ -28,20 +28,34 @@ fi ## Git info - branch names, commit short ref default_branch='main' -# if we're _not_ testing, then _actually_ check the origin -if [[ -z "${BATS_VERSION:-}" ]] ; then - default_branch="$(git remote show origin | ${grep} 'HEAD branch' | cut -d ' ' -f 5)" -fi # use release_branch if not empty if [[ -n "${release_branch:-}" ]] ; then default_branch="${release_branch}" +elif [[ -z "${BATS_VERSION:-}" ]] ; then + # if we're _not_ testing, then _actually_ check the origin + if [[ "${use_api:-}" == 'true' ]] ; then + default_branch="$( + curl -fsSL \ + -H "Accept: application/vnd.github+json" \ + -H "Authorization: Bearer ${github_token}" \ + -H "X-GitHub-Api-Version: 2022-11-28" \ + "${GITHUB_API_URL}/repos/${GITHUB_REPOSITORY}" \ + | jq -r '.default_branch' + )" + else + default_branch="$(git remote show origin | ${grep} 'HEAD branch' | cut -d ' ' -f 5)" + fi fi current_ref="${GITHUB_REF:-}" -git_commit="$(git rev-parse --short HEAD | sed 's/0*//')" # trim leading zeros, because semver doesn't allow that in - # the 'pre-release version' part, but we can't use the + char - # to make it 'build metadata' as that's not supported in K8s - # labels + +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 + # shellcheck disable=SC2001 + 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 ##==---------------------------------------------------------------------------- ## Version increment diff --git a/version-lookup.sh b/version-lookup.sh index 45ed51c..58c3fae 100755 --- a/version-lookup.sh +++ b/version-lookup.sh @@ -25,16 +25,33 @@ fi ##==---------------------------------------------------------------------------- ## Get tags from GitHub repo -# Skip if testing, otherwise pull tags +# Skip if testing, or if use_api is true, otherwise pull tags if [[ -z "${BATS_VERSION:-}" ]] ; then - git fetch --quiet --force origin 'refs/tags/*:refs/tags/*' + if [[ "${use_api:-}" != 'true' ]] ; then + git fetch --quiet --force origin 'refs/tags/*:refs/tags/*' + fi fi ##==---------------------------------------------------------------------------- ## Version parsing # detect current version - removing "v" from start of tag if it exists -current_version="$(git tag -l | { ${grep} -P "${pcre_allow_vprefix}" || true; } | sed 's/^v//g' | sort -V | tail -n 1)" +if [[ "${use_api:-}" == 'true' ]] ; then + current_version="$( + curl -fsSL \ + -H "Accept: application/vnd.github+json" \ + -H "Authorization: Bearer ${github_token}" \ + -H "X-GitHub-Api-Version: 2022-11-28" \ + "${GITHUB_API_URL}/repos/${GITHUB_REPOSITORY}/git/matching-refs/tags/" \ + | jq -r '.[].ref' | sed 's|refs/tags/||g' \ + | { ${grep} -P "${pcre_allow_vprefix}" || true; } | sed 's/^v//g' | sort -V | tail -n 1 + )" +else + current_version="$( + git tag -l \ + | { ${grep} -P "${pcre_allow_vprefix}" || true; } | sed 's/^v//g' | sort -V | tail -n 1 + )" +fi # support transition from an old reecetech calver style (yyyy-mm-Rr, where R is the literal `R`, and r is the nth release for the month) if [[ -z "${current_version:-}" ]] ; then