From 5990310e9957ce7ab91ef15572ba8fe9ee211934 Mon Sep 17 00:00:00 2001 From: Ku6epXBOCTuK Date: Sun, 4 Oct 2026 09:07:43 +0500 Subject: [PATCH] ci: update ci: version bump, changelog --- .github/actions/setup-cocogitto/action.yml | 23 +++++++ .github/workflows/bump.yml | 77 ++++++++++++++++++++++ .github/workflows/deploy.yml | 29 +------- .github/workflows/quality.yml | 30 +-------- .github/workflows/release.yml | 58 ++++++++++++++++ .github/workflows/verify.yml | 39 +++++++++++ cog.toml | 19 ++++++ docs/backlog.md | 3 - docs/decisions.md | 24 +++++++ scripts/sync-version.mjs | 16 +++++ 10 files changed, 258 insertions(+), 60 deletions(-) create mode 100644 .github/actions/setup-cocogitto/action.yml create mode 100644 .github/workflows/bump.yml create mode 100644 .github/workflows/release.yml create mode 100644 .github/workflows/verify.yml create mode 100644 cog.toml create mode 100644 scripts/sync-version.mjs diff --git a/.github/actions/setup-cocogitto/action.yml b/.github/actions/setup-cocogitto/action.yml new file mode 100644 index 0000000..f547976 --- /dev/null +++ b/.github/actions/setup-cocogitto/action.yml @@ -0,0 +1,23 @@ +name: "Setup Cocogitto" +description: "Installs a specific version of Cocogitto and cleans up the workspace" +inputs: + version: + description: "Cocogitto version to install" + required: true + default: "7.0.0" + +runs: + using: "composite" + steps: + - name: Install Cocogitto + shell: bash + run: | + VERSION="${{ inputs.version }}" + URL="https://github.com/cocogitto/cocogitto/releases/download/${VERSION}/cocogitto-${VERSION}-x86_64-unknown-linux-musl.tar.gz" + + curl -LOf "$URL" + tar -xzf "cocogitto-${VERSION}-x86_64-unknown-linux-musl.tar.gz" + + sudo mv $(find . -name cog -type f -executable) /usr/local/bin/ + git clean -fd + cog --version diff --git a/.github/workflows/bump.yml b/.github/workflows/bump.yml new file mode 100644 index 0000000..4d3e818 --- /dev/null +++ b/.github/workflows/bump.yml @@ -0,0 +1,77 @@ +name: Bump version + +on: + push: + branches: [main] + workflow_dispatch: + +permissions: + contents: write + +concurrency: + group: bump + cancel-in-progress: false + +jobs: + verify: + uses: ./.github/workflows/verify.yml + + bump: + needs: verify + runs-on: ubuntu-latest + outputs: + bumped: ${{ steps.check-bump.outputs.bumped }} + new_version: ${{ steps.get-tag.outputs.version }} + steps: + - name: Generate token + id: generate_token + uses: actions/create-github-app-token@v1 + with: + app-id: ${{ secrets.XBOCT_BOT_ID }} + private-key: ${{ secrets.XBOCT_BOT_PRIVATE_KEY }} + + - name: Checkout + uses: actions/checkout@v4 + with: + token: ${{ steps.generate_token.outputs.token }} + fetch-depth: 0 + + - name: Setup Cocogitto + uses: ./.github/actions/setup-cocogitto + + - name: Check if bump is needed + id: check-bump + run: | + BUMP_OUTPUT=$(cog bump --auto --dry-run 2>&1) + + if [[ "$BUMP_OUTPUT" == *"No conventional commits"* ]]; then + echo "No bump needed." + echo "bumped=false" >> "$GITHUB_OUTPUT" + else + echo "Changes detected, proceeding..." + echo "bumped=true" >> "$GITHUB_OUTPUT" + fi + + - name: Bump and push + if: steps.check-bump.outputs.bumped == 'true' + run: | + git config user.name "github-actions[bot]" + git config user.email "github-actions[bot]@users.noreply.github.com" + cog bump --auto + git push origin main --tags + + - name: Get new version + id: get-tag + if: steps.check-bump.outputs.bumped == 'true' + run: | + VERSION=$(git describe --tags --abbrev=0) + echo "Detected version: $VERSION" + echo "version=$VERSION" >> "$GITHUB_OUTPUT" + + release: + needs: bump + if: needs.bump.outputs.bumped == 'true' + uses: ./.github/workflows/release.yml + with: + version: ${{ needs.bump.outputs.new_version }} + secrets: inherit diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 57ee006..d95ccea 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -17,34 +17,7 @@ concurrency: jobs: verify: - runs-on: ubuntu-latest - steps: - - name: Checkout - uses: actions/checkout@v4 - - - name: Setup pnpm - uses: pnpm/action-setup@v4 - with: - version: ^11.20.0 - - - name: Setup Node - uses: actions/setup-node@v4 - with: - node-version: 24 - cache: pnpm - cache-dependency-path: | - pnpm-lock.yaml - web/pnpm-lock.yaml - - - name: Install root dependencies - run: pnpm install --frozen-lockfile - - - name: Install web dependencies - working-directory: web - run: pnpm install --frozen-lockfile - - - name: Run quality gate - run: pnpm verify + uses: ./.github/workflows/verify.yml build: needs: verify diff --git a/.github/workflows/quality.yml b/.github/workflows/quality.yml index 02f3d5a..8d3f7d8 100644 --- a/.github/workflows/quality.yml +++ b/.github/workflows/quality.yml @@ -16,35 +16,7 @@ concurrency: jobs: verify: - name: Fast quality gate - runs-on: ubuntu-latest - steps: - - name: Checkout - uses: actions/checkout@v4 - - - name: Setup pnpm - uses: pnpm/action-setup@v4 - with: - version: ^11.20.0 - - - name: Setup Node - uses: actions/setup-node@v4 - with: - node-version: 24 - cache: pnpm - cache-dependency-path: | - pnpm-lock.yaml - web/pnpm-lock.yaml - - - name: Install root dependencies - run: pnpm install --frozen-lockfile - - - name: Install web dependencies - working-directory: web - run: pnpm install --frozen-lockfile - - - name: Run quality gate - run: pnpm verify + uses: ./.github/workflows/verify.yml e2e: name: E2E (non-blocking baseline) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..5e86566 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,58 @@ +name: GitHub Release + +on: + workflow_call: + inputs: + version: + required: true + type: string + workflow_dispatch: + inputs: + version: + description: "Версия для релиза (например, v0.2.0)" + required: true + type: string + +permissions: + contents: write + +jobs: + release: + runs-on: ubuntu-latest + steps: + - name: Generate token + id: generate_token + uses: actions/create-github-app-token@v1 + with: + app-id: ${{ secrets.XBOCT_BOT_ID }} + private-key: ${{ secrets.XBOCT_BOT_PRIVATE_KEY }} + + - name: Checkout + uses: actions/checkout@v4 + with: + token: ${{ steps.generate_token.outputs.token }} + fetch-depth: 0 + + - name: Setup Cocogitto + uses: ./.github/actions/setup-cocogitto + + - name: Sync and reset + run: | + git fetch origin main --tags --force + git reset --hard origin/main + + - name: Get changelog + run: | + cog changelog "${{ inputs.version }}" > GITHUB_CHANGELOG.md + if [ ! -s GITHUB_CHANGELOG.md ]; then + echo "Release ${{ inputs.version }}" > GITHUB_CHANGELOG.md + echo "::warning title=Changelog::Changelog was empty, used default text." + fi + + - name: Create GitHub Release + uses: softprops/action-gh-release@v2 + with: + tag_name: ${{ inputs.version }} + name: Release ${{ inputs.version }} + body_path: GITHUB_CHANGELOG.md + token: ${{ steps.generate_token.outputs.token }} diff --git a/.github/workflows/verify.yml b/.github/workflows/verify.yml new file mode 100644 index 0000000..bbc7b9e --- /dev/null +++ b/.github/workflows/verify.yml @@ -0,0 +1,39 @@ +name: Verify + +on: + workflow_call: + +permissions: + contents: read + +jobs: + verify: + name: Fast quality gate + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Setup pnpm + uses: pnpm/action-setup@v4 + with: + version: ^11.20.0 + + - name: Setup Node + uses: actions/setup-node@v4 + with: + node-version: 24 + cache: pnpm + cache-dependency-path: | + pnpm-lock.yaml + web/pnpm-lock.yaml + + - name: Install root dependencies + run: pnpm install --frozen-lockfile + + - name: Install web dependencies + working-directory: web + run: pnpm install --frozen-lockfile + + - name: Run quality gate + run: pnpm verify diff --git a/cog.toml b/cog.toml new file mode 100644 index 0000000..2afe0dd --- /dev/null +++ b/cog.toml @@ -0,0 +1,19 @@ +branch_whitelist = ["main"] +ignore_merge_commits = true +tag_prefix = "v" + +pre_bump_hooks = ["node scripts/sync-version.mjs {{version}}"] + +[changelog] +path = "CHANGELOG.md" +template = "remote" +remote = "github.com" +repository = "easy-png-tools" +owner = "Ku6epXBOCTuK" + +[commit_types] +build = { omit_from_changelog = true } +chore = { omit_from_changelog = true } +ci = { omit_from_changelog = true } +docs = { omit_from_changelog = true } +test = { omit_from_changelog = true } diff --git a/docs/backlog.md b/docs/backlog.md index f8fb017..4b3329e 100644 --- a/docs/backlog.md +++ b/docs/backlog.md @@ -101,9 +101,6 @@ - [ ] Радиусы бордеров: `--radius-m` ненулевой и применён ко всем бордерам (`app.css`, `SchemaToolView.svelte`). Решить, где скругления реально есть в дизайне, а где должен быть 0 -- [ ] надо добавить версионирование и changelog (cocogitto), пример можно взять - отсюда - - [https://github.com/Ku6epXBOCTuK/XBOCT-page](https://github.com/Ku6epXBOCTuK/XBOCT-page) ## Переезд diff --git a/docs/decisions.md b/docs/decisions.md index f33f9b1..717e839 100644 --- a/docs/decisions.md +++ b/docs/decisions.md @@ -183,3 +183,27 @@ PR. Актуальные длительности — в логе прогона Альтернатива — `allowPaths: ["pages"]` — была бы слабее: она разрешила бы пустую секцию `pages` в любой локали, то есть пропущенный перевод страницы прошёл бы линтер молча. Пустая секция в EN и есть то, что делает правило точным. + +## 12. Бамп версии и changelog — при пуше в main, а не в PR + +Версионирование и changelog генерирует бот (`bump.yml`, cocogitto) на push в +`main`, а не на pull request. + +- При PR-боте параллельные PR бампили бы одну и ту же версию и конфликтовали по + `CHANGELOG.md`; коммиты бота внутри чужого PR — шум, а версия росла бы за ещё + не влитый код. Репозиторий trunk-based: коммиты идут прямо в `main`, деплой и + так запускается на push. +- Цикл: push в `main` → `verify.yml` (переиспользуемый gate) → `cog bump --auto` + бампит версии в обоих `package.json` (футер сайта читает `web/package.json`), + обновляет `CHANGELOG.md`, ставит тег и пушит без `--skip-ci`, чтобы версионный + коммит заново запустил деплой и сайт показал актуальную версию. Зацикливание + исключено dry-run проверкой: после версионного коммита conventional-коммитов + после тега нет, бот выходит. +- Пуш идёт токеном GitHub App (`XBOCT_BOT_ID`/`XBOCT_BOT_PRIVATE_KEY`), а не + `GITHUB_TOKEN`: пуш стандартным токеном не запускает workflow, и деплой с + новой версией не случился бы. +- `concurrency: bump` без `cancel-in-progress`: два бампа параллельно запушили + бы конфликтующие версии. +- Пересмотреть, если появятся внешние контрибьюторы и поток пойдёт через PR — + тогда боту понадобится режим «черновик релиза в PR» или squash-стратегия с + conventional-заголовком PR. diff --git a/scripts/sync-version.mjs b/scripts/sync-version.mjs new file mode 100644 index 0000000..81715b2 --- /dev/null +++ b/scripts/sync-version.mjs @@ -0,0 +1,16 @@ +import { readFileSync, writeFileSync } from "node:fs"; + +const version = process.argv[2]; +if (!version) { + console.error("usage: node scripts/sync-version.mjs "); + process.exit(1); +} + +for (const file of ["package.json", "web/package.json"]) { + const raw = readFileSync(file, "utf8"); + const manifest = JSON.parse(raw); + manifest.version = version; + const indent = raw.match(/(?<=\n)([^\S\n]+)"/)?.[1] ?? 2; + const eol = raw.endsWith("\n") ? "\n" : ""; + writeFileSync(file, JSON.stringify(manifest, null, indent) + eol); +}