Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
62 changes: 52 additions & 10 deletions .github/workflows/preview-deployment.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ on:
workflow_dispatch:
inputs:
force_native_build:
description: "Force native build"
description: "Force native build (will ignore check-changes logic if re-enabled)"
type: boolean
default: true
required: true
Expand All @@ -18,6 +18,7 @@ on:
- "assets/**"
- "package.json"
- "app.config.ts"
- "versions.json"
- "yarn.lock"
- "i18n/**"
- "patches/**"
Expand All @@ -26,12 +27,13 @@ on:

# Ensure only one workflow runs at a time
concurrency:
group: "preview-deployment"
cancel-in-progress: false
group: "preview-deployment-${{ github.ref }}"
cancel-in-progress: true

# Permissions might be needed if you decide to commit preview build numbers later,
# but for now, not committing them back.
permissions:
contents: write
id-token: write

jobs:
# check-changes:
Expand Down Expand Up @@ -68,16 +70,19 @@ jobs:
# echo "has_native_changes=false" >> $GITHUB_OUTPUT
# fi

ios-build:
ios-preview-build:
# needs: [check-changes]
# if: needs.check-changes.outputs.has_native_changes == 'true'
runs-on: ubuntu-latest
outputs:
ios_preview_build_number: ${{ steps.update_versions_json_preview.outputs.new_build_number }}

steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
ref: main
ref: ${{ github.ref }}
token: ${{ secrets.PAT_GITHUB }}
fetch-depth: 0

- name: Setup node
Expand All @@ -91,7 +96,42 @@ jobs:
- run: corepack enable

- name: Install dependencies
run: yarn install
run: yarn install --immutable

- name: Configure Git
run: |
git config --global user.name "GitHub Actions Bot (Preview Build)"
git config --global user.email "github-actions-bot-preview@users.noreply.github.com"

- name: Update iOS Preview Build Number in versions.json
id: update_versions_json_preview
run: |
node scripts/update-versions.js --platform=ios --env=preview
# The script outputs 'new_build_number'

- name: Commit and Push versions.json
run: |
if ! git diff --quiet versions.json; then
echo "versions.json was updated. Committing and pushing..."
git add versions.json
COMMIT_MSG="chore: Update iOS preview build number to ${{ steps.update_versions_json_preview.outputs.new_build_number }}"
git commit -m "$COMMIT_MSG"
git push origin ${{ github.ref_name }}
else
Comment on lines +112 to +120

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

鈿狅笍 Potential issue

Infinite loop risk on push trigger
Committing and pushing versions.json to main (or another branch) under a push-triggered workflow will retrigger this same workflow, causing repeated version bumps. Consider limiting the trigger conditions (e.g., exclude pushes made by the bot) or gating commits via if: github.actor != 'github-actions[bot]'.

馃 Prompt for AI Agents
In .github/workflows/preview-deployment.yml around lines 112 to 120, the current
workflow commits and pushes changes to versions.json on every push, which can
cause an infinite loop by retriggering the workflow. To fix this, add a
condition to skip the commit and push steps if the actor is the GitHub Actions
bot by using an if statement like `if: github.actor != 'github-actions[bot]'`
before running the commit and push commands. This prevents the workflow from
triggering itself repeatedly.

echo "versions.json was not changed. No commit needed."
fi

- name: Update app.config.ts with New iOS Preview Build Number (local to runner)
id: update_app_config_preview
run: |
NEW_BUILD_NUM_PREVIEW=${{ steps.update_versions_json_preview.outputs.new_build_number }}
if [ -z "$NEW_BUILD_NUM_PREVIEW" ]; then
echo "Error: Failed to get new_build_number from update_versions_json_preview step."
exit 1
fi
echo "New iOS Preview build number for this build is: $NEW_BUILD_NUM_PREVIEW"
node scripts/update-app-config-buildnum.js --platform=ios --env=preview --buildNumber=$NEW_BUILD_NUM_PREVIEW
echo "app.config.ts updated locally for preview build."

# Need this here because the "Setup EAS" setup will execute npx expo config and will need the "build" folder of the plugin to be there
- name: Build iOS notification extension plugin
Expand All @@ -107,10 +147,12 @@ jobs:
eas-cache: true
patch-watchers: true # Prevents ENOSPC errors on Ubuntu runners

- name: Build and submit to store
- name: Build and submit Preview to store
run: |
# Use the --non-interactive flag to run in CI mode
# Use the --auto-submit flag to submit to App Store
# EAS will now use the app.config.ts that has been locally modified
# with the incremented preview build number.
# EXPO_ENV=preview should be set for eas build if your app.config.ts relies on it
# to pick the right settings block. EAS CLI often does this automatically based on profile.
eas build --platform ios --profile preview --non-interactive --auto-submit

# - name: Resolve Sentry Issues
Expand Down
101 changes: 56 additions & 45 deletions .github/workflows/production-deployment.yml
Original file line number Diff line number Diff line change
@@ -1,51 +1,54 @@
# .github/workflows/production-deployment.yml
name: Production Deployment

on:
push:
branches:
- production # Triggers on push to the production branch
tags: # Trigger on new tags that match the pattern
- "v[0-9]+.[0-9]+.[0-9]+-build.[0-9]+" # e.g. v1.0.1-build.123

# Ensure only one deployment workflow runs at a time for production
concurrency:
group: "production-deployment"
cancel-in-progress: true # It's okay to cancel in-progress deployments if a newer commit comes in
group: "production-deployment-${{ github.ref }}"
cancel-in-progress: true

permissions:
id-token: write # For EAS Build
contents: read # For checkout
id-token: write
contents: write # For GitHub Release creation

jobs:
build-and-deploy:
build_and_deploy:
runs-on: ubuntu-latest
steps:
- name: Checkout production branch
- name: Checkout code for the specific tag
uses: actions/checkout@v4
with:
fetch-depth: 0 # Fetch all history to access parent commits
ref: ${{ github.ref }} # Checks out the specific tag that triggered the workflow
fetch-depth: 0 # For release notes

- name: Extract Meaningful Commit Messages
id: commit_messages
- name: Extract Version and Build Info from Tag
id: version_info
run: |
# HEAD is the merge commit on the production branch
# HEAD^1 is the first parent (previous state of production)
# HEAD^2 is the second parent (tip of main that was merged)
# This command gets the subject of commits from main introduced in this merge
# It formats them as "- Subject" and handles multi-line messages for the output
# It also reverses the order to show oldest first, newest last.
MESSAGES=$(git log --pretty="format:- %s" HEAD^1..HEAD^2 --reverse)
if [ -z "$MESSAGES" ]; then
# If no distinct commits (e.g., main was already merged or only fast-forward if that was allowed)
# Fallback to the merge commit's subject
MESSAGES="Changes from merge: $(git log -1 --pretty=%s)"
TAG_NAME="${{ github.ref_name }}" # e.g., v1.0.1-build.123
# Extract package version (e.g., 1.0.1)
APP_VERSION=$(echo "$TAG_NAME" | sed -n 's/^v\([0-9]*\.[0-9]*\.[0-9]*\)-build\.[0-9]*$/\1/p')
# Extract build number (e.g., 123)
BUILD_NUMBER=$(echo "$TAG_NAME" | sed -n 's/^v[0-9]*\.[0-9]*\.[0-9]*-build\.\([0-9]*\)$/\1/p')

if [ -z "$APP_VERSION" ] || [ -z "$BUILD_NUMBER" ]; then
echo "Error: Could not parse APP_VERSION or BUILD_NUMBER from tag $TAG_NAME"
# Fallback to package.json version if parsing fails, though tag should be the source of truth here
APP_VERSION=$(node -p "require('./package.json').version")
echo "Fallback APP_VERSION: $APP_VERSION"
# Build number might be harder to get as a fallback without reading versions.json for the specific context
fi
# Escape for multiline shell output to GITHUB_OUTPUT and EAS message
MESSAGES="${MESSAGES//'%'/'%25'}"
MESSAGES="${MESSAGES//$'\n'/'%0A'}" # For GITHUB_OUTPUT
MESSAGES="${MESSAGES//$'\r'/'%0D'}"
echo "formatted_messages<<EOF" >> $GITHUB_OUTPUT
echo "$MESSAGES" >> $GITHUB_OUTPUT
echo "EOF" >> $GITHUB_OUTPUT

echo "Release Tag: $TAG_NAME"
echo "App Version: $APP_VERSION"
echo "Build Number: $BUILD_NUMBER"
echo "release_tag=$TAG_NAME" >> $GITHUB_OUTPUT
echo "app_version=$APP_VERSION" >> $GITHUB_OUTPUT
echo "build_number=$BUILD_NUMBER" >> $GITHUB_OUTPUT

# ... (Setup Node, Install Deps, Build Plugin - same as before) ...
- name: Setup node
uses: actions/setup-node@v4
with:
Expand All @@ -59,7 +62,6 @@ jobs:
- name: Install dependencies
run: yarn install --immutable

# Need this here because the "Setup EAS" setup will execute npx expo config and will need the "build" folder of the plugin to be there
- name: Build iOS notification extension plugin
run: |
yarn plugins:build:notification-service-extension
Expand All @@ -74,19 +76,28 @@ jobs:
patch-watchers: true

- name: Build and Submit iOS production
id: eas_build
env:
RELEASE_TAG_VAL: ${{ steps.version_info.outputs.release_tag }}
run: |
echo "EAS Build Message Content:"
# For the actual EAS command, we need to replace %0A with actual newlines for readability if supported,
# or keep as a long string. EAS CLI message is a single string.
# Let's prepare a version for the CLI command.
CLI_MESSAGE=$(echo "${{ steps.commit_messages.outputs.formatted_messages }}" | sed 's/%0A/\n/g')
# Truncate if too long, EAS might have a limit (e.g. 250 chars, adjust as needed)
# This example truncates to 240 chars to be safe, adding "..."
MAX_LEN=240
if [ ${#CLI_MESSAGE} -gt $MAX_LEN ]; then
CLI_MESSAGE="$(echo "$CLI_MESSAGE" | cut -c 1-$((MAX_LEN-3)))..."
fi
echo "$CLI_MESSAGE"

# The EAS build will be associated with this specific commit.
CLI_MESSAGE="Production build for ${RELEASE_TAG_VAL}"
echo "EAS Build Message: $CLI_MESSAGE"
# EAS should pick up version from package.json and build number from app.config.ts
# which were set correctly by prepare-release.yml for this tag
eas build --platform ios --profile production --non-interactive --auto-submit --message "$CLI_MESSAGE"
echo "EAS Build and Submission successful."

- name: Create GitHub Release
if: success()
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
RELEASE_TAG: ${{ steps.version_info.outputs.release_tag }}
APP_VERSION: ${{ steps.version_info.outputs.app_version }} # Just the semver part
BUILD_NUM: ${{ steps.version_info.outputs.build_number }}
run: |
echo "Creating GitHub Release for $RELEASE_TAG..."
gh release create "$RELEASE_TAG" \
--title "Release $APP_VERSION (Build $BUILD_NUM)" \
--generate-notes \
--target ${{ github.ref_name }} # Target the tag itself
echo "GitHub Release $RELEASE_TAG created successfully."
94 changes: 75 additions & 19 deletions .github/workflows/promote-to-production.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,40 +3,96 @@ name: Promote to Production
on:
workflow_dispatch:

# Ensure only one promotion workflow runs at a time
concurrency:
group: "promote-to-production-${{ github.ref_name }}"
cancel-in-progress: false

permissions:
contents: write # Needed to push the merge commit
contents: write

jobs:
merge-to-production:
prepare_and_merge:
name: Promote iOS Production Build
runs-on: ubuntu-latest
outputs:
release_tag: ${{ steps.tag_and_commit.outputs.new_tag }}
app_version: ${{ steps.read_package_version.outputs.app_version }}
build_number: ${{ steps.update_versions_json.outputs.new_build_number }}

steps:
- name: Checkout source branch (the one being promoted)
- name: Checkout main branch
uses: actions/checkout@v4
with:
ref: ${{ github.ref }} # Use the ref from which the workflow is run (e.g., main)
token: ${{ secrets.PAT_GITHUB }} # Since production is protected, we need a PAT to push to it
fetch-depth: 0 # Fetch history to read package.json
ref: main
token: ${{ secrets.PAT_GITHUB }}
fetch-depth: 0

- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version-file: ".nvmrc"
cache: "yarn"
env:
SKIP_YARN_COREPACK_CHECK: "1"
- run: corepack enable
- run: yarn install --immutable

- name: Configure Git
run: |
git config --global user.name "GitHub Actions Bot"
git config --global user.email "github-actions[bot]@users.noreply.github.com"

- name: Merge source branch into production
- name: Read App Version from package.json
id: read_package_version
run: |
COMMIT_MSG="Merge branch '${{ github.ref_name }}' into production"
APP_VERSION=$(node -p "require('./package.json').version")
if [ -z "$APP_VERSION" ]; then
echo "Error: Could not read version from package.json"
exit 1
fi
echo "App Version from package.json: $APP_VERSION"
echo "app_version=$APP_VERSION" >> $GITHUB_OUTPUT

# Checkout production branch from remote
git fetch origin production
git checkout -B production origin/production
- name: Update iOS Production Build Number in versions.json
id: update_versions_json
run: |
node scripts/update-versions.js --platform=ios --env=production
# The script itself uses `::set-output name=new_build_number::VALUE`

Comment on lines +52 to +57

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

鈿狅笍 Potential issue

Deprecation warning: set-output
The update-versions.js script鈥檚 internal use of the deprecated ::set-output command will trigger actionlint errors. Please refactor the script to emit:

echo "new_build_number=$VALUE" >> $GITHUB_OUTPUT
馃О Tools
馃獩 actionlint (1.7.7)

54-54: workflow command "set-output" was deprecated. use echo "{name}={value}" >> $GITHUB_OUTPUT instead: https://docs.github.com/en/actions/using-workflows/workflow-commands-for-github-actions

(deprecated-commands)

馃 Prompt for AI Agents
In .github/workflows/promote-to-production.yml around lines 52 to 57, the
update-versions.js script uses the deprecated `::set-output` command to set
outputs, which causes actionlint errors. Modify the script to replace all
instances of `::set-output name=new_build_number::VALUE` with the new syntax by
appending `new_build_number=VALUE` to the file specified by the environment
variable GITHUB_OUTPUT using `echo "new_build_number=$VALUE" >> $GITHUB_OUTPUT`.

- name: Update app.config.ts with New iOS Production Build Number
id: update_app_config
run: |
NEW_BUILD_NUM_FROM_VERSIONS_JSON=${{ steps.update_versions_json.outputs.new_build_number }}
if [ -z "$NEW_BUILD_NUM_FROM_VERSIONS_JSON" ]; then
echo "Error: Failed to get new_build_number from update_versions_json step."
exit 1
fi
echo "New iOS Production build number from versions.json is: $NEW_BUILD_NUM_FROM_VERSIONS_JSON"
node scripts/update-app-config-buildnum.js --platform=ios --env=production --buildNumber=$NEW_BUILD_NUM_FROM_VERSIONS_JSON

- name: Commit Changes and Create Tag for iOS Production
id: tag_and_commit
run: |
APP_VERSION=${{ steps.read_package_version.outputs.app_version }}
NEW_BUILD_NUMBER=${{ steps.update_versions_json.outputs.new_build_number }}

git add versions.json
git add app.config.ts

# Merge the source branch (already checked out by the first step, HEAD points to it)
# ${{ github.ref_name }} is the short name of the branch, e.g., "main"
git merge ${{ github.ref_name }} -Xtheirs --no-ff --no-edit -m "$COMMIT_MSG"
COMMIT_MSG="chore(release): Increment iOS Production Build to $NEW_BUILD_NUMBER for App Version $APP_VERSION"
if git diff --staged --quiet; then
echo "No changes to commit for build number."
else
git commit -m "$COMMIT_MSG"
fi
git push origin main

NEW_TAG="v${APP_VERSION}-ios-build.${NEW_BUILD_NUMBER}"
echo "Creating and pushing tag $NEW_TAG..."
git tag -a "$NEW_TAG" -m "Release App Version $APP_VERSION (iOS Production Build $NEW_BUILD_NUMBER)"
git push origin "$NEW_TAG"
echo "new_tag=$NEW_TAG" >> $GITHUB_OUTPUT

- name: Merge main into production
run: |
echo "Merging main into production..."
git fetch origin production
git checkout -B production origin/production
git merge main -Xtheirs --no-ff -m "Merge branch 'main' into production for release ${{ steps.tag_and_commit.outputs.new_tag }}"
git push origin production
Loading