mirror of
https://github.com/ARMSX2/ARMSX2.git
synced 2026-08-24 16:50:16 -07:00
246 lines
9.6 KiB
YAML
246 lines
9.6 KiB
YAML
name: Upload to MoonStore
|
|
|
|
on:
|
|
workflow_run:
|
|
workflows: ["Build All Platforms"]
|
|
types: [completed]
|
|
workflow_dispatch:
|
|
inputs:
|
|
run_id:
|
|
description: Successful Build All Platforms run ID
|
|
required: true
|
|
type: string
|
|
|
|
concurrency:
|
|
group: moonstore-${{ github.event.workflow_run.id || inputs.run_id }}
|
|
cancel-in-progress: false
|
|
|
|
permissions:
|
|
actions: read
|
|
contents: read
|
|
|
|
jobs:
|
|
upload-to-moonstore:
|
|
name: Upload to MoonStore
|
|
if: >-
|
|
github.repository == 'ARMSX2/ARMSX2' &&
|
|
(github.event_name == 'workflow_dispatch' ||
|
|
(github.event.workflow_run.conclusion == 'success' &&
|
|
github.event.workflow_run.event == 'push' &&
|
|
github.event.workflow_run.head_branch == 'master'))
|
|
runs-on: ubuntu-24.04
|
|
timeout-minutes: 90
|
|
env:
|
|
MOONSTORE_API: https://moon-store.app/api/developer/v1
|
|
MOONSTORE_APP_ID: come.nanodata.armsx2
|
|
MOONSTORE_API_KEY: ${{ secrets.MOONSTORE_API_KEY }}
|
|
REQUESTED_RUN_ID: ${{ github.event.workflow_run.id || inputs.run_id }}
|
|
MAX_ARTIFACT_BYTES: "100000000"
|
|
|
|
steps:
|
|
- name: Resolve source run
|
|
id: source
|
|
shell: bash
|
|
env:
|
|
GH_TOKEN: ${{ github.token }}
|
|
run: |
|
|
set -euo pipefail
|
|
gh api "repos/$GITHUB_REPOSITORY/actions/runs/$REQUESTED_RUN_ID" > source-run.json
|
|
jq -e '
|
|
.name == "Build All Platforms" and
|
|
.event == "push" and
|
|
.head_branch == "master" and
|
|
.conclusion == "success"
|
|
' source-run.json >/dev/null
|
|
printf 'run_id=%s\n' "$(jq -r '.id' source-run.json)" >> "$GITHUB_OUTPUT"
|
|
printf 'head_sha=%s\n' "$(jq -r '.head_sha' source-run.json)" >> "$GITHUB_OUTPUT"
|
|
printf 'run_started_at=%s\n' "$(jq -r '.run_started_at' source-run.json)" >> "$GITHUB_OUTPUT"
|
|
|
|
- name: Download completed platform builds
|
|
uses: actions/download-artifact@v4
|
|
with:
|
|
github-token: ${{ github.token }}
|
|
repository: ${{ github.repository }}
|
|
run-id: ${{ steps.source.outputs.run_id }}
|
|
path: artifacts
|
|
|
|
- name: Prepare and validate release
|
|
id: release
|
|
shell: bash
|
|
env:
|
|
HEAD_SHA: ${{ steps.source.outputs.head_sha }}
|
|
RUN_STARTED_AT: ${{ steps.source.outputs.run_started_at }}
|
|
run: |
|
|
set -euo pipefail
|
|
test -n "$MOONSTORE_API_KEY"
|
|
|
|
one_file() {
|
|
local label="$1"
|
|
shift
|
|
local -a matches=()
|
|
mapfile -d '' matches < <(find "$@" -print0)
|
|
if [ "${#matches[@]}" -ne 1 ]; then
|
|
printf 'Expected exactly one %s artifact, found %s\n' "$label" "${#matches[@]}" >&2
|
|
printf ' %s\n' "${matches[@]:-none}" >&2
|
|
exit 1
|
|
fi
|
|
printf '%s' "${matches[0]}"
|
|
}
|
|
|
|
ANDROID="$(one_file 'Android GitHub APK' artifacts -type f -path '*/github/*' -iname '*.apk')"
|
|
IOS="$(one_file 'iOS IPA' artifacts -type f -iname '*.ipa')"
|
|
MACOS="$(one_file 'macOS archive' artifacts -type f -iname '*.tar.xz')"
|
|
LINUX="$(one_file 'Linux 4K AppImage' artifacts -type f -path '*linux-arm64-4k*' -iname '*.AppImage')"
|
|
|
|
mapfile -d '' WINDOWS_DIRS < <(
|
|
find artifacts -mindepth 1 -maxdepth 1 -type d -name 'armsx2-windows-arm64-*' -print0
|
|
)
|
|
if [ "${#WINDOWS_DIRS[@]}" -ne 1 ]; then
|
|
printf 'Expected exactly one Windows artifact directory, found %s\n' "${#WINDOWS_DIRS[@]}" >&2
|
|
exit 1
|
|
fi
|
|
|
|
START_DAY="${RUN_STARTED_AT%%T*}"
|
|
START_DAY="${START_DAY//-/}"
|
|
SHORT_SHA="${HEAD_SHA:0:8}"
|
|
VERSION="build-${START_DAY}-${SHORT_SHA}"
|
|
WINDOWS="$RUNNER_TEMP/ARMSX2-${VERSION}-Windows-arm64.zip"
|
|
(
|
|
cd "${WINDOWS_DIRS[0]}"
|
|
zip -q -r "$WINDOWS" .
|
|
)
|
|
|
|
mkdir -p prepared
|
|
cp "$ANDROID" "prepared/ARMSX2-${VERSION}-Android-arm64.apk"
|
|
cp "$IOS" "prepared/ARMSX2-${VERSION}-iOS-arm64.ipa"
|
|
cp "$MACOS" "prepared/ARMSX2-${VERSION}-macOS-arm64.tar.xz"
|
|
cp "$LINUX" "prepared/ARMSX2-${VERSION}-Linux-arm64-4K.AppImage"
|
|
cp "$WINDOWS" "prepared/ARMSX2-${VERSION}-Windows-arm64.zip"
|
|
|
|
|
|
while IFS= read -r -d '' file; do
|
|
bytes="$(stat -c '%s' "$file")"
|
|
if [ "$bytes" -ge "$MAX_ARTIFACT_BYTES" ]; then
|
|
printf '%s is %s bytes; MoonStore upload limit is below %s bytes\n' \
|
|
"$file" "$bytes" "$MAX_ARTIFACT_BYTES" >&2
|
|
exit 1
|
|
fi
|
|
printf '%s %s bytes %s\n' "$(sha256sum "$file" | cut -d' ' -f1)" "$bytes" "$file"
|
|
done < <(find prepared -type f -print0 | sort -z)
|
|
|
|
printf 'version=%s\n' "$VERSION" >> "$GITHUB_OUTPUT"
|
|
|
|
- name: Upload verified artifacts
|
|
shell: bash
|
|
env:
|
|
VERSION: ${{ steps.release.outputs.version }}
|
|
run: |
|
|
set -euo pipefail
|
|
mkdir -p responses
|
|
|
|
upload() {
|
|
local platform="$1"
|
|
local file="$2"
|
|
local response="responses/${platform}.json"
|
|
local status
|
|
local -a headers=(
|
|
-H "Authorization: Bearer $MOONSTORE_API_KEY"
|
|
-H "X-File-Name: $(basename "$file")"
|
|
)
|
|
if [ "$platform" = "windows" ]; then
|
|
headers+=(-H "X-MoonStore-Windows-Signature-Review: requested")
|
|
fi
|
|
if ! status="$(curl --silent --show-error \
|
|
--retry 3 --retry-delay 2 --connect-timeout 20 --max-time 1800 \
|
|
-X POST \
|
|
"${headers[@]}" \
|
|
--data-binary "@$file" \
|
|
"$MOONSTORE_API/artifacts?platform=${platform}&architecture=arm64" \
|
|
-o "$response" -w '%{http_code}')"; then
|
|
test ! -s "$response" || jq . "$response" >&2
|
|
return 1
|
|
fi
|
|
if [[ "$status" != 2?? ]]; then
|
|
printf 'MoonStore rejected the %s artifact with HTTP %s:\n' "$platform" "$status" >&2
|
|
jq . "$response" >&2 || sed -n '1,120p' "$response" >&2
|
|
return 1
|
|
fi
|
|
jq -e '.binary | type == "object"' "$response" >/dev/null
|
|
if [ "$platform" = "windows" ]; then
|
|
jq '
|
|
if .binary.launch then .
|
|
else
|
|
((.launch.candidates // []) |
|
|
map(select(.type == "executable" and (.path | ascii_downcase) == "armsx2.exe"))) as $matches |
|
|
if ($matches | length) == 1 then
|
|
.binary.launch = {kind: "portable", entry: $matches[0].path}
|
|
else
|
|
error("ARMSX2.exe launcher was not found uniquely")
|
|
end
|
|
end
|
|
' "$response" > "${response}.tmp"
|
|
mv "${response}.tmp" "$response"
|
|
fi
|
|
printf 'Uploaded %s: %s\n' "$platform" "$(jq -r '.binary.ref' "$response")"
|
|
}
|
|
|
|
upload android "prepared/ARMSX2-${VERSION}-Android-arm64.apk"
|
|
upload ios "prepared/ARMSX2-${VERSION}-iOS-arm64.ipa"
|
|
upload macos "prepared/ARMSX2-${VERSION}-macOS-arm64.tar.xz"
|
|
upload windows "prepared/ARMSX2-${VERSION}-Windows-arm64.zip"
|
|
upload linux "prepared/ARMSX2-${VERSION}-Linux-arm64-4K.AppImage"
|
|
|
|
- name: Publish the MoonStore update
|
|
shell: bash
|
|
env:
|
|
VERSION: ${{ steps.release.outputs.version }}
|
|
HEAD_SHA: ${{ steps.source.outputs.head_sha }}
|
|
run: |
|
|
set -euo pipefail
|
|
NOTES="Automated build from ${HEAD_SHA:0:8}. Source: https://github.com/${GITHUB_REPOSITORY}/commit/${HEAD_SHA}"
|
|
|
|
jq -n \
|
|
--arg version "$VERSION" \
|
|
--arg notes "$NOTES" \
|
|
--slurpfile android responses/android.json \
|
|
--slurpfile ios responses/ios.json \
|
|
--slurpfile macos responses/macos.json \
|
|
--slurpfile windows responses/windows.json \
|
|
--slurpfile linux responses/linux.json \
|
|
'{
|
|
version: $version,
|
|
notes: $notes,
|
|
platforms: ["android", "ios", "macos", "windows", "linux"],
|
|
binaries: {
|
|
android: $android[0].binary,
|
|
ios: $ios[0].binary,
|
|
macos: $macos[0].binary,
|
|
windows: $windows[0].binary,
|
|
linux: $linux[0].binary
|
|
},
|
|
publishOnApproval: true
|
|
}' > release.json
|
|
|
|
status="$(curl --silent --show-error \
|
|
--retry 3 --retry-delay 2 --connect-timeout 20 --max-time 1800 \
|
|
-X POST \
|
|
-H "Authorization: Bearer $MOONSTORE_API_KEY" \
|
|
-H "Content-Type: application/json" \
|
|
--data @release.json \
|
|
"$MOONSTORE_API/apps/$MOONSTORE_APP_ID/releases" \
|
|
-o release-response.json -w '%{http_code}')"
|
|
if [[ "$status" != 2?? ]]; then
|
|
printf 'MoonStore rejected the release with HTTP %s:\n' "$status" >&2
|
|
jq . release-response.json >&2 || sed -n '1,120p' release-response.json >&2
|
|
exit 1
|
|
fi
|
|
|
|
jq -e '.release.status == "released"' release-response.json >/dev/null || {
|
|
printf 'MoonStore accepted the release but did not publish it automatically:\n' >&2
|
|
jq '{requestId, release: {id: .release.id, version: .release.version, status: .release.status}}' \
|
|
release-response.json >&2
|
|
exit 1
|
|
}
|
|
jq '{requestId, release: {id: .release.id, version: .release.version, status: .release.status, platforms: .release.platforms}}' \
|
|
release-response.json
|