tests / package-smoke-linux (push) Skipped
tests / package-smoke-windows (push) Skipped
tests / package-smoke-macos (push) Skipped
tests / macos (push) Successful in 1m26s
tests / linux (push) Successful in 2m36s
tests / windows (push) Failing after 23m28s
tests / windows (pull_request) Skipped
tests / macos (pull_request) Skipped
tests / package-smoke-linux (pull_request) Skipped
tests / package-smoke-windows (pull_request) Skipped
tests / package-smoke-macos (pull_request) Skipped
tests / linux (pull_request) Successful in 2m36s
Signed-off-by: galeon <dertiellis@gmail.com>
300 lines
13 KiB
YAML
300 lines
13 KiB
YAML
name: release
|
||
|
||
# master -> релиз v<версия>, если такого ещё нет
|
||
# rc -> пре-релиз v<версия>-rcN, N — следующий свободный номер
|
||
# тег vX.Y.Z -> релиз, тег vX.Y.Z-rcN -> пре-релиз
|
||
# ручной запуск -> только сборки, файлы остаются артефактами прогона
|
||
on:
|
||
push:
|
||
branches: [master, rc]
|
||
tags: ["v*"]
|
||
workflow_dispatch:
|
||
|
||
concurrency:
|
||
group: release-${{ github.ref }}
|
||
|
||
env:
|
||
API: ${{ github.server_url }}/api/v1/repos/${{ github.repository }}
|
||
|
||
jobs:
|
||
create-release:
|
||
runs-on: linux
|
||
outputs:
|
||
version: ${{ steps.meta.outputs.version }}
|
||
tag: ${{ steps.meta.outputs.tag }}
|
||
skip: ${{ steps.meta.outputs.skip }}
|
||
release_id: ${{ steps.release.outputs.id }}
|
||
steps:
|
||
- uses: actions/checkout@v4
|
||
|
||
- id: meta
|
||
name: Версия из CMakeLists.txt, тег и тип релиза
|
||
env:
|
||
TOKEN: ${{ secrets.RELEASE_TOKEN }}
|
||
run: |
|
||
version=$(sed -nE 's/^project\(BiLauncher VERSION ([0-9]+\.[0-9]+\.[0-9]+).*/\1/p' CMakeLists.txt)
|
||
[ -n "$version" ] || { echo "Не нашёл project(BiLauncher VERSION ...)"; exit 1; }
|
||
|
||
# Теги релизов, включая черновики (токену с правом записи API отдаёт и их)
|
||
release_tags=$(curl -fsS -H "Authorization: token $TOKEN" "$API/releases?limit=50" \
|
||
| python3 -c 'import json,sys; [print(r["tag_name"]) for r in json.load(sys.stdin)]')
|
||
has_release() { printf '%s\n' "$release_tags" | grep -xF "$1" > /dev/null; }
|
||
# У черновика тега в git ещё нет, поэтому смотрим и в git, и в релизы
|
||
known() {
|
||
git ls-remote --tags origin | sed -E 's#.*refs/tags/##; s/\^\{\}$//'
|
||
printf '%s\n' "$release_tags"
|
||
}
|
||
|
||
tag=""; skip=false
|
||
case "${GITHUB_REF_TYPE}:${GITHUB_REF_NAME}" in
|
||
tag:*)
|
||
tag="${GITHUB_REF_NAME}"
|
||
base="${tag#v}"; base="${base%%-*}"
|
||
if [ "$base" != "$version" ]; then
|
||
echo "Тег $tag не совпадает с версией $version в CMakeLists.txt"; exit 1
|
||
fi
|
||
# Тег мог создать сам релиз из прогона по ветке — тогда второй раз не собираем
|
||
if has_release "$tag"; then
|
||
echo "Релиз $tag уже есть"; skip=true
|
||
fi
|
||
;;
|
||
branch:master)
|
||
tag="v$version"
|
||
if known | grep -xF "$tag" > /dev/null; then
|
||
echo "Релиз $tag уже есть, поднимите версию в CMakeLists.txt"; skip=true
|
||
fi
|
||
;;
|
||
branch:rc)
|
||
n=$(known | sed -nE "s/^v${version//./\\.}-rc([0-9]+)\$/\1/p" | sort -n | tail -1)
|
||
tag="v$version-rc$(( ${n:-0} + 1 ))"
|
||
;;
|
||
esac
|
||
[ -n "$tag" ] && version="${tag#v}"
|
||
|
||
echo "version=$version" >> "$GITHUB_OUTPUT"
|
||
echo "tag=$tag" >> "$GITHUB_OUTPUT"
|
||
echo "skip=$skip" >> "$GITHUB_OUTPUT"
|
||
echo "Версия: $version, тег: ${tag:-нет}, пропуск: $skip"
|
||
|
||
- id: release
|
||
name: Черновик релиза
|
||
if: steps.meta.outputs.tag != '' && steps.meta.outputs.skip != 'true'
|
||
env:
|
||
TOKEN: ${{ secrets.RELEASE_TOKEN }}
|
||
TAG: ${{ steps.meta.outputs.tag }}
|
||
run: |
|
||
base="${TAG#v}"; base="${base%%-*}"
|
||
notes=$(awk -v v="$base" '
|
||
/^## \[/ { if (on) exit; if (index($0, "[" v "]")) { on=1; next } }
|
||
on' CHANGELOG.md)
|
||
prerelease=false; case "$TAG" in *-rc*) prerelease=true;; esac
|
||
# target_commitish: у новой ветки тег появится на этом коммите при публикации
|
||
body=$(python3 -c 'import json,sys; print(json.dumps({"tag_name":sys.argv[1],"target_commitish":sys.argv[4],"name":"BiLauncher "+sys.argv[1],"body":sys.argv[2],"draft":True,"prerelease":sys.argv[3]=="true"}))' \
|
||
"$TAG" "$notes" "$prerelease" "$GITHUB_SHA")
|
||
id=$(curl -fsS -X POST "$API/releases" \
|
||
-H "Authorization: token $TOKEN" -H "Content-Type: application/json" \
|
||
-d "$body" | python3 -c 'import json,sys; print(json.load(sys.stdin)["id"])')
|
||
echo "id=$id" >> "$GITHUB_OUTPUT"
|
||
echo "Создан черновик $([ "$prerelease" = true ] && echo пре-)релиза $TAG (id $id)"
|
||
|
||
build-linux:
|
||
needs: create-release
|
||
if: needs.create-release.outputs.skip != 'true'
|
||
runs-on: linux
|
||
env:
|
||
VERSION: ${{ needs.create-release.outputs.version }}
|
||
RELEASE_ID: ${{ needs.create-release.outputs.release_id }}
|
||
outputs:
|
||
sums: ${{ steps.pack.outputs.sums }}
|
||
steps:
|
||
- uses: actions/checkout@v4
|
||
|
||
- name: Сборка
|
||
run: |
|
||
export PATH="$QT_TOOLS/CMake/bin:$QT_TOOLS/Ninja:$PATH"
|
||
rm -rf build AppDir dist
|
||
cmake -S . -B build -G Ninja -DCMAKE_BUILD_TYPE=Release \
|
||
-DCMAKE_PREFIX_PATH="$QT_ROOT" \
|
||
-DCMAKE_INSTALL_PREFIX=/usr -DCMAKE_INSTALL_LIBDIR=lib
|
||
cmake --build build -j 8
|
||
cmake --install build --prefix "$PWD/AppDir/usr"
|
||
|
||
- id: pack
|
||
name: AppImage и tar.gz
|
||
run: |
|
||
mkdir -p dist
|
||
cp AppDir/usr/share/applications/bilauncher.desktop AppDir/
|
||
cp AppDir/usr/share/icons/hicolor/256x256/apps/bilauncher.png AppDir/
|
||
ln -sf usr/bin/BiLauncher AppDir/AppRun
|
||
ARCH=x86_64 appimagetool --no-appstream AppDir "dist/BiLauncher-$VERSION-x86_64.AppImage"
|
||
cp -a AppDir/usr "BiLauncher-$VERSION"
|
||
tar -czf "dist/BiLauncher-$VERSION-linux-x86_64.tar.gz" "BiLauncher-$VERSION"
|
||
rm -rf "BiLauncher-$VERSION"
|
||
ls -lh dist
|
||
echo "sums=$(cd dist && sha256sum * | base64 -w0)" >> "$GITHUB_OUTPUT"
|
||
|
||
- name: Загрузка в релиз
|
||
if: env.RELEASE_ID != ''
|
||
env:
|
||
TOKEN: ${{ secrets.RELEASE_TOKEN }}
|
||
run: |
|
||
for f in dist/*; do
|
||
curl -fsS -X POST -H "Authorization: token $TOKEN" \
|
||
-F "attachment=@$f" "$API/releases/$RELEASE_ID/assets?name=$(basename "$f")" > /dev/null
|
||
echo "Загружен $(basename "$f")"
|
||
done
|
||
|
||
- name: Артефакты прогона
|
||
if: env.RELEASE_ID == ''
|
||
uses: actions/upload-artifact@v4
|
||
with:
|
||
name: linux
|
||
path: dist/
|
||
|
||
build-windows:
|
||
needs: create-release
|
||
if: needs.create-release.outputs.skip != 'true'
|
||
runs-on: windows
|
||
env:
|
||
VERSION: ${{ needs.create-release.outputs.version }}
|
||
RELEASE_ID: ${{ needs.create-release.outputs.release_id }}
|
||
outputs:
|
||
sums: ${{ steps.build.outputs.sums }}
|
||
steps:
|
||
- uses: actions/checkout@v4
|
||
|
||
- id: build
|
||
name: Сборка, установщик и portable-архив
|
||
shell: powershell
|
||
run: |
|
||
$ErrorActionPreference = "Stop"
|
||
$build = "C:\r\bl-build"; $stage = "C:\r\bl-stage"; $dist = "$PWD\dist"
|
||
Remove-Item -Recurse -Force $build, $stage, $dist -ErrorAction SilentlyContinue
|
||
|
||
$vs = & "${env:ProgramFiles(x86)}\Microsoft Visual Studio\Installer\vswhere.exe" -latest -products * `
|
||
-requires Microsoft.VisualStudio.Component.VC.Tools.x86.x64 -property installationPath
|
||
Import-Module "$vs\Common7\Tools\Microsoft.VisualStudio.DevShell.dll"
|
||
Enter-VsDevShell -VsInstallPath $vs -SkipAutomaticLocation -DevCmdArguments "-arch=x64 -host_arch=x64"
|
||
$env:PATH = "$env:QT_TOOLS\CMake_64\bin;$env:QT_TOOLS\Ninja;$env:PATH"
|
||
|
||
cmake -S . -B $build -G Ninja -DCMAKE_BUILD_TYPE=Release "-DCMAKE_PREFIX_PATH=$env:QT_ROOT"
|
||
if ($LASTEXITCODE) { throw "cmake configure" }
|
||
cmake --build $build
|
||
if ($LASTEXITCODE) { throw "cmake build" }
|
||
cmake --install $build --prefix $stage
|
||
if ($LASTEXITCODE) { throw "cmake install" }
|
||
|
||
New-Item -ItemType Directory -Force $dist | Out-Null
|
||
& "$env:ISCC_DIR\ISCC.exe" /Q "/DAppVersion=$env:VERSION" "/DSourceDir=$stage" "/DOutputDir=$dist" packaging\windows\BiLauncher.iss
|
||
if ($LASTEXITCODE) { throw "iscc" }
|
||
|
||
Remove-Item "$stage\bin\vc_redist.x64.exe" -ErrorAction SilentlyContinue
|
||
$portable = "C:\r\BiLauncher-$env:VERSION"
|
||
Remove-Item -Recurse -Force $portable -ErrorAction SilentlyContinue
|
||
Move-Item $stage $portable
|
||
& "$env:SystemRoot\System32\tar.exe" -a -c -f "$dist\BiLauncher-$env:VERSION-win64-portable.zip" -C C:\r "BiLauncher-$env:VERSION"
|
||
if ($LASTEXITCODE) { throw "zip" }
|
||
Remove-Item -Recurse -Force $portable
|
||
|
||
Get-ChildItem $dist | Format-Table Name, Length
|
||
$sums = Get-ChildItem $dist | ForEach-Object {
|
||
"{0} {1}" -f (Get-FileHash $_.FullName -Algorithm SHA256).Hash.ToLower(), $_.Name }
|
||
$b64 = [Convert]::ToBase64String([Text.Encoding]::UTF8.GetBytes(($sums -join "`n") + "`n"))
|
||
[IO.File]::AppendAllText($env:GITHUB_OUTPUT, "sums=$b64`n")
|
||
|
||
- name: Загрузка в релиз
|
||
if: env.RELEASE_ID != ''
|
||
shell: powershell
|
||
env:
|
||
TOKEN: ${{ secrets.RELEASE_TOKEN }}
|
||
run: |
|
||
foreach ($f in Get-ChildItem dist) {
|
||
curl.exe -fsS -X POST -H "Authorization: token $env:TOKEN" `
|
||
-F "attachment=@$($f.FullName)" "$env:API/releases/$env:RELEASE_ID/assets?name=$($f.Name)" | Out-Null
|
||
if ($LASTEXITCODE) { throw "Не удалось загрузить $($f.Name)" }
|
||
"Загружен $($f.Name)"
|
||
}
|
||
|
||
- name: Артефакты прогона
|
||
if: env.RELEASE_ID == ''
|
||
uses: actions/upload-artifact@v4
|
||
with:
|
||
name: windows
|
||
path: dist/
|
||
|
||
build-macos:
|
||
needs: create-release
|
||
if: needs.create-release.outputs.skip != 'true'
|
||
runs-on: macos
|
||
env:
|
||
VERSION: ${{ needs.create-release.outputs.version }}
|
||
RELEASE_ID: ${{ needs.create-release.outputs.release_id }}
|
||
outputs:
|
||
sums: ${{ steps.pack.outputs.sums }}
|
||
steps:
|
||
- uses: actions/checkout@v4
|
||
|
||
- name: Сборка (universal, arm64 + x86_64)
|
||
run: |
|
||
export PATH="$QT_TOOLS/CMake/CMake.app/Contents/bin:$QT_TOOLS/Ninja:$PATH"
|
||
rm -rf build stage dist dmgroot
|
||
cmake -S . -B build -G Ninja -DCMAKE_BUILD_TYPE=Release \
|
||
-DCMAKE_PREFIX_PATH="$QT_ROOT" \
|
||
-DCMAKE_OSX_ARCHITECTURES="arm64;x86_64"
|
||
cmake --build build
|
||
cmake --install build --prefix "$PWD/stage"
|
||
|
||
- id: pack
|
||
name: Ad-hoc подпись и DMG
|
||
run: |
|
||
codesign --force --deep --sign - stage/BiLauncher.app
|
||
codesign --verify --deep --strict stage/BiLauncher.app
|
||
mkdir -p dmgroot dist
|
||
cp -R stage/BiLauncher.app dmgroot/
|
||
ln -s /Applications dmgroot/Applications
|
||
hdiutil create -volname "BiLauncher" -srcfolder dmgroot -ov -format UDZO \
|
||
"dist/BiLauncher-$VERSION-macOS-universal.dmg"
|
||
rm -rf dmgroot
|
||
ls -lh dist
|
||
echo "sums=$(cd dist && shasum -a 256 * | base64 | tr -d '\n')" >> "$GITHUB_OUTPUT"
|
||
|
||
- name: Загрузка в релиз
|
||
if: env.RELEASE_ID != ''
|
||
env:
|
||
TOKEN: ${{ secrets.RELEASE_TOKEN }}
|
||
run: |
|
||
for f in dist/*; do
|
||
curl -fsS -X POST -H "Authorization: token $TOKEN" \
|
||
-F "attachment=@$f" "$API/releases/$RELEASE_ID/assets?name=$(basename "$f")" > /dev/null
|
||
echo "Загружен $(basename "$f")"
|
||
done
|
||
|
||
- name: Артефакты прогона
|
||
if: env.RELEASE_ID == ''
|
||
uses: actions/upload-artifact@v4
|
||
with:
|
||
name: macos
|
||
path: dist/
|
||
|
||
publish:
|
||
needs: [create-release, build-linux, build-windows, build-macos]
|
||
if: needs.create-release.outputs.release_id != ''
|
||
runs-on: linux
|
||
env:
|
||
RELEASE_ID: ${{ needs.create-release.outputs.release_id }}
|
||
TOKEN: ${{ secrets.RELEASE_TOKEN }}
|
||
steps:
|
||
- name: SHA256SUMS.txt и публикация
|
||
run: |
|
||
{
|
||
echo "${{ needs.build-windows.outputs.sums }}" | base64 -d
|
||
echo "${{ needs.build-linux.outputs.sums }}" | base64 -d
|
||
echo "${{ needs.build-macos.outputs.sums }}" | base64 -d
|
||
} | tr -d '\r' | sed '/^$/d' > SHA256SUMS.txt
|
||
cat SHA256SUMS.txt
|
||
curl -fsS -X POST -H "Authorization: token $TOKEN" \
|
||
-F "attachment=@SHA256SUMS.txt" "$API/releases/$RELEASE_ID/assets?name=SHA256SUMS.txt" > /dev/null
|
||
curl -fsS -X PATCH -H "Authorization: token $TOKEN" -H "Content-Type: application/json" \
|
||
-d '{"draft": false}' "$API/releases/$RELEASE_ID" > /dev/null
|
||
echo "Релиз опубликован"
|