mirror of
https://github.com/MSWS/TTT.git
synced 2025-12-07 23:06:33 -08:00
Compare commits
5 Commits
0.10.0-dev
...
0.10.2
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
721504f612 | ||
|
|
86c24533b5 | ||
|
|
eba49139c2 | ||
|
|
d33550a5a4 | ||
|
|
453ce77711 |
140
.github/workflows/release.yml
vendored
140
.github/workflows/release.yml
vendored
@@ -12,10 +12,18 @@ permissions:
|
||||
jobs:
|
||||
auto-release:
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
# Tweak these if you want a different model or style
|
||||
OPENAI_MODEL: gpt-4o-mini
|
||||
OPENAI_TEMPERATURE: "0.2"
|
||||
# Safety: cap how many characters we feed to the model
|
||||
MAX_CHANGELOG_CHARS: "50000"
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v5
|
||||
with:
|
||||
fetch-depth: 0
|
||||
fetch-tags: true
|
||||
|
||||
# 1. Calculate version using GitVersion
|
||||
- name: Install GitVersion
|
||||
@@ -48,7 +56,7 @@ jobs:
|
||||
run: |
|
||||
cd build/TTT
|
||||
zip -r TTT-${{ steps.gitversion.outputs.fullSemVer }}.zip *
|
||||
|
||||
|
||||
# 2. Get latest tag
|
||||
- name: Get latest tag
|
||||
id: latest_tag
|
||||
@@ -68,27 +76,131 @@ jobs:
|
||||
git tag ${{ steps.gitversion.outputs.fullSemVer }}
|
||||
git push origin ${{ steps.gitversion.outputs.fullSemVer }}
|
||||
|
||||
# 4. Determine previous tag for changelog
|
||||
# 4. Determine previous relevant tag (lineage-aware)
|
||||
- name: Determine previous relevant tag
|
||||
id: prev_tag
|
||||
run: |
|
||||
set -euo pipefail
|
||||
branch="${GITHUB_REF_NAME}"
|
||||
if [[ "$branch" == "main" ]]; then
|
||||
prev=$(git tag --sort=-creatordate | grep -E '^[0-9]+\.[0-9]+\.[0-9]+$' | sed -n 2p)
|
||||
else
|
||||
prev=$(git tag --sort=-creatordate | grep -E '^[0-9]+\.[0-9]+\.[0-9]+-' | sed -n 2p)
|
||||
fi
|
||||
echo "tag=${prev:-0.0.0}" >> $GITHUB_OUTPUT
|
||||
|
||||
# 5. Generate changelog
|
||||
# Use HEAD^ to skip the tag we just created. If no parent, fall back to HEAD.
|
||||
if git rev-parse --verify -q HEAD^ >/dev/null; then
|
||||
base_rev="HEAD^"
|
||||
else
|
||||
base_rev="HEAD"
|
||||
fi
|
||||
|
||||
# Match stable tags on main and prerelease tags on non-main
|
||||
if [[ "$branch" == "main" ]]; then
|
||||
pattern='[0-9]*.[0-9]*.[0-9]*'
|
||||
else
|
||||
pattern='[0-9]*.[0-9]*.[0-9]*-*'
|
||||
fi
|
||||
|
||||
# Nearest tag reachable on this lineage, not just "second most recent by date"
|
||||
prev=$(git describe --tags --abbrev=0 --match "$pattern" --tags "$base_rev" 2>/dev/null || true)
|
||||
|
||||
echo "tag=${prev:-0.0.0}" >> "$GITHUB_OUTPUT"
|
||||
|
||||
|
||||
# 5. Generate changelog using local git (no compare API)
|
||||
- name: Generate changelog
|
||||
run: |
|
||||
gh api repos/${{ github.repository }}/compare/${{ steps.prev_tag.outputs.tag }}...${{ steps.gitversion.outputs.fullSemVer }} \
|
||||
--jq '.commits[].commit.message' > CHANGELOG.md
|
||||
env:
|
||||
GH_TOKEN: ${{ github.token }}
|
||||
set -euo pipefail
|
||||
|
||||
# 6. Create release
|
||||
prev="${{ steps.prev_tag.outputs.tag }}"
|
||||
curr="${{ steps.gitversion.outputs.fullSemVer }}"
|
||||
|
||||
# Choose what you want in the raw feed: %s = subject only, %B = full message
|
||||
GIT_LOG_FORMAT='%s'
|
||||
|
||||
if [[ "$prev" == "0.0.0" ]]; then
|
||||
# First release: whole history to this tag, first-parent to reflect main’s narrative
|
||||
git log --first-parent --no-merges --format="${GIT_LOG_FORMAT}" --reverse "$curr" > CHANGELOG.md
|
||||
else
|
||||
# Strict range between the previous reachable tag and the new tag on this lineage
|
||||
git log --first-parent --no-merges --format="${GIT_LOG_FORMAT}" --reverse "$prev..$curr" > CHANGELOG.md
|
||||
fi
|
||||
|
||||
# Fallback in case nothing was captured
|
||||
if [[ ! -s CHANGELOG.md ]]; then
|
||||
echo "No commits found between $prev and $curr on first-parent. Using full messages without first-parent filter." >&2
|
||||
if [[ "$prev" == "0.0.0" ]]; then
|
||||
git log --no-merges --format="${GIT_LOG_FORMAT}" --reverse "$curr" > CHANGELOG.md
|
||||
else
|
||||
git log --no-merges --format="${GIT_LOG_FORMAT}" --reverse "$prev..$curr" > CHANGELOG.md
|
||||
fi
|
||||
fi
|
||||
|
||||
cat CHANGELOG.md
|
||||
|
||||
# 5b. Rewrite changelog with OpenAI
|
||||
- name: Rewrite changelog with OpenAI
|
||||
id: ai_changelog
|
||||
if: success()
|
||||
env:
|
||||
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
|
||||
OPENAI_MODEL: ${{ env.OPENAI_MODEL }}
|
||||
OPENAI_TEMPERATURE: ${{ env.OPENAI_TEMPERATURE }}
|
||||
MAX_CHANGELOG_CHARS: ${{ env.MAX_CHANGELOG_CHARS }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
|
||||
# Ensure we have a changelog to work with
|
||||
if [[ ! -s CHANGELOG.md ]]; then
|
||||
echo "CHANGELOG.md is empty. Skipping AI rewrite."
|
||||
echo "skipped=true" >> $GITHUB_OUTPUT
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Trim the input to a safe size for token limits
|
||||
head -c "${MAX_CHANGELOG_CHARS}" CHANGELOG.md > CHANGELOG_RAW.md
|
||||
|
||||
# Build the JSON body. We feed system guidance and the raw changelog
|
||||
# See OpenAI Responses API docs for the schema and output_text helper. :contentReference[oaicite:0]{index=0}
|
||||
jq -Rs --arg sys "You are an expert release-notes editor. Rewrite the text so it is grouped by Features, Fixes, Docs, and Chore. Use clear user-facing language. Remove internal ticket IDs and commit hashes unless essential. Merge duplicates. Use imperative voice. Output valid Markdown only. Include a short summary at the top." \
|
||||
--arg temp "${OPENAI_TEMPERATURE}" \
|
||||
--arg model "${OPENAI_MODEL}" \
|
||||
'{model:$model, temperature: ($temp|tonumber), input:[{role:"system", content:$sys},{role:"user", content:.}]}' CHANGELOG_RAW.md > request.json
|
||||
|
||||
# Call the API
|
||||
# Basic retry on transient failures
|
||||
for i in 1 2 3; do
|
||||
HTTP_CODE=$(curl -sS -w "%{http_code}" -o ai_response.json \
|
||||
https://api.openai.com/v1/responses \
|
||||
-H "Content-Type: application/json" \
|
||||
-H "Authorization: Bearer $OPENAI_API_KEY" \
|
||||
--data-binary @request.json) && break || true
|
||||
echo "Call attempt $i failed with HTTP $HTTP_CODE"
|
||||
sleep $((i*i))
|
||||
done
|
||||
|
||||
if [[ "${HTTP_CODE:-000}" -lt 200 || "${HTTP_CODE:-000}" -ge 300 ]]; then
|
||||
echo "OpenAI API call failed with HTTP $HTTP_CODE. Keeping raw changelog."
|
||||
echo "skipped=true" >> $GITHUB_OUTPUT
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Prefer output_text if present. Fallback to first text item. :contentReference[oaicite:1]{index=1}
|
||||
if jq -e '.output_text' ai_response.json >/dev/null; then
|
||||
jq -r '.output_text' ai_response.json > CHANGELOG.md
|
||||
else
|
||||
jq -r '.output[0].content[] | select(.type=="output_text") | .text' ai_response.json | sed '/^[[:space:]]*$/d' > CHANGELOG.md
|
||||
fi
|
||||
|
||||
# If the rewrite somehow produced an empty file, keep the raw one
|
||||
if [[ ! -s CHANGELOG.md ]]; then
|
||||
echo "AI returned empty content. Restoring raw changelog."
|
||||
mv CHANGELOG_RAW.md CHANGELOG.md
|
||||
echo "skipped=true" >> $GITHUB_OUTPUT
|
||||
exit 0
|
||||
fi
|
||||
|
||||
echo "skipped=false" >> $GITHUB_OUTPUT
|
||||
echo "Rewritten changelog:"
|
||||
cat CHANGELOG.md
|
||||
|
||||
# 6. Create release using the (possibly rewritten) changelog
|
||||
- name: Create GitHub release
|
||||
uses: softprops/action-gh-release@v2
|
||||
with:
|
||||
|
||||
Reference in New Issue
Block a user