From 9f7654f1f3ad9869f3b56ee4b31ec499b7700c7a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=A4=A9=E6=B5=B7=20=E5=8E=9F?= Date: Mon, 25 May 2026 00:06:04 +0900 Subject: [PATCH 1/2] chore(release): adopt calver workflow --- .agents/skills/changelog/SKILL.md | 8 +- .agents/skills/save-it-release/SKILL.md | 149 ++++++++++++++++++ .../skills/save-it-release/agents/openai.yaml | 4 + .../scripts/check_release_state.sh | 40 +++++ .../scripts/extract_release_notes.sh | 16 ++ .github/workflows/release-manual.yml | 8 +- .github/workflows/release.yml | 2 +- AGENTS.md | 1 + CHANGELOG.md | 2 +- 9 files changed, 221 insertions(+), 9 deletions(-) create mode 100644 .agents/skills/save-it-release/SKILL.md create mode 100644 .agents/skills/save-it-release/agents/openai.yaml create mode 100755 .agents/skills/save-it-release/scripts/check_release_state.sh create mode 100755 .agents/skills/save-it-release/scripts/extract_release_notes.sh diff --git a/.agents/skills/changelog/SKILL.md b/.agents/skills/changelog/SKILL.md index 010c839..7ee278b 100644 --- a/.agents/skills/changelog/SKILL.md +++ b/.agents/skills/changelog/SKILL.md @@ -1,6 +1,6 @@ --- name: changelog -description: Maintain and update CHANGELOG.md using Keep a Changelog 1.1.0 conventions with SemVer-friendly release sections, Unreleased workflow, and consistent change categorization. +description: Maintain and update CHANGELOG.md using Keep a Changelog 1.1.0 conventions with CalVer release sections, Unreleased workflow, and consistent change categorization. metadata: short-description: Keep a Changelog workflow --- @@ -16,7 +16,7 @@ Use this skill when the user asks to create, update, normalize, or release `CHAN - Use reverse chronological order. - Keep an `[Unreleased]` section at the top. - Use ISO dates: `YYYY-MM-DD`. -- Follow SemVer version headers: `## [x.y.z] - YYYY-MM-DD`. +- Follow this repository's CalVer version headers: `## [YYYY.M.PATCH] - YYYY-MM-DD`. ## Allowed Change Types @@ -68,14 +68,14 @@ Use these sections when needed (omit empty ones): All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), -and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +and this project uses [Calendar Versioning](https://calver.org/) with the `YYYY.M.PATCH` scheme for new releases. ## [Unreleased] ### Added - ... -## [1.2.3] - 2026-04-26 +## [2026.5.1] - 2026-04-26 ### Fixed - ... diff --git a/.agents/skills/save-it-release/SKILL.md b/.agents/skills/save-it-release/SKILL.md new file mode 100644 index 0000000..1f981ed --- /dev/null +++ b/.agents/skills/save-it-release/SKILL.md @@ -0,0 +1,149 @@ +--- +name: save-it-release +description: Prepare, verify, and publish `save_it` releases by updating `CHANGELOG.md` and `mix.exs`, creating the release commit and tag, and publishing a GitHub release with notes extracted from the changelog. Use when the user asks to cut a stable release, prepare a prerelease, or verify release readiness for this repository. This repository uses CalVer `YYYY.M.PATCH` and prerelease tags such as `YYYY.M.PATCH-rc.N`. +--- + +# Save It Release + +Use this skill when the task is specifically about the `save_it` release flow. + +This repository uses: +- `CHANGELOG.md` as the source of release notes +- `mix.exs` `version` as the application version +- CalVer `YYYY.M.PATCH` for stable versions, for example `2026.5.1` +- git tags that match the version string directly, for example `2026.5.1` +- GitHub Release publication to trigger `.github/workflows/release.yml` +- `.github/workflows/release-manual.yml` for manual prereleases such as `2026.5.2-rc.1` + +## Workflow + +1. Read the current release state. +2. Decide whether this is release preparation, stable release publication, or manual prerelease publication. +3. Align `CHANGELOG.md` and `mix.exs`. +4. Verify release notes and git state. +5. Execute the matching release path. +6. Report the exact tag, commit, release URL, and workflow status. + +## Preflight + +Run: + +```bash +git fetch --tags --prune +git status --short --branch +git tag --sort=-version:refname | sed -n '1,20p' +``` + +Rules: +- Prefer cutting stable releases from `main`. +- If the tree is dirty, stop and surface the changed files before continuing. +- Check whether the target stable tag or GitHub release already exists before creating anything. + +Use the helper script for a quick snapshot: + +```bash +.agents/skills/save-it-release/scripts/check_release_state.sh YYYY.M.PATCH +``` + +## Release Preparation + +When the user asks to prepare a release but not publish it yet: + +1. Update `CHANGELOG.md`. +- Keep `[Unreleased]` at the top. +- Move shipped items into `## [YYYY.M.PATCH] - YYYY-MM-DD`. +- Add the compare link for the new version. +- Keep entries user-facing and in English. +2. Update `mix.exs`: + +```elixir +version: "YYYY.M.PATCH" +``` + +3. Show the diff for `CHANGELOG.md` and `mix.exs`. +4. Do not tag or publish unless the user explicitly asks to release. + +If changelog drafting is still needed, also use `.agents/skills/changelog/SKILL.md`. + +## Stable Release Publication + +When the user asks to publish a stable release: + +1. Confirm the released version exists in both `CHANGELOG.md` and `mix.exs`. +2. Extract release notes with: + +```bash +.agents/skills/save-it-release/scripts/extract_release_notes.sh YYYY.M.PATCH +``` + +3. Commit release metadata changes using the repository convention: + +```bash +git add CHANGELOG.md mix.exs +git commit -m "chore(release): bump version to YYYY.M.PATCH" +``` + +4. Create and push the stable tag: + +```bash +git tag -a YYYY.M.PATCH -m "YYYY.M.PATCH" +git push origin main +git push origin refs/tags/YYYY.M.PATCH +``` + +5. Publish the GitHub release from the extracted notes: + +```bash +tmpfile="$(mktemp)" +.agents/skills/save-it-release/scripts/extract_release_notes.sh YYYY.M.PATCH > "$tmpfile" +gh release create YYYY.M.PATCH \ + --verify-tag \ + --title "YYYY.M.PATCH" \ + --notes-file "$tmpfile" +rm -f "$tmpfile" +``` + +6. Check whether the `Release` workflow was triggered: + +```bash +gh run list --limit 5 +``` + +If the user wants more confidence before release, run the acceptance flow from `.agents/skills/acceptance-testing/SKILL.md`. + +## Manual Prerelease Publication + +When the user asks for a prerelease: + +1. Keep the version in the repository's CalVer prerelease form, for example `2026.5.2-rc.1`. +2. Prefer the existing GitHub Actions workflow instead of manually crafting a prerelease: + +```bash +gh workflow run "Release (manual)" -f tag=YYYY.M.PATCH-rc.N +``` + +3. This workflow publishes a GitHub prerelease and triggers Docker publish with prerelease semantics. + +## Guardrails + +- Never publish a stable release from a dirty working tree. +- Never create a stable release if `mix.exs` and `CHANGELOG.md` disagree on the version. +- Never use a non-CalVer stable version format in this repository unless the project convention is explicitly changed again. +- Never add a `v` prefix to new release tags in this repository. +- Never invent release notes from raw commit history when the matching changelog section is missing. +- Never recreate an existing tag or GitHub release. +- Never use the manual prerelease workflow for a normal stable release when direct GitHub release publication is intended. + +## Related Files + +- `CHANGELOG.md` +- `mix.exs` +- `.github/workflows/release.yml` +- `.github/workflows/release-manual.yml` +- `.agents/skills/changelog/SKILL.md` +- `.agents/skills/acceptance-testing/SKILL.md` + +## Resources + +- `scripts/extract_release_notes.sh` +- `scripts/check_release_state.sh` diff --git a/.agents/skills/save-it-release/agents/openai.yaml b/.agents/skills/save-it-release/agents/openai.yaml new file mode 100644 index 0000000..0962586 --- /dev/null +++ b/.agents/skills/save-it-release/agents/openai.yaml @@ -0,0 +1,4 @@ +interface: + display_name: "Save It Release" + short_description: "Prepare and publish save_it releases" + default_prompt: "Use this skill to prepare and publish a save_it release safely." diff --git a/.agents/skills/save-it-release/scripts/check_release_state.sh b/.agents/skills/save-it-release/scripts/check_release_state.sh new file mode 100755 index 0000000..d4cd7b8 --- /dev/null +++ b/.agents/skills/save-it-release/scripts/check_release_state.sh @@ -0,0 +1,40 @@ +#!/usr/bin/env bash + +set -euo pipefail + +if [ "$#" -ne 1 ]; then + echo "usage: $0 " >&2 + exit 1 +fi + +version="$1" +tag="${version}" +branch="$(git branch --show-current)" + +echo "branch=${branch}" +echo "tag=${tag}" +echo "head=$(git rev-parse --short HEAD)" + +echo +echo "[git status]" +git status --short --branch + +echo +echo "[mix.exs version]" +rg -n "version:\\s*\"${version}\"" mix.exs || true + +echo +echo "[changelog section]" +rg -n "^## \\[${version}\\] - " CHANGELOG.md || true + +echo +echo "[local tag]" +git rev-parse --verify "${tag}" >/dev/null 2>&1 && echo "exists" || echo "missing" + +echo +echo "[remote tag]" +git ls-remote --tags origin "refs/tags/${tag}" | sed '/^$/d' || true + +echo +echo "[github release]" +gh release view "${tag}" --json url,isDraft,isPrerelease,publishedAt --jq '{url, isDraft, isPrerelease, publishedAt}' 2>/dev/null || echo "missing" diff --git a/.agents/skills/save-it-release/scripts/extract_release_notes.sh b/.agents/skills/save-it-release/scripts/extract_release_notes.sh new file mode 100755 index 0000000..3bdb2b9 --- /dev/null +++ b/.agents/skills/save-it-release/scripts/extract_release_notes.sh @@ -0,0 +1,16 @@ +#!/usr/bin/env bash + +set -euo pipefail + +if [ "$#" -ne 1 ]; then + echo "usage: $0 " >&2 + exit 1 +fi + +version="$1" + +awk -v version="$version" ' + $0 ~ "^## \\[" version "\\]" { in_section=1; next } + in_section && /^## \[/ { exit } + in_section { print } +' CHANGELOG.md diff --git a/.github/workflows/release-manual.yml b/.github/workflows/release-manual.yml index 22e5073..2320d44 100644 --- a/.github/workflows/release-manual.yml +++ b/.github/workflows/release-manual.yml @@ -5,7 +5,7 @@ on: workflow_dispatch: inputs: tag: - description: "Release tag to create (for example: v0.4.1)" + description: "Release tag to create (for example: 2026.5.1 or 2026.5.2-rc.1)" required: true type: string @@ -18,6 +18,7 @@ concurrency: jobs: release: + name: release (${{ inputs.tag }}) runs-on: ubuntu-latest outputs: version: ${{ steps.prepare.outputs.version }} @@ -31,7 +32,7 @@ jobs: env: INPUT_TAG: ${{ inputs.tag }} run: | - echo "version=${INPUT_TAG#v}" >> "$GITHUB_OUTPUT" + echo "version=${INPUT_TAG}" >> "$GITHUB_OUTPUT" - name: Ensure GitHub CLI run: gh --version @@ -42,7 +43,7 @@ jobs: RELEASE_BRANCH: ${{ github.ref_name }} INPUT_TAG: ${{ inputs.tag }} run: | - version="${INPUT_TAG#v}" + version="${INPUT_TAG}" awk -v version="$version" ' $0 ~ "^## \\[" version "\\]" { next_section=1; next } @@ -61,6 +62,7 @@ jobs: --prerelease docker: + name: docker (${{ needs.release.outputs.version }}) needs: release uses: ./.github/workflows/docker-publish.yml with: diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 6ef7bf4..af6e872 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -27,7 +27,7 @@ jobs: IS_PRERELEASE: ${{ github.event.release.prerelease }} RELEASE_TAG: ${{ github.event.release.tag_name }} run: | - version="${RELEASE_TAG#v}" + version="${RELEASE_TAG}" if [ -z "$version" ]; then echo "Release tag is empty" exit 1 diff --git a/AGENTS.md b/AGENTS.md index a96e067..36ab263 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -7,6 +7,7 @@ This file provides guidance to coding agents working in this repository. - Project: `save_it` - Stack: Elixir (Telegram bot), Docker, external downloader/search services - Primary goal: ship practical features quickly with controlled complexity +- Versioning: CalVer `YYYY.M.PATCH` for stable releases, with git tags using the same value without a `v` prefix, and prereleases such as `YYYY.M.PATCH-rc.N` ## Environment and Tooling diff --git a/CHANGELOG.md b/CHANGELOG.md index 3dd617c..8052faa 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,7 +3,7 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), -and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +and this project uses [Calendar Versioning](https://calver.org/) with the `YYYY.M.PATCH` scheme for new releases. ## [Unreleased] From 18d59202c02c5822ca2159a228277810ee685a11 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=A4=A9=E6=B5=B7=20=E5=8E=9F?= Date: Mon, 25 May 2026 00:12:24 +0900 Subject: [PATCH 2/2] chore(release): update github release title --- .agents/skills/save-it-release/SKILL.md | 2 +- .github/workflows/release-manual.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.agents/skills/save-it-release/SKILL.md b/.agents/skills/save-it-release/SKILL.md index 1f981ed..36cb6c0 100644 --- a/.agents/skills/save-it-release/SKILL.md +++ b/.agents/skills/save-it-release/SKILL.md @@ -98,7 +98,7 @@ tmpfile="$(mktemp)" .agents/skills/save-it-release/scripts/extract_release_notes.sh YYYY.M.PATCH > "$tmpfile" gh release create YYYY.M.PATCH \ --verify-tag \ - --title "YYYY.M.PATCH" \ + --title "save_it YYYY.M.PATCH" \ --notes-file "$tmpfile" rm -f "$tmpfile" ``` diff --git a/.github/workflows/release-manual.yml b/.github/workflows/release-manual.yml index 2320d44..5c103e9 100644 --- a/.github/workflows/release-manual.yml +++ b/.github/workflows/release-manual.yml @@ -57,7 +57,7 @@ jobs: gh release create "$INPUT_TAG" \ --target "$RELEASE_BRANCH" \ - --title "$INPUT_TAG" \ + --title "save_it $INPUT_TAG" \ --notes-file release-notes.md \ --prerelease