Wire Forge-native release infrastructure
Some checks failed
Cache: Publish Nix / Publish Nix Cache (push) Waiting to run
Build Rust / Cargo Test (push) Successful in 4m14s
Build Site / Next.js Build (push) Failing after 6s
Infra: OpenTofu / OpenTofu (grafana) (push) Successful in 5s
Lint Governance / BEP Metadata (push) Successful in 0s
Build: Android / Android Rust Core Stub (push) Failing after 23s
Some checks failed
Cache: Publish Nix / Publish Nix Cache (push) Waiting to run
Build Rust / Cargo Test (push) Successful in 4m14s
Build Site / Next.js Build (push) Failing after 6s
Infra: OpenTofu / OpenTofu (grafana) (push) Successful in 5s
Lint Governance / BEP Metadata (push) Successful in 0s
Build: Android / Android Rust Core Stub (push) Failing after 23s
This commit is contained in:
parent
97c569fb35
commit
002bd382e9
199 changed files with 14268 additions and 185 deletions
299
.forgejo/workflows/publish-store-uploads.yml
Normal file
299
.forgejo/workflows/publish-store-uploads.yml
Normal file
|
|
@ -0,0 +1,299 @@
|
|||
name: "Publish: Release Uploads"
|
||||
run-name: "Publish: Release Uploads (Build ${{ inputs.build_number }})"
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
build_number:
|
||||
description: Build number to publish
|
||||
required: true
|
||||
upload_app_store:
|
||||
description: Upload iOS/macOS/visionOS artifacts to App Store Connect
|
||||
required: false
|
||||
default: "false"
|
||||
upload_sparkle:
|
||||
description: Publish Sparkle artifacts
|
||||
required: false
|
||||
default: "true"
|
||||
upload_microsoft_store:
|
||||
description: Upload Windows package to Microsoft Partner Center beta lane
|
||||
required: false
|
||||
default: "false"
|
||||
sparkle_channel:
|
||||
description: Sparkle channel, defaults to build-<number>
|
||||
required: false
|
||||
default: ""
|
||||
sparkle_point_main:
|
||||
description: Point Sparkle main appcast/default channel to selected channel
|
||||
required: false
|
||||
default: "true"
|
||||
testflight_distribute_external:
|
||||
description: Distribute to external TestFlight groups
|
||||
required: false
|
||||
default: "false"
|
||||
testflight_groups:
|
||||
description: Optional comma-separated TestFlight groups for external distribution
|
||||
required: false
|
||||
default: ""
|
||||
ios_uses_non_exempt_encryption:
|
||||
description: Set true only when the iOS build uses non-exempt encryption
|
||||
required: false
|
||||
default: "false"
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
concurrency:
|
||||
group: burrow-publish-store-uploads-${{ github.event.inputs.build_number }}
|
||||
cancel-in-progress: true
|
||||
|
||||
env:
|
||||
BURROW_RELEASE_GCS_BUCKET: ${{ vars.BURROW_RELEASE_GCS_BUCKET || 'burrow-net-releases' }}
|
||||
BURROW_GOOGLE_PROJECT_ID: ${{ vars.GOOGLE_PROJECT_ID || 'project-88c23ce9-918a-470a-b33' }}
|
||||
GOOGLE_CLOUD_PROJECT: ${{ vars.GOOGLE_PROJECT_ID || 'project-88c23ce9-918a-470a-b33' }}
|
||||
BURROW_GOOGLE_PROJECT_NUMBER: ${{ vars.GOOGLE_PROJECT_NUMBER || '416198671487' }}
|
||||
BURROW_GOOGLE_WIF_POOL_ID: ${{ vars.BURROW_GOOGLE_WIF_POOL_ID || 'burrow-authentik' }}
|
||||
BURROW_GOOGLE_WIF_PROVIDER_ID: ${{ vars.BURROW_GOOGLE_WIF_PROVIDER_ID || 'forgejo-runners' }}
|
||||
BURROW_GOOGLE_WIF_SERVICE_ACCOUNT: ${{ vars.BURROW_GOOGLE_WIF_SERVICE_ACCOUNT || 'burrow-forgejo-runner@project-88c23ce9-918a-470a-b33.iam.gserviceaccount.com' }}
|
||||
BURROW_AUTHENTIK_WIF_ISSUER: ${{ vars.BURROW_AUTHENTIK_WIF_ISSUER || 'https://auth.burrow.net/application/o/google-cloud/' }}
|
||||
BURROW_AUTHENTIK_WIF_AUDIENCE: ${{ vars.BURROW_AUTHENTIK_WIF_AUDIENCE || 'google-wif.burrow.net' }}
|
||||
BURROW_AUTHENTIK_WIF_CLIENT_ID: ${{ vars.BURROW_AUTHENTIK_WIF_CLIENT_ID || 'google-wif.burrow.net' }}
|
||||
BURROW_AUTHENTIK_WIF_CLIENT_SECRET: ${{ secrets.BURROW_AUTHENTIK_WIF_CLIENT_SECRET }}
|
||||
BURROW_NIX_CACHE_URL: ${{ vars.BURROW_NIX_CACHE_URL || 'https://nix.burrow.net/burrow' }}
|
||||
BURROW_NIX_CACHE_PUBLIC_KEY: ${{ vars.BURROW_NIX_CACHE_PUBLIC_KEY }}
|
||||
BURROW_APPLE_BUNDLE_ID: ${{ vars.BURROW_APPLE_BUNDLE_ID || 'net.burrow.app' }}
|
||||
|
||||
jobs:
|
||||
upload-app-store:
|
||||
name: Upload (App Store Connect)
|
||||
if: ${{ github.event.inputs.upload_app_store == 'true' }}
|
||||
runs-on: namespace-profile-macos-large
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: https://code.forgejo.org/actions/checkout@v4
|
||||
with:
|
||||
token: ${{ github.token }}
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Ensure Nix
|
||||
shell: bash
|
||||
run: bash Scripts/ci/ensure-nix.sh
|
||||
|
||||
- name: Configure Age
|
||||
shell: bash
|
||||
env:
|
||||
AGE_FORGE_SSH_KEY: ${{ secrets.AGE_FORGE_SSH_KEY }}
|
||||
run: Scripts/resolve-age-identity.sh >> "$GITHUB_ENV"
|
||||
|
||||
- name: Decrypt Release Secrets
|
||||
uses: ./.forgejo/actions/decrypt-release-secrets
|
||||
|
||||
- name: Validate App Store Credentials
|
||||
shell: bash
|
||||
run: Scripts/ci/check-release-config.sh app-store
|
||||
|
||||
- name: Download Apple Artifacts From GCS
|
||||
shell: bash
|
||||
env:
|
||||
BUILD_NUMBER: ${{ github.event.inputs.build_number }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
nix develop .#ci -c Scripts/ci/google-wif-auth.sh
|
||||
mkdir -p publish/apple
|
||||
nix develop .#ci -c gcloud storage rsync --recursive "gs://${BURROW_RELEASE_GCS_BUCKET}/builds/${BUILD_NUMBER}/apple" publish/apple
|
||||
find publish/apple -type f -print | sort
|
||||
|
||||
- name: Upload Apple Packages
|
||||
shell: bash
|
||||
run: |
|
||||
set -euo pipefail
|
||||
Scripts/ci/check-release-config.sh app-store
|
||||
key_dir="${RUNNER_TEMP:-/tmp}/burrow-asc"
|
||||
altool_key_dir="${HOME}/.appstoreconnect/private_keys"
|
||||
mkdir -p "$key_dir" "$altool_key_dir"
|
||||
key_path="$key_dir/AuthKey_${ASC_API_KEY_ID}.p8"
|
||||
if [[ -n "${ASC_API_KEY_PATH:-}" && -f "${ASC_API_KEY_PATH:-}" ]]; then
|
||||
cp "$ASC_API_KEY_PATH" "$key_path"
|
||||
else
|
||||
printf '%s' "$ASC_API_KEY_BASE64" | base64 --decode > "$key_path"
|
||||
fi
|
||||
cp "$key_path" "$altool_key_dir/AuthKey_${ASC_API_KEY_ID}.p8"
|
||||
chmod 600 "$key_path" "$altool_key_dir/AuthKey_${ASC_API_KEY_ID}.p8"
|
||||
shopt -s nullglob
|
||||
artifacts=(publish/apple/*.ipa publish/apple/*.pkg)
|
||||
if (( ${#artifacts[@]} == 0 )); then
|
||||
echo "::error ::No Apple upload artifacts found for build ${{ github.event.inputs.build_number }}."
|
||||
exit 1
|
||||
fi
|
||||
for artifact in "${artifacts[@]}"; do
|
||||
upload_type="ios"
|
||||
if [[ "$artifact" == *.pkg ]]; then
|
||||
upload_type="macos"
|
||||
fi
|
||||
xcrun altool --upload-app \
|
||||
--type "$upload_type" \
|
||||
--file "$artifact" \
|
||||
--apiKey "$ASC_API_KEY_ID" \
|
||||
--apiIssuer "$ASC_API_ISSUER_ID"
|
||||
done
|
||||
|
||||
release-ios-testflight:
|
||||
name: Release (TestFlight iOS Testers)
|
||||
needs: upload-app-store
|
||||
if: ${{ github.event.inputs.upload_app_store == 'true' }}
|
||||
runs-on: namespace-profile-linux-medium
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: https://code.forgejo.org/actions/checkout@v4
|
||||
with:
|
||||
token: ${{ github.token }}
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Ensure Nix
|
||||
shell: bash
|
||||
run: bash Scripts/ci/ensure-nix.sh
|
||||
|
||||
- name: Configure Age
|
||||
shell: bash
|
||||
env:
|
||||
AGE_FORGE_SSH_KEY: ${{ secrets.AGE_FORGE_SSH_KEY }}
|
||||
run: Scripts/resolve-age-identity.sh >> "$GITHUB_ENV"
|
||||
|
||||
- name: Decrypt Release Secrets
|
||||
uses: ./.forgejo/actions/decrypt-release-secrets
|
||||
|
||||
- name: Validate App Store Credentials
|
||||
shell: bash
|
||||
run: Scripts/ci/check-release-config.sh app-store
|
||||
|
||||
- name: Distribute iOS Build To TestFlight
|
||||
shell: bash
|
||||
env:
|
||||
BUILD_NUMBER: ${{ github.event.inputs.build_number }}
|
||||
TESTFLIGHT_DISTRIBUTE_EXTERNAL: ${{ github.event.inputs.testflight_distribute_external || 'false' }}
|
||||
TESTFLIGHT_GROUPS: ${{ github.event.inputs.testflight_groups || '' }}
|
||||
TESTFLIGHT_INTERNAL_GROUP: Internal
|
||||
IOS_USES_NON_EXEMPT_ENCRYPTION: ${{ github.event.inputs.ios_uses_non_exempt_encryption || 'false' }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
Scripts/ci/check-release-config.sh app-store
|
||||
api_key_json="$(mktemp "${RUNNER_TEMP:-/tmp}/burrow-appstore-api-key.XXXXXX.json")"
|
||||
key_file="$(mktemp "${RUNNER_TEMP:-/tmp}/burrow-appstore-key.XXXXXX.p8")"
|
||||
if [[ -n "${ASC_API_KEY_PATH:-}" && -f "${ASC_API_KEY_PATH:-}" ]]; then
|
||||
cp "$ASC_API_KEY_PATH" "$key_file"
|
||||
else
|
||||
printf '%s' "$ASC_API_KEY_BASE64" | base64 --decode > "$key_file"
|
||||
fi
|
||||
KEY_FILE="$key_file" python3 -c 'import json, os, pathlib; print(json.dumps({"key_id": os.environ["ASC_API_KEY_ID"], "issuer_id": os.environ["ASC_API_ISSUER_ID"], "key": pathlib.Path(os.environ["KEY_FILE"]).read_text(), "duration": 1200, "in_house": False}))' > "$api_key_json"
|
||||
|
||||
distribute_external="${TESTFLIGHT_DISTRIBUTE_EXTERNAL:-false}"
|
||||
if [[ -z "$distribute_external" ]]; then
|
||||
distribute_external="false"
|
||||
fi
|
||||
uses_non_exempt="${IOS_USES_NON_EXEMPT_ENCRYPTION:-false}"
|
||||
if [[ -z "$uses_non_exempt" ]]; then
|
||||
uses_non_exempt="false"
|
||||
fi
|
||||
|
||||
args=(
|
||||
run pilot
|
||||
"api_key_path:${api_key_json}"
|
||||
"app_identifier:${BURROW_APPLE_BUNDLE_ID:-net.burrow.app}"
|
||||
"app_platform:ios"
|
||||
"distribute_only:true"
|
||||
"build_number:${BUILD_NUMBER}"
|
||||
"wait_processing_interval:30"
|
||||
"wait_processing_timeout_duration:1800"
|
||||
"distribute_external:${distribute_external}"
|
||||
"uses_non_exempt_encryption:${uses_non_exempt}"
|
||||
)
|
||||
|
||||
if [[ -n "${TESTFLIGHT_GROUPS}" ]]; then
|
||||
args+=("groups:${TESTFLIGHT_GROUPS}")
|
||||
elif [[ "$distribute_external" != "true" && -n "${TESTFLIGHT_INTERNAL_GROUP:-}" ]]; then
|
||||
args+=("groups:${TESTFLIGHT_INTERNAL_GROUP}")
|
||||
fi
|
||||
|
||||
nix run nixpkgs#fastlane -- "${args[@]}"
|
||||
rm -f "$api_key_json" "$key_file"
|
||||
|
||||
upload-sparkle:
|
||||
name: Upload (Sparkle)
|
||||
if: ${{ github.event.inputs.upload_sparkle == 'true' }}
|
||||
runs-on: namespace-profile-linux-medium
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: https://code.forgejo.org/actions/checkout@v4
|
||||
with:
|
||||
token: ${{ github.token }}
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Resolve Sparkle Channel
|
||||
id: channel
|
||||
shell: bash
|
||||
env:
|
||||
BUILD_NUMBER: ${{ github.event.inputs.build_number }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
channel="${{ github.event.inputs.sparkle_channel }}"
|
||||
if [[ -z "$channel" ]]; then
|
||||
channel="build-${BUILD_NUMBER}"
|
||||
fi
|
||||
echo "channel=$channel" >> "$GITHUB_OUTPUT"
|
||||
|
||||
- name: Ensure Nix
|
||||
shell: bash
|
||||
run: bash Scripts/ci/ensure-nix.sh
|
||||
|
||||
- name: Publish Sparkle Channel
|
||||
shell: bash
|
||||
env:
|
||||
BUILD_NUMBER: ${{ github.event.inputs.build_number }}
|
||||
CHANNEL: ${{ steps.channel.outputs.channel }}
|
||||
SPARKLE_POINT_MAIN: ${{ github.event.inputs.sparkle_point_main }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
nix develop .#ci -c Scripts/ci/google-wif-auth.sh
|
||||
mkdir -p "publish/sparkle/${CHANNEL}"
|
||||
nix develop .#ci -c gcloud storage rsync --recursive "gs://${BURROW_RELEASE_GCS_BUCKET}/builds/${BUILD_NUMBER}/sparkle/${CHANNEL}" "publish/sparkle/${CHANNEL}" || true
|
||||
if [[ ! -f "publish/sparkle/${CHANNEL}/appcast.xml" ]]; then
|
||||
echo "::warning ::No Sparkle appcast staged for build ${BUILD_NUMBER}; skipping Sparkle publish."
|
||||
find "publish/sparkle/${CHANNEL}" -maxdepth 2 -type f -print || true
|
||||
exit 0
|
||||
fi
|
||||
nix develop .#ci -c gcloud storage rsync --recursive "publish/sparkle/${CHANNEL}" "gs://${BURROW_RELEASE_GCS_BUCKET}/sparkle/${CHANNEL}"
|
||||
if [[ "$SPARKLE_POINT_MAIN" == "true" ]]; then
|
||||
printf '%s\n' "$CHANNEL" > main-channel.txt
|
||||
nix develop .#ci -c gcloud storage cp main-channel.txt "gs://${BURROW_RELEASE_GCS_BUCKET}/sparkle/main-channel.txt"
|
||||
nix develop .#ci -c gcloud storage cp "publish/sparkle/${CHANNEL}/appcast.xml" "gs://${BURROW_RELEASE_GCS_BUCKET}/sparkle/appcast.xml"
|
||||
nix develop .#ci -c gcloud storage rsync --recursive "publish/sparkle/${CHANNEL}" "gs://${BURROW_RELEASE_GCS_BUCKET}/sparkle/default"
|
||||
fi
|
||||
|
||||
upload-microsoft-store:
|
||||
name: Upload (Microsoft Store Beta)
|
||||
if: ${{ github.event.inputs.upload_microsoft_store == 'true' }}
|
||||
runs-on: namespace-profile-windows-large
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: https://code.forgejo.org/actions/checkout@v4
|
||||
with:
|
||||
token: ${{ github.token }}
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Validate Microsoft Store Credentials
|
||||
shell: pwsh
|
||||
env:
|
||||
MICROSOFT_TENANT_ID: ${{ secrets.MICROSOFT_TENANT_ID }}
|
||||
MICROSOFT_CLIENT_ID: ${{ secrets.MICROSOFT_CLIENT_ID }}
|
||||
MICROSOFT_CLIENT_SECRET: ${{ secrets.MICROSOFT_CLIENT_SECRET }}
|
||||
run: |
|
||||
foreach ($name in "MICROSOFT_TENANT_ID","MICROSOFT_CLIENT_ID","MICROSOFT_CLIENT_SECRET") {
|
||||
if ([string]::IsNullOrWhiteSpace([Environment]::GetEnvironmentVariable($name))) {
|
||||
throw "missing required environment variable: $name"
|
||||
}
|
||||
}
|
||||
|
||||
- name: Stop Until Store Package Exists
|
||||
shell: pwsh
|
||||
run: |
|
||||
Write-Host "::warning ::Burrow only builds a Windows Rust stub today; Microsoft Store package upload is wired for credentials but waits on MSIX packaging."
|
||||
Loading…
Add table
Add a link
Reference in a new issue