CI: release from GitHub Actions to GitHub releases
The release workflow moves from .gitea to .github: macOS on the macos-signing runner, Windows and Linux (WSL) on ely-windows. The persistent clones fetch from GitHub. ci.sh creates or reuses the tag's release through GitHub's API and replaces a rerun's assets of the same name; the update manifests point at GitHub's download URLs. Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
3 files changed
+38
-27
No files matched your search
@@ -1,18 +1,21 @@
|
||||
# A tag builds, packages and uploads all three platforms.
|
||||
# Tags only: no pull request ever reaches the self-hosted runners.
|
||||
name: release
|
||||
on:
|
||||
push:
|
||||
tags: ['v*']
|
||||
permissions:
|
||||
contents: write
|
||||
jobs:
|
||||
macos:
|
||||
# A GUI-session agent: daemons see no login keychain.
|
||||
runs-on: macos-signing
|
||||
runs-on: [self-hosted, macos-signing]
|
||||
timeout-minutes: 720
|
||||
steps:
|
||||
- name: Build, package and upload for macOS
|
||||
shell: bash
|
||||
env:
|
||||
ELY_RELEASE_TOKEN: ${{ secrets.GITEA_TOKEN }}
|
||||
ELY_RELEASE_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
# The dev clone's engines: LibreOffice from scratch outlasts the runner.
|
||||
ELY_SHARE: /Users/zacharyzhang/Documents/GitHub/ElyOfficeSuite
|
||||
ELY_PATH: /Users/zacharyzhang/.cargo/bin:/opt/homebrew/bin
|
||||
@@ -21,42 +24,45 @@ jobs:
|
||||
ELY_NOTARY_PROFILE: ${{ vars.ELY_NOTARY_PROFILE }}
|
||||
run: |
|
||||
dir=$HOME/ely-ci/ElyOffice
|
||||
[ -d "$dir/.git" ] || git clone https://git.zacharyzhang.com/ZacharyZhang-NY/ElyOffice.git "$dir"
|
||||
[ -d "$dir/.git" ] || git clone https://github.com/ELY-Open-Source/ElyOffice.git "$dir"
|
||||
git -C "$dir" remote set-url origin https://github.com/ELY-Open-Source/ElyOffice.git
|
||||
git -C "$dir" fetch --force --tags origin
|
||||
git -C "$dir" checkout --force "${{ github.sha }}"
|
||||
"$dir/scripts/ci.sh" macos "${{ github.ref_name }}"
|
||||
windows:
|
||||
runs-on: windows
|
||||
runs-on: [self-hosted, ely-windows]
|
||||
timeout-minutes: 360
|
||||
steps:
|
||||
- name: Build, package and upload for Windows
|
||||
shell: bash
|
||||
env:
|
||||
ELY_RELEASE_TOKEN: ${{ secrets.GITEA_TOKEN }}
|
||||
ELY_RELEASE_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
ELY_SHARE: /c/Users/zhang/Documents/Github/ElyOffice
|
||||
ELY_PATH: /c/Program Files/CMake/bin:/c/Users/zhang/AppData/Local/Microsoft/WinGet/Packages/Ninja-build.Ninja_Microsoft.Winget.Source_8wekyb3d8bbwe
|
||||
run: |
|
||||
dir=$HOME/ely-ci/ElyOffice
|
||||
[ -d "$dir/.git" ] || git clone https://git.zacharyzhang.com/ZacharyZhang-NY/ElyOffice.git "$dir"
|
||||
[ -d "$dir/.git" ] || git clone https://github.com/ELY-Open-Source/ElyOffice.git "$dir"
|
||||
git -C "$dir" remote set-url origin https://github.com/ELY-Open-Source/ElyOffice.git
|
||||
git -C "$dir" fetch --force --tags origin
|
||||
git -C "$dir" checkout --force "${{ github.sha }}"
|
||||
"$dir/scripts/ci.sh" windows "${{ github.ref_name }}"
|
||||
linux:
|
||||
# WSL on the Windows runner keeps a built kernel.
|
||||
runs-on: windows
|
||||
runs-on: [self-hosted, ely-windows]
|
||||
needs: windows
|
||||
timeout-minutes: 360
|
||||
steps:
|
||||
- name: Build, package and upload for Linux
|
||||
shell: bash
|
||||
env:
|
||||
ELY_RELEASE_TOKEN: ${{ secrets.GITEA_TOKEN }}
|
||||
ELY_RELEASE_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
WSLENV: ELY_RELEASE_TOKEN
|
||||
run: |
|
||||
wsl -d Ubuntu --exec bash -lc '
|
||||
set -euo pipefail
|
||||
dir=$HOME/ely-ci/ElyOffice
|
||||
[ -d "$dir/.git" ] || git clone https://git.zacharyzhang.com/ZacharyZhang-NY/ElyOffice.git "$dir"
|
||||
[ -d "$dir/.git" ] || git clone https://github.com/ELY-Open-Source/ElyOffice.git "$dir"
|
||||
git -C "$dir" remote set-url origin https://github.com/ELY-Open-Source/ElyOffice.git
|
||||
git -C "$dir" fetch --force --tags origin
|
||||
git -C "$dir" checkout --force "${{ github.sha }}"
|
||||
ELY_SHARE=$HOME/Documents/Github/ElyOffice "$dir/scripts/ci.sh" linux "${{ github.ref_name }}"
|
||||
@@ -7,7 +7,7 @@ batch=${1:-1}
|
||||
dist=${ELY_DIST:-$root/dist}
|
||||
version=$(awk -F'"' '/^version = / { print $2; exit }' "$root/Cargo.toml")
|
||||
arch=$(uname -m)
|
||||
releases=https://git.zacharyzhang.com/ZacharyZhang-NY/ElyOffice/releases
|
||||
releases=https://github.com/ELY-Open-Source/ElyOffice/releases
|
||||
[ -z "${ELY_NOTARY_PROFILE:-}" ] || [ -n "${ELY_SIGN_IDENTITY:-}" ] || {
|
||||
echo "release.sh: notarizing needs ELY_SIGN_IDENTITY, a Developer ID" >&2
|
||||
exit 1
|
||||
|
||||
+22
-17
@@ -10,7 +10,7 @@ version=$(awk -F'"' '/^version = / { print $2; exit }' "$root/Cargo.toml")
|
||||
echo "ci.sh: tag $tag is not v$version" >&2
|
||||
exit 1
|
||||
}
|
||||
: "${ELY_RELEASE_TOKEN:?the Gitea token that uploads}"
|
||||
: "${ELY_RELEASE_TOKEN:?the GitHub token that uploads}"
|
||||
if [ "$os" = macos ]; then
|
||||
: "${ELY_SIGN_IDENTITY:?the Developer ID Application certificate}"
|
||||
: "${ELY_NOTARY_PROFILE:?the notarytool keychain profile}"
|
||||
@@ -72,13 +72,14 @@ if [ "$os" = linux ]; then
|
||||
fi
|
||||
|
||||
# The tag's release, made by whichever platform comes first.
|
||||
api=https://git.zacharyzhang.com/api/v1/repos/ZacharyZhang-NY/ElyOffice
|
||||
auth="Authorization: token $ELY_RELEASE_TOKEN"
|
||||
release_id() { curl -fsS -H "$auth" "$api/releases/tags/$tag" | python3 -c 'import json, sys; print(json.load(sys.stdin)["id"])'; }
|
||||
repo=ELY-Open-Source/ElyOffice
|
||||
api=https://api.github.com/repos/$repo
|
||||
auth=(-H "Authorization: Bearer $ELY_RELEASE_TOKEN" -H "Accept: application/vnd.github+json" -H "X-GitHub-Api-Version: 2022-11-28")
|
||||
release_id() { curl -fsS "${auth[@]}" "$api/releases/tags/$tag" | python3 -c 'import json, sys; print(json.load(sys.stdin)["id"])' | tr -d '\r'; }
|
||||
if ! id=$(release_id 2>/dev/null); then
|
||||
body="{\"tag_name\": \"$tag\", \"name\": \"Ely Office $version\"}"
|
||||
# Another platform may make it first; the read decides.
|
||||
curl -fsS -H "$auth" -H "Content-Type: application/json" -d "$body" "$api/releases" >/dev/null || true
|
||||
# Another platform may make it first (422); the read decides.
|
||||
curl -fsS "${auth[@]}" -H "Content-Type: application/json" -d "$body" "$api/releases" >/dev/null || true
|
||||
id=$(release_id)
|
||||
fi
|
||||
names=()
|
||||
@@ -92,19 +93,23 @@ for file in "$dist"/*; do
|
||||
fi
|
||||
names+=("$name")
|
||||
done
|
||||
# Rebuilt bytes differ; never mix them with earlier uploads.
|
||||
have=$(curl -fsS -H "$auth" "$api/releases/$id/assets" | python3 -c 'import json, sys; print("\n".join(a["name"] for a in json.load(sys.stdin)))')
|
||||
taken=()
|
||||
for name in "${names[@]}"; do
|
||||
if grep -qxF "$name" <<<"$have"; then taken+=("$name"); fi
|
||||
# Each asset's id and name, a page of 100 at a time; Windows Python writes CRLF.
|
||||
have=
|
||||
for ((page = 1; ; page++)); do
|
||||
got=$(curl -fsS "${auth[@]}" "$api/releases/$id/assets?per_page=100&page=$page" |
|
||||
python3 -c 'import json, sys; print("\n".join("%s\t%s" % (a["id"], a["name"]) for a in json.load(sys.stdin)))' | tr -d '\r')
|
||||
[ -n "$got" ] || break
|
||||
have+=$got$'\n'
|
||||
done
|
||||
if [ ${#taken[@]} -gt 0 ]; then
|
||||
echo "ci.sh: already on $tag; delete them, then rerun: ${taken[*]}" >&2
|
||||
exit 1
|
||||
fi
|
||||
# Rebuilt bytes replace a rerun's earlier upload; other platforms' files stay.
|
||||
cd "$dist"
|
||||
for name in "${names[@]}"; do
|
||||
file=$dist/$name
|
||||
for old in $(awk -F'\t' -v name="$name" '$2 == name { print $1 }' <<<"$have"); do
|
||||
echo "ci.sh: replacing $name"
|
||||
curl -fsS "${auth[@]}" -X DELETE "$api/releases/assets/$old" >/dev/null
|
||||
done
|
||||
echo "ci.sh: uploading $name"
|
||||
curl -fsS -H "$auth" -F "attachment=@$file" "$api/releases/$id/assets?name=$name" >/dev/null
|
||||
curl -fsS "${auth[@]}" -H "Content-Type: application/octet-stream" --data-binary "@$name" \
|
||||
"https://uploads.github.com/repos/$repo/releases/$id/assets?name=$name" >/dev/null
|
||||
done
|
||||
echo "ci.sh: $os uploaded to $tag"
|
||||
Reference in new issue
Block a user