Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
112 changes: 112 additions & 0 deletions .github/workflows/auto-tags.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
name: Auto tag from PR labels

on:
pull_request:
types: [closed]
branches: [main]

permissions:
contents: write

jobs:
tag:
if: github.event.pull_request.merged == true
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0

- name: Fetch tags
run: git fetch --tags --force

- name: Determine bump from PR labels
id: bump
shell: bash
env:
PR_LABELS: ${{ toJson(github.event.pull_request.labels) }}
run: |
labels=$(echo "$PR_LABELS" | jq -r '.[].name' | tr '[:upper:]' '[:lower:]')
echo "PR labels: $labels"

# If 'no-tag' present, skip tagging entirely.
if echo "$labels" | grep -q '\bno-tag\b'; then
echo "skip=true" >> "$GITHUB_OUTPUT"
echo "Tagging skipped due to 'no-tag' label."
exit 0
fi

level="patch" # default
if echo "$labels" | grep -q '\bmajor\b'; then level="major"
elif echo "$labels" | grep -q '\bminor\b'; then level="minor"
elif echo "$labels" | grep -q '\bpatch\b'; then level="patch"
fi

echo "level=$level" >> "$GITHUB_OUTPUT"
echo "Selected bump: $level"

- name: Compute next tag
id: next
if: steps.bump.outputs.skip != 'true'
shell: bash
env:
LEVEL: ${{ steps.bump.outputs.level }}
run: |
latest="$(git tag --list 'v*.*.*' | sort -V | tail -n1)"
if [[ -z "$latest" ]]; then
latest="v0.1.0"
echo "No previous tag; starting at $latest"
fi
ver="${latest#v}"
IFS='.' read -r MA MI PA <<<"$ver"

case "$LEVEL" in
major) MA=$((MA+1)); MI=0; PA=0 ;;
minor) MI=$((MI+1)); PA=0 ;;
patch|*) PA=$((PA+1)) ;;
esac

next="v${MA}.${MI}.${PA}"
echo "next=$next" >> "$GITHUB_OUTPUT"
echo "latest=$latest -> next=$next"

- name: Tag and push
if: steps.bump.outputs.skip != 'true'
env:
NEXT: ${{ steps.next.outputs.next }}
run: |
if git rev-parse -q --verify "refs/tags/${NEXT}" >/dev/null; then
echo "Tag ${NEXT} already exists; nothing to do."
exit 0
fi
git config user.name "github-actions[bot]"
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
git tag -a "$NEXT" -m "chore(release): $NEXT"
git push origin "$NEXT"

- name: Comment with result
if: steps.bump.outputs.skip != 'true'
uses: actions/github-script@v7
with:
script: |
const next = '${{ steps.next.outputs.next }}';
const level = '${{ steps.bump.outputs.level }}';
github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.payload.pull_request.number,
body: `🔖 Released **${next}** (bump: \`${level}\`).`
});

- name: Comment: tagging skipped
if: steps.bump.outputs.skip == 'true'
uses: actions/github-script@v7
with:
script: |
github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.payload.pull_request.number,
body: `⏭️ Tag creation skipped due to \`no-tag\` label.`
});