From 3c5a959cd7b0c6bbd66fc4adf274fa8e0621a42b Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 12 Oct 2026 17:00:42 +0000 Subject: [PATCH] Build and publish releases from version tags release.yml runs on a pushed vX.Y.Z tag on windows-latest: checks the tag matches package.json, runs lint and tests, builds the portable exe with electron-builder and publishes the GitHub release "GetBox X.Y.Z" with the exe attached and the matching CHANGELOG.md section as notes (scripts/release-notes.cjs). Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_019LtWxNVyWyutDLyX8cWQFC --- .github/workflows/release.yml | 52 +++++++++++++++++++++++++++++++++++ README.md | 6 ++++ scripts/release-notes.cjs | 23 ++++++++++++++++ 3 files changed, 81 insertions(+) create mode 100644 .github/workflows/release.yml create mode 100644 scripts/release-notes.cjs diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..00c2c89 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,52 @@ +name: Release + +# Push a tag vX.Y.Z on main → build the Windows portable exe and publish the +# GitHub release with the matching CHANGELOG.md section as its notes. +on: + push: + tags: ['v*'] + +permissions: + contents: write + +jobs: + release: + runs-on: windows-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + node-version: 22 + cache: npm + - name: Tag matches package.json + shell: bash + run: | + expected="v$(node -p "require('./package.json').version")" + if [ "$expected" != "$GITHUB_REF_NAME" ]; then + echo "::error::tag $GITHUB_REF_NAME does not match package.json ($expected)"; exit 1 + fi + - run: npm ci + - run: npm run lint + - name: Tests + shell: bash + run: | + node scripts/verify-catalog.cjs --no-links + node scripts/smoke.cjs + node scripts/test-download.cjs + node scripts/test-resilience.cjs + node scripts/test-app-full.cjs + - run: npm run build + - name: Package portable exe + run: npx electron-builder --win portable --publish never + - name: Release notes + id: notes + shell: bash + run: | + node scripts/release-notes.cjs "$GITHUB_REF_NAME" > release-notes.md + echo "name=GetBox ${GITHUB_REF_NAME#v}" >> "$GITHUB_OUTPUT" + - uses: softprops/action-gh-release@v2 + with: + name: ${{ steps.notes.outputs.name }} + body_path: release-notes.md + files: release/GetBox-*-portable.exe + fail_on_unmatched_files: true diff --git a/README.md b/README.md index 6a59b9b..dd38ac3 100644 --- a/README.md +++ b/README.md @@ -124,6 +124,12 @@ npm run dist Пока у пользователя ничего нет, лента показывает выбор редакции. В карточке программы — блоки «Часто ставят вместе» и «Альтернативы». +### Выпуск релиза + +1. Поднимите `version` в `package.json` и добавьте раздел `## X.Y.Z` в `CHANGELOG.md`. +2. После слияния в `main` поставьте тег: `git tag vX.Y.Z && git push origin vX.Y.Z`. +3. Workflow `release.yml` на `windows-latest` прогонит проверки, соберёт `GetBox-X.Y.Z-portable.exe` и опубликует релиз «GetBox X.Y.Z» с разделом из `CHANGELOG.md`. + ## Структура репозитория ```text diff --git a/scripts/release-notes.cjs b/scripts/release-notes.cjs new file mode 100644 index 0000000..c169709 --- /dev/null +++ b/scripts/release-notes.cjs @@ -0,0 +1,23 @@ +/** + * Print the CHANGELOG.md section for one version — the body of its GitHub release. + * + * Run: node scripts/release-notes.cjs 1.2.5 (a leading "v" is accepted) + */ +const fs = require('node:fs'); +const path = require('node:path'); + +const version = (process.argv[2] ?? '').replace(/^v/, ''); +if (!version) { + console.error('usage: node scripts/release-notes.cjs '); + process.exit(1); +} + +const changelog = fs.readFileSync(path.join(__dirname, '..', 'CHANGELOG.md'), 'utf-8'); +const lines = changelog.split('\n'); +const start = lines.findIndex((l) => l.trim() === `## ${version}`); +if (start < 0) { + console.error(`CHANGELOG.md has no "## ${version}" section`); + process.exit(1); +} +const end = lines.findIndex((l, i) => i > start && l.startsWith('## ')); +console.log(lines.slice(start + 1, end < 0 ? undefined : end).join('\n').trim());