sync-team dry-run #25
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# This workflow executes a dry-run of the sync-team tool after a push to any pull request. | |
# This allows us to see which changes would be applied to live services after the PR | |
# would be merged. | |
# | |
# The workflow uses the `workflow_run` trigger, which should always run in the default branch of | |
# this repository. This is required so that the workflow has permissions to post PR comments. | |
# We should not check out any code from the PR, as it could present a security hazard. | |
# Instead, we simply download a GitHub artifact with a directory of JSON files and use that as | |
# input for sync-team. | |
# This artifact is created and uploaded on PR pushes using the CI workflow in `main.yml`. | |
# Details about `workflow_run`: | |
# https://docs.github.com/en/actions/writing-workflows/choosing-when-your-workflow-runs/events-that-trigger-workflows#workflow_run: | |
name: sync-team dry-run | |
on: | |
workflow_run: | |
workflows: [ CI ] | |
types: | |
- completed | |
jobs: | |
dry-run: | |
runs-on: ubuntu-latest | |
if: ${{ github.event.workflow_run.conclusion == 'success' && github.event.workflow_run.event == 'pull_request' }} | |
concurrency: | |
# Only run this once at a time on any given PR | |
group: dry-run-${{ github.event.workflow_run.head_branch }} | |
cancel-in-progress: true | |
permissions: | |
pull-requests: write | |
steps: | |
- uses: actions/checkout@v4 | |
with: | |
repository: rust-lang/sync-team | |
persist-credentials: false | |
- name: Install Rust Stable | |
run: | | |
rustc -vV | |
rustup update stable | |
rustup default stable | |
rustc -vV | |
# Pinning a specific version to avoid surprises | |
- uses: Swatinem/rust-cache@27b8ea9368cf428f0bfe41b0876b1a7e809d9844 | |
- name: Download built JSON API | |
uses: actions/download-artifact@v4 | |
with: | |
name: team-api-output | |
path: team-api | |
run-id: ${{ github.event.workflow_run.id }} | |
github-token: ${{ secrets.GITHUB_TOKEN }} | |
# GitHub tokens generated from GitHub Apps can access resources from one organization, | |
# so we need to generate a token for each organization. | |
- name: Generate GitHub token (rust-lang) | |
uses: actions/create-github-app-token@v1 | |
id: rust-lang-token | |
with: | |
# GitHub App ID secret name | |
app-id: ${{ secrets.SYNC_TEAM_GH_APP_ID }} | |
# GitHub App private key secret name | |
private-key: ${{ secrets.SYNC_TEAM_GH_APP_PRIVATE_KEY }} | |
# Set the owner, so the token can be used in all repositories | |
owner: rust-lang | |
- name: Generate GitHub token (rust-lang-ci) | |
uses: actions/create-github-app-token@v1 | |
id: rust-lang-ci-token | |
with: | |
app-id: ${{ secrets.SYNC_TEAM_GH_APP_ID }} | |
private-key: ${{ secrets.SYNC_TEAM_GH_APP_PRIVATE_KEY }} | |
owner: rust-lang-ci | |
- name: Generate GitHub token (rust-lang-deprecated) | |
uses: actions/create-github-app-token@v1 | |
id: rust-lang-deprecated-token | |
with: | |
app-id: ${{ secrets.SYNC_TEAM_GH_APP_ID }} | |
private-key: ${{ secrets.SYNC_TEAM_GH_APP_PRIVATE_KEY }} | |
owner: rust-lang-deprecated | |
- name: Generate GitHub token (rust-lang-nursery) | |
uses: actions/create-github-app-token@v1 | |
id: rust-lang-nursery-token | |
with: | |
app-id: ${{ secrets.SYNC_TEAM_GH_APP_ID }} | |
private-key: ${{ secrets.SYNC_TEAM_GH_APP_PRIVATE_KEY }} | |
owner: rust-lang-nursery | |
- name: Generate GitHub token (bors-rs) | |
uses: actions/create-github-app-token@v1 | |
id: bors-rs-token | |
with: | |
app-id: ${{ secrets.SYNC_TEAM_GH_APP_ID }} | |
private-key: ${{ secrets.SYNC_TEAM_GH_APP_PRIVATE_KEY }} | |
owner: bors-rs | |
- name: Generate GitHub token (rust-analyzer) | |
uses: actions/create-github-app-token@v1 | |
id: rust-analyzer-token | |
with: | |
app-id: ${{ secrets.SYNC_TEAM_GH_APP_ID }} | |
private-key: ${{ secrets.SYNC_TEAM_GH_APP_PRIVATE_KEY }} | |
owner: rust-analyzer | |
- name: Generate GitHub token (rust-embedded) | |
uses: actions/create-github-app-token@v1 | |
id: rust-embedded-token | |
with: | |
app-id: ${{ secrets.SYNC_TEAM_GH_APP_ID }} | |
private-key: ${{ secrets.SYNC_TEAM_GH_APP_PRIVATE_KEY }} | |
owner: rust-embedded | |
- name: Generate GitHub token (rust-dev-tools) | |
uses: actions/create-github-app-token@v1 | |
id: rust-dev-tools-token | |
with: | |
app-id: ${{ secrets.SYNC_TEAM_GH_APP_ID }} | |
private-key: ${{ secrets.SYNC_TEAM_GH_APP_PRIVATE_KEY }} | |
owner: rust-dev-tools | |
- name: Run sync-team dry-run check | |
env: | |
GITHUB_TOKEN_RUST_LANG: ${{ steps.rust-lang-token.outputs.token }} | |
GITHUB_TOKEN_RUST_LANG_CI: ${{ steps.rust-lang-ci-token.outputs.token }} | |
GITHUB_TOKEN_RUST_LANG_DEPRECATED: ${{ steps.rust-lang-deprecated-token.outputs.token }} | |
GITHUB_TOKEN_RUST_LANG_NURSERY: ${{ steps.rust-lang-nursery-token.outputs.token }} | |
GITHUB_TOKEN_BORS_RS: ${{ steps.bors-rs-token.outputs.token }} | |
GITHUB_TOKEN_RUST_ANALYZER: ${{ steps.rust-analyzer-token.outputs.token }} | |
GITHUB_TOKEN_RUST_EMBEDDED: ${{ steps.rust-embedded-token.outputs.token }} | |
GITHUB_TOKEN_RUST_DEV_TOOLS: ${{ steps.rust-dev-tools-token.outputs.token }} | |
run: | | |
# Perform build and execution separately to avoid any potential output from | |
# cargo leaking into the output file. | |
cargo build --release | |
./target/release/sync-team print-plan --services github --team-json team-api 2>&1 | tee -a output.txt | |
- name: Prepare comment | |
run: | | |
cat > comment.txt << EOL | |
<details> | |
<summary>Dry-run check results</summary> | |
<pre><code> | |
EOL | |
cat output.txt >> comment.txt | |
printf "</pre></code>\n</details>\n" >> comment.txt | |
cat comment.txt | |
- name: Extract PR number | |
run: | | |
# We read the PR number that is stored in the uploaded archive | |
# and check that it is an integer (as the workflow could upload whatever it wants). | |
UNSANITIZED_PR=`cat team-api/pr.txt` | |
if [[ ${UNSANITIZED_PR} =~ ^[0-9]+$ ]]; then | |
echo "PR_NUMBER=${UNSANITIZED_PR}" >> $GITHUB_ENV | |
else | |
echo "Invalid PR number passed: ${UNSANITIZED_PR}" | |
exit 1 | |
fi | |
- name: Send comment | |
env: | |
GH_TOKEN: ${{ github.token }} | |
run: | | |
PR=${PR_NUMBER} | |
echo "Pull request ${PR}" | |
# --edit-last doesn't work if there is no previous comment, so we have to figure out | |
# if we should create a comment or not | |
if gh issue view ${PR} --repo rust-lang/team --json comments \ | |
--jq '.comments.[].author.login' | grep --quiet --fixed-strings "github-actions"; then | |
echo "Editing comment" | |
gh pr comment ${PR} --repo rust-lang/team --body-file comment.txt --edit-last | |
else | |
echo "Creating new comment" | |
gh pr comment ${PR} --repo rust-lang/team --body-file comment.txt | |
fi |