From cb9ecc1e8f9fefd7baa48c0299aebf1abfc2f04d Mon Sep 17 00:00:00 2001 From: Marvin Klerx Date: Fri, 8 May 2026 16:06:33 +0200 Subject: [PATCH 1/3] generate changelog --- .github/workflows/changelog.yml | 107 ++++++++++++++++++++++++++++++++ 1 file changed, 107 insertions(+) create mode 100644 .github/workflows/changelog.yml diff --git a/.github/workflows/changelog.yml b/.github/workflows/changelog.yml new file mode 100644 index 0000000..88ba563 --- /dev/null +++ b/.github/workflows/changelog.yml @@ -0,0 +1,107 @@ +on: + pull_request: + types: [opened, synchronize, reopened] + +permissions: + contents: write + pull-requests: read + +jobs: + changelog: + runs-on: ubuntu-latest + steps: + - name: Checkout (full history) + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Fetch base branch + run: | + git fetch origin "${{ github.event.pull_request.base.ref }}":"origin/${{ github.event.pull_request.base.ref }}" + + - name: Compute commit range + changed files + id: changes + run: | + BASE="origin/${{ github.event.pull_request.base.ref }}" + HEAD="${{ github.sha }}" + + echo "base=$BASE" >> $GITHUB_OUTPUT + echo "head=$HEAD" >> $GITHUB_OUTPUT + + git log --no-merges --pretty=format:"- %s (%h)" "$BASE..$HEAD" > /tmp/commits.txt + git diff --name-status "$BASE...$HEAD" > /tmp/files.txt + git diff "$BASE...$HEAD" > /tmp/diff.patch + + - name: Generate CHANGELOG.md (LLM) + env: + OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }} + OPENAI_BASE_URL: ${{ secrets.OPENAI_BASE_URL }} # optional (for Azure/enterprise gateways) + OPENAI_MODEL: ${{ secrets.OPENAI_MODEL }} # e.g. gpt-4o-mini + run: | + python3 - << 'PY' + import os, json, pathlib, textwrap, urllib.request + + commits = pathlib.Path("/tmp/commits.txt").read_text(errors="ignore") + files = pathlib.Path("/tmp/files.txt").read_text(errors="ignore") + diff = pathlib.Path("/tmp/diff.patch").read_text(errors="ignore") + + # Safety: avoid sending enormous diffs + MAX_DIFF_CHARS = 120_000 + if len(diff) > MAX_DIFF_CHARS: + diff = diff[:MAX_DIFF_CHARS] + "\n\n[diff truncated]\n" + + system = """You are a release-notes assistant. + Produce a concise, developer-friendly CHANGELOG entry in Markdown. + Group changes into: Added, Changed, Fixed, Docs, Tests, Chore (only include sections that have items). + Use bullet points. Prefer user-impact phrasing, but stay accurate to the diff. + Do NOT invent changes. If uncertain, omit.""" + user = f"""Generate a CHANGELOG.md update for this PR compared to base branch. + + Commits: + {commits} + + Changed files (name-status): + {files} + + Unified diff: + {diff} + """ + + base_url = os.getenv("OPENAI_BASE_URL", "https://api.openai.com/v1").rstrip("/") + api_key = os.environ["OPENAI_API_KEY"] + model = os.getenv("OPENAI_MODEL", "gpt-4o-mini") + + payload = { + "model": model, + "messages": [ + {"role":"system","content": system}, + {"role":"user","content": user}, + ], + "temperature": 0.2 + } + + req = urllib.request.Request( + base_url + "/chat/completions", + data=json.dumps(payload).encode("utf-8"), + headers={ + "Authorization": f"Bearer {api_key}", + "Content-Type": "application/json", + }, + method="POST" + ) + with urllib.request.urlopen(req) as resp: + data = json.loads(resp.read().decode("utf-8")) + + md = data["choices"][0]["message"]["content"].strip() + "\n" + pathlib.Path("CHANGELOG.md").write_text(md, encoding="utf-8") + print("Wrote CHANGELOG.md") + PY + + - name: Commit CHANGELOG.md back to PR branch + run: | + git config user.name "changelog-bot" + git config user.email "changelog-bot@users.noreply.github.com" + git add CHANGELOG.md + git diff --cached --quiet && echo "No changelog changes to commit." && exit 0 + git commit -m "Update CHANGELOG.md" + git push \ No newline at end of file From fb4fbf8e9645f120fd6a7970fe534e804e3030e3 Mon Sep 17 00:00:00 2001 From: Marvin Klerx Date: Fri, 8 May 2026 16:10:53 +0200 Subject: [PATCH 2/3] fix ci --- .github/workflows/changelog.yml | 49 ++++++++++++++++----------------- 1 file changed, 24 insertions(+), 25 deletions(-) diff --git a/.github/workflows/changelog.yml b/.github/workflows/changelog.yml index 88ba563..2f5af4e 100644 --- a/.github/workflows/changelog.yml +++ b/.github/workflows/changelog.yml @@ -32,23 +32,21 @@ jobs: git diff --name-status "$BASE...$HEAD" > /tmp/files.txt git diff "$BASE...$HEAD" > /tmp/diff.patch - - name: Generate CHANGELOG.md (LLM) + - name: Generate CHANGELOG.md (GitHub Copilot) env: - OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }} - OPENAI_BASE_URL: ${{ secrets.OPENAI_BASE_URL }} # optional (for Azure/enterprise gateways) - OPENAI_MODEL: ${{ secrets.OPENAI_MODEL }} # e.g. gpt-4o-mini + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | python3 - << 'PY' - import os, json, pathlib, textwrap, urllib.request + import os, json, pathlib, urllib.request commits = pathlib.Path("/tmp/commits.txt").read_text(errors="ignore") - files = pathlib.Path("/tmp/files.txt").read_text(errors="ignore") - diff = pathlib.Path("/tmp/diff.patch").read_text(errors="ignore") + files = pathlib.Path("/tmp/files.txt").read_text(errors="ignore") + diff = pathlib.Path("/tmp/diff.patch").read_text(errors="ignore") # Safety: avoid sending enormous diffs MAX_DIFF_CHARS = 120_000 if len(diff) > MAX_DIFF_CHARS: - diff = diff[:MAX_DIFF_CHARS] + "\n\n[diff truncated]\n" + diff = diff[:MAX_DIFF_CHARS] + "\n\n[diff truncated]\n" system = """You are a release-notes assistant. Produce a concise, developer-friendly CHANGELOG entry in Markdown. @@ -67,30 +65,31 @@ jobs: {diff} """ - base_url = os.getenv("OPENAI_BASE_URL", "https://api.openai.com/v1").rstrip("/") - api_key = os.environ["OPENAI_API_KEY"] - model = os.getenv("OPENAI_MODEL", "gpt-4o-mini") + # GitHub Models API — authenticated via built-in GITHUB_TOKEN, no external secrets required + api_key = os.environ["GITHUB_TOKEN"] + base_url = "https://models.inference.ai.azure.com" + model = "openai/gpt-4o-mini" payload = { - "model": model, - "messages": [ - {"role":"system","content": system}, - {"role":"user","content": user}, - ], - "temperature": 0.2 + "model": model, + "messages": [ + {"role": "system", "content": system}, + {"role": "user", "content": user}, + ], + "temperature": 0.2, } req = urllib.request.Request( - base_url + "/chat/completions", - data=json.dumps(payload).encode("utf-8"), - headers={ - "Authorization": f"Bearer {api_key}", - "Content-Type": "application/json", - }, - method="POST" + base_url + "/chat/completions", + data=json.dumps(payload).encode("utf-8"), + headers={ + "Authorization": f"Bearer {api_key}", + "Content-Type": "application/json", + }, + method="POST", ) with urllib.request.urlopen(req) as resp: - data = json.loads(resp.read().decode("utf-8")) + data = json.loads(resp.read().decode("utf-8")) md = data["choices"][0]["message"]["content"].strip() + "\n" pathlib.Path("CHANGELOG.md").write_text(md, encoding="utf-8") From bde887bb9692601def5e6d3130708c15eab195c6 Mon Sep 17 00:00:00 2001 From: Marvin Klerx Date: Fri, 8 May 2026 16:11:20 +0200 Subject: [PATCH 3/3] fix ci --- .github/workflows/changelog.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/changelog.yml b/.github/workflows/changelog.yml index 2f5af4e..8a1c765 100644 --- a/.github/workflows/changelog.yml +++ b/.github/workflows/changelog.yml @@ -1,3 +1,5 @@ +name: Generate CHANGELOG.md + on: pull_request: types: [opened, synchronize, reopened]