# GitLab CI/CD

Source: https://help.testapp.io/gitlab-ci-cd/

GitLab CI/CD pipelines allow you to build and upload both Android and iOS apps to TestApp.io, notifying your testers for testing and feedback.

## Configuration

| Key | Description | Env Var(s) | Default |
| --- | --- | --- | --- |
| api_token | You can get it from [https://portal.testapp.io/profile/tokens](https://portal.testapp.io/profile/tokens) | TESTAPPIO_API_TOKEN |  |
| app_id | You can get it from your app page at [https://portal.testapp.io/apps](https://portal.testapp.io/apps) | TESTAPPIO_APP_ID |  |
| release | It can be either both or Android or iOS | TESTAPPIO_RELEASE |  |
| apk | Path to the Android APK file | TESTAPPIO_ANDROID_PATH |  |
| ipa | Path to the iOS IPA file | TESTAPPIO_IOS_PATH |  |
| release_notes | Manually add the release notes to be displayed for the testers | TESTAPPIO_RELEASE_NOTES |  |
| git_release_notes | Collect release notes from the latest git commit message to be displayed for the testers: true or false | TESTAPPIO_GIT_RELEASE_NOTES | true |
| git_commit_id | Include the last commit ID in the release notes (works with both release notes options): true or false | TESTAPPIO_GIT_COMMIT_ID | false |
| notify | Send notifications to your team members about this release: true or false | TESTAPPIO_NOTIFY | false |

*Check* [*TA-CLI*](https://help.testapp.io/ta-cli/) *for more info*

---

## iOS

> **Using Fastlane?**[TestApp.io Fastlane plugin](https://help.testapp.io/fastlane-plugin/)[Setup iOS Project for Fastlane](https://help.testapp.io/setup-ios-project-for-fastlane/)

### Add macOS runner

A macOS computer is required to build and package your iOS apps (IPA); however, GitLab does not provide such a runner. We will create the runner ourselves and register it to GitLab.

More info: [https://docs.gitlab.com/runner/install/osx.html](https://docs.gitlab.com/runner/install/osx.html)

#### Install Xcode

Make sure that `xcodebuild` is using `Xcode` rather than the command line tools:

```sh
sudo xcode-select --switch /Applications/Xcode.app/Contents/Developer
```

Verify:

```sh
xcode-select -p
```

**Import the codesign certificate and provisioning profile to build and export the IPA file in Xcode.**

**Make sure that you can archive and export an IPA file from Xcode manually before setting up the pipeline.**

#### Install GitLab runner

macOS amd64:

```sh
sudo curl --output /usr/local/bin/gitlab-runner "https://gitlab-runner-downloads.s3.amazonaws.com/latest/binaries/gitlab-runner-darwin-amd64"
```

macOS Apple Silicon/arm64:

```sh
sudo curl --output /usr/local/bin/gitlab-runner "https://gitlab-runner-downloads.s3.amazonaws.com/latest/binaries/gitlab-runner-darwin-arm64"
```

Make it executable:

```sh
sudo chmod +x /usr/local/bin/gitlab-runner
```

Install as service:

```sh
gitlab-runner install
```

```sh
gitlab-runner start
```

#### Check the status

```sh
gitlab-runner status
```

gitlab-runner: Service is running

#### And finally, register the runner

```sh
gitlab-runner register
```

The runner is now registered. Go to your GitLab project under Settings > CI/CD > Runners to verify it appears.

![Verify GitLab Runner is working](https://f000.backblazeb2.com/file/help-testappio/2022/03/Screen-Shot-2022-03-24-at-2.26.55-AM_o.png)

The runner is ready. Let's build and package our iOS apps with this runner.

### Create global variables `TESTAPPIO_API_TOKEN` and `TESTAPPIO_APP_ID`

Go to Settings > CI/CD > Variables > Add variable. Set the key field to `TESTAPPIO_API_TOKEN` (you can name it whatever you want. we will refer to it in the pipeline script). Put the API token in the value box. Uncheck `Protect variable` and check `Mask variable`. Then add the `TESTAPPIO_APP_ID` variable the same way.

### Create the ExportOptions.plist file

A sample ExportOptions.plist file:

```xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
	<key>destination</key>
	<string>export</string>
	<key>method</key>
	<string>development</string>
	<key>signingStyle</key>
	<string>automatic</string>
	<key>stripSwiftSymbols</key>
	<true/>
	<key>teamID</key>
	<string>YOUR_TEAM_ID</string>
	<key>thinning</key>
	<string>&lt;thin-for-all-variants&gt;</string>
</dict>
</plist>
```

Replace `YOUR_TEAM_ID` with your Apple Developer Team ID. The easiest way to generate the ExportOptions.plist file is to export the IPA through Xcode. Once you've successfully exported your IPA, Xcode creates an ExportOptions.plist file that you can use for the CI pipeline.

### Add the following script block to your pipeline script (`.gitlab-ci.yml`)

> `tags`

```yaml
stages:
  - build
  - archive
  - upload
variables:
  release: "ios"
  release_notes: "My release notes here..."
  notify: false
  ProjectName: "myproject"
  SchemeName: "myschema"


build-job:
  stage: build
  script:
    - xcodebuild clean -project $ProjectName.xcodeproj -scheme $SchemeName
    - xcodebuild test -project $ProjectName.xcodeproj -scheme $SchemeName -destination 'platform=iOS Simulator,name=iPhone 15,OS=17.5'
  tags:
    - ipa-macos

archive-job:
  stage: archive
  script:
    - xcodebuild clean archive -archivePath build/$ProjectName -scheme $SchemeName
    - xcodebuild -exportArchive -archivePath "build/$ProjectName.xcarchive" -exportPath "build/$ProjectName.ipa" -exportOptionsPlist "ExportOptions.plist"
  artifacts:
    paths:
      - build/$ProjectName.ipa
  tags:
    - ipa-macos

upload-job:
  stage: upload
  before_script:
    - export INSTALL_DIR=$CI_PROJECT_DIR
    - curl -Ls https://github.com/testappio/cli/releases/latest/download/install | bash
  script:
    - $CI_PROJECT_DIR/ta-cli publish --api_token=$TESTAPPIO_API_TOKEN --app_id=$TESTAPPIO_APP_ID --release=$release --ipa=$CI_PROJECT_DIR/build/$ProjectName.ipa --release_notes=$release_notes --notify=$notify --source="Gitlab"
  tags:
    - linux
```

### Things to consider

- Make sure to set the variable `ProjectName` with the name of your Xcode project. If you're using a different scheme than the default, make sure you pass in the proper `SchemeName` too (the default is the same as the `ProjectName`).
- In the `xcodebuild test` command, the `-destination` option is set to launch an iPhone 15 image running iOS 17.5 in the Simulator. If you want to run a different device (iPad, for example), you'll need to change this.
- If you're using a workspace rather than a project (e.g., because your app uses [Cocoapods](https://cocoapods.org/)), change the `-project ProjectName.xcodeproj` options to `-workspace WorkspaceName.xcworkspace`. Run `xcodebuild --help` in the Terminal to explore more build options.

Here is the [sample project](https://gitlab.com/testappio/sample-ios-app) we used for demonstrating the process.

---

## Android

It's much easier for Android projects, no custom runner or codesign setup is required.

### Create global variables `TESTAPPIO_API_TOKEN` and `TESTAPPIO_APP_ID`

Go to Settings > CI/CD > Variables > Add variable. Set the key field to `TESTAPPIO_API_TOKEN` (you can name it whatever you want. we will refer to it in the pipeline script). Put the API token in the value box. Uncheck `Protect variable` and check `Mask variable`. Then add the `TESTAPPIO_APP_ID` variable the same way.

### Add the following code snippet to your pipeline script (`.gitlab-ci.yml`)

```yaml
image: eclipse-temurin:17-jdk

variables:
  ANDROID_COMPILE_SDK: "34"
  ANDROID_BUILD_TOOLS: "34.0.0"
  release: "android"
  release_notes: "My release notes here..."
  notify: false

# install the android sdk
before_script:
  - apt-get --quiet update --yes
  - apt-get --quiet install --yes wget tar unzip lib32stdc++6 lib32z1
  - wget --quiet --output-document=android-sdk.zip https://dl.google.com/android/repository/commandlinetools-linux-8092744_latest.zip
  - unzip -d android-sdk-linux android-sdk.zip
  - mv android-sdk-linux/cmdline-tools android-sdk-linux/latest
  - mkdir -p android-sdk-linux/cmdline-tools
  - mv android-sdk-linux/latest android-sdk-linux/cmdline-tools/
  - echo y | android-sdk-linux/cmdline-tools/latest/bin/sdkmanager "platforms;android-${ANDROID_COMPILE_SDK}" >/dev/null
  - echo y | android-sdk-linux/cmdline-tools/latest/bin/sdkmanager "platform-tools" >/dev/null
  - echo y | android-sdk-linux/cmdline-tools/latest/bin/sdkmanager "build-tools;${ANDROID_BUILD_TOOLS}" >/dev/null
  - export ANDROID_HOME=$PWD/android-sdk-linux
  - export PATH=$PATH:$PWD/android-sdk-linux/platform-tools/
  - chmod +x ./gradlew
  # temporarily disable checking for EPIPE error and use yes to accept all licenses
  - set +o pipefail
  - yes | android-sdk-linux/cmdline-tools/latest/bin/sdkmanager --licenses
  - set -o pipefail

stages:
  - build
  - upload

assembleDebug:
  stage: build
  script:
    - ./gradlew assembleDebug
  artifacts:
    paths:
      - app/build/outputs/

upload-job:
  stage: upload
  before_script:
    - export INSTALL_DIR=$CI_PROJECT_DIR
    - curl -Ls https://github.com/testappio/cli/releases/latest/download/install | bash
  script:
    - $CI_PROJECT_DIR/ta-cli publish --api_token=$TESTAPPIO_API_TOKEN --app_id=$TESTAPPIO_APP_ID --release=$release --apk=$CI_PROJECT_DIR/app/build/outputs/apk/debug/app-debug.apk --release_notes=$release_notes --notify=$notify --source="Gitlab"
```

---

## Related Articles

- [Setup iOS Project for Fastlane](https://help.testapp.io/setup-ios-project-for-fastlane/)
- [TestApp.io Fastlane Plugin](https://help.testapp.io/fastlane-plugin/)
- [ta-cli Documentation](https://help.testapp.io/ta-cli/)
- [GitHub Actions Setup](https://help.testapp.io/github-action/)

---

Need help? [Contact us](https://testapp.io/contact-us/). we're happy to assist!
