diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index ae336b6..ff352e1 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -27,15 +27,27 @@ jobs: secrets: gh_token: ${{ secrets.GITHUB_TOKEN }} - create-tag: + calculate-tag: needs: determine-version - uses: ./.github/workflows/workflow-create-tag.yml + uses: ./.github/workflows/workflow-compute-next-tag.yml with: target-branch: main version-bump: ${{ needs.determine-version.outputs.version-bump }} secrets: gh_token: ${{ secrets.GITHUB_TOKEN }} + create-tag: + needs: + - determine-version + - calculate-tag + uses: ./.github/workflows/workflow-create-tag.yml + with: + target-branch: main + next-tag: ${{ needs.calculate-tag.outputs.new-tag }} + previous-tag: ${{ needs.calculate-tag.outputs.previous-tag }} + secrets: + gh_token: ${{ secrets.GITHUB_TOKEN }} + create-release: needs: - determine-version diff --git a/.github/workflows/workflow-compute-next-tag.yml b/.github/workflows/workflow-compute-next-tag.yml new file mode 100644 index 0000000..435bf1a --- /dev/null +++ b/.github/workflows/workflow-compute-next-tag.yml @@ -0,0 +1,95 @@ +name: Compute Next Tag + +on: + workflow_call: + inputs: + target-branch: + description: "Branch to fetch before calculating the next tag." + required: false + default: main + type: string + version-bump: + description: "Which part of the semver should be incremented (major/minor/patch)." + required: true + type: string + secrets: + gh_token: + description: "Token passed from caller (defaults to the built-in GITHUB_TOKEN)." + required: false + outputs: + new-tag: + description: "Next tag derived from the latest v* tag and the selected bump." + value: ${{ jobs.calculate.outputs.new-tag }} + previous-tag: + description: "Latest tag used as the base for the next version." + value: ${{ jobs.calculate.outputs.previous-tag }} + +permissions: + contents: read + +jobs: + calculate: + runs-on: ubuntu-latest + permissions: + contents: read + outputs: + new-tag: ${{ steps.compute.outputs.new_tag }} + previous-tag: ${{ steps.compute.outputs.previous_tag }} + steps: + - name: Check out repository with tags + uses: actions/checkout@v4 + with: + ref: ${{ inputs.target-branch }} + fetch-depth: 0 + + - name: Compute next tag + id: compute + env: + VERSION_BUMP_INPUT: ${{ inputs.version-bump }} + run: | + set -euo pipefail + + version_bump="${VERSION_BUMP_INPUT,,}" + case "$version_bump" in + major|minor|patch) ;; + *) + echo "Unsupported version bump '$version_bump'." + exit 1 + ;; + esac + + git fetch --tags + + latest_tag=$(git tag --list 'v*' --sort=-v:refname | head -n1) + if [ -z "$latest_tag" ]; then + latest_tag="v0.0.0" + fi + previous_tag="$latest_tag" + + version="${latest_tag#v}" + IFS='.' read -r major minor patch <<<"$version" + major=${major:-0} + minor=${minor:-0} + patch=${patch:-0} + + case "$version_bump" in + major) + major=$((major + 1)) + minor=0 + patch=0 + ;; + minor) + minor=$((minor + 1)) + patch=0 + ;; + patch) + patch=$((patch + 1)) + ;; + esac + + new_tag="v${major}.${minor}.${patch}" + + { + echo "new_tag=$new_tag" + echo "previous_tag=$previous_tag" + } >> "$GITHUB_OUTPUT" diff --git a/.github/workflows/workflow-create-tag.yml b/.github/workflows/workflow-create-tag.yml index 486b19a..e4af6b9 100644 --- a/.github/workflows/workflow-create-tag.yml +++ b/.github/workflows/workflow-create-tag.yml @@ -8,8 +8,12 @@ on: required: false default: main type: string - version-bump: - description: "Which part of the semver should be incremented (major/minor/patch)." + next-tag: + description: "Explicit tag to create (required)." + required: true + type: string + previous-tag: + description: "Previously released tag that the next tag is based on (required)." required: true type: string secrets: @@ -42,7 +46,8 @@ jobs: - name: Create and push tag id: create env: - VERSION_BUMP_INPUT: ${{ inputs.version-bump }} + NEXT_TAG_INPUT: ${{ inputs.next-tag }} + PREVIOUS_TAG_INPUT: ${{ inputs.previous-tag }} TARGET_BRANCH_INPUT: ${{ inputs.target-branch }} GH_TOKEN: ${{ secrets.gh_token != '' && secrets.gh_token || secrets.GITHUB_TOKEN }} run: | @@ -51,48 +56,23 @@ jobs: git config user.name "github-actions[bot]" git config user.email "github-actions[bot]@users.noreply.github.com" - version_bump="${VERSION_BUMP_INPUT,,}" - case "$version_bump" in - major|minor|patch) ;; - *) - echo "Unsupported version bump '$version_bump'." - exit 1 - ;; - esac - git fetch origin "$TARGET_BRANCH_INPUT" --tags git checkout "$TARGET_BRANCH_INPUT" git pull origin "$TARGET_BRANCH_INPUT" - latest_tag=$(git tag --list 'v*' --sort=-v:refname | head -n1) - if [ -z "$latest_tag" ]; then - latest_tag="v0.0.0" + next_tag_input="${NEXT_TAG_INPUT:-}" + previous_tag_input="${PREVIOUS_TAG_INPUT:-}" + + if [ -z "$next_tag_input" ] || [ -z "$previous_tag_input" ]; then + echo "Both next-tag and previous-tag inputs are required." + exit 1 fi - previous_tag="$latest_tag" - version="${latest_tag#v}" - IFS='.' read -r major minor patch <<<"$version" - major=${major:-0} - minor=${minor:-0} - patch=${patch:-0} - case "$version_bump" in - major) - major=$((major + 1)) - minor=0 - patch=0 - ;; - minor) - minor=$((minor + 1)) - patch=0 - ;; - patch) - patch=$((patch + 1)) - ;; - esac + new_tag="$next_tag_input" + previous_tag="$previous_tag_input" - new_tag="v${major}.${minor}.${patch}" echo "Creating tag $new_tag (previous tag $previous_tag)." - git tag -a "$new_tag" -m "Automated $version_bump release" + git tag -a "$new_tag" -m "Automated release $new_tag" git push origin "$new_tag" echo "::notice title=Tag created::${new_tag} (from ${previous_tag})" diff --git a/README.md b/README.md index b83f5e1..f06ef25 100644 --- a/README.md +++ b/README.md @@ -65,21 +65,46 @@ jobs: ``` ### `workflow-create-tag.yml` -Creates and pushes the next semver tag based on the provided bump. +Creates and pushes the provided tag (no version calculation inside this workflow). **Inputs** - `target-branch` (default `main`): branch to check out before tagging. -- `version-bump` (required): `major`, `minor`, or `patch`. +- `next-tag` (required): tag to create (e.g., `v1.2.3`). +- `previous-tag` (required): previous tag that `next-tag` is based on. **Outputs** - `new-tag`: tag that was created (e.g., `v1.2.3`). -- `previous-tag`: latest existing tag before the bump. +- `previous-tag`: previous tag that was passed in. **Example** ```yaml jobs: create-tag: uses: vinitu-net/github-workflows/.github/workflows/workflow-create-tag.yml@vX.Y.Z + with: + target-branch: main + next-tag: ${{ needs.calculate-tag.outputs.new-tag }} + previous-tag: ${{ needs.calculate-tag.outputs.previous-tag }} + secrets: + gh_token: ${{ secrets.GITHUB_TOKEN }} +``` + +### `workflow-compute-next-tag.yml` +Calculates the next semver tag from the provided bump and latest existing `v*` tag. + +**Inputs** +- `target-branch` (default `main`): branch to check out before reading tags. +- `version-bump` (required): `major`, `minor`, or `patch`. + +**Outputs** +- `new-tag`: computed next tag (e.g., `v1.2.3`). +- `previous-tag`: latest existing tag before the bump (or `v0.0.0` if none). + +**Example** +```yaml +jobs: + calculate-tag: + uses: vinitu-net/github-workflows/.github/workflows/workflow-compute-next-tag.yml@vX.Y.Z with: target-branch: main version-bump: ${{ needs.determine-version.outputs.version-bump }} @@ -134,16 +159,27 @@ jobs: secrets: gh_token: ${{ secrets.GITHUB_TOKEN }} - create-tag: + calculate-tag: needs: [determine-version, merge] if: ${{ needs.merge.outputs.merged == 'true' }} - uses: vinitu-net/github-workflows/.github/workflows/workflow-create-tag.yml@vX.Y.Z + uses: vinitu-net/github-workflows/.github/workflows/workflow-compute-next-tag.yml@vX.Y.Z with: target-branch: main version-bump: ${{ needs.determine-version.outputs.version-bump }} secrets: gh_token: ${{ secrets.GITHUB_TOKEN }} + create-tag: + needs: [determine-version, merge, calculate-tag] + if: ${{ needs.merge.outputs.merged == 'true' }} + uses: vinitu-net/github-workflows/.github/workflows/workflow-create-tag.yml@vX.Y.Z + with: + target-branch: main + next-tag: ${{ needs.calculate-tag.outputs.new-tag }} + previous-tag: ${{ needs.calculate-tag.outputs.previous-tag }} + secrets: + gh_token: ${{ secrets.GITHUB_TOKEN }} + create-release: needs: [merge, create-tag] if: ${{ needs.merge.outputs.merged == 'true' }}