blob: d5d5e83b8b18661442397c662835e433fa2094c4 [file] [edit]
# Copyright (C) 2026 The Android Open Source Project
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# Opens a PR that merges `main` into `canary` with `canary`'s history
# preserved and `main`'s tree as the result. Manual trigger via the
# GitHub Actions UI; a maintainer reviews and merges the PR to update
# canary.
#
# Uses the tree-replacing merge pattern (git merge -s ours + git
# read-tree) so canary always moves forward, preserves history on
# both sides, and handles cherry-picks on canary that have different
# SHAs than their counterparts on main. Convention: every fix goes
# to main first and is then cherry-picked to canary; anything
# canary-only is silently dropped by this operation.
#
# Authenticates with an installation token minted from the
# `perfetto-automation` GitHub App so the PR open / push events fan
# out to other workflow runs (GITHUB_TOKEN pushes do not).
#
# Merging the PR pushes to canary, which triggers UI Cloud Build to
# redeploy the canary channel. See RFC-0022.
name: Cut canary (open PR merging main → canary)
on:
workflow_dispatch:
permissions: {}
jobs:
cut-canary:
runs-on: ubuntu-latest
environment: perfetto-automation
steps:
- name: Mint app token
id: app-token
uses: actions/create-github-app-token@v2
with:
app-id: ${{ secrets.PERFETTO_BOT_APP_ID }}
private-key: ${{ secrets.PERFETTO_BOT_PRIVATE_KEY }}
- name: Checkout canary
uses: actions/checkout@v4
with:
ref: canary
fetch-depth: 0
token: ${{ steps.app-token.outputs.token }}
- name: Fetch main
run: git fetch origin main
- name: Short-circuit if canary already matches main
run: |
if [[ "$(git rev-parse HEAD^{tree})" == \
"$(git rev-parse origin/main^{tree})" ]]; then
echo "::notice::canary tree already matches main; nothing to do."
echo "SKIP=1" >> "$GITHUB_ENV"
fi
- name: Configure git
if: env.SKIP != '1'
run: |
# Email must match the CLA-approved address for the automation app.
git config user.name "perfetto-automation[bot]"
git config user.email "perfetto-automation-github-app@google.com"
- name: Merge main into canary (replace tree with main)
if: env.SKIP != '1'
run: |
git merge -s ours origin/main --no-commit
git read-tree -m -u origin/main
git commit -m "Cut canary from main (automated)"
# Reuse a stable branch name so stale PRs don't pile up when a
# cut is superseded before it's merged. Close any existing PR
# and delete the remote branch before pushing the fresh one.
- name: Close stale PR and delete stale branch
if: env.SKIP != '1'
env:
GH_TOKEN: ${{ steps.app-token.outputs.token }}
run: |
BRANCH="dev/github-bot/cut-canary"
for N in $(gh pr list --head "$BRANCH" --state open --json number --jq '.[].number'); do
echo "Closing stale PR #$N"
gh pr close "$N" --comment "Superseded by a newer canary cut."
done
git push origin --delete "$BRANCH" || true
- name: Push branch and open PR
if: env.SKIP != '1'
env:
GH_TOKEN: ${{ steps.app-token.outputs.token }}
run: |
BRANCH="dev/github-bot/cut-canary"
git push origin "HEAD:refs/heads/$BRANCH"
MAIN_SHA=$(git rev-parse --short origin/main)
gh pr create \
--base canary \
--head "$BRANCH" \
--title "Cut canary from main ($MAIN_SHA)" \
--body "$(cat <<EOF
Automated canary cut from \`main\` (\`$MAIN_SHA\`).
**Merge with "Create a merge commit"** so the two-parent
merge commit survives into \`canary\`'s history.
EOF
)"
echo "::notice::Opened PR from $BRANCH → canary."