From 9fad1912c8471744aa4c26df3ef46b380efaead4 Mon Sep 17 00:00:00 2001 From: Sandipan Date: Wed, 28 Feb 2024 00:43:41 +0530 Subject: [PATCH] ci: use self hosted runner for concourse builds and deprecate circleci completely (#3095) * save * save * fix fastfile * chore: deprecate circleci * fix: refs --- .circleci/config.yml | 355 -------------------------------- ci/image/Dockerfile | 18 +- ci/pipeline.yml | 203 +++++++++--------- ci/tasks/build-android.sh | 29 +++ ci/tasks/build-ios.sh | 34 +++ ci/tasks/build-on-circleci.sh | 101 --------- ci/tasks/cancel-circleci-job.sh | 7 - ci/tasks/upload-to-gcs.sh | 12 ++ ci/values.yml | 8 +- ios/fastlane/Fastfile | 7 + 10 files changed, 208 insertions(+), 566 deletions(-) delete mode 100644 .circleci/config.yml create mode 100755 ci/tasks/build-android.sh create mode 100755 ci/tasks/build-ios.sh delete mode 100755 ci/tasks/build-on-circleci.sh delete mode 100755 ci/tasks/cancel-circleci-job.sh create mode 100755 ci/tasks/upload-to-gcs.sh diff --git a/.circleci/config.yml b/.circleci/config.yml deleted file mode 100644 index 1130427ae3..0000000000 --- a/.circleci/config.yml +++ /dev/null @@ -1,355 +0,0 @@ -version: 2.1 - -orbs: - gh: circleci/github-cli@2.0 - node: circleci/node@5.1.1 - -parameters: - version: - type: string - default: "" - platform: - type: string - default: "" - git_ref: - type: string - default: "" - gcs_directory: - type: string - default: "" - build_number: - type: string - default: "" - task: - type: string - default: "" - gcs_url: - type: string - default: "" - -jobs: - test_android_in_pr: - docker: - - image: cimg/android:2024.01 - resource_class: xlarge - environment: - TERM: dumb - JAVA_OPTS: -Xms512m -Xmx2g - GRADLE_OPTS: -Xmx3g -Dorg.gradle.daemon=false -Dorg.gradle.jvmargs="-Xmx2g -XX:+HeapDumpOnOutOfMemoryError" - working_directory: ~/galoy-mobile - shell: /bin/bash --login -o pipefail - steps: - # if workflow was triggered by API then don't run the test jobs - - run: | - if [ << pipeline.trigger_source >> = "api" ]; then - circleci-agent step halt - fi - - checkout: - path: ~/galoy-mobile - - - node/install: - install-yarn: true - node-version: '18.18.2' - - - run: sudo apt-get install gcc g++ make - - run: gpg --keyserver keyserver.ubuntu.com --recv-keys 409B6B1796C275462A1703113804BB82D39DC0E3 7D2BAF1CF37B13E2069D6956105BD0E739499BDB - - - restore_cache: - key: 1-gem-{{ checksum "android/Gemfile.lock" }} - - run: cd android && bundle config set deployment 'true' - - run: cd android && bundle check || bundle install - - save_cache: - key: 1-gem-{{ checksum "android/Gemfile.lock" }} - paths: - - android/vendor - - - restore_cache: - key: yarn-{{ checksum "yarn.lock" }} - - run: yarn install - - save_cache: - key: yarn-{{ checksum "yarn.lock" }} - paths: - - node_modules - - run: echo $RELEASE_KEYSTORE | base64 -d > android/app/release.keystore - - run: yarn android:prepareAssets - - run: - name: Test Browserstack - command: | - set -o pipefail - cd android && bundle exec fastlane browserstack | tee browserstack_output.log - error_code=$? - SESSION_ID=$(cat browserstack_output.log | grep sessionId | head -n1 | sed -n "s/^.*'\(.*\)'.*$/\1/ p") - echo "Session ID" - echo $SESSION_ID - echo "Browserstack URL" - echo "https://app-automate.browserstack.com/dashboard/v2/builds/$BROWSERSTACK_ANDROID_BUILD/sessions/$SESSION_ID" - VIDEO_URL=$(curl -s -u "$BROWSERSTACK_USER:$BROWSERSTACK_ACCESS_KEY" -X GET "https://api-cloud.browserstack.com/app-automate/sessions/$SESSION_ID.json" | jq -r '.automation_session.video_url') - echo "Video URL" - echo $VIDEO_URL - exit $error_code - - test_ios_in_pr: - macos: - xcode: 15.2.0 - resource_class: macos.x86.medium.gen2 - working_directory: ~/galoy-mobile - environment: - FL_OUTPUT_DIR: output - shell: /bin/bash --login -o pipefail - steps: - # if workflow was triggered by API then don't run the test jobs - - run: | - if [ << pipeline.trigger_source >> = "api" ]; then - circleci-agent step halt - fi - - checkout: - path: ~/galoy-mobile - - - run: - name: Check Ruby version - command: | - rbenv versions - echo "Ruby version in .ruby-version:" - cat .ruby-version - echo "Ruby version in Gemfile:" - grep -E "^ruby" Gemfile - - - run: - name: Install Bundler 2.2.30 - command: | - gem install bundler:2.2.30 - echo "export BUNDLE_PATH=$(bundle show --path)" >> $BASH_ENV - source $BASH_ENV - - - add_ssh_keys: - fingerprints: - - "19:7e:f3:6c:be:a7:17:01:7d:09:ca:39:c3:98:86:90" - - restore_cache: - key: 1-gem-{{ checksum "ios/Gemfile.lock" }} - - run: cd ios && bundle config set deployment 'true' - - run: cd ios && bundle config set --local path 'vendor/bundle' - - run: cd ios && bundle check || bundle install - - run: gem install cocoapods - - save_cache: - key: 1-gem-{{ checksum "ios/Gemfile.lock" }} - paths: - - ios/vendor - - restore_cache: - key: 1-yarn-{{ checksum "yarn.lock" }}-pod1-{{ checksum "ios/Podfile.lock" }} - - run: yarn install - - save_cache: - key: 1-yarn-{{ checksum "yarn.lock" }}-pod1-{{ checksum "ios/Podfile.lock" }} - paths: - - node_modules - - ios/Pods - - run: - name: Import Apple Certificates - command: | - tmpfile=$(mktemp /tmp/wwdr-cert.cer) - curl -f -o $tmpfile https://www.apple.com/certificateauthority/AppleWWDRCAG3.cer && security import $tmpfile ~/Library/Keychains/login.keychain-db - - run: - name: Browserstack Testing - command: | - set -o pipefail - cd ios && bundle exec fastlane browserstack | tee browserstack_output.log - error_code=$? - SESSION_ID=$(cat browserstack_output.log | grep sessionId | head -n1 | sed -n "s/^.*'\(.*\)'.*$/\1/ p") - echo "Session ID" - echo $SESSION_ID - echo "Browserstack URL" - echo "https://app-automate.browserstack.com/dashboard/v2/builds/$BROWSERSTACK_IOS_BUILD/sessions/$SESSION_ID" - VIDEO_URL=$(curl -s -u "$BROWSERSTACK_USER:$BROWSERSTACK_ACCESS_KEY" -X GET "https://api-cloud.browserstack.com/app-automate/sessions/$SESSION_ID.json" | jq -r '.automation_session.video_url') - echo "Video URL" - echo $VIDEO_URL - exit $error_code - no_output_timeout: 15m - - build_android: - docker: - - image: cimg/android:2024.01 - resource_class: xlarge - environment: - TERM: dumb - JAVA_OPTS: -Xms2g -Xmx4g - GRADLE_OPTS: -Dorg.gradle.daemon=false -Dorg.gradle.jvmargs="-Xmx4g -XX:+HeapDumpOnOutOfMemoryError" - PUBLIC_VERSION: << pipeline.parameters.version >> - BUILD_NUMBER: << pipeline.parameters.build_number >> - GCS_DIRECTORY: << pipeline.parameters.gcs_directory >> - working_directory: ~/galoy-mobile - shell: /bin/bash --login -o pipefail - steps: - # if workflow was triggered by github then don't run the test jobs - - run: | - if [ << pipeline.trigger_source >> = "webhook" ]; then - circleci-agent step halt - fi - - gh/install - - checkout: - path: ~/galoy-mobile - - - node/install: - install-yarn: true - node-version: '18.18.2' - - - run: git checkout << pipeline.parameters.git_ref >> - - run: gpg --keyserver keyserver.ubuntu.com --recv-keys 409B6B1796C275462A1703113804BB82D39DC0E3 7D2BAF1CF37B13E2069D6956105BD0E739499BDB - - run: echo $GCLOUD_BUCKET_KEY | base64 --decode > key.json - - run: gcloud auth activate-service-account --key-file key.json - - - run: cd android && bundle config set deployment 'true' - - run: cd android && bundle check || bundle install - - - restore_cache: - key: 2-yarn-{{ checksum "yarn.lock" }}-android - - run: yarn global add node-gyp - - run: yarn install - - save_cache: - key: 2-yarn-{{ checksum "yarn.lock" }}-android - paths: - - node_modules - - run: echo $JAVA_OPTS - - run: echo $GRADLE_OPTS - - run: echo $RELEASE_KEYSTORE | base64 -d > android/app/release.keystore - - run: - name: build - command: | - cd android - sed -i'' -e "s/versionCode .*$/versionCode $BUILD_NUMBER/g" app/build.gradle - bundle exec fastlane android build 2>&1 | tee android_build_output.log - no_output_timeout: 15m - - run: - name: upload to gcs - command: gsutil cp -r android/app/build/outputs/* gs://galoy-build-artifacts/galoy-mobile/$GCS_DIRECTORY/galoy-mobile-$(date +%s)-v${PUBLIC_VERSION}/ - - store_artifacts: - path: android/android_build_output.log - - build_ios: - macos: - xcode: 15.2.0 - resource_class: macos.x86.medium.gen2 - environment: - PUBLIC_VERSION: << pipeline.parameters.version >> - BUILD_NUMBER: << pipeline.parameters.build_number >> - GCS_DIRECTORY: << pipeline.parameters.gcs_directory >> - working_directory: ~/galoy-mobile - shell: /bin/bash --login -o pipefail - steps: - # if workflow was triggered by github then don't run the test jobs - - run: | - if [ << pipeline.trigger_source >> = "webhook" ]; then - circleci-agent step halt - fi - - gh/install - - checkout: - path: ~/galoy-mobile - - run: git checkout << pipeline.parameters.git_ref >> - - run: - name: Install Bundler 2.2.30 - command: | - gem install bundler:2.2.30 - echo "export BUNDLE_PATH=$(bundle show --path)" >> $BASH_ENV - source $BASH_ENV - - add_ssh_keys: - fingerprints: - - "19:7e:f3:6c:be:a7:17:01:7d:09:ca:39:c3:98:86:90" - - run: brew update - - run: HOMEBREW_NO_AUTO_UPDATE=1 brew install --cask google-cloud-sdk - - run: echo $GCLOUD_BUCKET_KEY | base64 --decode > key.json - - run: gcloud auth activate-service-account --key-file key.json - - restore_cache: - key: 1-gem-{{ checksum "ios/Gemfile.lock" }} - - run: | - rbenv install 2.7.7 - rbenv global 2.7.7 - - run: cd ios && bundle config set deployment 'true' - - run: cd ios && bundle config set --local path 'vendor/bundle' - - run: cd ios && bundle check || bundle install - - run: gem install cocoapods - - save_cache: - key: 1-gem-{{ checksum "ios/Gemfile.lock" }} - paths: - - ios/vendor - - restore_cache: - key: 1-yarn-{{ checksum "yarn.lock" }}-pod1-{{ checksum "ios/Podfile.lock" }} - - run: yarn install - - save_cache: - key: 1-yarn-{{ checksum "yarn.lock" }}-pod1-{{ checksum "ios/Podfile.lock" }} - paths: - - node_modules - - ios/Pods - - run: - name: Import Apple Certificates - command: | - tmpfile=$(mktemp /tmp/wwdr-cert.cer) - curl -f -o $tmpfile https://www.apple.com/certificateauthority/AppleWWDRCAG3.cer && security import $tmpfile ~/Library/Keychains/login.keychain-db - - run: - name: build - command: | - cd ios - sed -i'' -e "s/MARKETING_VERSION.*/MARKETING_VERSION = $PUBLIC_VERSION;/g" GaloyApp.xcodeproj/project.pbxproj - bundle exec fastlane build 2>&1 | tee ios_build_output.log - no_output_timeout: 15m - - run: - name: upload to gcs - command: | - timestamp=$(date +%s) - gsutil cp -r ~/galoy-mobile/ios/Blink.ipa gs://galoy-build-artifacts/galoy-mobile/$GCS_DIRECTORY/galoy-mobile-$timestamp-v${PUBLIC_VERSION}/ - gsutil cp -r ~/galoy-mobile/ios/Blink.app.dSYM.zip gs://galoy-build-artifacts/galoy-mobile/$GCS_DIRECTORY/galoy-mobile-$timestamp-v${PUBLIC_VERSION}/ - - store_artifacts: - path: ios/ios_build_output.log - - upload_to_app_store: - macos: - xcode: 15.2.0 - resource_class: macos.x86.medium.gen2 - environment: - GCS_URL: << pipeline.parameters.gcs_url >> - working_directory: ~/galoy-mobile - shell: /bin/bash --login -o pipefail - steps: - # if workflow was triggered by github then don't run the test jobs - - run: | - if [ << pipeline.trigger_source >> = "webhook" ]; then - circleci-agent step halt - fi - - gh/install - - checkout: - path: ~/galoy-mobile - - run: brew update - - run: HOMEBREW_NO_AUTO_UPDATE=1 brew install --cask google-cloud-sdk - - run: echo $GCLOUD_BUCKET_KEY | base64 --decode > key.json - - run: gcloud auth activate-service-account --key-file key.json - - run: git checkout << pipeline.parameters.git_ref >> - - run: cd ios && gsutil cp -r "$GCS_URL" . - - restore_cache: - key: 1-gem-{{ checksum "ios/Gemfile.lock" }} - - run: cd ios && bundle check || bundle install - - save_cache: - key: 1-gem-{{ checksum "ios/Gemfile.lock" }} - paths: - - ios/vendor - - run: - name: Import Apple Certificates - command: | - tmpfile=$(mktemp /tmp/wwdr-cert.cer) - curl -f -o $tmpfile https://www.apple.com/certificateauthority/AppleWWDRCAG3.cer && security import $tmpfile ~/Library/Keychains/login.keychain-db - - run: cd ios && bundle exec fastlane app_store_upload - -workflows: - build_android_and_upload_to_bucket: - when: - equal: [android, << pipeline.parameters.platform >>] - jobs: - - build_android - build_ios_and_upload_to_bucket: - when: - equal: [ios, << pipeline.parameters.platform >>] - jobs: - - build_ios - upload_to_app_store: - when: - and: - - equal: [upload_to_app_store, << pipeline.parameters.task >>] - - equal: ["api", << pipeline.trigger_source >>] - jobs: - - upload_to_app_store diff --git a/ci/image/Dockerfile b/ci/image/Dockerfile index 6bcc47d51d..892c19e92f 100644 --- a/ci/image/Dockerfile +++ b/ci/image/Dockerfile @@ -1,9 +1,12 @@ -FROM node:18-alpine +FROM node:20-alpine RUN apk update \ - && apk add bash curl wget tar git jq make perl-utils \ + && apk add bash curl wget tar git jq make perl-utils python3 \ && apk add yq --repository=http://dl-cdn.alpinelinux.org/alpine/edge/community +RUN curl -sSL https://sdk.cloud.google.com | bash +ENV PATH $PATH:/root/google-cloud-sdk/bin + ENV GH_CLI_VERSION 2.23.0 RUN mkdir ghcli && cd ghcli \ && wget https://github.com/cli/cli/releases/download/v${GH_CLI_VERSION}/gh_${GH_CLI_VERSION}_linux_386.tar.gz -O ghcli.tar.gz \ @@ -22,12 +25,13 @@ RUN wget https://github.com/minamijoyo/hcledit/releases/download/v${HCLEDIT_VERS && chmod +x /usr/local/bin/hcledit \ && rm hcledit_${HCLEDIT_VERSION}_linux_amd64.tar.gz +ARG GHTOKEN_VERSION=2.0.1 RUN wget -O ghtoken \ - https://raw.githubusercontent.com/Link-/gh-token/main/gh-token && \ - echo "6a6b111355432e08dd60ac0da148e489cdb0323a059ee8cbe624fd37bf2572ae ghtoken" | \ - shasum -c - && \ - chmod u+x ./ghtoken && \ - mv ./ghtoken /usr/local/bin/ghtoken + https://github.com/Link-/gh-token/releases/download/v${GHTOKEN_VERSION}/linux-amd64 && \ + echo "f76e8cb35f0b04b59073a486cc952e50fa9f1c930a25619ea9abcf44a13165c4 ghtoken" | \ + shasum -c - && \ + chmod u+x ./ghtoken && \ + mv ./ghtoken /usr/local/bin/ghtoken RUN wget https://github.com/mike-engel/jwt-cli/releases/download/4.0.0/jwt-linux.tar.gz \ && echo "6b0740c3f4c7134a0cbcf802b95b033bd2246d592ad16aa2ee2d80e5b289b4d6 jwt-linux.tar.gz" > jwt-linux.sha256 \ diff --git a/ci/pipeline.yml b/ci/pipeline.yml index 88ea28f7aa..099a887ed7 100644 --- a/ci/pipeline.yml +++ b/ci/pipeline.yml @@ -24,20 +24,6 @@ source: repository: #@ release_pipeline_image() #@ end -#@ def cancel_circleci_build_on_abort(): -task: cancel -config: - platform: linux - image_resource: #@ task_image_config() - inputs: - - name: pipeline-tasks - - name: job-number - run: - path: pipeline-tasks/ci/tasks/cancel-circleci-job.sh - params: - CIRCLECI_TOKEN: #@ data.values.circleci_token -#@ end - groups: - name: all jobs: @@ -139,26 +125,40 @@ jobs: - get: pipeline-tasks - get: build-number-android - task: build + tags: [ mac-m1 ] config: - platform: linux - image_resource: #@ task_image_config() + platform: darwin inputs: - name: repo - name: pipeline-tasks - name: build-number-android outputs: - - name: job-number + - name: repo + - name: artifacts run: - path: pipeline-tasks/ci/tasks/build-on-circleci.sh + path: /bin/sh + args: + - "-c" + - "arch -arm64 pipeline-tasks/ci/tasks/build-android.sh" params: - PLATFORM: android - WAIT_FOR_BUILD_MINS: 30 - BUILD_NUMBER_FILE: build-number-android/android - GIT_REF_FILE: repo/.git/ref + VERSION_FILE: repo/.git/ref + ANDROID_KEYSTORE: #@ data.values.android_keystore + - task: upload-to-gcs + config: + platform: linux + image_resource: #@ task_image_config() + inputs: + - name: repo + - name: artifacts + - name: pipeline-tasks + run: + path: pipeline-tasks/ci/tasks/upload-to-gcs.sh + params: + INPUTS: android/app/build/outputs/* VERSION_FILE: repo/.git/ref GCS_DIRECTORY: dev/android - CIRCLECI_TOKEN: #@ data.values.circleci_token - on_abort: #@ cancel_circleci_build_on_abort() + bucket: #@ data.values.build_artifacts_bucket_name + json_key: #@ data.values.build_artifacts_bucket_creds - name: dev-build-ios serial: true @@ -172,26 +172,45 @@ jobs: - get: pipeline-tasks - get: build-number-ios - task: build + tags: [ mac-m1 ] config: - platform: linux - image_resource: #@ task_image_config() + platform: darwin inputs: - name: repo - name: pipeline-tasks - name: build-number-ios outputs: - - name: job-number + - name: repo + - name: artifacts run: - path: pipeline-tasks/ci/tasks/build-on-circleci.sh + path: /bin/sh + args: + - "-c" + - "arch -arm64 pipeline-tasks/ci/tasks/build-ios.sh" params: - PLATFORM: ios - WAIT_FOR_BUILD_MINS: 45 - BUILD_NUMBER_FILE: build-number-ios/ios - GIT_REF_FILE: repo/.git/ref VERSION_FILE: repo/.git/ref + MATCH_PASSWORD: #@ data.values.fastlane_match_password + MATCH_KEYCHAIN_PASSWORD: #@ data.values.fastlane_match_keychain_password + GITHUB_SSH_KEY: #@ data.values.github_private_key + APPSTORE_API_KEY: #@ data.values.appstore_api_key + APPSTORE_API_KEY_ID: #@ data.values.appstore_api_key_id + APPSTORE_ISSUER_ID: #@ data.values.appstore_issuer_id + - task: upload-to-gcs + config: + platform: linux + image_resource: #@ task_image_config() + inputs: + - name: repo + - name: artifacts + - name: pipeline-tasks + run: + path: pipeline-tasks/ci/tasks/upload-to-gcs.sh + params: + INPUTS: ios/Blink.ipa GCS_DIRECTORY: dev/ios - CIRCLECI_TOKEN: #@ data.values.circleci_token - on_abort: #@ cancel_circleci_build_on_abort() + VERSION_FILE: repo/.git/ref + bucket: #@ data.values.build_artifacts_bucket_name + json_key: #@ data.values.build_artifacts_bucket_creds - name: e2e-test-android serial: true @@ -205,24 +224,6 @@ jobs: - get: bundled-deps passed: ["test-unit"] - get: pipeline-tasks - - task: e2e-test - config: - platform: linux - image_resource: #@ task_image_config() - inputs: - - name: repo - - name: bundled-deps - - name: built-dev-apk - - name: pipeline-tasks - run: - path: pipeline-tasks/ci/tasks/e2e-test-android.sh - params: - BROWSERSTACK_USER: #@ data.values.browserstack_user - BROWSERSTACK_ACCESS_KEY: #@ data.values.browserstack_access_key - BROWSERSTACK_ANDROID_BUILD: #@ data.values.browserstack_android_build - GALOY_TEST_TOKENS: #@ data.values.galoy_test_tokens - GALOY_TOKEN_2: #@ data.values.galoy_token_2 - MAILSLURP_API_KEY: #@ data.values.mailslurp_api_key - name: e2e-test-ios serial: true @@ -236,24 +237,6 @@ jobs: - get: bundled-deps passed: ["test-unit"] - get: pipeline-tasks - - task: e2e-test - config: - platform: linux - image_resource: #@ task_image_config() - inputs: - - name: repo - - name: bundled-deps - - name: built-dev-ipa - - name: pipeline-tasks - run: - path: pipeline-tasks/ci/tasks/e2e-test-ios.sh - params: - BROWSERSTACK_USER: #@ data.values.browserstack_user - BROWSERSTACK_ACCESS_KEY: #@ data.values.browserstack_access_key - BROWSERSTACK_IOS_BUILD: #@ data.values.browserstack_ios_build - GALOY_TEST_TOKENS: #@ data.values.galoy_test_tokens - GALOY_TOKEN_2: #@ data.values.galoy_token_2 - MAILSLURP_API_KEY: #@ data.values.mailslurp_api_key - name: prerelease serial: true @@ -341,29 +324,42 @@ jobs: params: PLATFORM: android - task: build + tags: [ mac-m1 ] config: - platform: linux - image_resource: #@ task_image_config() + platform: darwin inputs: - name: repo - name: pipeline-tasks - name: build-number-android - - name: built-dev-apk - name: testflight-version outputs: - - name: job-number + - name: repo + - name: artifacts run: - path: pipeline-tasks/ci/tasks/build-on-circleci.sh + path: /bin/sh + args: + - "-c" + - "arch -arm64 pipeline-tasks/ci/tasks/build-android.sh" params: - PLATFORM: android - WAIT_FOR_BUILD_MINS: 30 - BUILD_NUMBER_FILE: build-number-android/android - GIT_REF_FILE: built-dev-apk/url - GIT_REF_PATTERN: dev/android/galoy-mobile-.+-v(.+)/apk VERSION_FILE: testflight-version/version + ANDROID_KEYSTORE: #@ data.values.android_keystore + - task: upload-to-gcs + config: + platform: linux + image_resource: #@ task_image_config() + inputs: + - name: repo + - name: artifacts + - name: pipeline-tasks + - name: testflight-version + run: + path: pipeline-tasks/ci/tasks/upload-to-gcs.sh + params: + INPUTS: android/app/build/outputs/* GCS_DIRECTORY: prod/android - CIRCLECI_TOKEN: #@ data.values.circleci_token - on_abort: #@ cancel_circleci_build_on_abort() + VERSION_FILE: testflight-version/version + bucket: #@ data.values.build_artifacts_bucket_name + json_key: #@ data.values.build_artifacts_bucket_creds - put: build-number-android params: repository: build-number-android @@ -400,29 +396,47 @@ jobs: params: PLATFORM: ios - task: build + tags: [ mac-m1 ] config: - platform: linux - image_resource: #@ task_image_config() + platform: darwin inputs: - name: repo - name: pipeline-tasks - name: build-number-ios - - name: built-dev-ipa - name: testflight-version outputs: - - name: job-number + - name: repo + - name: artifacts run: - path: pipeline-tasks/ci/tasks/build-on-circleci.sh + path: /bin/sh + args: + - "-c" + - "arch -arm64 pipeline-tasks/ci/tasks/build-ios.sh" params: - PLATFORM: ios - WAIT_FOR_BUILD_MINS: 45 - BUILD_NUMBER_FILE: build-number-ios/ios - GIT_REF_FILE: built-dev-ipa/url - GIT_REF_PATTERN: dev/ios/galoy-mobile-.+-v(.+)/Blink VERSION_FILE: testflight-version/version + MATCH_PASSWORD: #@ data.values.fastlane_match_password + MATCH_KEYCHAIN_PASSWORD: #@ data.values.fastlane_match_keychain_password + GITHUB_SSH_KEY: #@ data.values.github_private_key + APPSTORE_API_KEY: #@ data.values.appstore_api_key + APPSTORE_API_KEY_ID: #@ data.values.appstore_api_key_id + APPSTORE_ISSUER_ID: #@ data.values.appstore_issuer_id + - task: upload-to-gcs + config: + platform: linux + image_resource: #@ task_image_config() + inputs: + - name: repo + - name: artifacts + - name: pipeline-tasks + - name: testflight-version + run: + path: pipeline-tasks/ci/tasks/upload-to-gcs.sh + params: + INPUTS: ios/Blink.ipa GCS_DIRECTORY: prod/ios - CIRCLECI_TOKEN: #@ data.values.circleci_token - on_abort: #@ cancel_circleci_build_on_abort() + VERSION_FILE: testflight-version/version + bucket: #@ data.values.build_artifacts_bucket_name + json_key: #@ data.values.build_artifacts_bucket_creds - put: build-number-ios params: repository: build-number-ios @@ -460,7 +474,6 @@ resources: source: ignore_paths: - "ci/*" - - ".circleci/*" - ".github/*" - "docs/*" - "README.md" diff --git a/ci/tasks/build-android.sh b/ci/tasks/build-android.sh new file mode 100755 index 0000000000..33ef22d85f --- /dev/null +++ b/ci/tasks/build-android.sh @@ -0,0 +1,29 @@ +#!/bin/zsh + +set -eu + +export BUILD_NUMBER=$(cat build-number-android/android) +export PUBLIC_VERSION=$(cat $VERSION_FILE) + +GIT_REF=$(cat repo/.git/ref) + +source "$HOME/.rvm/scripts/rvm" +rvm use $(cat repo/.ruby-version) + +pushd repo +git checkout $GIT_REF + +yarn global add node-gyp +yarn install + +echo $ANDROID_KEYSTORE | base64 -d > android/app/release.keystore + +pushd android +bundle install +sed -i'' -e "s/versionCode .*$/versionCode $BUILD_NUMBER/g" app/build.gradle +bundle exec fastlane android build +popd +popd + +mkdir -p artifacts/android/app/build/outputs +cp -r repo/android/app/build/outputs/* artifacts/android/app/build/outputs diff --git a/ci/tasks/build-ios.sh b/ci/tasks/build-ios.sh new file mode 100755 index 0000000000..38032c9755 --- /dev/null +++ b/ci/tasks/build-ios.sh @@ -0,0 +1,34 @@ +#!/bin/zsh + +set -eu + +echo $GITHUB_SSH_KEY > id_rsa +chmod 600 id_rsa +ssh-add ./id_rsa +rm id_rsa + +BUILD_NUMBER=$(cat build-number-ios/ios) +export PUBLIC_VERSION=$(cat $VERSION_FILE) + +GIT_REF=$(cat repo/.git/ref) + +source "$HOME/.rvm/scripts/rvm" +rvm use $(cat repo/.ruby-version) + +pushd repo +git checkout $GIT_REF + +yarn global add node-gyp +yarn install + +tmpfile=$(mktemp /tmp/wwdr-cert.cer) +curl -f -o $tmpfile https://www.apple.com/certificateauthority/AppleWWDRCAG3.cer && security import $tmpfile ~/Library/Keychains/login.keychain-db + +pushd ios +sed -i'' -e "s/MARKETING_VERSION.*/MARKETING_VERSION = $PUBLIC_VERSION;/g" GaloyApp.xcodeproj/project.pbxproj +bundle exec fastlane ios build +popd +popd + +mkdir -p artifacts/ios +cp repo/ios/Blink.ipa artifacts/ios diff --git a/ci/tasks/build-on-circleci.sh b/ci/tasks/build-on-circleci.sh deleted file mode 100755 index 93dd6a28eb..0000000000 --- a/ci/tasks/build-on-circleci.sh +++ /dev/null @@ -1,101 +0,0 @@ -#!/bin/bash - -if [[ ! -z "$BUILD_NUMBER_FILE" ]]; then - BUILD_NUMBER=$(cat $BUILD_NUMBER_FILE) -fi - -if [[ ! -z "$GIT_REF_PATTERN" ]]; then - [[ "$(cat $GIT_REF_FILE)" =~ $GIT_REF_PATTERN ]] - git_ref=$(echo "${BASH_REMATCH[1]}") -else - git_ref=$(cat $GIT_REF_FILE) -fi - -set -eu - -version=$(cat $VERSION_FILE) - -pushd repo - -pipeline_id=$( - curl -s --request POST \ - --url https://circleci.com/api/v2/project/gh//GaloyMoney/galoy-mobile/pipeline \ - --header "Circle-Token: $CIRCLECI_TOKEN" \ - --header 'content-type: application/json' \ - --data '{"branch":"main","parameters":{ "version": "'"$version"'", "platform": "'$PLATFORM'", "git_ref": "'"$git_ref"'", "build_number": "'$BUILD_NUMBER'", "gcs_directory": "'$GCS_DIRECTORY'" }}' \ - | jq -r '.id' -) - -echo pipeline_id:$pipeline_id -sleep 1 - -workflow_id=$( - curl -s --request GET \ - --url https://circleci.com/api/v2/pipeline/$pipeline_id/workflow \ - --header "Circle-Token: $CIRCLECI_TOKEN" \ - | jq --arg name "build_${PLATFORM}_and_upload_to_bucket" -r '.items[] | select(.name == $name) | .id' -) - -pipeline_number=$( - curl -s --request GET \ - --url https://circleci.com/api/v2/pipeline/$pipeline_id/workflow \ - --header "Circle-Token: $CIRCLECI_TOKEN" \ - | tee response | jq --arg name "build_${PLATFORM}_and_upload_to_bucket" -r '.items[] | select(.name == $name) | .pipeline_number' -) - -echo workflow_id:$workflow_id - -job_number=$( - curl -s --request GET \ - --url https://circleci.com/api/v2/workflow/$workflow_id/job \ - --header "Circle-Token: $CIRCLECI_TOKEN" \ - | tee response | jq --arg name "build_${PLATFORM}" -r '.items[] | select(.name == $name) | .job_number' -) - -echo $job_number > ../job-number/number -echo job_number:$job_number - -echo "-------------------------------------------------------------------------------------------------------------------------------" -echo "Waiting for CircleCI to finish Building $PLATFORM...." -echo "Follow Build Here: https://app.circleci.com/pipelines/github/GaloyMoney/galoy-mobile/$pipeline_number/workflows/$workflow_id/jobs/$job_number" -echo "-------------------------------------------------------------------------------------------------------------------------------" - -echo "[•] Polling for $WAIT_FOR_BUILD_MINS mins at a frequency of 5 seconds" - -times=$(echo "$WAIT_FOR_BUILD_MINS * 12" | bc) -set +e -for (( i = 0; i <= $times; i++ )) -do - status=$( - curl -s --request GET \ - --url https://circleci.com/api/v2/project/gh//GaloyMoney/galoy-mobile/job/$job_number \ - | jq -r '.status' - ) - if [[ $status != "running" && $status != "queued" ]]; then break; fi; - sleep 5 -done -set -e - -echo "[•] Final Status: $status" - -if [[ "$status" == "success" ]] -then - echo "[✓] Build succeeded!" - exit 0 -fi - -echo "[✗] Build failed!" -echo "[•] If final status wasn't failed, please cross check with CircleCI task." - -artifacts_url=$( - curl -s --request GET \ - --url https://circleci.com/api/v2/project/gh/GaloyMoney/galoy-mobile/7477/artifacts \ - | jq -r '.items[0].url' -) -wget -nv $artifacts_url -O build.log >> /dev/null - -echo "\n⌄⌄⌄⌄⌄⌄⌄⌄⌄⌄⌄⌄⌄⌄⌄⌄⌄⌄⌄⌄⌄⌄⌄⌄⌄⌄⌄⌄⌄⌄⌄⌄⌄⌄⌄⌄⌄⌄⌄⌄⌄ LOGS FROM CIRCLECI ⌄⌄⌄⌄⌄⌄⌄⌄⌄⌄⌄⌄⌄⌄⌄⌄⌄⌄⌄⌄⌄⌄⌄⌄⌄⌄⌄⌄⌄⌄⌄⌄⌄⌄⌄⌄⌄⌄⌄⌄⌄\n" -cat build.log -echo "\n⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃" - -if [[ "$status" != "success" ]]; then exit 1; fi diff --git a/ci/tasks/cancel-circleci-job.sh b/ci/tasks/cancel-circleci-job.sh deleted file mode 100755 index 81e36a2e86..0000000000 --- a/ci/tasks/cancel-circleci-job.sh +++ /dev/null @@ -1,7 +0,0 @@ -#!/bin/bash - -job_number=$(cat job-number/number) - -curl --request POST \ - --url https://circleci.com/api/v2/project/gh//GaloyMoney/galoy-mobile/job/$job_number/cancel \ - --header "Circle-Token: $CIRCLECI_TOKEN" diff --git a/ci/tasks/upload-to-gcs.sh b/ci/tasks/upload-to-gcs.sh new file mode 100755 index 0000000000..7fa86a613d --- /dev/null +++ b/ci/tasks/upload-to-gcs.sh @@ -0,0 +1,12 @@ +#!/bin/bash + +set -eu + +version=$(cat $VERSION_FILE) + +echo $json_key > key.json +gcloud auth activate-service-account --key-file key.json + +pushd artifacts + +gsutil cp -r $INPUTS gs://$bucket/galoy-mobile/$GCS_DIRECTORY/galoy-mobile-$(date +%s)-v${version}/ diff --git a/ci/values.yml b/ci/values.yml index 04a838cc4b..baa423ad81 100644 --- a/ci/values.yml +++ b/ci/values.yml @@ -25,7 +25,6 @@ build_artifacts_bucket_creds: ((build-artifacts-bucket-creds.creds_json)) artifacts_bucket_name: ((staging-gcp-creds.bucket_name)) staging_inception_creds: ((staging-gcp-creds.creds_json)) -circleci_token: ((circleci-token.circleci_token)) browserstack_user: ((browserstack-creds.browserstack_user)) browserstack_access_key: ((browserstack-creds.browserstack_access_key)) browserstack_ios_build: ((browserstack-creds.browserstack_ios_build)) @@ -33,3 +32,10 @@ browserstack_android_build: ((browserstack-creds.browserstack_android_build)) galoy_test_tokens: ((galoy-tokens.galoy_test_tokens)) galoy_token_2: ((galoy-tokens.galoy_token_2)) mailslurp_api_key: ((galoy-tokens.mailslurp_api_key)) + +android_keystore: ((android.keystore)) +fastlane_match_password: ((fastlane.match_password)) +fastlane_match_keychain_password: ((fastlane.match_keychain_password)) +appstore_api_key: ((appstore.appstore_api_key)) +appstore_api_key_id: ((appstore.appstore_api_key_id)) +appstore_issuer_id: ((appstore.appstore_api_issuer_id)) diff --git a/ios/fastlane/Fastfile b/ios/fastlane/Fastfile index 3bfcf8af4e..924252abdb 100644 --- a/ios/fastlane/Fastfile +++ b/ios/fastlane/Fastfile @@ -34,6 +34,13 @@ platform :ios do desc "Build Releasable IPA" lane :build do + app_store_connect_api_key( + key_id: ENV["APPSTORE_API_KEY_ID"], + issuer_id: ENV["APPSTORE_ISSUER_ID"], + key_content: ENV["APPSTORE_API_KEY"], + is_key_content_base64: true + ) + increment_build_number(build_number: ENV["BUILD_NUMBER"], xcodeproj: "GaloyApp.xcodeproj") match(type: "appstore", readonly: is_ci) gym(scheme: "GaloyApp")