diff --git a/.github/actions/create-version-bump-pr/action.yml b/.github/actions/create-version-bump-pr/action.yml new file mode 100644 index 000000000..24de7b333 --- /dev/null +++ b/.github/actions/create-version-bump-pr/action.yml @@ -0,0 +1,65 @@ +name: Create Version Bump PR +description: Creates a PR from staging changes onto dev branch +inputs: + platform: + description: Platform name (ios or android) + required: true + version: + description: Current version string + required: true + file_paths: + description: File paths to include in the PR (newline separated) + required: true + github_token: + description: GitHub token for creating PR + required: true + +runs: + using: composite + steps: + - name: Create version bump PR + shell: bash + run: | + BRANCH_NAME="ci/bump-${{ inputs.platform }}-build-${{ github.run_id }}" + + git config user.name "github-actions[bot]" + git config user.email "github-actions[bot]@users.noreply.github.com" + + # Check if there are changes + git add ${{ inputs.file_paths }} + if [[ -z $(git status -s) ]]; then + echo "No changes to commit. Skipping PR creation." + exit 0 + fi + + # Commit changes on temporary branch + git checkout -b temp-version-commit + git commit -m "chore: bump ${{ inputs.platform }} version for ${{ inputs.version }} [skip ci]" + + # Create new branch from dev + git fetch origin dev + git checkout -b ${BRANCH_NAME} origin/dev + + # Cherry-pick only the version changes + git cherry-pick temp-version-commit + + # Clean up temporary branch + git branch -D temp-version-commit + + # Push and create PR + git push --set-upstream origin ${BRANCH_NAME} + + # Determine PR title based on platform + if [ "${{ inputs.platform }}" = "mobile" ]; then + PR_TITLE="chore: bump mobile app version to ${{ inputs.version }}" + else + PR_TITLE="chore: bump ${{ inputs.platform }} build for ${{ inputs.version }}" + fi + + gh pr create \ + --base dev \ + --head ${BRANCH_NAME} \ + --title "$PR_TITLE" \ + --body "Automated version bump by CI" + env: + GH_TOKEN: ${{ inputs.github_token }} diff --git a/.github/workflows/mobile-deploy.yml b/.github/workflows/mobile-deploy.yml index f494bb77d..0cd5f14b1 100644 --- a/.github/workflows/mobile-deploy.yml +++ b/.github/workflows/mobile-deploy.yml @@ -152,6 +152,26 @@ jobs: echo "NODE_VERSION=$VERSION" >> "$GITHUB_ENV" echo "NODE_VERSION_SANITIZED=${VERSION//\//-}" >> "$GITHUB_ENV" + - name: Determine version bump from PR labels or input + id: version-bump + run: | + VERSION_BUMP="${{ inputs.version_bump || 'build' }}" + + # Override with PR label if present + if [ "${{ github.event_name }}" = "pull_request" ]; then + LABELS='${{ toJSON(github.event.pull_request.labels.*.name) }}' + if echo "$LABELS" | grep -q "version:major"; then + VERSION_BUMP="major" + elif echo "$LABELS" | grep -q "version:minor"; then + VERSION_BUMP="minor" + elif echo "$LABELS" | grep -q "version:patch"; then + VERSION_BUMP="patch" + fi + fi + + echo "version_bump=$VERSION_BUMP" >> $GITHUB_OUTPUT + echo "๐Ÿ“ฆ Version bump type: $VERSION_BUMP" + - name: Verify branch and commit (iOS) if: inputs.platform != 'android' run: | @@ -526,7 +546,7 @@ jobs: # Determine deployment track and version bump DEPLOYMENT_TRACK="${{ inputs.deployment_track || 'internal' }}" - VERSION_BUMP="${{ inputs.version_bump || 'build' }}" + VERSION_BUMP="${{ steps.version-bump.outputs.version_bump }}" TEST_MODE="${{ inputs.test_mode || false }}" echo "๐Ÿ“ฑ Deployment Configuration:" @@ -593,26 +613,6 @@ jobs: # Clean up rm -f versions.txt - - name: Get version from package.json - if: inputs.platform != 'android' - uses: ./.github/actions/get-version - with: - app_path: ${{ env.APP_PATH }} - - - name: Open PR for iOS build number bump - if: ${{ !env.ACT && (github.event_name != 'pull_request' || github.event.pull_request.merged == true) && success() }} - uses: peter-evans/create-pull-request@v6 - with: - title: "chore: bump iOS build for ${{ env.VERSION }}" - body: "Automated bump of iOS build number by CI" - commit-message: "chore: incrementing ios build number for version ${{ env.VERSION }} [github action]" - branch: ci/bump-ios-build-${{ github.run_id }} - base: dev - add-paths: | - app/version.json - app/ios/Self.xcodeproj/project.pbxproj - app/ios/OpenPassport/Info.plist - - name: Monitor cache usage if: always() run: | @@ -743,6 +743,26 @@ jobs: echo "NODE_VERSION=$VERSION" >> "$GITHUB_ENV" echo "NODE_VERSION_SANITIZED=${VERSION//\//-}" >> "$GITHUB_ENV" + - name: Determine version bump from PR labels or input + id: version-bump + run: | + VERSION_BUMP="${{ inputs.version_bump || 'build' }}" + + # Override with PR label if present + if [ "${{ github.event_name }}" = "pull_request" ]; then + LABELS='${{ toJSON(github.event.pull_request.labels.*.name) }}' + if echo "$LABELS" | grep -q "version:major"; then + VERSION_BUMP="major" + elif echo "$LABELS" | grep -q "version:minor"; then + VERSION_BUMP="minor" + elif echo "$LABELS" | grep -q "version:patch"; then + VERSION_BUMP="patch" + fi + fi + + echo "version_bump=$VERSION_BUMP" >> $GITHUB_OUTPUT + echo "๐Ÿ“ฆ Version bump type: $VERSION_BUMP" + - name: Verify branch and commit (Android) if: inputs.platform != 'ios' run: | @@ -937,7 +957,7 @@ jobs: # Determine deployment track and version bump DEPLOYMENT_TRACK="${{ inputs.deployment_track || 'internal' }}" - VERSION_BUMP="${{ inputs.version_bump || 'build' }}" + VERSION_BUMP="${{ steps.version-bump.outputs.version_bump }}" TEST_MODE="${{ inputs.test_mode || false }}" echo "๐Ÿค– Build Configuration:" @@ -966,27 +986,6 @@ jobs: --package-name "${{ secrets.ANDROID_PACKAGE_NAME }}" \ --track "$DEPLOYMENT_TRACK" - # Version updates moved to separate job to avoid race conditions - - - name: Get version from package.json - if: inputs.platform != 'ios' - uses: ./.github/actions/get-version - with: - app_path: ${{ env.APP_PATH }} - - - name: Open PR for Android build number bump - if: ${{ !env.ACT && (github.event_name != 'pull_request' || github.event.pull_request.merged == true) && success() }} - uses: peter-evans/create-pull-request@v6 - with: - title: "chore: bump Android build for ${{ env.VERSION }}" - body: "Automated bump of Android build number by CI" - commit-message: "chore: incrementing android build version for version ${{ env.VERSION }} [github action]" - branch: ci/bump-android-build-${{ github.run_id }} - base: dev - add-paths: | - app/version.json - app/android/app/build.gradle - - name: Monitor cache usage if: always() run: | @@ -1016,122 +1015,61 @@ jobs: echo "====================================" echo "๐Ÿ’ก GitHub Actions cache limit: 10GB per repository" - # Separate job to update version files after successful deployment - # This avoids race conditions when both iOS and Android run in parallel - update-version: + # Consolidated version bump PR - runs after both platforms complete + create-version-bump-pr: runs-on: ubuntu-latest needs: [build-ios, build-android] if: | always() && - (inputs.test_mode != true || github.event_name == 'pull_request') && + (github.event_name != 'pull_request' || github.event.pull_request.merged == true) && (needs.build-ios.result == 'success' || needs.build-android.result == 'success') env: APP_PATH: ${{ github.workspace }}/app steps: - uses: actions/checkout@v4 with: - token: ${{ github.token }} fetch-depth: 0 - ref: dev - - name: Read and sanitize Node.js version - shell: bash - run: | - if [ ! -f .nvmrc ] || [ -z "$(cat .nvmrc)" ]; then - echo "โŒ .nvmrc is missing or empty"; exit 1; - fi - VERSION="$(tr -d '\r\n' < .nvmrc)" - VERSION="${VERSION#v}" - if ! [[ "$VERSION" =~ ^[0-9]+(\.[0-9]+){0,2}$ ]]; then - echo "Invalid .nvmrc content: '$VERSION'"; exit 1; - fi - echo "NODE_VERSION=$VERSION" >> "$GITHUB_ENV" - echo "NODE_VERSION_SANITIZED=${VERSION//\//-}" >> "$GITHUB_ENV" + # Checkout staging where the builds ran + ref: ${{ github.event.pull_request.merge_commit_sha || 'staging' }} - - uses: actions/setup-node@v4 + - name: Get version from package.json + id: get-version + uses: ./.github/actions/get-version with: - node-version: ${{ env.NODE_VERSION }} + app_path: ${{ env.APP_PATH }} - - name: Update package.json version + - name: Determine platforms that succeeded + id: platforms run: | - cd ${{ env.APP_PATH }} - - # Get current version from package.json - CURRENT_VERSION=$(node -p "require('./package.json').version") - - # Get new version from version.json (if it exists and has version field) - if [ -f version.json ] && grep -q '"version"' version.json; then - NEW_VERSION=$(node -pe 'require("./version.json").version' 2>/dev/null || echo "") - else - # Fallback: use current version from package.json - NEW_VERSION="$CURRENT_VERSION" + PLATFORMS="" + if [ "${{ needs.build-ios.result }}" = "success" ]; then + PLATFORMS="${PLATFORMS}iOS " fi - - # Only update if versions differ - if [ "$CURRENT_VERSION" != "$NEW_VERSION" ] && [ -n "$NEW_VERSION" ]; then - echo "๐Ÿ“ฆ Updating package.json version:" - echo " From: v$CURRENT_VERSION" - echo " To: v$NEW_VERSION" - - # Use yarn to update package.json and the lockfile - yarn version --new-version "$NEW_VERSION" --no-git-tag-version -y - else - echo "โ„น๏ธ Version already up to date or no version field in version.json" + if [ "${{ needs.build-android.result }}" = "success" ]; then + PLATFORMS="${PLATFORMS}Android" fi + echo "platforms=${PLATFORMS}" >> $GITHUB_OUTPUT + echo "๐Ÿ“ฑ Successful builds: $PLATFORMS" - - name: Create PR with version files - run: | - set -e - - BRANCH_NAME="ci/update-version-${{ github.run_id }}" - - git config user.name "github-actions[bot]" - git config user.email "github-actions[bot]@users.noreply.github.com" - - # Check if there are any changes to commit - git add app/version.json app/package.json yarn.lock - if [[ -z $(git status -s) ]]; then - echo "No version file changes to commit. Skipping PR creation." - exit 0 - fi - - if [ "$GITHUB_EVENT_NAME" = "pull_request" ]; then - echo "๐Ÿงช Pull request event detected - running in dry-run mode." - echo "The following changes would be included in the version bump PR:" - git --no-pager diff --cached - exit 0 - fi - - # Commit the changes on a temporary local branch - git checkout -b temp-for-version-commit - git commit -m "chore: update version files after deployment [skip ci]" - - # Create a new branch from dev - git fetch origin dev - git checkout -b ${BRANCH_NAME} origin/dev - - # Cherry-pick the commit with the version changes - git cherry-pick temp-for-version-commit - - # Clean up temporary branch - git branch -D temp-for-version-commit - - # Push the new branch and create the PR - git push --set-upstream origin ${BRANCH_NAME} - - gh pr create \ - --base dev \ - --head ${BRANCH_NAME} \ - --title "chore: update version files after deployment" \ - --body "Automated update of version files after successful deployment." - env: - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + - name: Create consolidated version bump PR + uses: ./.github/actions/create-version-bump-pr + with: + platform: mobile + version: ${{ steps.get-version.outputs.version }} + file_paths: | + app/version.json + app/package.json + app/ios/Self.xcodeproj/project.pbxproj + app/ios/OpenPassport/Info.plist + app/android/app/build.gradle + github_token: ${{ secrets.GITHUB_TOKEN }} # Create git tags after successful deployment create-release-tags: - needs: [build-ios, build-android, update-version] + needs: [build-ios, build-android, create-version-bump-pr] if: | always() && - needs.update-version.result == 'success' && + needs.create-version-bump-pr.result == 'success' && (needs.build-ios.result == 'success' || needs.build-android.result == 'success') && (inputs.deployment_track == 'production') runs-on: ubuntu-latest diff --git a/app/fastlane/Fastfile b/app/fastlane/Fastfile index aac1f584b..cf16250c2 100644 --- a/app/fastlane/Fastfile +++ b/app/fastlane/Fastfile @@ -101,8 +101,8 @@ platform :ios do case version_bump when "major", "minor", "patch" - # VersionManager doesn't handle semantic versions, use npm - sh("cd .. && npm version #{version_bump} --no-git-tag-version") + # Use Node.js with semver to bump version + sh("cd .. && node -e \"const fs = require('fs'); const pkg = require('./package.json'); const semver = require('semver'); pkg.version = semver.inc(pkg.version, '#{version_bump}'); fs.writeFileSync('./package.json', JSON.stringify(pkg, null, 2) + '\\n');\"") UI.success("โœ… Bumped #{version_bump} version") # Sync the new version to iOS project files @@ -304,8 +304,8 @@ platform :android do case version_bump when "major", "minor", "patch" - # For semantic version bumps, we need to use npm version - sh("cd .. && npm version #{version_bump} --no-git-tag-version") + # Use Node.js with semver to bump version + sh("cd .. && node -e \"const fs = require('fs'); const pkg = require('./package.json'); const semver = require('semver'); pkg.version = semver.inc(pkg.version, '#{version_bump}'); fs.writeFileSync('./package.json', JSON.stringify(pkg, null, 2) + '\\n');\"") UI.success("โœ… Bumped #{version_bump} version") # Get the new version and sync to build.gradle new_version = Fastlane::Helpers::VersionManager.get_current_version