diff --git a/.gitea/workflows/release.yml b/.gitea/workflows/release.yml index b6d11f1..2b615f9 100644 --- a/.gitea/workflows/release.yml +++ b/.gitea/workflows/release.yml @@ -5,6 +5,10 @@ on: tags: - 'v*' +concurrency: + group: release-${{ github.ref_name }} + cancel-in-progress: false + jobs: release: runs-on: ubuntu-latest @@ -38,11 +42,52 @@ jobs: TAG: ${{ steps.ver.outputs.tag }} run: | set -euo pipefail - git clone --depth 1 --branch "$TAG" \ + # Full clone (with tags) so release notes can diff against the previous tag. + git clone --branch "$TAG" \ "https://oauth2:${TOKEN}@git.kuns.dev/${REPO}.git" \ "$WORK/src" git -C "$WORK/src" log -1 --oneline + - name: Generate release notes + env: + WORK: ${{ steps.ws.outputs.dir }} + TAG: ${{ steps.ver.outputs.tag }} + run: | + set -euo pipefail + cd "$WORK/src" + + PREV="$(git tag --sort=v:refname | grep -E '^v' \ + | awk -v t="$TAG" '$0==t{print prev} {prev=$0}')" + if [ -n "$PREV" ]; then + RANGE="${PREV}..${TAG}" + else + RANGE="$TAG" + fi + + emit_group() { + # $1 conventional-type, $2 heading + local lines + lines="$(git log "$RANGE" --no-merges --pretty=format:'%s|%h' \ + | grep -E "^${1}(\([^)]*\))?(!)?: " || true)" + [ -z "$lines" ] && return 0 + printf '### %s\n\n' "$2" + while IFS='|' read -r subject hash; do + printf -- '- %s (%s)\n' "${subject#*: }" "$hash" + done <<< "$lines" + printf '\n' + } + + { + emit_group feat "Features" + emit_group fix "Fixes" + emit_group perf "Performance" + emit_group refactor "Refactoring" + emit_group docs "Documentation" + } > RELEASE_NOTES.md + + echo "--- release notes ---" + cat RELEASE_NOTES.md + - name: Publish ClaudeDo.App (win-x64, self-contained) env: WORK: ${{ steps.ws.outputs.dir }} @@ -128,7 +173,8 @@ jobs: BODY=$(jq -n \ --arg tag "$TAG" \ --arg name "$TAG" \ - '{tag_name:$tag, name:$name, body:"", draft:false, prerelease:false, target_commitish:"main"}') + --rawfile body "$WORK/src/RELEASE_NOTES.md" \ + '{tag_name:$tag, name:$name, body:$body, draft:true, prerelease:false, target_commitish:"main"}') RESP=$(curl -sS -X POST \ -H "Authorization: token ${TOKEN}" \ -H "Content-Type: application/json" \ @@ -166,6 +212,32 @@ jobs: done echo "All assets uploaded." + - name: Publish release + env: + RELEASE_ID: ${{ steps.release.outputs.release_id }} + TOKEN: ${{ secrets.GITEA_TOKEN }} + run: | + set -euo pipefail + curl -sS --fail-with-body -X PATCH \ + -H "Authorization: token ${TOKEN}" \ + -H "Content-Type: application/json" \ + -d '{"draft":false}' \ + "${GITEA_API}/repos/${REPO}/releases/${RELEASE_ID}" \ + > /dev/null + echo "Release ${RELEASE_ID} published." + + - name: Delete draft release on failure + if: failure() && steps.release.outputs.release_id != '' + env: + RELEASE_ID: ${{ steps.release.outputs.release_id }} + TOKEN: ${{ secrets.GITEA_TOKEN }} + run: | + curl -sS -X DELETE \ + -H "Authorization: token ${TOKEN}" \ + "${GITEA_API}/repos/${REPO}/releases/${RELEASE_ID}" \ + > /dev/null || true + echo "Cleaned up draft release ${RELEASE_ID}." + - name: Cleanup workspace if: always() env: diff --git a/.gitignore b/.gitignore index 54868af..58292ca 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,9 @@ # Local dev worktrees (created by using-git-worktrees skill) .worktrees/ +# Brainstorming visual companion artifacts +.superpowers/ + # .NET build output bin/ obj/