mirror of
https://github.com/kunkundi/crossdesk.git
synced 2026-10-16 00:33:22 +08:00
[feat] support standalone iOS and Android releases
This commit is contained in:
@@ -3,6 +3,12 @@ name: Build Android
|
||||
on:
|
||||
workflow_dispatch:
|
||||
workflow_call:
|
||||
inputs:
|
||||
source_tag:
|
||||
description: "Existing source tag for a standalone Android release."
|
||||
required: false
|
||||
type: string
|
||||
default: ""
|
||||
outputs:
|
||||
version:
|
||||
description: "Independent Android version and build date."
|
||||
@@ -11,6 +17,7 @@ on:
|
||||
paths:
|
||||
- ".github/workflows/build-android.yml"
|
||||
- ".github/workflows/build.yml"
|
||||
- ".github/workflows/release-mobile.yml"
|
||||
- ".gitmodules"
|
||||
- "LICENSE"
|
||||
- "apps/android/**"
|
||||
@@ -32,11 +39,14 @@ jobs:
|
||||
version: ${{ steps.package.outputs.version }}
|
||||
env:
|
||||
XMAKE_VERSION: "3.1.1"
|
||||
CROSSDESK_SOURCE_TAG: ${{ inputs.source_tag || '' }}
|
||||
CROSSDESK_RELEASE_BUILD: ${{ inputs.source_tag && 'YES' || 'NO' }}
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v5
|
||||
with:
|
||||
fetch-depth: 0
|
||||
ref: ${{ inputs.source_tag || github.ref }}
|
||||
submodules: recursive
|
||||
persist-credentials: false
|
||||
|
||||
@@ -120,13 +130,19 @@ jobs:
|
||||
raise ValueError(f"Invalid Android version: {version!r}")
|
||||
build_date = datetime.datetime.now(ZoneInfo("Asia/Shanghai")).strftime("%Y%m%d")
|
||||
# Match the dated release tags used by the desktop and iOS jobs.
|
||||
if os.environ["GITHUB_REF_TYPE"] == "tag":
|
||||
tag = os.environ.get("CROSSDESK_SOURCE_TAG")
|
||||
if not tag and os.environ["GITHUB_REF_TYPE"] == "tag":
|
||||
tag = os.environ["GITHUB_REF_NAME"]
|
||||
if tag:
|
||||
tag = tag.removeprefix("android-")
|
||||
match = re.fullmatch(r"v?[0-9]+(?:\.[0-9]+){1,3}-(?:[0-9]+-)?([0-9]{8})(?:-[0-9]+)?", tag)
|
||||
if match:
|
||||
build_date = match[1]
|
||||
datetime.datetime.strptime(build_date, "%Y%m%d")
|
||||
version = f"v{version}-{build_date}"
|
||||
source_tag = os.environ.get("CROSSDESK_SOURCE_TAG", "")
|
||||
if source_tag.startswith("android-v") and source_tag.removeprefix("android-") != version:
|
||||
raise ValueError(f"Android source tag does not match the app version: {source_tag} vs {version}")
|
||||
output = Path(os.environ["RUNNER_TEMP"]) / "crossdesk-android"
|
||||
for variant, source in (
|
||||
("unsigned", "release/app-release-unsigned.apk"),
|
||||
|
||||
@@ -10,6 +10,11 @@ on:
|
||||
default: "0"
|
||||
workflow_call:
|
||||
inputs:
|
||||
source_tag:
|
||||
description: "Existing source tag for a standalone iOS release."
|
||||
required: false
|
||||
type: string
|
||||
default: ""
|
||||
patch:
|
||||
description: "Optional patch number from the main build workflow."
|
||||
required: false
|
||||
@@ -23,6 +28,7 @@ on:
|
||||
paths:
|
||||
- ".github/workflows/build-ios.yml"
|
||||
- ".github/workflows/build.yml"
|
||||
- ".github/workflows/release-mobile.yml"
|
||||
- ".gitmodules"
|
||||
- "LICENSE"
|
||||
- "apps/ios/**"
|
||||
@@ -42,6 +48,7 @@ jobs:
|
||||
version: ${{ steps.ios_version.outputs.version }}
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ github.token }}
|
||||
CROSSDESK_SOURCE_TAG: ${{ inputs.source_tag || '' }}
|
||||
IOS_DEPLOYMENT_TARGET: "16.0"
|
||||
EXPECTED_IOS_SDK: "26.5"
|
||||
XMAKE_VERSION: "3.1.1"
|
||||
@@ -53,7 +60,8 @@ jobs:
|
||||
env:
|
||||
PATCH_NUMBER: ${{ inputs.patch || '0' }}
|
||||
run: |
|
||||
VERSION_REF="${GITHUB_REF##*/}"
|
||||
VERSION_REF="${CROSSDESK_SOURCE_TAG:-${GITHUB_REF##*/}}"
|
||||
VERSION_REF="${VERSION_REF#ios-}"
|
||||
VERSION_BASE="${VERSION_REF#v}"
|
||||
BUILD_DATE=$(TZ=Asia/Shanghai date +%Y%m%d)
|
||||
|
||||
@@ -101,11 +109,14 @@ jobs:
|
||||
uses: actions/checkout@v5
|
||||
with:
|
||||
fetch-depth: 0
|
||||
ref: ${{ inputs.source_tag || github.ref }}
|
||||
|
||||
- name: Select corresponding source tag
|
||||
shell: bash
|
||||
run: |
|
||||
if [[ "${GITHUB_REF_TYPE}" == "tag" ]]; then
|
||||
if [[ -n "${CROSSDESK_SOURCE_TAG}" ]]; then
|
||||
echo "CROSSDESK_RELEASE_BUILD=YES" >> "${GITHUB_ENV}"
|
||||
elif [[ "${GITHUB_REF_TYPE}" == "tag" ]]; then
|
||||
echo "CROSSDESK_SOURCE_TAG=${GITHUB_REF_NAME}" >> "${GITHUB_ENV}"
|
||||
echo "CROSSDESK_RELEASE_BUILD=YES" >> "${GITHUB_ENV}"
|
||||
fi
|
||||
@@ -126,6 +137,10 @@ jobs:
|
||||
exit 1
|
||||
fi
|
||||
VERSION_NUM="v${IOS_VERSION_BASE}-${VERSION_NUM##*-}"
|
||||
if [[ "${CROSSDESK_SOURCE_TAG}" == ios-v* && "${CROSSDESK_SOURCE_TAG#ios-}" != "${VERSION_NUM}" ]]; then
|
||||
echo "iOS source tag does not match the app version: ${CROSSDESK_SOURCE_TAG} vs ${VERSION_NUM}" >&2
|
||||
exit 1
|
||||
fi
|
||||
echo "IOS_VERSION_BASE=${IOS_VERSION_BASE}" >> "${GITHUB_ENV}"
|
||||
echo "VERSION_NUM=${VERSION_NUM}" >> "${GITHUB_ENV}"
|
||||
echo "version=${VERSION_NUM}" >> "${GITHUB_OUTPUT}"
|
||||
|
||||
@@ -7,6 +7,8 @@ on:
|
||||
- "!ci/linux-build-image"
|
||||
tags:
|
||||
- "*"
|
||||
- "!ios-v*"
|
||||
- "!android-v*"
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
patch:
|
||||
|
||||
@@ -0,0 +1,149 @@
|
||||
name: Release Mobile
|
||||
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- "ios-v*"
|
||||
- "android-v*"
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
source_tag:
|
||||
description: "Existing tag: ios-v0.0.1-20261002 or android-v0.1.0-20261002."
|
||||
required: true
|
||||
type: string
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
prepare:
|
||||
name: Validate mobile source tag
|
||||
runs-on: ubuntu-24.04
|
||||
outputs:
|
||||
platform: ${{ steps.source.outputs.platform }}
|
||||
tag: ${{ steps.source.outputs.tag }}
|
||||
version: ${{ steps.source.outputs.version }}
|
||||
sha: ${{ steps.source.outputs.sha }}
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v5
|
||||
with:
|
||||
fetch-depth: 0
|
||||
persist-credentials: false
|
||||
|
||||
- name: Resolve source tag
|
||||
id: source
|
||||
shell: python
|
||||
env:
|
||||
SOURCE_TAG: ${{ inputs.source_tag || github.ref_name }}
|
||||
run: |
|
||||
import datetime
|
||||
import os
|
||||
import re
|
||||
import subprocess
|
||||
|
||||
tag = os.environ["SOURCE_TAG"]
|
||||
match = re.fullmatch(r"(ios|android)-(v[0-9]+\.[0-9]+\.[0-9]+-([0-9]{8}))", tag)
|
||||
if not match:
|
||||
raise ValueError("Use an existing ios-v<app-version>-YYYYMMDD or android-v<app-version>-YYYYMMDD tag")
|
||||
datetime.datetime.strptime(match[3], "%Y%m%d")
|
||||
sha = subprocess.check_output(
|
||||
["git", "rev-parse", "--verify", f"refs/tags/{tag}^{{commit}}"], text=True).strip()
|
||||
with open(os.environ["GITHUB_OUTPUT"], "a") as stream:
|
||||
stream.write(f"platform={match[1]}\ntag={tag}\nversion={match[2]}\nsha={sha}\n")
|
||||
|
||||
build-ios:
|
||||
name: Build iOS release
|
||||
needs: prepare
|
||||
if: needs.prepare.outputs.platform == 'ios'
|
||||
uses: ./.github/workflows/build-ios.yml
|
||||
with:
|
||||
source_tag: ${{ needs.prepare.outputs.tag }}
|
||||
|
||||
build-android:
|
||||
name: Build Android release
|
||||
needs: prepare
|
||||
if: needs.prepare.outputs.platform == 'android'
|
||||
uses: ./.github/workflows/build-android.yml
|
||||
with:
|
||||
source_tag: ${{ needs.prepare.outputs.tag }}
|
||||
|
||||
release:
|
||||
name: Publish mobile release
|
||||
needs: [prepare, build-ios, build-android]
|
||||
if: ${{ !cancelled() && (needs.build-ios.result == 'success' || needs.build-android.result == 'success') }}
|
||||
runs-on: ubuntu-24.04
|
||||
permissions:
|
||||
contents: write
|
||||
concurrency:
|
||||
group: mobile-release-${{ needs.prepare.outputs.tag }}
|
||||
cancel-in-progress: false
|
||||
env:
|
||||
PLATFORM: ${{ needs.prepare.outputs.platform }}
|
||||
SOURCE_TAG: ${{ needs.prepare.outputs.tag }}
|
||||
SOURCE_SHA: ${{ needs.prepare.outputs.sha }}
|
||||
VERSION: ${{ needs.prepare.outputs.version }}
|
||||
BUILD_VERSION: ${{ needs.build-ios.outputs.version || needs.build-android.outputs.version }}
|
||||
steps:
|
||||
- name: Verify release version
|
||||
shell: bash
|
||||
run: |
|
||||
if [[ "${BUILD_VERSION}" != "${VERSION}" ]]; then
|
||||
echo "Source tag version ${VERSION} does not match the app version ${BUILD_VERSION}" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
- name: Download mobile release artifact
|
||||
uses: actions/download-artifact@v8
|
||||
with:
|
||||
name: crossdesk-${{ env.PLATFORM }}-arm64-unsigned-${{ env.VERSION }}
|
||||
path: release
|
||||
|
||||
- name: Prepare release notes
|
||||
shell: bash
|
||||
run: |
|
||||
if [[ "${PLATFORM}" == "ios" ]]; then
|
||||
PLATFORM_NAME="iOS"
|
||||
SIGNING_NOTE="The arm64 ZIP contains an unsigned app, source metadata, third-party sources and any generated dSYM. Sign the app before device installation."
|
||||
else
|
||||
PLATFORM_NAME="Android"
|
||||
SIGNING_NOTE="The arm64 Release APK is unsigned. Sign it with your own key before installation. It includes source metadata, license documents and native build recipes."
|
||||
fi
|
||||
cat > "${RUNNER_TEMP}/mobile-release-notes.md" << EOF
|
||||
${PLATFORM_NAME} ${VERSION}
|
||||
|
||||
${SIGNING_NOTE}
|
||||
|
||||
Source: [${SOURCE_TAG}](https://github.com/${GITHUB_REPOSITORY}/tree/${SOURCE_SHA}).
|
||||
Clone this tag with recursive submodules to obtain the corresponding source.
|
||||
[Source and rebuild instructions](https://github.com/${GITHUB_REPOSITORY}/blob/${SOURCE_SHA}/apps/${PLATFORM}/README.md).
|
||||
EOF
|
||||
|
||||
- name: Publish GitHub Release
|
||||
uses: softprops/action-gh-release@v2
|
||||
with:
|
||||
tag_name: ${{ env.SOURCE_TAG }}
|
||||
target_commitish: ${{ env.SOURCE_SHA }}
|
||||
name: ${{ env.PLATFORM == 'ios' && 'iOS' || 'Android' }} ${{ env.VERSION }}
|
||||
draft: false
|
||||
prerelease: false
|
||||
make_latest: "false"
|
||||
files: release/*
|
||||
fail_on_unmatched_files: true
|
||||
generate_release_notes: false
|
||||
body_path: ${{ runner.temp }}/mobile-release-notes.md
|
||||
|
||||
- name: Upload mobile artifact to download server
|
||||
uses: burnett01/rsync-deployments@5.2
|
||||
with:
|
||||
switches: -avzr --progress
|
||||
path: release/*
|
||||
remote_path: /var/www/html/downloads/
|
||||
remote_host: ${{ secrets.SERVER_HOST }}
|
||||
remote_user: ${{ secrets.SERVER_USER }}
|
||||
remote_key: ${{ secrets.SERVER_KEY }}
|
||||
|
||||
- name: Summarize release
|
||||
shell: bash
|
||||
run: |
|
||||
echo "Published [${SOURCE_TAG}](https://github.com/${GITHUB_REPOSITORY}/releases/tag/${SOURCE_TAG}) and uploaded its unsigned ${PLATFORM} artifact to the download server." >> "${GITHUB_STEP_SUMMARY}"
|
||||
@@ -10,6 +10,7 @@ permissions:
|
||||
jobs:
|
||||
update-version-json:
|
||||
name: Update version.json with release information
|
||||
if: ${{ !startsWith(github.event.release.tag_name, 'ios-v') && !startsWith(github.event.release.tag_name, 'android-v') }}
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
|
||||
Reference in New Issue
Block a user