rust-lang/rust

4 workflows · maturity 50% · 7 patterns · GitHub ↗

Security 12.5/100

Practices

✓ Matrix✓ Permissions○ Security scan○ AI review○ Cache✓ Concurrency○ Reusable workflows

Detected patterns

Security dimensions

permissions
12.5
security scan
0
supply chain
0
secret handling
0
harden runner
0

Workflows (4)

ci matrix perms .github/workflows/ci.yml
Triggers
push, pull_request
Runs on
ubuntu-24.04-arm, ${{ matrix.os }}, ubuntu-24.04
Jobs
calculate_matrix, job, outcome
Matrix
include→ ${{ fromJSON(needs.calculate_matrix.outputs.jobs) }}
Commands
  • cd src/ci/citool CARGO_INCREMENTAL=0 cargo test
  • cd src/ci/citool CARGO_INCREMENTAL=0 cargo run calculate-job-matrix >> $GITHUB_OUTPUT
  • # Check if cargo is installed if ! command -v cargo &> /dev/null; then echo "Cargo not found, installing Rust..." curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --profile=minimal # Make cargo available in PATH echo "$HOME/.cargo/bin" >> $GITHUB_PATH fi
  • git config --global core.autocrlf false
  • src/ci/scripts/free-disk-space-linux.sh
  • echo "disk usage:" df -h
  • echo "[CI_PR_NUMBER=$num]"
  • src/ci/scripts/setup-environment.sh
View raw YAML
# This file defines our primary CI workflow that runs on pull requests
# and also on pushes to special branches (auto, try).
#
# The actual definition of the executed jobs is calculated by the
# `src/ci/citool` crate, which
# uses job definition data from src/ci/github-actions/jobs.yml.
# You should primarily modify the `jobs.yml` file if you want to modify
# what jobs are executed in CI.

name: CI
on:
  push:
    branches:
      - automation/bors/auto
      - automation/bors/try
      - try-perf
  pull_request:
    branches:
      - "**"

permissions:
  contents: read
  packages: write

defaults:
  run:
    # On Linux, macOS, and Windows, use the system-provided bash as the default
    # shell. (This should only make a difference on Windows, where the default
    # shell is PowerShell.)
    shell: bash

concurrency:
  # For a given workflow, if we push to the same branch, cancel all previous builds on that branch.
  # We add an exception for try builds (automation/bors/try branch) and unrolled rollup builds
  # (try-perf), which are all triggered on the same branch, but which should be able to run
  # concurrently.
  group: ${{ github.workflow }}-${{ ((github.ref == 'refs/heads/try-perf' || github.ref == 'refs/heads/automation/bors/try') && github.sha) || github.ref }}
  cancel-in-progress: true
env:
  TOOLSTATE_REPO: "https://github.com/rust-lang-nursery/rust-toolstate"
  # This will be empty in PR jobs.
  TOOLSTATE_REPO_ACCESS_TOKEN: ${{ secrets.TOOLSTATE_REPO_ACCESS_TOKEN }}
jobs:
  # The job matrix for `calculate_matrix` is defined in src/ci/github-actions/jobs.yml.
  # It calculates which jobs should be executed, based on the data of the ${{ github }} context.
  # If you want to modify CI jobs, take a look at src/ci/github-actions/jobs.yml.
  calculate_matrix:
    name: Calculate job matrix
    runs-on: ubuntu-24.04-arm
    outputs:
      jobs: ${{ steps.jobs.outputs.jobs }}
      run_type: ${{ steps.jobs.outputs.run_type }}
    steps:
      - name: Checkout the source code
        uses: actions/checkout@v5
      - name: Test citool
        # Only test citool on the auto branch, to reduce latency of the calculate matrix job
        # on PR/try builds.
        if: ${{ github.ref == 'refs/heads/automation/bors/auto' }}
        run: |
          cd src/ci/citool
          CARGO_INCREMENTAL=0 cargo test
      - name: Calculate the CI job matrix
        env:
          COMMIT_MESSAGE: ${{ github.event.head_commit.message }}
        run: |
          cd src/ci/citool
          CARGO_INCREMENTAL=0 cargo run calculate-job-matrix >> $GITHUB_OUTPUT
        id: jobs
  job:
    name: ${{ matrix.full_name }}
    needs: [ calculate_matrix ]
    runs-on: "${{ matrix.os }}"
    timeout-minutes: 360
    # The bors environment contains secrets required for elevated workflows (try and auto builds),
    # which need to access e.g. S3 and upload artifacts. We want to provide access to that
    # environment only on the try/auto branches, which are only accessible to bors.
    # This also ensures that PR CI (which doesn't get write access to S3) works, as it cannot
    # access the environment.
    #
    # We only enable the environment for the rust-lang/rust repository, so that CI works on forks.
    environment: ${{ ((github.repository == 'rust-lang/rust' && (github.ref == 'refs/heads/try-perf' || github.ref == 'refs/heads/automation/bors/try' || github.ref == 'refs/heads/automation/bors/auto')) && 'bors') || '' }}
    env:
      CI_JOB_NAME: ${{ matrix.name }}
      CI_JOB_DOC_URL: ${{ matrix.doc_url }}
      GITHUB_WORKFLOW_RUN_ID: ${{ github.run_id }}
      GITHUB_REPOSITORY: ${{ github.repository }}
      CARGO_REGISTRIES_CRATES_IO_PROTOCOL: sparse
      # commit of PR sha or commit sha. `GITHUB_SHA` is not accurate for PRs.
      HEAD_SHA: ${{ github.event.pull_request.head.sha || github.sha }}
      DOCKER_TOKEN: ${{ secrets.GITHUB_TOKEN }}
      SCCACHE_BUCKET: rust-lang-ci-sccache2
      SCCACHE_REGION: us-west-1
      CACHE_DOMAIN: ci-caches.rust-lang.org
    continue-on-error: ${{ matrix.continue_on_error || false }}
    strategy:
      # If the user starts multiple jobs in a try build, let them all finish.
      # Try builds are sometimes used to test several jobs at once, and it is useful to know which
      # of them would succeed or not.
      fail-fast: ${{ needs.calculate_matrix.outputs.run_type != 'try' }}
      matrix:
        # Check the `calculate_matrix` job to see how is the matrix defined.
        include: ${{ fromJSON(needs.calculate_matrix.outputs.jobs) }}
    steps:
      - name: Install cargo in AWS CodeBuild
        if: matrix.codebuild
        run: |
          # Check if cargo is installed
          if ! command -v cargo &> /dev/null; then
            echo "Cargo not found, installing Rust..."
            curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --profile=minimal
            # Make cargo available in PATH
            echo "$HOME/.cargo/bin" >> $GITHUB_PATH
          fi

      - name: disable git crlf conversion
        run: git config --global core.autocrlf false

      - name: checkout the source code
        uses: actions/checkout@v5
        with:
          fetch-depth: 2

      # Free up disk space on Linux by removing preinstalled components that
      # we do not need. We do this to enable some of the less resource
      # intensive jobs to run on free runners, which however also have
      # less disk space.
      - name: free up disk space
        run: src/ci/scripts/free-disk-space-linux.sh
        if: matrix.free_disk

      # If we don't need to free up disk space then just report how much space we have
      - name: print disk usage
        run: |
          echo "disk usage:"
          df -h
        if: matrix.free_disk == false

      # Rust Log Analyzer can't currently detect the PR number of a GitHub
      # Actions build on its own, so a hint in the log message is needed to
      # point it in the right direction.
      - name: configure the PR in which the error message will be posted
        run: echo "[CI_PR_NUMBER=$num]"
        env:
          num: ${{ github.event.number }}
        if: needs.calculate_matrix.outputs.run_type == 'pr'

      - name: add extra environment variables
        run: src/ci/scripts/setup-environment.sh
        env:
          # Since it's not possible to merge `${{ matrix.env }}` with the other
          # variables in `job.<name>.env`, the variables defined in the matrix
          # are passed to the `setup-environment.sh` script encoded in JSON,
          # which then uses log commands to actually set them.
          EXTRA_VARIABLES: ${{ toJson(matrix.env) }}

      - name: ensure the channel matches the target branch
        run: src/ci/scripts/verify-channel.sh

      - name: collect CPU statistics
        run: src/ci/scripts/collect-cpu-stats.sh

      - name: show the current environment
        run: src/ci/scripts/dump-environment.sh

      - name: install awscli
        run: src/ci/scripts/install-awscli.sh

      - name: install sccache
        run: src/ci/scripts/install-sccache.sh

      - name: install clang
        run: src/ci/scripts/install-clang.sh

      - name: install tidy
        run: src/ci/scripts/install-tidy.sh

      - name: install WIX
        run: src/ci/scripts/install-wix.sh

      - name: disable git crlf conversion
        run: src/ci/scripts/disable-git-crlf-conversion.sh

      - name: checkout submodules
        run: src/ci/scripts/checkout-submodules.sh

      - name: install MinGW
        run: src/ci/scripts/install-mingw.sh

      - name: install ninja
        run: src/ci/scripts/install-ninja.sh

      - name: enable ipv6 on Docker
        # Don't run on codebuild because systemctl is not available
        if: ${{ !matrix.codebuild }}
        run: src/ci/scripts/enable-docker-ipv6.sh

      # Disable automatic line ending conversion (again). On Windows, when we're
      # installing dependencies, something switches the git configuration directory or
      # re-enables autocrlf. We've not tracked down the exact cause -- and there may
      # be multiple -- but this should ensure submodules are checked out with the
      # appropriate line endings.
      - name: disable git crlf conversion
        run: src/ci/scripts/disable-git-crlf-conversion.sh

      - name: ensure line endings are correct
        run: src/ci/scripts/verify-line-endings.sh

      - name: ensure backported commits are in upstream branches
        run: src/ci/scripts/verify-backported-commits.sh

      - name: ensure the stable version number is correct
        run: src/ci/scripts/verify-stable-version-number.sh

      # Show the environment just before we run the build
      # This makes it easier to diagnose problems with the above install scripts.
      - name: show the current environment
        run: src/ci/scripts/dump-environment.sh

      # Pre-build citool before the following step uninstalls rustup
      # Build it into the build directory, to avoid modifying sources
      - name: build citool
        run: |
          cd src/ci/citool
          CARGO_INCREMENTAL=0 CARGO_TARGET_DIR=../../../build/citool cargo build

      - name: run the build
        run: |
          set +e
          # Redirect stderr to stdout to avoid reordering the two streams in the GHA logs.
          src/ci/scripts/run-build-from-ci.sh 2>&1
          STATUS=$?
          set -e

          if [[ "$STATUS" -ne 0 && -n "$CI_JOB_DOC_URL" ]]; then
            echo "****************************************************************************"
            echo "To find more information about this job, visit the following URL:"
            echo "$CI_JOB_DOC_URL"
            echo "****************************************************************************"
          fi
          exit ${STATUS}
        env:
          AWS_ACCESS_KEY_ID: ${{ secrets.CACHES_AWS_ACCESS_KEY_ID }}
          AWS_SECRET_ACCESS_KEY: ${{ secrets.CACHES_AWS_SECRET_ACCESS_KEY }}

      - name: create github artifacts
        run: src/ci/scripts/create-doc-artifacts.sh

      - name: print disk usage
        # We also want to know the disk usage when the job fails.
        if: always()
        run: |
          echo "disk usage:"
          df -h

      - name: upload artifacts to github
        uses: actions/upload-artifact@v4
        with:
          # name is set in previous step
          name: ${{ env.DOC_ARTIFACT_NAME }}
          path: obj/artifacts/doc
          if-no-files-found: ignore
          retention-days: 5

      - name: upload artifacts to S3
        run: src/ci/scripts/upload-artifacts.sh
        env:
          AWS_ACCESS_KEY_ID: ${{ secrets.ARTIFACTS_AWS_ACCESS_KEY_ID }}
          AWS_SECRET_ACCESS_KEY: ${{ secrets.ARTIFACTS_AWS_SECRET_ACCESS_KEY }}
        # Adding a condition on DEPLOY=1 or DEPLOY_ALT=1 is not needed as all deploy
        # builders *should* have the AWS credentials available. Still, explicitly
        # adding the condition is helpful as this way CI will not silently skip
        # deploying artifacts from a dist builder if the variables are misconfigured,
        # erroring about invalid credentials instead.
        if: github.event_name == 'push' || env.DEPLOY == '1' || env.DEPLOY_ALT == '1'

      - name: postprocess metrics into the summary
        # This step is not critical, and if some I/O problem happens, we don't want
        # to cancel the build.
        continue-on-error: true
        run: |
          if [ -f build/metrics.json ]; then
            METRICS=build/metrics.json
          elif [ -f obj/build/metrics.json ]; then
            METRICS=obj/build/metrics.json
          else
            echo "No metrics.json found"
            exit 0
          fi

          # Get closest bors merge commit
          PARENT_COMMIT=`git rev-list --author='bors@rust-lang.org' --author='122020455+rust-bors\[bot\]@users.noreply.github.com' -n1 --first-parent HEAD^1`

          ./build/citool/debug/citool postprocess-metrics \
              --job-name ${CI_JOB_NAME} \
              --parent ${PARENT_COMMIT} \
              ${METRICS} >> ${GITHUB_STEP_SUMMARY}

      - name: upload job metrics to DataDog
        # This step is not critical, and if some I/O problem happens, we don't want
        # to cancel the build.
        continue-on-error: true
        if: needs.calculate_matrix.outputs.run_type != 'pr'
        env:
          DATADOG_API_KEY: ${{ secrets.DATADOG_API_KEY }}
          DD_GITHUB_JOB_NAME: ${{ matrix.full_name }}
        run: ./build/citool/debug/citool upload-build-metrics build/cpu-usage.csv

  # This job is used to publish toolstate for successful auto builds.
  outcome:
    name: publish toolstate
    runs-on: ubuntu-24.04
    needs: [ calculate_matrix, job ]
    if: ${{ needs.calculate_matrix.outputs.run_type == 'auto' }}
    environment: ${{ (github.repository == 'rust-lang/rust' && 'bors') || '' }}
    steps:
      - name: checkout the source code
        uses: actions/checkout@v5
        with:
          fetch-depth: 2
      # Publish the toolstate if an auto build succeeds (just before push to the default branch)
      - name: publish toolstate
        run: src/ci/publish_toolstate.sh
        shell: bash
        env:
          TOOLSTATE_ISSUES_API_URL: https://api.github.com/repos/rust-lang/rust/issues
          TOOLSTATE_PUBLISH: 1
dependencies perms .github/workflows/dependencies.yml
Triggers
schedule, workflow_dispatch
Runs on
ubuntu-24.04, ubuntu-24.04, ubuntu-24.04
Jobs
not-waiting-on-bors, update, pr
Commands
  • # Fetch state and labels of PR # Or exit successfully if PR does not exist JSON=$(gh pr view cargo_update --repo $GITHUB_REPOSITORY --json labels,state || exit 0) STATE=$(echo "$JSON" | jq -r '.state') WAITING_ON_BORS=$(echo "$JSON" | jq '.labels[] | any(.name == "S-waiting-on-bors"; .)') # Exit with error if open and S-waiting-on-bors if [[ "$STATE" == "OPEN" && "$WAITING_ON_BORS" == "true" ]]; then exit 1 fi
  • # Extract the stage0 version TOOLCHAIN=$(awk -F= '{a[$1]=$2} END {print(a["compiler_version"] "-" a["compiler_date"])}' src/stage0) # Install and set as default rustup toolchain install --no-self-update --profile minimal $TOOLCHAIN rustup default $TOOLCHAIN
  • ./src/tools/update-lockfile.sh
  • echo "${COMMIT_MESSAGE}" > commit.txt cat cargo_update.log >> commit.txt echo "${PR_MESSAGE}" > body.md echo '```txt' >> body.md cat cargo_update.log >> body.md echo '```' >> body.md
  • git config user.name github-actions git config user.email github-actions@github.com git switch --force-create cargo_update git add ./Cargo.lock ./library/Cargo.lock ./src/tools/rustbook/Cargo.lock git commit --no-verify --file=commit.txt
  • git push --no-verify --force --set-upstream origin cargo_update
  • # Exit with error if PR is closed STATE=$(gh pr view cargo_update --repo $GITHUB_REPOSITORY --json state --jq '.state') if [[ "$STATE" != "OPEN" ]]; then exit 1 fi gh pr edit cargo_update --title "${PR_TITLE}" --body-file body.md --repo $GITHUB_REPOSITORY
  • gh pr create --title "${PR_TITLE}" --body-file body.md --repo $GITHUB_REPOSITORY
View raw YAML
# Automatically run `cargo update` periodically

---
name: Bump dependencies in Cargo.lock
on:
  schedule:
    # Run weekly
    - cron: '0 0 * * Sun'
  workflow_dispatch:
    # Needed so we can run it manually
permissions:
  contents: read
defaults:
  run:
    shell: bash
env:
  # So cargo doesn't complain about unstable features
  RUSTC_BOOTSTRAP: 1
  PR_TITLE: Weekly `cargo update`
  PR_MESSAGE: |
    Automation to keep dependencies in `Cargo.lock` current.
    r? dep-bumps

    The following is the output from `cargo update`:
  COMMIT_MESSAGE: "cargo update \n\n"

jobs:
  not-waiting-on-bors:
    if: github.repository_owner == 'rust-lang'
    name: skip if S-waiting-on-bors
    runs-on: ubuntu-24.04
    steps:
      - env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        run: |
          # Fetch state and labels of PR
          # Or exit successfully if PR does not exist
          JSON=$(gh pr view cargo_update --repo $GITHUB_REPOSITORY --json labels,state || exit 0)
          STATE=$(echo "$JSON" | jq -r '.state')
          WAITING_ON_BORS=$(echo "$JSON" | jq '.labels[] | any(.name == "S-waiting-on-bors"; .)')

          # Exit with error if open and S-waiting-on-bors
          if [[ "$STATE" == "OPEN" && "$WAITING_ON_BORS" == "true" ]]; then
            exit 1
          fi

  update:
    if: github.repository_owner == 'rust-lang'
    name: update dependencies
    needs: not-waiting-on-bors
    runs-on: ubuntu-24.04
    steps:
      - name: checkout the source code
        uses: actions/checkout@v5
        with:
          submodules: recursive
      - name: install the bootstrap toolchain
        run: |
          # Extract the stage0 version
          TOOLCHAIN=$(awk -F= '{a[$1]=$2} END {print(a["compiler_version"] "-" a["compiler_date"])}' src/stage0)
          # Install and set as default
          rustup toolchain install --no-self-update --profile minimal $TOOLCHAIN
          rustup default $TOOLCHAIN

      - name: cargo update
        run: ./src/tools/update-lockfile.sh

      - name: upload Cargo.lock artifact for use in PR
        uses: actions/upload-artifact@v4
        with:
          name: Cargo-lock
          path: |
            Cargo.lock
            library/Cargo.lock
            src/tools/rustbook/Cargo.lock
          retention-days: 1
      - name: upload cargo-update log artifact for use in PR
        uses: actions/upload-artifact@v4
        with:
          name: cargo-updates
          path: cargo_update.log
          retention-days: 1

  pr:
    if: github.repository_owner == 'rust-lang'
    name: amend PR
    needs: update
    runs-on: ubuntu-24.04
    permissions:
      contents: write
      pull-requests: write
    steps:
      - name: checkout the source code
        uses: actions/checkout@v5

      - name: download Cargo.lock from update job
        uses: actions/download-artifact@v4
        with:
          name: Cargo-lock
      - name: download cargo-update log from update job
        uses: actions/download-artifact@v4
        with:
          name: cargo-updates

      - name: craft PR body and commit message
        run: |
          echo "${COMMIT_MESSAGE}" > commit.txt
          cat cargo_update.log >> commit.txt

          echo "${PR_MESSAGE}" > body.md
          echo '```txt' >> body.md
          cat cargo_update.log >> body.md
          echo '```' >> body.md

      - name: commit
        run: |
          git config user.name github-actions
          git config user.email github-actions@github.com
          git switch --force-create cargo_update
          git add ./Cargo.lock ./library/Cargo.lock ./src/tools/rustbook/Cargo.lock
          git commit --no-verify --file=commit.txt

      - name: push
        run: git push --no-verify --force --set-upstream origin cargo_update

      - name: edit existing open pull request
        id: edit
        # Don't fail job if we need to open new PR
        continue-on-error: true
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        run: |
          # Exit with error if PR is closed
          STATE=$(gh pr view cargo_update --repo $GITHUB_REPOSITORY --json state --jq '.state')
          if [[ "$STATE" != "OPEN" ]]; then
            exit 1
          fi

          gh pr edit cargo_update --title "${PR_TITLE}" --body-file body.md --repo $GITHUB_REPOSITORY

      - name: open new pull request
        # Only run if there wasn't an existing PR
        if: steps.edit.outcome != 'success'
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        run: gh pr create --title "${PR_TITLE}" --body-file body.md --repo $GITHUB_REPOSITORY
ghcr .github/workflows/ghcr.yml
Triggers
workflow_dispatch, schedule
Runs on
ubuntu-24.04
Jobs
mirror
Commands
  • echo "${{ secrets.GITHUB_TOKEN }}" | docker login ghcr.io -u ${{ github.repository_owner }} --password-stdin
  • curl -sL "https://github.com/google/go-containerregistry/releases/download/${VERSION}/go-containerregistry_${OS}_${ARCH}.tar.gz" | tar -xzf -
  • # List of DockerHub images to mirror to ghcr.io images=( # Mirrored because used by the tidy job, which doesn't cache Docker images "ubuntu:22.04" # Mirrored because used by x86-64-gnu-miri "ubuntu:24.04" # Mirrored because used by all linux CI jobs, including tidy "moby/buildkit:buildx-stable-1" # Mirrored because used when CI is running inside a Docker container "alpine:3.4" # Mirrored because used by dist-x86_64-linux "centos:7" ) # Mirror each image from DockerHub to ghcr.io for img in "${images[@]}"; do echo "Mirroring ${img}..." # Remove namespace from the image if any. # E.g. "moby/buildkit:buildx-stable-1" becomes "buildkit:buildx-stable-1" dest_image=$(echo "${img}" | cut -d'/' -f2-) ./crane copy \ "docker.io/${img}" \ "ghcr.io/${{ github.repository_owner }}/${dest_image}" done
View raw YAML
# Mirror DockerHub images used by the Rust project to ghcr.io.
# Images are available at https://github.com/orgs/rust-lang/packages.
#
# In some CI jobs, we pull images from ghcr.io instead of Docker Hub because
# Docker Hub has a rate limit, while ghcr.io doesn't.
# Those images are pushed to ghcr.io by this job.
#
# While Docker Hub rate limit *shouldn't* be an issue on GitHub Actions,
# it certainly is for AWS codebuild.
#
# Note that authenticating to DockerHub or other registries isn't possible
# for PR jobs, because forks can't access secrets.
# That's why we use ghcr.io: it has no rate limit and it doesn't require authentication.

name: GHCR image mirroring

on:
  workflow_dispatch:
  schedule:
    # Run daily at midnight UTC
    - cron: '0 0 * * *'

jobs:
  mirror:
    name: DockerHub mirror
    runs-on: ubuntu-24.04
    if: github.repository == 'rust-lang/rust'
    permissions:
      # Needed to write to the ghcr.io registry
      packages: write
    steps:
      - uses: actions/checkout@v5
        with:
          persist-credentials: false

      - name: Log in to registry
        run: echo "${{ secrets.GITHUB_TOKEN }}" | docker login ghcr.io -u ${{ github.repository_owner }} --password-stdin

      # Download crane in the current directory.
      # We use crane because it copies the docker image for all the architectures available in
      # DockerHub for the image.
      # Learn more about crane at
      # https://github.com/google/go-containerregistry/blob/main/cmd/crane/README.md
      - name: Download crane
        run: |
          curl -sL "https://github.com/google/go-containerregistry/releases/download/${VERSION}/go-containerregistry_${OS}_${ARCH}.tar.gz" | tar -xzf -
        env:
          VERSION: v0.20.2
          OS: Linux
          ARCH: x86_64

      - name: Mirror DockerHub
        run: |
          # List of DockerHub images to mirror to ghcr.io
          images=(
            # Mirrored because used by the tidy job, which doesn't cache Docker images
            "ubuntu:22.04"
            # Mirrored because used by x86-64-gnu-miri
            "ubuntu:24.04"
            # Mirrored because used by all linux CI jobs, including tidy
            "moby/buildkit:buildx-stable-1"
            # Mirrored because used when CI is running inside a Docker container
            "alpine:3.4"
            # Mirrored because used by dist-x86_64-linux
            "centos:7"
          )

          # Mirror each image from DockerHub to ghcr.io
          for img in "${images[@]}"; do
            echo "Mirroring ${img}..."
            # Remove namespace from the image if any.
            # E.g. "moby/buildkit:buildx-stable-1" becomes "buildkit:buildx-stable-1"
            dest_image=$(echo "${img}" | cut -d'/' -f2-)
            ./crane copy \
              "docker.io/${img}" \
              "ghcr.io/${{ github.repository_owner }}/${dest_image}"
          done
post-merge .github/workflows/post-merge.yml
Triggers
push
Runs on
ubuntu-24.04
Jobs
analysis
Commands
  • # Give GitHub some time to propagate the information that the PR was merged sleep 60 # Get closest bors merge commit PARENT_COMMIT=`git rev-list --author='bors@rust-lang.org' --author='122020455+rust-bors\[bot\]@users.noreply.github.com' -n1 --first-parent HEAD^1` echo "Parent: ${PARENT_COMMIT}" # Find PR for the current commit HEAD_PR=`gh pr list --search "${{ github.sha }}" --state merged --json number --jq '.[0].number'` if [ -z "${HEAD_PR}" ]; then echo "PR for commit SHA ${{ github.sha }} not found, exiting" exit 1 fi echo "HEAD: ${{ github.sha }} (#${HEAD_PR})" cd src/ci/citool printf "<details>\n<summary>What is this?</summary>\n" >> output.log printf "This is an experimental post-merge analysis report that shows differences in test outcomes between the merged PR and its parent PR.\n" >> output.log printf "</details>\n\n" >> output.log cargo run --release post-merge-report ${PARENT_COMMIT} ${{ github.sha }} >> output.log cat output.log gh pr comment ${HEAD_PR} -F output.log
View raw YAML
# Workflow that runs after a merge to the default branch, analyses changes in test executions
# and posts the result to the merged PR.

name: Post merge analysis

on:
  push:
    branches:
      - main

jobs:
  analysis:
    runs-on: ubuntu-24.04
    if: github.repository == 'rust-lang/rust'
    permissions:
      pull-requests: write
    steps:
      - uses: actions/checkout@v5
        with:
          # Make sure that we have enough commits to find the parent merge commit.
          # Since all merges should be through merge commits, fetching two commits
          # should be enough to get the parent bors merge commit.
          fetch-depth: 2
      - name: Perform analysis and send PR
        env:
          GH_TOKEN: ${{ github.token }}
        run: |
          # Give GitHub some time to propagate the information that the PR was merged
          sleep 60

          # Get closest bors merge commit
          PARENT_COMMIT=`git rev-list --author='bors@rust-lang.org' --author='122020455+rust-bors\[bot\]@users.noreply.github.com' -n1 --first-parent HEAD^1`
          echo "Parent: ${PARENT_COMMIT}"

          # Find PR for the current commit
          HEAD_PR=`gh pr list --search "${{ github.sha }}" --state merged --json number --jq '.[0].number'`
          if [ -z "${HEAD_PR}" ]; then
            echo "PR for commit SHA ${{ github.sha }} not found, exiting"
            exit 1
          fi
          echo "HEAD: ${{ github.sha }} (#${HEAD_PR})"

          cd src/ci/citool

          printf "<details>\n<summary>What is this?</summary>\n" >> output.log
          printf "This is an experimental post-merge analysis report that shows differences in test outcomes between the merged PR and its parent PR.\n" >> output.log
          printf "</details>\n\n" >> output.log

          cargo run --release post-merge-report ${PARENT_COMMIT} ${{ github.sha }} >> output.log

          cat output.log

          gh pr comment ${HEAD_PR} -F output.log