Files
ElyOffice/scripts/ci.sh
T
ZacharyZhang-NYandClaude 41321fd05f 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>
2026-10-19 19:19:04 -04:00

116 lines
4.4 KiB
Bash
Executable File

#!/usr/bin/env bash
# A platform's release. Usage: ci.sh <macos|windows|linux> <tag>
set -euo pipefail
root=$(cd "$(dirname "$0")/.." && pwd)
os=${1:?macos, windows or linux}
tag=${2:?the release tag, such as v0.1.3}
version=$(awk -F'"' '/^version = / { print $2; exit }' "$root/Cargo.toml")
[ "$tag" = "v$version" ] || {
echo "ci.sh: tag $tag is not v$version" >&2
exit 1
}
: "${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}"
fi
[ -z "${ELY_PATH:-}" ] || PATH=$ELY_PATH:$PATH
cd "$root"
# Linux builds and packages in the Ubuntu 26.04 container.
inside=()
[ "$os" != linux ] || inside=(packaging/linux/container.sh)
# Engines another clone on this host built; else built here.
if [ -n "${ELY_SHARE:-}" ]; then
for part in engines reference; do
# Never mix this clone's own build with shared engines.
if [ "$os" != windows ] && { [ -e "$part" ] || [ -L "$part" ]; }; then
# A sentinel keeps a trailing newline in the target.
target=$( (readlink "$part" || true) && printf x)
target=${target%x}
[ "$target" = "$ELY_SHARE/$part"$'\n' ] || {
echo "ci.sh: $root/$part is not a link to $ELY_SHARE/$part; remove it" >&2
exit 1
}
fi
if [ ! -e "$part" ]; then
case $os in
windows) powershell -NoProfile -Command "New-Item -ItemType Junction -Path '$part' -Target '$(cygpath -w "$ELY_SHARE/$part")' | Out-Null" ;;
*) ln -s "$ELY_SHARE/$part" "$part" ;;
esac
fi
done
else
scripts/fetch-references.sh
${inside[@]+"${inside[@]}"} scripts/build-mupdf.sh
${inside[@]+"${inside[@]}"} scripts/build-git.sh
${inside[@]+"${inside[@]}"} scripts/fetch-git-lfs.sh
${inside[@]+"${inside[@]}"} scripts/fetch-tessdata.sh
${inside[@]+"${inside[@]}"} scripts/build-libreoffice.sh
fi
dist=$root/dist
rm -rf "$dist"
batch=$(awk -F'\t' '$4 == 1 { print $1 }' packaging/apps.tsv)
case $os in
macos) packaging/macos/release.sh 1 ;;
windows)
for slug in $batch; do packaging/windows/installer.sh "$slug"; done
packaging/windows/bundle.sh
;;
linux) for slug in $batch; do ${inside[@]+"${inside[@]}"} packaging/linux/package.sh "$slug"; done ;;
*)
echo "ci.sh: no release for $os" >&2
exit 1
;;
esac
# Windows checkouts flatten symlinks; Linux and macOS write source.
if [ "$os" = linux ]; then
packaging/source.sh "$dist"
fi
# The tag's release, made by whichever platform comes first.
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 (422); the read decides.
curl -fsS "${auth[@]}" -H "Content-Type: application/json" -d "$body" "$api/releases" >/dev/null || true
id=$(release_id)
fi
names=()
for file in "$dist"/*; do
[ -f "$file" ] || continue
name=$(basename "$file")
# Linux alone publishes the source pair.
if [ "$os" != linux ] && [[ $name == *-source.tar.gz ]]; then
echo "ci.sh: $name is Linux's to upload"
continue
fi
names+=("$name")
done
# 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
# Rebuilt bytes replace a rerun's earlier upload; other platforms' files stay.
cd "$dist"
for name in "${names[@]}"; do
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 "${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"