GitHub Actions
Generate an API token from the dashboard's API Tokens page. Add it as a GitHub repository secret named BUILDTREE_TOKEN. Add a repository variable BUILDTREE_PROJECT_SLUG for the project slug.
Android
# .github/workflows/buildtree-android.yml
name: buildtree (android)
on:
pull_request:
push:
branches: [main, develop]
jobs:
android:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-java@v4
with:
distribution: temurin
java-version: "17"
- uses: actions/setup-node@v4
with:
node-version: "22"
- run: npm install -g @buildtree/cli
- working-directory: android
run: ./gradlew assembleRelease
env:
STORE_PASSWORD: ${{ secrets.ANDROID_STORE_PASSWORD }}
KEY_PASSWORD: ${{ secrets.ANDROID_KEY_PASSWORD }}
- env:
BUILDTREE_TOKEN: ${{ secrets.BUILDTREE_TOKEN }}
run: |
buildtree upload \
android/app/build/outputs/apk/release/app-release.apk \
--project ${{ vars.BUILDTREE_PROJECT_SLUG }} \
--env dev \
--branch ${{ github.head_ref || github.ref_name }}
github.head_ref is the source branch on PR events and falls back to github.ref_name on push events.
iOS
iOS requires macOS runners and Apple Developer credentials. The example below uses Fastlane match.
# .github/workflows/buildtree-ios.yml
name: buildtree (ios)
on:
pull_request:
push:
branches: [main, develop]
jobs:
ios:
runs-on: macos-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: "22"
- uses: ruby/setup-ruby@v1
with:
ruby-version: "3.2"
bundler-cache: true
- env:
MATCH_PASSWORD: ${{ secrets.MATCH_PASSWORD }}
APP_STORE_CONNECT_KEY: ${{ secrets.APP_STORE_CONNECT_KEY }}
run: bundle exec fastlane match adhoc --readonly
- run: npm install -g @buildtree/cli
- run: bundle exec fastlane build_adhoc
- env:
BUILDTREE_TOKEN: ${{ secrets.BUILDTREE_TOKEN }}
run: |
buildtree upload \
ios/build/MyApp.ipa \
--project ${{ vars.BUILDTREE_PROJECT_SLUG }} \
--env dev \
--branch ${{ github.head_ref || github.ref_name }}
Comment the install URL on the PR
- id: upload
env:
BUILDTREE_TOKEN: ${{ secrets.BUILDTREE_TOKEN }}
run: |
OUTPUT=$(buildtree upload \
android/app/build/outputs/apk/release/app-release.apk \
--project ${{ vars.BUILDTREE_PROJECT_SLUG }} \
--env dev \
--branch ${{ github.head_ref || github.ref_name }})
echo "$OUTPUT"
PINNED_URL=$(echo "$OUTPUT" | grep "Pinned URL" | awk '{print $3}')
echo "pinned=$PINNED_URL" >> $GITHUB_OUTPUT
- if: github.event_name == 'pull_request'
uses: actions/github-script@v7
with:
script: |
github.rest.issues.createComment({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
body: `Android build ready.\n\nInstall: ${{ steps.upload.outputs.pinned }}`
})
Tag a release on tag push
on:
push:
tags: ["v*"]
jobs:
release:
runs-on: ubuntu-latest
steps:
# build steps as above
- env:
BUILDTREE_TOKEN: ${{ secrets.BUILDTREE_TOKEN }}
run: |
buildtree upload \
android/app/build/outputs/apk/release/app-release.apk \
--project ${{ vars.BUILDTREE_PROJECT_SLUG }} \
--env prod \
--release ${{ github.ref_name }}
The release-tag install URL /install/release/<project>/v1.2.0 stays frozen at this build.