# Bitbucket Pipelines

Source: https://help.testapp.io/bitbucket-pipelines/

Bitbucket Pipelines can upload your Android (APK) and iOS (IPA) builds to TestApp.io at the end of every build, so your testers get the new version without anyone uploading it by hand.

## Before you start

- An **API token**: create one at [https://portal.testapp.io/profile/tokens](https://portal.testapp.io/profile/tokens)
- Your **App ID**: open your app in the portal ([https://portal.testapp.io/apps](https://portal.testapp.io/apps)), go to Integrations → Releases, pick any tool, and copy the App ID from the setup panel.
- A pipeline that already builds your APK or IPA.

You can upload with **ta-cli** (the quickest way) or with the **fastlane plugin** if you already use fastlane. Step 1 applies to both.

## 1. Add repository variables

In Bitbucket, go to **Repository settings > Pipelines > Repository variables** and add:

- `TESTAPPIO_API_TOKEN`: your API token. Tick **Secured** so it is masked in logs.
- `TESTAPPIO_APP_ID`: your App ID.

## 2. Option 1: Upload with ta-cli (easiest)

### Android

Add an upload step after your build step. The build step must list the APK under `artifacts` so the upload step can read it.

```yaml
pipelines:
  branches:
    main:
      - step:
          name: Build APK
          # use the Android build image and commands you already have
          script:
            - ./gradlew assembleRelease
          artifacts:
            - app/build/outputs/apk/release/*.apk
      - step:
          name: Upload to TestApp.io
          script:
            - export INSTALL_DIR=$BITBUCKET_CLONE_DIR
            - curl -Ls https://github.com/testappio/cli/releases/latest/download/install | bash
            - $BITBUCKET_CLONE_DIR/ta-cli publish --api_token=$TESTAPPIO_API_TOKEN --app_id=$TESTAPPIO_APP_ID --release=android --apk=app/build/outputs/apk/release/app-release.apk --git_release_notes=true --git_commit_id=true --notify=true --source="Bitbucket"
```

### iOS

Building an IPA needs macOS. Bitbucket's hosted build machines run Linux, so the iOS build runs on a self-hosted macOS runner ([https://support.atlassian.com/bitbucket-cloud/docs/runners/](https://support.atlassian.com/bitbucket-cloud/docs/runners/)). The upload step is the same; only the file flags change:

```yaml
      - step:
          name: Upload to TestApp.io
          runs-on:
            - self.hosted
            - macos
          script:
            - export INSTALL_DIR=$BITBUCKET_CLONE_DIR
            - curl -Ls https://github.com/testappio/cli/releases/latest/download/install | bash
            - $BITBUCKET_CLONE_DIR/ta-cli publish --api_token=$TESTAPPIO_API_TOKEN --app_id=$TESTAPPIO_APP_ID --release=ios --ipa=build/MyApp.ipa --git_release_notes=true --git_commit_id=true --notify=true --source="Bitbucket"
```

The IPA must be signed with an Ad Hoc or Development profile so it can be installed on test devices.

## 3. Option 2: Upload with the fastlane plugin

Already using fastlane? The TestApp.io plugin does the same upload from a lane. It needs Ruby 3.0 or newer. See the [fastlane plugin guide](https://help.testapp.io/fastlane-plugin/) for every option.

Create a `Gemfile` in your repository like this, then run `bundle exec fastlane add_plugin testappio` once on your machine (it creates `fastlane/Pluginfile`). Commit the `Gemfile` and the `fastlane` folder:

```ruby
source "https://rubygems.org"
gem "fastlane"

plugins_path = File.join(File.dirname(__FILE__), "fastlane", "Pluginfile")
eval_gemfile(plugins_path) if File.exist?(plugins_path)
```

Add a lane to `fastlane/Fastfile`. Lanes run inside the `fastlane` folder, so file paths start with `../`:

```ruby
lane :upload_android do
  upload_to_testappio(
    api_token:         ENV["TESTAPPIO_API_TOKEN"],
    app_id:            ENV["TESTAPPIO_APP_ID"],
    release:           "android",
    apk_file:          "../app/build/outputs/apk/release/app-release.apk",
    git_release_notes: true,
    git_commit_id:     true,
    notify:            true
  )
end
```

Then replace the upload step in your pipeline with one that runs the lane:

```yaml
      - step:
          name: Upload to TestApp.io
          image: ruby:3.3
          script:
            - bundle install
            - bundle exec fastlane upload_android
```

For iOS, use the same step on the self-hosted macOS runner (add the `runs-on` lines shown above) and a lane that passes `release: "ios"` and `ipa_file: "../build/MyApp.ipa"`. The plugin marks the upload as coming from fastlane for you, so there is no `source` option to set.

## ta-cli options

- `--release`: `android`, `ios` or `both` (pass both `--apk` and `--ipa`).
- `--release_notes="..."`: notes shown to testers.
- `--git_release_notes=true`: use the last commit message as the notes.
- `--git_commit_id=true`: add the last commit ID to the notes.
- `--notify=true`: notify your team members about the new release.
- `--archive_latest_release=true`: archive the previous latest release once this one is uploaded.

See [https://help.testapp.io/ta-cli/](https://help.testapp.io/ta-cli/) for every ta-cli option.

> **Tip:** Once your pipeline uploads a build, team members using the [TestApp.io mobile app](https://help.testapp.io/mobile-app-getting-started/) receive a push notification and can install the build with a single tap. You can also create [share links](https://help.testapp.io/how-to-share/) to distribute builds to external testers and clients.

---

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