ci(release): publish the release first, then attach the APK
ci / contract (сгенерированный код совпадает с openapi.yaml) (push) Successful in 46s
ci / ts (packages + web) (push) Successful in 38s
ci / docker (образы собираются — их сервер собирает сам при обновлении) (apps/web/Dockerfile, web, ) (push) Successful in 44s
ci / docker (образы собираются — их сервер собирает сам при обновлении) (services/api/Dockerfile, storage-agent, storage-agent) (push) Successful in 51s
ci / docker (образы собираются — их сервер собирает сам при обновлении) (services/recommender/Dockerfile, recommender, ) (push) Successful in 29s
ci / mobile (Metro-бандл Android) (push) Successful in 51s
ci / api (push) Successful in 1m23s
ci / recommender (push) Successful in 37s
ci / docker (образы собираются — их сервер собирает сам при обновлении) (services/api/Dockerfile, api, api) (push) Successful in 1m33s
release / release (заметки) (push) Failing after 5s
release / android (APK в релиз) (push) Skipped
release / verify (push) Successful in 1m19s
ci / contract (сгенерированный код совпадает с openapi.yaml) (push) Successful in 46s
ci / ts (packages + web) (push) Successful in 38s
ci / docker (образы собираются — их сервер собирает сам при обновлении) (apps/web/Dockerfile, web, ) (push) Successful in 44s
ci / docker (образы собираются — их сервер собирает сам при обновлении) (services/api/Dockerfile, storage-agent, storage-agent) (push) Successful in 51s
ci / docker (образы собираются — их сервер собирает сам при обновлении) (services/recommender/Dockerfile, recommender, ) (push) Successful in 29s
ci / mobile (Metro-бандл Android) (push) Successful in 51s
ci / api (push) Successful in 1m23s
ci / recommender (push) Successful in 37s
ci / docker (образы собираются — их сервер собирает сам при обновлении) (services/api/Dockerfile, api, api) (push) Successful in 1m33s
release / release (заметки) (push) Failing after 5s
release / android (APK в релиз) (push) Skipped
release / verify (push) Successful in 1m19s
The release job now creates the Gitea release right after verification with generated notes: Android build status, changes grouped by Conventional Commit type with commit links, server update steps and APK install/check notes. The android job attaches the APK and .sha256 and rewrites only the status block (building / built with size, versionCode and SHA-256 / failed with a log link). scripts/release.mjs is idempotent on re-runs and unit-tested. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
622eb84bc9
commit
d3b2e7bfc3
5 files changed
+424
-55
No files matched your search
@@ -1,4 +1,6 @@
|
||||
# Релиз по тегу vMAJOR.MINOR.PATCH[-rc.N] (docs/ci-cd.md): проверки → подписанный APK → Gitea Release.
|
||||
# Релиз по тегу vMAJOR.MINOR.PATCH[-rc.N] (docs/ci-cd.md): проверки → Gitea Release с заметками → APK.
|
||||
# Релиз создаётся сразу после проверок (статус Android — «собирается»); сборка APK докладывает в него файлы
|
||||
# и переписывает статус: собран / не удалась (scripts/release.mjs).
|
||||
# Docker-образы не публикуются: сервер собирает их сам из клонированного репозитория (deploy/update.sh).
|
||||
#
|
||||
# Секреты (Settings → Actions → Secrets):
|
||||
@@ -42,16 +44,43 @@ jobs:
|
||||
- name: TypeScript
|
||||
run: pnpm i18n:check && pnpm test:scripts && pnpm typecheck && pnpm test
|
||||
|
||||
android-release:
|
||||
name: android + release
|
||||
release:
|
||||
name: release (заметки)
|
||||
needs: verify
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
# вся история и теги: заметки строятся по коммитам с прошлого релиза
|
||||
with: { fetch-depth: 0 }
|
||||
- uses: actions/setup-node@v4
|
||||
with: { node-version: "${{ env.NODE_VERSION }}" }
|
||||
- name: Gitea Release
|
||||
env:
|
||||
GITEA_API: ${{ github.server_url }}/api/v1/repos/${{ github.repository }}
|
||||
GITEA_TOKEN: ${{ secrets.RELEASE_TOKEN }}
|
||||
TAG: ${{ github.ref_name }}
|
||||
VERSION: ${{ needs.verify.outputs.version }}
|
||||
PRERELEASE: ${{ needs.verify.outputs.prerelease }}
|
||||
run: node scripts/release.mjs create
|
||||
|
||||
android:
|
||||
name: android (APK в релиз)
|
||||
needs: [verify, release]
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
PIPU_VERSION: ${{ needs.verify.outputs.version }}
|
||||
PIPU_VERSION_CODE: ${{ needs.verify.outputs.version_code }}
|
||||
# для scripts/release.mjs
|
||||
GITEA_API: ${{ github.server_url }}/api/v1/repos/${{ github.repository }}
|
||||
GITEA_TOKEN: ${{ secrets.RELEASE_TOKEN }}
|
||||
TAG: ${{ github.ref_name }}
|
||||
VERSION: ${{ needs.verify.outputs.version }}
|
||||
VERSION_CODE: ${{ needs.verify.outputs.version_code }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with: { fetch-depth: 0 }
|
||||
# при перезапуске одной этой сборки статус «не удалась» сменится на «собирается»
|
||||
- name: Статус в релизе — собирается
|
||||
run: node scripts/release.mjs android building
|
||||
- uses: actions/setup-java@v4
|
||||
with: { distribution: temurin, java-version: "17" }
|
||||
- uses: android-actions/setup-android@v3
|
||||
@@ -106,9 +135,11 @@ jobs:
|
||||
"$bt/apksigner" sign --ks release.keystore --ks-pass env:KEYSTORE_PASSWORD \
|
||||
--ks-key-alias "$KEY_ALIAS" --key-pass env:KEY_PASSWORD --out "$out" "$src"
|
||||
rm release.keystore
|
||||
echo "SIGNING=release" >> "$GITHUB_ENV"
|
||||
elif [ "$PRERELEASE" = "true" ]; then
|
||||
echo "::warning::ANDROID_KEYSTORE_BASE64 не задан — APK подписан отладочным ключом и не обновится поверх релизного"
|
||||
cp "$src" "$out"
|
||||
echo "SIGNING=debug" >> "$GITHUB_ENV"
|
||||
else
|
||||
echo "::error::ANDROID_KEYSTORE_BASE64 не задан — релиз с отладочной подписью не выпускается (rc-теги допускают)"
|
||||
exit 1
|
||||
@@ -117,41 +148,9 @@ jobs:
|
||||
sha256sum "$out" | cut -d' ' -f1 > "$out.sha256"
|
||||
echo "APK=$out" >> "$GITHUB_ENV"
|
||||
|
||||
- name: Changelog
|
||||
env:
|
||||
PRERELEASE: ${{ needs.verify.outputs.prerelease }}
|
||||
run: |
|
||||
# для финального релиза — изменения с прошлого финального, а не с последнего rc
|
||||
exclude=()
|
||||
[ "$PRERELEASE" = "true" ] || exclude=(--exclude '*-rc*')
|
||||
prev="$(git describe --tags --abbrev=0 "${exclude[@]}" "${GITHUB_REF_NAME}^" 2>/dev/null || true)"
|
||||
range="${prev:+$prev..}${GITHUB_REF_NAME}"
|
||||
{
|
||||
echo "## Pipu Music ${PIPU_VERSION}"
|
||||
echo
|
||||
for t in feat fix perf refactor docs ci chore; do
|
||||
lines="$(git log --no-merges --format='%s' "$range" | grep -E "^${t}(\(|:|!)" || true)"
|
||||
[ -n "$lines" ] || continue
|
||||
case $t in feat) h="Новое";; fix) h="Исправления";; perf) h="Производительность";; *) h="$t";; esac
|
||||
echo "### $h"; echo "$lines" | sed 's/^/- /'; echo
|
||||
done
|
||||
} > CHANGELOG_RELEASE.md
|
||||
cat CHANGELOG_RELEASE.md
|
||||
- name: APK в релиз
|
||||
run: node scripts/release.mjs android success "$APK"
|
||||
|
||||
- name: Gitea Release
|
||||
env:
|
||||
TOKEN: ${{ secrets.RELEASE_TOKEN }}
|
||||
API: ${{ github.server_url }}/api/v1/repos/${{ github.repository }}
|
||||
PRERELEASE: ${{ needs.verify.outputs.prerelease }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
body="$(jq -n --arg tag "$GITHUB_REF_NAME" --arg name "Pipu Music $PIPU_VERSION" \
|
||||
--rawfile notes CHANGELOG_RELEASE.md --argjson pre "$PRERELEASE" \
|
||||
'{tag_name:$tag, name:$name, body:$notes, prerelease:$pre, draft:false}')"
|
||||
id="$(curl -fsS -X POST -H "Authorization: token $TOKEN" -H 'Content-Type: application/json' \
|
||||
-d "$body" "$API/releases" | jq -r .id)"
|
||||
for f in "$APK" "$APK.sha256"; do
|
||||
curl -fsS -X POST -H "Authorization: token $TOKEN" \
|
||||
-F "attachment=@$f" "$API/releases/$id/assets?name=$(basename "$f")" > /dev/null
|
||||
echo "uploaded $(basename "$f")"
|
||||
done
|
||||
- name: Статус в релизе — сборка не удалась
|
||||
if: failure()
|
||||
run: node scripts/release.mjs android failure
|
||||
Reference in new issue
Block a user