From f72fb08ce93d8683325adb6d18a7cb5bd5a734c5 Mon Sep 17 00:00:00 2001 From: ZhuchkaTriplesix Date: Sun, 19 Apr 2026 00:03:00 +0300 Subject: [PATCH] ci build --- .github/workflows/ci.yml | 30 +++++++++++ .github/workflows/release.yml | 98 ++++++++++++++++++++++++++++------- cliff.toml | 84 ++++++++++++++++++++++++++++++ docs/tags-and-releases.md | 95 +++++++++++++++++++++++++++++++++ 4 files changed, 288 insertions(+), 19 deletions(-) create mode 100644 cliff.toml create mode 100644 docs/tags-and-releases.md diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 05ef09f0..ff2c9c6e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -3,6 +3,8 @@ name: CI on: push: branches: [ main, dev, '**-connector', '**-connection-pull' ] + tags: + - 'v*' pull_request: branches: [ main, dev ] @@ -44,3 +46,31 @@ jobs: - name: Analyze code run: flutter analyze + + # Release smoke build: same tag also runs release.yml (artifacts). This job + # gates tags on a real linux release compile after tests + analyze. + build-linux-release: + name: Build Linux (release) + needs: [test, analyze] + if: startsWith(github.ref, 'refs/tags/v') + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Install Linux dependencies + run: | + sudo apt-get update + sudo apt-get install -y clang cmake ninja-build pkg-config libgtk-3-dev + + - name: Setup Flutter + uses: subosito/flutter-action@v2 + with: + flutter-version: '3.38.5' + channel: 'stable' + cache: true + + - name: Get dependencies + run: flutter pub get + + - name: Build Linux (release) + run: flutter build linux --release diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index bd375a14..a8584512 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -1,14 +1,21 @@ -# Сборка релизов и публикация в GitHub Releases. -# Запуск: создайте и запушьте тег, например v0.1.0: -# git tag v0.1.0 -# git push origin v0.1.0 +# Release: сборка артефактов → единая публикация с git-cliff и SHA256SUMS. +# Триггер: git tag v0.1.0 && git push origin v0.1.0 +# +# Рекомендуемые коммиты: Conventional Commits (feat:, fix:, …) — см. cliff.toml name: Release on: push: tags: - - 'v*' # v0.1.0, v1.0.0, etc. + - 'v*' + +permissions: + contents: write + +concurrency: + group: release-${{ github.ref }} + cancel-in-progress: false jobs: build-windows: @@ -36,16 +43,11 @@ jobs: $dir = "build\windows\x64\runner\Release" Compress-Archive -Path "$dir\*" -DestinationPath "Querya-Desktop-$tag-windows.zip" - - name: Create Release and upload Windows - uses: softprops/action-gh-release@v2 + - uses: actions/upload-artifact@v4 with: - tag_name: ${{ github.ref_name }} - name: Release ${{ github.ref_name }} - generate_release_notes: true - files: Querya-Desktop-${{ github.ref_name }}-windows.zip - allow_updates: true - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + name: bundle-windows + path: Querya-Desktop-${{ github.ref_name }}-windows.zip + if-no-files-found: error build-linux: name: Build Linux @@ -74,15 +76,73 @@ jobs: - name: Zip Linux artifact run: | cd build/linux/x64/release/bundle - zip -r ../../../../../../Querya-Desktop-${{ github.ref_name }}-linux.zip . + zip -r "${GITHUB_WORKSPACE}/Querya-Desktop-${{ github.ref_name }}-linux.zip" . + + - uses: actions/upload-artifact@v4 + with: + name: bundle-linux + path: Querya-Desktop-${{ github.ref_name }}-linux.zip + if-no-files-found: error + + publish: + name: Publish GitHub Release + needs: [build-windows, build-linux] + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - uses: taiki-e/install-action@v2 + with: + tool: git-cliff@2.11.0 + + - uses: actions/download-artifact@v4 + with: + path: artifacts + pattern: bundle-* + merge-multiple: true + + - name: Layout distribution files + run: | + set -euo pipefail + mkdir -p dist + find artifacts -name '*.zip' -exec mv -t dist/ {} + + test "$(find dist -name '*.zip' | wc -l)" -eq 2 + cd dist + sha256sum *.zip | tee SHA256SUMS.txt + + - name: Generate changelog (git-cliff + GitHub API) + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + GITHUB_REPO: ${{ github.repository }} + run: | + set -euo pipefail + TAG="${{ github.ref_name }}" + # Текст страницы релиза: без глобального header из cliff.toml + git-cliff --latest \ + --config cliff.toml \ + --strip header \ + --github-token "$GITHUB_TOKEN" \ + --github-repo "$GITHUB_REPO" \ + -o release-body.md + # Вложение: полный фрагмент с header (удобно архивировать / копировать в docs) + git-cliff --latest \ + --config cliff.toml \ + --github-token "$GITHUB_TOKEN" \ + --github-repo "$GITHUB_REPO" \ + -o "CHANGELOG-${TAG}.md" - - name: Upload to Release (Linux) + - name: Create GitHub Release uses: softprops/action-gh-release@v2 with: tag_name: ${{ github.ref_name }} name: Release ${{ github.ref_name }} - generate_release_notes: true - files: Querya-Desktop-${{ github.ref_name }}-linux.zip - allow_updates: true + body_path: release-body.md + fail_on_unmatched_files: true + files: | + dist/*.zip + dist/SHA256SUMS.txt + CHANGELOG-${{ github.ref_name }}.md env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/cliff.toml b/cliff.toml new file mode 100644 index 00000000..7b6f17bf --- /dev/null +++ b/cliff.toml @@ -0,0 +1,84 @@ +# git-cliff — https://git-cliff.org/docs/configuration +# Conventional Commits: https://www.conventionalcommits.org/ +# +# Явный remote: SSH origin (`git@github.com:…`) без этого даёт пустые ссылки в changelog. +# Форки могут переопределить секцию или задать GITHUB_REPO при генерации. + +[remote.github] +owner = "QueryaHub" +repo = "Querya-Desktop" + +[changelog] +header = """ +# Changelog + +Release history. Commit messages should follow [Conventional Commits](https://www.conventionalcommits.org/) (`feat:`, `fix:`, `docs:`, …) so entries group correctly. + +""" +body = """ +{%- macro commit_url(id) -%} +https://github.com/{{ remote.github.owner }}/{{ remote.github.repo }}/commit/{{ id }} +{%- endmacro -%} + +{% macro print_commit(commit) -%} +- {% if commit.scope %}**{{ commit.scope }}:** {% endif %}\ +{% if commit.breaking %}[**breaking**] {% endif %}\ +{{ commit.message | upper_first | trim }} — \ +[`{{ commit.id | truncate(length=7, end="") }}`]({{ self::commit_url(id=commit.id) }}) +{%- endmacro %} + +{% if version %} +## [{{ version }}] — {{ timestamp | date(format="%Y-%m-%d") }} +{% if previous.version %} +[Compare {{ previous.version }}…{{ version }}](https://github.com/{{ remote.github.owner }}/{{ remote.github.repo }}/compare/{{ previous.version }}..{{ version }}) +{% endif %} +{% else %} +## [unreleased] +{% endif %} + +{% for group, commits in commits | group_by(attribute="group") %} +### {{ group }} +{% for commit in commits -%} +{{ self::print_commit(commit=commit) }} +{% endfor %} +{% endfor %} +{%- if github %} +{%- set newbies = github.contributors | filter(attribute="is_first_time", value=true) %} +{%- if newbies | length != 0 %} + +### New contributors +{% for c in newbies -%} +- @{{ c.username }}{% if c.pr_number %} ([#{{ c.pr_number }}](https://github.com/{{ remote.github.owner }}/{{ remote.github.repo }}/pull/{{ c.pr_number }})){% endif %} +{% endfor %} +{%- endif %} +{%- endif %} +""" +footer = """ +""" +trim = true + +[git] +conventional_commits = true +# Включать и неконвенциональные коммиты (попадут в «Прочее»). +filter_unconventional = false +split_commits = false +commit_parsers = [ + { message = "^feat", group = "Features" }, + { message = "^fix", group = "Bug Fixes" }, + { message = "^doc", group = "Documentation" }, + { message = "^perf", group = "Performance" }, + { message = "^refactor", group = "Refactor" }, + { message = "^style", group = "Styling" }, + { message = "^test", group = "Tests" }, + { message = "^build", group = "Build" }, + { message = "^ci", group = "CI" }, + { message = "^chore", group = "Chore" }, + { message = "^revert", group = "Revert" }, + { message = ".*", group = "Other" }, +] +protect_breaking_commits = true +filter_commits = false +tag_pattern = "v[0-9].*" +skip_tags = "beta|alpha|rc" +topo_order = false +sort_commits = "newest" diff --git a/docs/tags-and-releases.md b/docs/tags-and-releases.md new file mode 100644 index 00000000..48004555 --- /dev/null +++ b/docs/tags-and-releases.md @@ -0,0 +1,95 @@ +# Теги и релизы + +Кратко: как помечать версии в Git и что при этом делает CI. + +## Зачем теги + +- **Версия в Git** — неизменяемая метка на коммите (`v0.2.0` всегда указывает на один и тот же снимок кода). +- **Автосборка** — при пуше тега вида `v*` запускается workflow **Release** (см. `.github/workflows/release.yml`): сборки Linux и Windows, checksums, GitHub Release с текстом из [git-cliff](https://git-cliff.org/) и вложениями. + +Теги **не заменяют** обычные коммиты в `main` / `dev`: сначала коммиты попадают в нужную ветку, затем на выбранный коммит вешается тег. + +## Имя тега + +- Используйте префикс **`v`** и семантическую версию, например: `v0.1.0`, `v1.2.3`. +- В CI и [cliff.toml](../cliff.toml) ожидаются теги, попадающие под шаблон **`v*`** (например `v0.1.0`). Теги вроде `1.0.0` без `v` workflow **не** подхватит. +- Предрелизные суффиксы в имени тега возможны, но в `cliff.toml` для changelog **пропускаются** паттерны вроде `beta`, `alpha`, `rc` в `skip_tags` — ориентируйтесь на обычные релизные теги `v1.0.0`. + +## Создать и отправить тег + +Убедитесь, что нужный коммит уже в удалённом репозитории (или запушьте ветку, затем тег). + +**Тег на текущий коммит:** + +```bash +git checkout main # или dev — как принято у вас +git pull +git tag v0.2.0 +git push origin v0.2.0 +``` + +**Тег на конкретный коммит:** + +```bash +git tag v0.2.0 abc1234 +git push origin v0.2.0 +``` + +**Удалить тег** (осторожно, если релиз уже опубликован): + +```bash +git tag -d v0.2.0 +git push origin :refs/tags/v0.2.0 +``` + +На GitHub вручную: **Releases → Draft** не заменяет пуш тега; для автоматизации ориентируйтесь на `git push origin `. + +## Что появится в GitHub после пуша тега + +1. Запускается workflow **Release**. +2. Собираются артефакты **Windows** и **Linux** (zip). +3. Генерируется **`SHA256SUMS.txt`** для проверки архивов. +4. Формируется описание релиза и файл **`CHANGELOG-<тег>.md`** через **git-cliff** (группировка по Conventional Commits, при наличии токена — данные с GitHub API). +5. Создаётся или обновляется **GitHub Release** с телом из changelog и вложениями (zip + checksums + markdown). + +Отдельно при пуше тега `v*` может выполняться **CI** из `.github/workflows/ci.yml` (тесты, анализ, при необходимости сборка Linux). + +## Коммиты и changelog + +Чтобы разделы релиза (Features, Bug Fixes и т.д.) выглядели аккуратно, сообщения коммитов лучше вести в стиле [Conventional Commits](https://www.conventionalcommits.org/), например: + +- `feat(connections): …` +- `fix(postgres): …` +- `docs: …` + +Остальные сообщения не пропадают: они попадают в группу **Other** (см. [cliff.toml](../cliff.toml)). + +## Версия в приложении + +Номер в **Git-теге** и поле **`version`** в [pubspec.yaml](../pubspec.yaml) — разные сущности. Для согласованности перед релизом обычно обновляют `pubspec.yaml`, коммитят, затем вешают тег на этот коммит (или наоборот — по договорённости в команде). + +## Где смотреть настройки + +| Файл | Назначение | +|------|------------| +| [.github/workflows/release.yml](../.github/workflows/release.yml) | Триггер по тегам `v*`, сборка, релиз | +| [.github/workflows/ci.yml](../.github/workflows/ci.yml) | CI при пуше веток и тегов `v*` | +| [cliff.toml](../cliff.toml) | Правила changelog (группы, теги, remote) | + +## Локальная проверка changelog (опционально) + +Установите [git-cliff](https://git-cliff.org/docs/installation), в корне репозитория: + +```bash +git-cliff --latest --strip header +``` + +Для расширенного контекста (PR, контрибьюторы) нужен токен GitHub: + +```bash +export GITHUB_TOKEN=ghp_... +export GITHUB_REPO=QueryaHub/Querya-Desktop +git-cliff --latest --github-token "$GITHUB_TOKEN" --github-repo "$GITHUB_REPO" --strip header +``` + +(В форке подставьте свой `owner/repo`.)