From 89b14f89439513746aaeed293e64b15a1cbcd93e Mon Sep 17 00:00:00 2001 From: Jean-Adrien DUCASTAING Date: Tue, 15 Sep 2026 18:38:33 +0200 Subject: [PATCH] chore(ci): improves changelog and add slack announcement --- .github/workflows/release.yml | 23 +++++++++++++++++++++++ AGENTS.md | 23 ++++++++++++++++++++--- cliff.toml | 7 ++++++- 3 files changed, 49 insertions(+), 4 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 1541c5c..1609106 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -55,3 +55,26 @@ jobs: gh release create "$GITHUB_REF_NAME" dist/* --title "$GITHUB_REF_NAME" --notes-file notes.md + + - name: Announce on Slack + env: + WEBHOOK: ${{ secrets.RELEASE_SLACK_WEBHOOK_URL }} + RELEASE_URL: ${{ github.server_url }}/${{ github.repository }}/releases/tag/${{ github.ref_name }} + run: | + if [ -z "$WEBHOOK" ]; then + echo "::warning::RELEASE_SLACK_WEBHOOK_URL is not set, skipping the announcement" + exit 0 + fi + # Escape Slack's entities first (& < > are markup to it, so an unescaped + # "" in a commit message would vanish), then markdown -> mrkdwn, + # which renders neither "### x" nor "**bold**". Truncated well under + # Slack's 40k text limit; the link carries the full notes either way. + body=$(sed -e 's/&/\&/g; s//\>/g' notes.md \ + | sed -E 's/^#+ +(.*)$/*\1*/; s/\*\*([^*]+)\*\*/*\1*/g' \ + | head -c 3500) + jq -n --arg tag "$GITHUB_REF_NAME" --arg url "$RELEASE_URL" \ + --arg repo "$GITHUB_REPOSITORY" --arg body "$body" \ + '{text: ("*\($repo) \($tag)* released\n<\($url)|Release notes> · `uv add lighton-sdk`\n\n\($body)")}' \ + > slack.json + curl -sS --fail-with-body -X POST -H 'Content-Type: application/json' \ + --data @slack.json "$WEBHOOK" diff --git a/AGENTS.md b/AGENTS.md index 0eaa1d5..f60e4b9 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -379,11 +379,28 @@ generalize speculatively for a shape only one subclass needs. `DESC` (optional) becomes the **annotated tag message**, free-text release notes. - The pushed tag fires `.github/workflows/release.yml`: it re-checks `tag == uv version`, `uv build`s the sdist+wheel, runs **git-cliff** (`cliff.toml`, conventional-commit - grouping), prepends the annotated-tag message (the `DESC`) above the changelog, and - `gh release create`s with the artifacts attached. + grouping), prepends the annotated-tag message (the `DESC`) above the changelog, + publishes to PyPI, `gh release create`s with the artifacts attached, and finally + announces on Slack. +- **Changelog credits contributors** via `commit.author.name` in `cliff.toml`, which + squash-merged PRs carry from the PR author. Deliberately the git name and not a + GitHub `@handle`: a handle would auto-link in a release but needs `[remote.github]` + plus a token, and would make the changelog un-renderable offline. Note git author + names are whatever each contributor configured, so spelling can vary between commits. +- **Slack announcement** is the last step, posting the assembled notes to the + `RELEASE_SLACK_WEBHOOK_URL` repo secret. It **skips with a warning when the secret is + absent**, so a fork or a repo without Slack still releases cleanly. The notes are + markdown and Slack speaks mrkdwn, so the step escapes `& < >` first (they are markup + to Slack, and an unescaped `` in a commit message would silently vanish), then + rewrites `### x` and `**bold**` to `*x*`, and caps the body well under Slack's 40k + limit; the linked release always carries the full text. The payload is built with + `jq --arg`, never string interpolation, so quotes and `$` in a commit message can't + break the JSON. It runs **after** the release exists, so a webhook failure can never + cost you the release, but it does fail the job loudly rather than announcing nothing + in silence. - **Version is single-source:** `pyproject.toml`. `__version__` in `lighton/__init__.py` reads it via `importlib.metadata.version("lighton")`, don't hard-code it back. -- Attach-wheels only; no PyPI publish yet (add `uv publish` + a trusted publisher when wanted). +- Artifacts are attached to the release **and** published to PyPI (`uv publish`, `PYPI_PUBLISH_TOKEN` secret). ## Conventions diff --git a/cliff.toml b/cliff.toml index ffa10dc..4900630 100644 --- a/cliff.toml +++ b/cliff.toml @@ -1,11 +1,16 @@ # git-cliff — changelog from conventional commits. See https://git-cliff.org +# +# Contributor credit uses `commit.author.name`, the git author, which squash-merged +# PRs carry from the PR author. A GitHub @handle would auto-link in a release, but +# needs [remote.github] plus a token, and would leave the changelog un-renderable +# offline; the name is free and works everywhere. [changelog] header = "" body = """ {% for group, commits in commits | group_by(attribute="group") %} ### {{ group | upper_first }} {% for commit in commits %} -- {{ commit.message | upper_first }}\ +- {{ commit.message | upper_first }}{% if commit.author.name %} ({{ commit.author.name }}){% endif %}\ {% endfor %} {% endfor %} """