diff --git a/.github/workflows/autotag.yml b/.github/workflows/autotag.yml new file mode 100644 index 000000000..6eef2eedc --- /dev/null +++ b/.github/workflows/autotag.yml @@ -0,0 +1,80 @@ +name: autotag + +# main push 마다 Conventional Commits 기준으로 다음 SemVer 태그를 자동 생성한다. +# feat! / BREAKING CHANGE → major (vX+1.0.0) +# feat: → minor (vX.Y+1.0) +# 그 외 전부 (fix/docs/...) → patch (vX.Y.Z+1) ← 매 push 최소 1칸 보장 +# install.hexa(최신 v* 태그 빌드)가 이 태그를 그대로 소비 → 누구나 동일 최신 빌드. +# GITHUB_TOKEN 으로 푸시한 태그는 다른 워크플로를 재트리거하지 않음(루프 방지). + +on: + push: + branches: [void/main] + +permissions: + contents: write + +concurrency: + group: autotag-${{ github.ref }} + cancel-in-progress: false + +jobs: + autotag: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + fetch-tags: true + + - name: Compute + push next SemVer tag + shell: bash + run: | + set -euo pipefail + + # 최신 semver 태그 (없으면 v0.0.0 부터 시작). + last="$(git tag --list 'v*' --sort=-v:refname | head -1)" + [ -z "$last" ] && last="v0.0.0" + base="${last#v}" + IFS=. read -r MA MI PA <<<"$base" + MA="${MA:-0}"; MI="${MI:-0}"; PA="${PA:-0}" + + # 마지막 태그 이후 커밋 메시지 수집 (태그가 실재할 때만 범위 한정). + if git rev-parse -q --verify "refs/tags/${last}" >/dev/null 2>&1; then + range="${last}..HEAD" + else + range="HEAD" + fi + msgs="$(git log --format='%s%x1f%b%x1e' "$range")" + + # ── ATLAS-PATCH HOOK (hexa-lang) ───────────────────────────── + # 기본 generic: 아래 줄은 no-op. hexa-lang 에서는 atlas builtin 추가가 + # 매우 잦으므로 minor 가 아니라 patch 로만 올린다 — feat(atlas)/atlas + # register/embedded.gen.hexa 변경은 minor 판정에서 제외한다. + ATLAS_PATCH_ONLY=0 # hexa-lang 에서만 1 로 켠다. + + bump=patch + if grep -qE '[a-z]+(\([^)]*\))?!:' <<<"$msgs" || grep -q 'BREAKING CHANGE' <<<"$msgs"; then + bump=major + else + feats="$(grep -oE 'feat(\([^)]*\))?:' <<<"$msgs" || true)" + if [ "$ATLAS_PATCH_ONLY" = "1" ]; then + # atlas 스코프 feat 는 제외하고 남은 feat 가 있을 때만 minor. + feats="$(grep -vE 'feat\(atlas\)' <<<"$feats" || true)" + fi + [ -n "$feats" ] && bump=minor + fi + + case "$bump" 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 "last=$last bump=$bump next=$next" + + if git rev-parse -q --verify "refs/tags/${next}" >/dev/null 2>&1; then + echo "tag ${next} already exists — skip"; exit 0 + fi + git tag "$next" "${GITHUB_SHA}" + git push origin "$next"