ci: automate release orchestration for desktop and mobile (#4861)
This commit is contained in:
parent
d386c00ebd
commit
1e13ce6834
|
|
@ -16,9 +16,9 @@ const RELEASE_PATTERNS = {
|
|||
|
||||
const EXIT_CODES = {
|
||||
SUCCESS: 0,
|
||||
NO_RELEASE_FOUND: 1,
|
||||
GIT_ERROR: 2,
|
||||
ENV_ERROR: 3,
|
||||
OUTPUT_ERROR: 4,
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -38,6 +38,23 @@ function setGitHubEnv(key, value) {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Write output variable to GitHub Output
|
||||
* @param {string} key - Output key
|
||||
* @param {string} value - Output value
|
||||
*/
|
||||
function setGitHubOutput(key, value) {
|
||||
try {
|
||||
if (!process.env.GITHUB_OUTPUT) {
|
||||
return
|
||||
}
|
||||
appendFileSync(process.env.GITHUB_OUTPUT, `${key}=${value}\n`)
|
||||
} catch (error) {
|
||||
console.error(`Failed to set output variable ${key}:`, error.message)
|
||||
process.exit(EXIT_CODES.OUTPUT_ERROR)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the latest commit message
|
||||
* @returns {string} Latest commit message
|
||||
|
|
@ -88,7 +105,7 @@ function main() {
|
|||
|
||||
if (!releaseInfo) {
|
||||
console.info("No desktop or mobile release found in commit message.")
|
||||
process.exit(EXIT_CODES.NO_RELEASE_FOUND)
|
||||
process.exit(EXIT_CODES.SUCCESS)
|
||||
}
|
||||
|
||||
const { platform, version, tagName } = releaseInfo
|
||||
|
|
@ -97,6 +114,9 @@ function main() {
|
|||
setGitHubEnv("tag_version", tagName)
|
||||
setGitHubEnv("platform", platform)
|
||||
setGitHubEnv("version", version)
|
||||
setGitHubOutput("tag_version", tagName)
|
||||
setGitHubOutput("platform", platform)
|
||||
setGitHubOutput("version", version)
|
||||
|
||||
console.info(`Found ${platform} release: ${version}`)
|
||||
console.info(`Tag will be created: ${tagName}`)
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ concurrency:
|
|||
jobs:
|
||||
build:
|
||||
name: Build Android apk for device
|
||||
if: github.secret_source != 'None'
|
||||
if: github.secret_source != 'None' && (github.event_name != 'push' || !startsWith(github.event.head_commit.message || '', 'release(mobile):'))
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
|
|
@ -104,13 +104,34 @@ jobs:
|
|||
with:
|
||||
type: "mobile"
|
||||
|
||||
- name: Prepare Release Notes
|
||||
if: github.event.inputs.release == 'true'
|
||||
id: release_notes
|
||||
run: |
|
||||
version="${{ steps.version.outputs.APP_VERSION }}"
|
||||
changelog_file="apps/mobile/changelog/${version}.md"
|
||||
release_notes_file="$RUNNER_TEMP/mobile-release-notes.md"
|
||||
|
||||
if [ -f "$changelog_file" ]; then
|
||||
cp "$changelog_file" "$release_notes_file"
|
||||
else
|
||||
{
|
||||
echo "# What's New in v${version}"
|
||||
echo
|
||||
echo "- No changelog file found at ${changelog_file}."
|
||||
} > "$release_notes_file"
|
||||
fi
|
||||
|
||||
echo "body_path=${release_notes_file}" >> "$GITHUB_OUTPUT"
|
||||
|
||||
- name: Create Release Draft
|
||||
if: github.event.inputs.release == 'true'
|
||||
uses: softprops/action-gh-release@v2
|
||||
with:
|
||||
name: Mobile v${{ steps.version.outputs.APP_VERSION }}
|
||||
draft: false
|
||||
draft: true
|
||||
prerelease: true
|
||||
tag_name: mobile/v${{ steps.version.outputs.APP_VERSION }}
|
||||
body_path: ${{ steps.release_notes.outputs.body_path }}
|
||||
# .aab cannot be installed directly on your Android Emulator or device.
|
||||
files: ${{ github.workspace }}/build.apk
|
||||
|
|
|
|||
|
|
@ -37,6 +37,7 @@ env:
|
|||
|
||||
jobs:
|
||||
release:
|
||||
if: github.secret_source != 'None' && (github.event_name != 'push' || !startsWith(github.event.head_commit.message || '', 'release(desktop):'))
|
||||
runs-on: ${{ matrix.os }}
|
||||
env:
|
||||
PROD: ${{ github.event.inputs.tag_version == 'true' || github.ref_type == 'tag' || github.event.inputs.store == 'true' }}
|
||||
|
|
@ -293,6 +294,26 @@ jobs:
|
|||
with:
|
||||
type: "desktop"
|
||||
|
||||
- name: Prepare Release Notes
|
||||
if: env.RELEASE == 'true'
|
||||
id: release_notes
|
||||
run: |
|
||||
version="${{ steps.version.outputs.APP_VERSION }}"
|
||||
changelog_file="apps/desktop/changelog/${version}.md"
|
||||
release_notes_file="$RUNNER_TEMP/desktop-release-notes.md"
|
||||
|
||||
if [ -f "$changelog_file" ]; then
|
||||
cp "$changelog_file" "$release_notes_file"
|
||||
else
|
||||
{
|
||||
echo "# What's New in v${version}"
|
||||
echo
|
||||
echo "- No changelog file found at ${changelog_file}."
|
||||
} > "$release_notes_file"
|
||||
fi
|
||||
|
||||
echo "body_path=${release_notes_file}" >> "$GITHUB_OUTPUT"
|
||||
|
||||
- name: Create Release Draft
|
||||
if: env.RELEASE == 'true'
|
||||
uses: softprops/action-gh-release@v2
|
||||
|
|
@ -301,6 +322,7 @@ jobs:
|
|||
draft: false
|
||||
prerelease: true
|
||||
tag_name: desktop/v${{ steps.version.outputs.APP_VERSION }}
|
||||
body_path: ${{ steps.release_notes.outputs.body_path }}
|
||||
files: |
|
||||
apps/desktop/out/make/**/Folo-*.dmg
|
||||
apps/desktop/out/make/**/Folo-*.zip
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ concurrency:
|
|||
|
||||
jobs:
|
||||
check-runner:
|
||||
if: github.secret_source != 'None' && (github.event_name != 'push' || !startsWith(github.event.head_commit.message || '', 'release(mobile):'))
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
runner-label: ${{ steps.set-runner.outputs.runner-label }}
|
||||
|
|
@ -41,7 +42,7 @@ jobs:
|
|||
|
||||
build-ipa-self-hosted:
|
||||
name: Build iOS IPA (self-hosted)
|
||||
if: github.secret_source != 'None' && needs.check-runner.outputs.runner-label == 'self-hosted'
|
||||
if: needs.check-runner.outputs.runner-label == 'self-hosted'
|
||||
needs: check-runner
|
||||
runs-on: [self-hosted, macOS]
|
||||
|
||||
|
|
@ -84,7 +85,7 @@ jobs:
|
|||
|
||||
build-ipa-github:
|
||||
name: Build iOS IPA (GitHub)
|
||||
if: github.secret_source != 'None' && needs.check-runner.outputs.runner-label == 'macos-latest'
|
||||
if: needs.check-runner.outputs.runner-label == 'macos-latest'
|
||||
needs: check-runner
|
||||
runs-on: macos-latest
|
||||
|
||||
|
|
|
|||
|
|
@ -1,13 +1,20 @@
|
|||
name: 🔄 Branch Synchronization
|
||||
name: 🔄 Sync Release Branches To Dev
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
- mobile-main
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
|
||||
jobs:
|
||||
sync-branches:
|
||||
sync-to-dev:
|
||||
runs-on: ubuntu-latest
|
||||
if: |
|
||||
(github.ref == 'refs/heads/main' && startsWith(github.event.head_commit.message, 'release(desktop):')) ||
|
||||
(github.ref == 'refs/heads/mobile-main' && startsWith(github.event.head_commit.message, 'release(mobile):'))
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v6
|
||||
|
|
@ -16,27 +23,13 @@ jobs:
|
|||
|
||||
- name: Set up Git
|
||||
run: |
|
||||
git config --global user.name 'GitHub Actions'
|
||||
git config --global user.email 'actions@github.com'
|
||||
git config --global user.name "github-actions[bot]"
|
||||
git config --global user.email "github-actions[bot]@users.noreply.github.com"
|
||||
|
||||
- name: Prepare sync branch
|
||||
id: branch
|
||||
- name: Merge source branch into dev
|
||||
run: |
|
||||
echo "SYNC_BRANCH_MAIN_DEV=sync/main-to-dev-$(date +'%Y%m%d')" >> $GITHUB_ENV
|
||||
|
||||
- name: Sync main to dev
|
||||
if: github.ref == 'refs/heads/main'
|
||||
run: |
|
||||
# Sync main to dev
|
||||
git checkout main
|
||||
SYNC_BRANCH_DEV=${{ env.SYNC_BRANCH_MAIN_DEV }}
|
||||
git checkout -B $SYNC_BRANCH_DEV
|
||||
DIFF=$(git diff origin/dev...)
|
||||
if [ -z "$DIFF" ]; then
|
||||
echo "No changes to sync"
|
||||
exit 0
|
||||
fi
|
||||
git push origin $SYNC_BRANCH_DEV -f
|
||||
gh pr create --base dev --head $SYNC_BRANCH_DEV --title "Sync main branch to dev branch" --body "Automatic sync" || exit 0
|
||||
env:
|
||||
GH_TOKEN: ${{ github.token }}
|
||||
source_branch="${GITHUB_REF_NAME}"
|
||||
git fetch origin main mobile-main dev
|
||||
git checkout dev
|
||||
git merge --no-ff "origin/${source_branch}" -m "chore(sync): merge ${source_branch} into dev"
|
||||
git push origin dev
|
||||
|
|
|
|||
|
|
@ -1,18 +1,24 @@
|
|||
name: 🏷️ Tag on SemVer Commit
|
||||
name: 🏷️ Release Orchestrator
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
- mobile-main
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
actions: write
|
||||
|
||||
jobs:
|
||||
create_tag:
|
||||
name: Create Release Tag
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
tag_version: ${{ env.tag_version }}
|
||||
platform: ${{ env.platform }}
|
||||
version: ${{ env.version }}
|
||||
tag_version: ${{ steps.release_info.outputs.tag_version }}
|
||||
platform: ${{ steps.release_info.outputs.platform }}
|
||||
version: ${{ steps.release_info.outputs.version }}
|
||||
ref_name: ${{ steps.release_info.outputs.ref_name }}
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
|
|
@ -30,36 +36,82 @@ jobs:
|
|||
- name: Extract release information
|
||||
id: extract_info
|
||||
run: .github/scripts/extract-release-info.mjs
|
||||
continue-on-error: false
|
||||
continue-on-error: true
|
||||
|
||||
- name: Expose release outputs
|
||||
id: release_info
|
||||
run: |
|
||||
echo "tag_version=${tag_version:-}" >> "$GITHUB_OUTPUT"
|
||||
echo "platform=${platform:-}" >> "$GITHUB_OUTPUT"
|
||||
echo "version=${version:-}" >> "$GITHUB_OUTPUT"
|
||||
echo "ref_name=${GITHUB_REF_NAME}" >> "$GITHUB_OUTPUT"
|
||||
|
||||
- name: Validate git configuration
|
||||
if: env.tag_version
|
||||
if: steps.release_info.outputs.tag_version != ''
|
||||
run: |
|
||||
git config --global user.name "github-actions[bot]"
|
||||
git config --global user.email "github-actions[bot]@users.noreply.github.com"
|
||||
|
||||
- name: Create and push tag
|
||||
if: env.tag_version
|
||||
if: steps.release_info.outputs.tag_version != ''
|
||||
run: |
|
||||
echo "Creating tag: ${{ env.tag_version }}"
|
||||
if git rev-parse "${{ env.tag_version }}" >/dev/null 2>&1; then
|
||||
echo "Tag ${{ env.tag_version }} already exists, skipping creation"
|
||||
git fetch --tags --force
|
||||
echo "Creating tag: ${{ steps.release_info.outputs.tag_version }}"
|
||||
if git rev-parse "${{ steps.release_info.outputs.tag_version }}" >/dev/null 2>&1; then
|
||||
echo "Tag ${{ steps.release_info.outputs.tag_version }} already exists, skipping creation"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
git tag "${{ env.tag_version }}"
|
||||
git push origin "${{ env.tag_version }}"
|
||||
echo "Successfully created and pushed tag: ${{ env.tag_version }}"
|
||||
git tag "${{ steps.release_info.outputs.tag_version }}"
|
||||
git push origin "${{ steps.release_info.outputs.tag_version }}"
|
||||
echo "Successfully created and pushed tag: ${{ steps.release_info.outputs.tag_version }}"
|
||||
|
||||
trigger_builds:
|
||||
name: Trigger Platform Builds
|
||||
needs: create_tag
|
||||
if: needs.create_tag.outputs.tag_version
|
||||
if: needs.create_tag.outputs.tag_version != ''
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
if: needs.create_tag.outputs.platform == 'desktop' && needs.create_tag.outputs.ref_name == 'main'
|
||||
uses: actions/checkout@v6
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Configure Git
|
||||
if: needs.create_tag.outputs.platform == 'desktop' && needs.create_tag.outputs.ref_name == 'main'
|
||||
run: |
|
||||
git config --global user.name "github-actions[bot]"
|
||||
git config --global user.email "github-actions[bot]@users.noreply.github.com"
|
||||
|
||||
- name: Resolve desktop build version
|
||||
id: desktop_build_version
|
||||
if: needs.create_tag.outputs.platform == 'desktop' && needs.create_tag.outputs.ref_name == 'main'
|
||||
run: |
|
||||
git fetch --tags --force
|
||||
latest_tag="$(git tag -l 'desktop-build/v*' --sort=-v:refname | head -n 1)"
|
||||
if [ -z "$latest_tag" ]; then
|
||||
last_build=110
|
||||
else
|
||||
last_build="${latest_tag#desktop-build/v}"
|
||||
fi
|
||||
|
||||
next_build=$((last_build + 1))
|
||||
build_tag="desktop-build/v${next_build}"
|
||||
|
||||
if git rev-parse "$build_tag" >/dev/null 2>&1; then
|
||||
echo "Build tag $build_tag already exists."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
git tag "$build_tag"
|
||||
git push origin "$build_tag"
|
||||
echo "build_version=${next_build}" >> "$GITHUB_OUTPUT"
|
||||
echo "Desktop build version: ${next_build}"
|
||||
|
||||
- name: Trigger Desktop Build
|
||||
if: needs.create_tag.outputs.platform == 'desktop'
|
||||
if: needs.create_tag.outputs.platform == 'desktop' && needs.create_tag.outputs.ref_name == 'main'
|
||||
uses: actions/github-script@v8
|
||||
with:
|
||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
|
@ -70,13 +122,15 @@ jobs:
|
|||
workflow_id: 'build-desktop.yml',
|
||||
ref: 'main',
|
||||
inputs: {
|
||||
tag_version: 'true'
|
||||
tag_version: 'true',
|
||||
store: 'true',
|
||||
build_version: '${{ steps.desktop_build_version.outputs.build_version }}'
|
||||
}
|
||||
});
|
||||
console.log('Desktop build triggered successfully');
|
||||
|
||||
- name: Trigger Mobile Build
|
||||
if: needs.create_tag.outputs.platform == 'mobile'
|
||||
- name: Trigger Mobile Preview Release Build
|
||||
if: needs.create_tag.outputs.platform == 'mobile' && needs.create_tag.outputs.ref_name == 'mobile-main'
|
||||
uses: actions/github-script@v8
|
||||
with:
|
||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
|
@ -85,9 +139,45 @@ jobs:
|
|||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
workflow_id: 'build-android.yml',
|
||||
ref: 'main',
|
||||
ref: 'mobile-main',
|
||||
inputs: {
|
||||
profile: 'preview',
|
||||
release: 'true'
|
||||
}
|
||||
});
|
||||
console.log('Mobile build triggered successfully');
|
||||
console.log('Mobile preview release build triggered successfully');
|
||||
|
||||
- name: Trigger Mobile Production Android Build
|
||||
if: needs.create_tag.outputs.platform == 'mobile' && needs.create_tag.outputs.ref_name == 'mobile-main'
|
||||
uses: actions/github-script@v8
|
||||
with:
|
||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
script: |
|
||||
const response = await github.rest.actions.createWorkflowDispatch({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
workflow_id: 'build-android.yml',
|
||||
ref: 'mobile-main',
|
||||
inputs: {
|
||||
profile: 'production',
|
||||
release: 'false'
|
||||
}
|
||||
});
|
||||
console.log('Mobile production Android build triggered successfully');
|
||||
|
||||
- name: Trigger Mobile Production iOS Build
|
||||
if: needs.create_tag.outputs.platform == 'mobile' && needs.create_tag.outputs.ref_name == 'mobile-main'
|
||||
uses: actions/github-script@v8
|
||||
with:
|
||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
script: |
|
||||
const response = await github.rest.actions.createWorkflowDispatch({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
workflow_id: 'build-ios.yml',
|
||||
ref: 'mobile-main',
|
||||
inputs: {
|
||||
profile: 'production'
|
||||
}
|
||||
});
|
||||
console.log('Mobile production iOS build triggered successfully');
|
||||
|
|
|
|||
Loading…
Reference in New Issue