diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 222466a..19be81b 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -85,7 +85,7 @@ jobs: [[ "$MAIN_SHA" == "$GITHUB_SHA" ]] || { echo "main moved during the build; rerun from the current main commit." >&2; exit 1; } PREVIOUS_TAG="$(gh release list --limit 100 \ --json tagName,isDraft,isPrerelease,publishedAt \ - | jq -er '[.[] | select(.isDraft == false and .isPrerelease == false)] | sort_by(.publishedAt) | last | .tagName')" + | jq -r '[.[] | select(.isDraft == false and .isPrerelease == false)] | sort_by(.publishedAt) | last | .tagName // empty')" NOTES_FILE="${RUNNER_TEMP}/release-notes.md" GITHUB_REPOSITORY="${GITHUB_REPOSITORY}" \ ./scripts/generate_macos_release_notes.sh \ diff --git a/changelog.md b/changelog.md index 1fd5436..cae9c4e 100644 --- a/changelog.md +++ b/changelog.md @@ -66,6 +66,10 @@ ## Chores +- 2026-09-29: Ersten Release ohne vorhandene Tags oder vorherige Releases vorbereitet. + - Dateien: `.github/workflows/release.yml`, `scripts/generate_macos_release_notes.sh`, `docs/distribution.md`, `changelog.md`. + - Funktionalität: Die Vorbereitung eines ersten Releases akzeptiert jetzt einen leeren Release-Verlauf. GitHub generiert Notizen ohne vorherigen Tag; direkte Commits werden ab dem Repository-Root aufgenommen. Kein Produktversionsbump, da dies Release-Tooling ist. + - 2026-09-29: Emoji aus automatisch generierten Release-Notizen entfernt. - Dateien: `.github/release.yml`, `.github/PULL_REQUEST_TEMPLATE.md`, `scripts/generate_macos_release_notes.sh`, `docs/distribution.md`, `changelog.md`. - Funktionalität: Kategorieüberschriften sind textbasiert. Der Release-Notizgenerator entfernt Emoji-Zeichen und ihre Unicode-Sequenzbestandteile aus PR-Titeln, direkten Commit-Nachrichten, Beitragendennamen und dem übrigen generierten Text. Die PR-Vorlage bittet um emoji-freie Titel. Die Produktversion bleibt unverändert, da sich nur Release-Tooling und Dokumentation ändern. diff --git a/docs/distribution.md b/docs/distribution.md index 53948c4..f9e06c0 100644 --- a/docs/distribution.md +++ b/docs/distribution.md @@ -21,7 +21,7 @@ Expected assets: The Finder DMG layout uses the matching 800 × 500 SVG background and `dmgbuild` metadata. `create_macos_dmg.sh` verifies the app's ad-hoc signature after packaging. Release builds contain no speech model; onboarding downloads one on first launch. The Whisper CLI is linked statically against Whisper/GGML, and `validate_macos_app_runtime.sh` verifies the executable and runtime manifest. -To prepare a draft from `main`, run **Actions → macOS Release** with `action=prepare` and the value from `VERSION`. The workflow finds the previous published release, asks GitHub's Release Notes API to summarize merged PRs, groups them using `.github/release.yml`, and includes contributors plus a full changelog link. A helper adds commit subjects and authors for direct commits that have no associated PR, so older work is not lost. PR titles must be descriptive on their own; apply one category label listed in `.github/PULL_REQUEST_TEMPLATE.md` before merging. The generated body removes emoji characters from PR titles, commit subjects, author names, and category headings. It also includes concise install guidance and a machine-readable source commit used by the publish check. The notes are suitable both for the draft and published release; there is no internal “publish this draft” text. +To prepare a draft from `main`, run **Actions → macOS Release** with `action=prepare` and the value from `VERSION`. The workflow finds the previous published release, asks GitHub's Release Notes API to summarize merged PRs, groups them using `.github/release.yml`, and includes contributors plus a full changelog link. A helper adds commit subjects and authors for direct commits that have no associated PR, so older work is not lost. When no previous published release is found, the workflow omits the previous-tag parameter; if the repository also has no Git tags, GitHub generates notes across the repository's full history and the helper includes direct commits from the repository root. PR titles must be descriptive on their own; apply one category label listed in `.github/PULL_REQUEST_TEMPLATE.md` before merging. The generated body removes emoji characters from PR titles, commit subjects, author names, and category headings. It also includes concise install guidance and a machine-readable source commit used by the publish check. The notes are suitable both for the draft and published release; there is no internal “publish this draft” text. GitHub does not create the release tag while the release is a draft. After installation testing, run the same workflow with `action=publish` and the same version. The workflow checks branch, version, source commit, draft state and assets, then verifies the downloaded checksum and DMG before creating the tag at the tested source commit while publishing. For manual local verification steps, see [`macos-release-checklist.md`](macos-release-checklist.md). The old Developer ID archive, export, notarization, stapling, and Sparkle appcast scripts remain available for a future signed distribution, but they are not part of the current release path. diff --git a/scripts/generate_macos_release_notes.sh b/scripts/generate_macos_release_notes.sh index f559ec8..19b7b35 100755 --- a/scripts/generate_macos_release_notes.sh +++ b/scripts/generate_macos_release_notes.sh @@ -2,7 +2,7 @@ set -euo pipefail if [[ "$#" -ne 4 ]]; then - echo "Usage: $0 " >&2 + echo "Usage: $0 " >&2 exit 2 fi @@ -25,26 +25,30 @@ strip_release_emojis() { echo "Source commit must be a full lowercase Git SHA: ${SOURCE_COMMIT}" >&2 exit 2 } -[[ -n "${PREVIOUS_TAG}" ]] || { - echo "A previous published release tag is required to generate release notes." >&2 - exit 2 -} git cat-file -e "${SOURCE_COMMIT}^{commit}" -git rev-parse --verify "refs/tags/${PREVIOUS_TAG}^{commit}" >/dev/null -git merge-base --is-ancestor "${PREVIOUS_TAG}" "${SOURCE_COMMIT}" || { - echo "Previous release ${PREVIOUS_TAG} is not an ancestor of ${SOURCE_COMMIT}." >&2 - exit 1 -} +NOTES_ARGUMENTS=( + --method POST + "repos/${GITHUB_REPOSITORY_VALUE}/releases/generate-notes" + -f "tag_name=${RELEASE_TAG}" + -f "target_commitish=${SOURCE_COMMIT}" + -f "configuration_file_path=.github/release.yml" +) +COMMIT_RANGE="${SOURCE_COMMIT}" + +if [[ -n "${PREVIOUS_TAG}" ]]; then + git rev-parse --verify "refs/tags/${PREVIOUS_TAG}^{commit}" >/dev/null + git merge-base --is-ancestor "${PREVIOUS_TAG}" "${SOURCE_COMMIT}" || { + echo "Previous release ${PREVIOUS_TAG} is not an ancestor of ${SOURCE_COMMIT}." >&2 + exit 1 + } + NOTES_ARGUMENTS+=(-f "previous_tag_name=${PREVIOUS_TAG}") + COMMIT_RANGE="${PREVIOUS_TAG}..${SOURCE_COMMIT}" +fi -NOTES_RESPONSE="$(gh api --method POST \ - "repos/${GITHUB_REPOSITORY_VALUE}/releases/generate-notes" \ - -f "tag_name=${RELEASE_TAG}" \ - -f "target_commitish=${SOURCE_COMMIT}" \ - -f "previous_tag_name=${PREVIOUS_TAG}" \ - -f "configuration_file_path=.github/release.yml")" +NOTES_RESPONSE="$(gh api "${NOTES_ARGUMENTS[@]}")" GENERATED_NOTES="$(jq -r '.body' <<<"${NOTES_RESPONSE}")" -DIRECT_COMMITS="$(git rev-list --no-merges "${PREVIOUS_TAG}..${SOURCE_COMMIT}")" +DIRECT_COMMITS="$(git rev-list --no-merges "${COMMIT_RANGE}")" DIRECT_NOTES=() while IFS= read -r COMMIT; do [[ -n "${COMMIT}" ]] || continue