[llvm] [workflows] Rework pre-commit CI for the release branch (PR #92058)

via llvm-commits llvm-commits at lists.llvm.org
Mon May 13 19:06:55 PDT 2024


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-github-workflow

Author: Tom Stellard (tstellar)

<details>
<summary>Changes</summary>

This rewrites the pre-commit CI for the release branch so that it behaves almost exactly like the current buildkite builders.  It builds every project and uses a better filtering method for selecting which projects to build.

In addition, with this change we drop the Linux and Windows test configs, since these are already covered by buildkite and add a config for macos/aarch64.

---

Patch is 33.21 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/92058.diff


15 Files Affected:

- (added) .github/workflows/ci-tests.yml (+176) 
- (removed) .github/workflows/clang-tests.yml (-38) 
- (added) .github/workflows/compute-projects-to-test/action.yml (+44) 
- (added) .github/workflows/compute-projects-to-test/compute-projects-to-test.sh (+240) 
- (added) .github/workflows/continue-timeout-job.yml (+75) 
- (added) .github/workflows/get-job-id/action.yml (+30) 
- (removed) .github/workflows/libclc-tests.yml (-39) 
- (removed) .github/workflows/lld-tests.yml (-38) 
- (removed) .github/workflows/lldb-tests.yml (-39) 
- (modified) .github/workflows/llvm-tests.yml (-10) 
- (added) .github/workflows/pr-sccache-restore/action.yml (+26) 
- (added) .github/workflows/pr-sccache-save/action.yml (+27) 
- (added) .github/workflows/timeout-restore/action.yml (+33) 
- (added) .github/workflows/timeout-save/action.yml (+94) 
- (added) .github/workflows/unprivileged-download-artifact/action.yml (+77) 


``````````diff
diff --git a/.github/workflows/ci-tests.yml b/.github/workflows/ci-tests.yml
new file mode 100644
index 0000000000000..9ca74eda83e16
--- /dev/null
+++ b/.github/workflows/ci-tests.yml
@@ -0,0 +1,176 @@
+name: "CI Tests"
+
+permissions:
+  contents: read
+
+on:
+  pull_request:
+    types:
+      - opened
+      - synchronize
+      - reopened
+      # When a PR is closed, we still start this workflow, but then skip
+      # all the jobs, which makes it effectively a no-op.  The reason to
+      # do this is that it allows us to take advantage of concurrency groups
+      # to cancel in progress CI jobs whenever the PR is closed.
+      - closed
+    branches:
+      - 'release/**'
+
+concurrency:
+  group: ${{ github.workflow }}-${{ github.event.pull_request.number }}
+  cancel-in-progress: True
+
+jobs:
+  compute-test-configs:
+    name: "Compute Configurations to Test"
+    if: >-
+      github.repository_owner == 'llvm' &&
+      github.event.action != 'closed'
+    runs-on: ubuntu-22.04
+    outputs:
+      skip-build: ${{ steps.vars.outputs.skip-build }}
+      test-platforms: ${{ steps.platforms.outputs.result }}
+    steps:
+      - name: Fetch LLVM sources
+        uses: actions/checkout at v4
+        with:
+          fetch-depth: 2
+
+      - name: Compute projects to test
+        id: vars
+        uses: ./.github/workflows/compute-projects-to-test
+
+      - name: Compute platforms to test
+        uses: actions/github-script at 60a0d83039c74a4aee543508d2ffcb1c3799cdea #v7.0.1
+        id: platforms
+        with:
+          script: |
+
+            function add_config(configs, config) {
+              if(config.check_targets) {
+                configs.push(config);
+              }
+            }
+
+            linuxConfig = {
+              name: "linux-x86_64",
+              runs_on: "ubuntu-22.04",
+              check_targets: "${{ steps.vars.outputs.Linux-check-targets }}",
+              projects: "${{ steps.vars.outputs.Linux-projects }}"
+            }
+            windowsConfig = {
+              name: "windows-x86_64",
+              runs_on: "windows-2022",
+              check_targets: "${{ steps.vars.outputs.Windows-check-targets }}",
+              projects: "${{ steps.vars.outputs.Windows-projects }}"
+            }
+            macConfig = {
+              name: "macos-x86_64",
+              runs_on: "macos-13",
+              check_targets: "${{ steps.vars.outputs.macOS-check-targets }}",
+              projects: "${{ steps.vars.outputs.macOS-projects }}"
+            }
+            macArmConfig = {
+              name: "macos-aarch64",
+              runs_on: "macos-14",
+              check_targets: "${{ steps.vars.outputs.macOS-check-targets }}",
+              projects: "${{ steps.vars.outputs.macOS-projects }}"
+            }
+
+            configs = []
+
+            const base_ref = process.env.GITHUB_BASE_REF;
+            if (base_ref.startsWith('release/')) {
+              // This is a pull request against a release branch.
+              add_config(configs, macConfig)
+              add_config(configs, macArmConfig)
+            }
+
+            if (configs.length == 0) {
+              core.setOutput('skip-build', 'true');
+            }
+            return configs;
+
+  ci-build-test:
+    # If this job name is changed, then we need to update the job-name
+    # paramater for the timeout-save step below.
+    name: "Build"
+    needs:
+      - compute-test-configs
+    permissions:
+      actions: write #pr-sccache-save may delete artifacts.
+    runs-on: ${{ matrix.runs_on }}
+    strategy:
+      fail-fast: false
+      matrix:
+        include: ${{ fromJson(needs.compute-test-configs.outputs.test-platforms) }}
+    if: needs.compute-test-configs.outputs.skip-build != 'true'
+    steps:
+      - name: Fetch LLVM sources
+        uses: actions/checkout at v4
+
+      - name: Timeout Restore
+        id: timeout
+        uses: ./.github/workflows/timeout-restore
+        with:
+          artifact-name-suffix: ${{ matrix.name }}
+
+      - name: Setup Windows
+        uses: llvm/actions/setup-windows at main
+        if: ${{ runner.os == 'Windows' }}
+        with:
+          arch: amd64
+
+      - name: Install Ninja
+        uses: llvm/actions/install-ninja at main
+
+      - name: Setup sccache
+        uses: hendrikmuhs/ccache-action at v1
+        with:
+          max-size: 2G
+          variant: sccache
+          key: ci-${{ matrix.name }}
+
+      - name: Restore sccache from previous PR run
+        uses: ./.github/workflows/pr-sccache-restore
+        with:
+          artifact-name-suffix: ${{ matrix.name }}
+
+      - name: Configure
+        if: ${{ steps.timeout.outputs.exists != 'true' }}
+        shell: bash
+        run: |
+          # -DLLVM_DISABLE_ASSEMBLY_FILES=ON is a
+          # workaround for a test failure on some lld tests on MacOS
+          # https://github.com/llvm/llvm-project/issues/81967
+          cmake -B build -GNinja \
+            -DCMAKE_BUILD_TYPE=Release \
+            -DLLVM_ENABLE_PROJECTS="${{ matrix.projects }}" \
+            -DLLVM_ENABLE_ASSERTIONS=ON \
+            -DLLVM_LIT_ARGS="-v --no-progress-bar" \
+            -DCMAKE_C_COMPILER_LAUNCHER=sccache \
+            -DCMAKE_CXX_COMPILER_LAUNCHER=sccache \
+            ${{ (runner.os == 'macOS' && '-DLLVM_DISABLE_ASSEMBLY_FILES=ON') || ''}} \
+            -S llvm
+
+      - name: Build
+        shell: bash
+        timeout-minutes: 330
+        run: |
+          ninja -C build -k 0 ${{ matrix.check_targets }}
+
+      - name: Timeout Save
+        if: always()
+        uses: ./.github/workflows/timeout-save
+        with:
+          job-name: "Build (${{ matrix.name }}, ${{ matrix.runs_on }} ${{ matrix.check_targets }} ${{ matrix.projects }})"
+          artifact-name-suffix: ${{ matrix.name }}
+          timeout-step: "Build"
+          timeout-minutes: 330
+
+      - name: Save sccache for next PR run
+        if: always()
+        uses: ./.github/workflows/pr-sccache-save
+        with:
+          artifact-name-suffix: ${{ matrix.name }}
diff --git a/.github/workflows/clang-tests.yml b/.github/workflows/clang-tests.yml
deleted file mode 100644
index 2569ce19518e3..0000000000000
--- a/.github/workflows/clang-tests.yml
+++ /dev/null
@@ -1,38 +0,0 @@
-name: Clang Tests
-
-permissions:
-  contents: read
-
-on:
-  workflow_dispatch:
-  push:
-    branches:
-      - 'release/**'
-    paths:
-      - 'clang/**'
-      - '.github/workflows/clang-tests.yml'
-      - '.github/workflows/llvm-project-tests.yml'
-      - '!llvm/**'
-  pull_request:
-    branches:
-      - 'release/**'
-    paths:
-      - 'clang/**'
-      - '.github/workflows/clang-tests.yml'
-      - '.github/workflows/llvm-project-tests.yml'
-      - '!llvm/**'
-
-concurrency:
-  # Skip intermediate builds: always.
-  # Cancel intermediate builds: only if it is a pull request build.
-  group: ${{ github.workflow }}-${{ github.ref }}
-  cancel-in-progress: ${{ startsWith(github.ref, 'refs/pull/') }}
-
-jobs:
-  check_clang:
-    if: github.repository_owner == 'llvm'
-    name: Test clang,lldb,libclc
-    uses: ./.github/workflows/llvm-project-tests.yml
-    with:
-      build_target: check-clang
-      projects: clang;lldb;libclc
diff --git a/.github/workflows/compute-projects-to-test/action.yml b/.github/workflows/compute-projects-to-test/action.yml
new file mode 100644
index 0000000000000..6cb343cef9ba0
--- /dev/null
+++ b/.github/workflows/compute-projects-to-test/action.yml
@@ -0,0 +1,44 @@
+name: 'Compute Projects To Test'
+inputs:
+  projects:
+    required: false
+    type: 'string'
+  
+  os-list:
+    description: >-
+      A space delimited list of operating systems that will be tested.  The
+      operating system values should match those used for GitHub's runner.os
+      context value: Linux, Windows, macOS.
+    required: false
+    default: "Linux Windows macOS"
+
+outputs:
+  Linux-check-targets:
+    description: "A space delimited list of check-targets to pass to ninja."
+    value: ${{ steps.compute-projects.outputs.Linux-check-targets }}
+  Linux-projects:
+    description: "A semi-colon delimited list of projects to pass to -DLLVM_ENABLE_PROJECTS."
+    value: ${{ steps.compute-projects.outputs.Linux-projects }}
+  Windows-check-targets:
+    description: "A space delimited list of check-targets to pass to ninja."
+    value: ${{ steps.compute-projects.outputs.Windows-check-targets }}
+  Windows-projects:
+    description: "A semi-colon delimited list of projects to pass to -DLLVM_ENABLE_PROJECTS."
+    value: ${{ steps.compute-projects.outputs.Windows-projects }}
+  macOS-check-targets:
+    description: "A space delimited list of check-targets to pass to ninja."
+    value: ${{ steps.compute-projects.outputs.macOS-check-targets }}
+  macOS-projects:
+    description: "A semi-colon delimited list of projects to pass to -DLLVM_ENABLE_PROJECTS."
+    value: ${{ steps.compute-projects.outputs.macOS-projects }}
+
+
+runs:
+  using: "composite"
+  steps:
+    - id: compute-projects
+      shell: bash
+      run: |
+        for os in ${{ inputs.os-list }}; do
+          RUNNER_OS=$os .github/workflows/compute-projects-to-test/compute-projects-to-test.sh ${{ inputs.projects }}
+        done
diff --git a/.github/workflows/compute-projects-to-test/compute-projects-to-test.sh b/.github/workflows/compute-projects-to-test/compute-projects-to-test.sh
new file mode 100755
index 0000000000000..fcab06b46c4ee
--- /dev/null
+++ b/.github/workflows/compute-projects-to-test/compute-projects-to-test.sh
@@ -0,0 +1,240 @@
+#!/usr/bin/env bash
+#===----------------------------------------------------------------------===##
+#
+# Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+# See https://llvm.org/LICENSE.txt for license information.
+# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+#
+#===----------------------------------------------------------------------===##
+
+#
+# This file generates a Buildkite pipeline that triggers the various CI jobs for
+# the LLVM project during pre-commit CI.
+#
+# See https://buildkite.com/docs/agent/v3/cli-pipeline#pipeline-format.
+#
+# As this outputs a yaml file, it's possible to log messages to stderr or
+# prefix with "#".
+
+
+set -eu
+set -o pipefail
+
+# Environment variables script works with:
+
+# Set by GitHub
+: ${GITHUB_OUTPUT:=}
+: ${RUNNER_OS:=}
+
+# Allow users to specify which projects to build.
+all_projects="bolt clang clang-tools-extra compiler-rt cross-project-tests flang libc libclc lld lldb llvm mlir openmp polly pstl"
+if [ "$#" -ne 0 ]; then
+  wanted_projects="${@}"
+else
+  wanted_projects="${all_projects}"
+fi
+
+# List of files affected by this commit
+: ${MODIFIED_FILES:=$(git diff --name-only HEAD~1...HEAD)}
+
+echo "Files modified:" >&2
+echo "$MODIFIED_FILES" >&2
+modified_dirs=$(echo "$MODIFIED_FILES" | cut -d'/' -f1 | sort -u)
+echo "Directories modified:" >&2
+echo "$modified_dirs" >&2
+echo "wanted_projects: $wanted_projects"
+
+function remove-unwanted-projects() {
+  projects=${@}
+  for project in ${projects}; do
+    if echo "$wanted_projects" | tr ' ' '\n' | grep -q -E "^${project}$"; then
+      echo "${project}"
+    fi
+  done
+}
+
+function compute-projects-to-test() {
+  projects=${@}
+  for project in ${projects}; do
+    echo "${project}"
+    case ${project} in
+    lld)
+      for p in bolt cross-project-tests; do
+        echo $p
+      done
+    ;;
+    llvm)
+      for p in bolt clang clang-tools-extra flang lld lldb mlir polly; do
+        echo $p
+      done
+    ;;
+    clang)
+      for p in clang-tools-extra compiler-rt flang libc lldb openmp cross-project-tests; do
+        echo $p
+      done
+    ;;
+    clang-tools-extra)
+      echo libc
+    ;;
+    mlir)
+      echo flang
+    ;;
+    *)
+      # Nothing to do
+    ;;
+    esac
+  done
+}
+
+function add-dependencies() {
+  projects=${@}
+  for project in ${projects}; do
+    echo "${project}"
+    case ${project} in
+    bolt)
+      for p in lld llvm; do
+        echo $p
+      done
+    ;;
+    cross-project-tests)
+      for p in lld clang; do
+        echo $p
+      done
+    ;;
+    clang-tools-extra)
+      for p in llvm clang; do
+        echo $p
+      done
+    ;;
+    compiler-rt|libc|openmp)
+      echo clang lld
+    ;;
+    flang|lldb)
+      for p in llvm clang; do
+        echo $p
+      done
+    ;;
+    lld|mlir|polly)
+      echo llvm
+    ;;
+    *)
+      # Nothing to do
+    ;;
+    esac
+  done
+}
+
+function exclude-linux() {
+  projects=${@}
+  for project in ${projects}; do
+    case ${project} in
+    cross-project-tests) ;; # tests failing
+    lldb)                ;; # tests failing
+    openmp)              ;; # https://github.com/google/llvm-premerge-checks/issues/410
+    *)
+      echo "${project}"
+    ;;
+    esac
+  done
+}
+
+function exclude-windows() {
+  projects=${@}
+  for project in ${projects}; do
+    case ${project} in
+    cross-project-tests) ;; # tests failing
+    compiler-rt)         ;; # tests taking too long
+    openmp)              ;; # TODO: having trouble with the Perl installation
+    libc)                ;; # no Windows support
+    lldb)                ;; # tests failing
+    bolt)                ;; # tests are not supported yet
+    *)
+      echo "${project}"
+    ;;
+    esac
+  done
+}
+
+function exclude-mac() {
+  projects=${@}
+  for project in ${projects}; do
+    case ${project} in
+    cross-project-tests) ;; # tests failing
+    openmp)              ;; # https://github.com/google/llvm-premerge-checks/issues/410
+    lldb)                ;; # tests failing
+    flang)               ;; # tests failing
+    bolt)                ;; # tests failing
+    *)
+      echo "${project}"
+    ;;
+    esac
+  done
+
+}
+
+# Prints only projects that are both present in $modified_dirs and the passed
+# list.
+function keep-modified-projects() {
+  projects=${@}
+  for project in ${projects}; do
+    if echo "$modified_dirs" | grep -q -E "^${project}$"; then
+      echo "${project}"
+    fi
+  done
+}
+
+function check-targets() {
+  projects=${@}
+  for project in ${projects}; do
+    case ${project} in
+    clang-tools-extra)
+      echo "check-clang-tools"
+    ;;
+    compiler-rt)
+      echo "check-all"
+    ;;
+    cross-project-tests)
+      echo "check-cross-project"
+    ;;
+    lldb)
+      echo "check-all" # TODO: check-lldb may not include all the LLDB tests?
+    ;;
+    pstl)
+      echo "check-all"
+    ;;
+    libclc)
+      echo "check-all"
+    ;;
+    *)
+      echo "check-${project}"
+    ;;
+    esac
+  done
+}
+
+# Generic pipeline for projects that have not defined custom steps.
+#
+# Individual projects should instead define the pre-commit CI tests that suits their
+# needs while letting them run on the infrastructure provided by LLVM.
+
+# Figure out which projects need to be built on each platform
+modified_projects="$(keep-modified-projects ${all_projects})"
+echo "modified_projects: $modified_projects"
+
+if [ "${RUNNER_OS}" = "Linux" ]; then
+  projects_to_test=$(exclude-linux $(compute-projects-to-test ${modified_projects}))
+elif [ "${RUNNER_OS}" = "Windows" ]; then
+  projects_to_test=$(exclude-windows $(compute-projects-to-test ${modified_projects}))
+elif [ "${RUNNER_OS}" = "macOS" ]; then
+  projects_to_test=$(exclude-mac $(compute-projects-to-test ${modified_projects}))
+else
+  echo "Unknown runner OS: $RUNNER_OS"
+  exit 1
+fi
+check_targets=$(check-targets $(remove-unwanted-projects ${projects_to_test}) | sort | uniq)
+projects=$(remove-unwanted-projects $(add-dependencies ${projects_to_test}) | sort | uniq)
+
+echo "$RUNNER_OS-check-targets=$(echo ${check_targets} | tr ' ' ' ')" >> $GITHUB_OUTPUT
+echo "$RUNNER_OS-projects=$(echo ${projects} | tr ' ' ';')" >> $GITHUB_OUTPUT
+
+cat $GITHUB_OUTPUT
diff --git a/.github/workflows/continue-timeout-job.yml b/.github/workflows/continue-timeout-job.yml
new file mode 100644
index 0000000000000..f3ff58c77cfe0
--- /dev/null
+++ b/.github/workflows/continue-timeout-job.yml
@@ -0,0 +1,75 @@
+name: Continue Timeout Job
+
+on:
+  workflow_run:
+    workflows:
+      - "Windows Precommit Tests"
+      - "CI Tests"
+    types:
+      - completed
+
+permissions:
+  contents: read
+
+jobs:
+  restart:
+    name: "Restart Job"
+    permissions:
+      actions: write
+    runs-on: ubuntu-22.04
+    if: github.event.workflow_run.conclusion == 'failure'
+    steps:
+      - name: "Restart Job"
+        uses: actions/github-script at 60a0d83039c74a4aee543508d2ffcb1c3799cdea #v7.0.1
+        with:
+          script: |
+            const response = await github.rest.actions.listWorkflowRunArtifacts({
+              owner: context.repo.owner,
+              repo: context.repo.repo,
+              run_id: context.payload.workflow_run.id
+            })
+
+            job_ids = [];
+
+            for (artifact of response.data.artifacts) {
+              console.log(artifact);
+              const match = artifact.name.match(/timeout-([0-9]+)/);
+              console.log(match);
+              if (!match) {
+                continue;
+              }
+              job_ids.push(match[1]);
+
+              // Delete the timeout artifact to prepare for the next run
+              await github.rest.actions.deleteArtifact({
+                owner: context.repo.owner,
+                repo: context.repo.repo,
+                artifact_id: artifact.id
+              });
+            }
+
+            if (job_ids.length == 0) {
+              return;
+            }
+
+            if (job_ids.length > 1) {
+              // We aren't able to re-start multiple jobs individually, so our
+              // only option is to restart all failed jobs.
+              await github.rest.actions.reRunWorkflowFailedJobs({
+                owner: context.repo.owner,
+                repo: context.repo.repo,
+                run_id: context.payload.workflow_run.id
+              })
+              console.log("Restarted workflow: " + context.payload.workflow_run.id);
+              return;
+            }
+
+            job_id = job_ids[0];
+            // This function does not exist even though it is in the document
+            //github.rest.actions.reRunJobForWorkflow({
+            await github.request('POST /repos/{owner}/{repo}/actions/jobs/{job_id}/rerun', {
+              owner: context.repo.owner,
+              repo: context.repo.repo,
+              job_id: job_id
+            })
+            console.log("Restarted job: " + job_id);
diff --git a/.github/workflows/get-job-id/action.yml b/.github/workflows/get-job-id/action.yml
new file mode 100644
index 0000000000000..65495efd86820
--- /dev/null
+++ b/.github/workflows/get-job-id/action.yml
@@ -0,0 +1,30 @@
+name: Get Job ID
+inputs:
+  job-name:
+    required: false
+    type: 'string'
+
+outputs:
+  job-id:
+    description: "A space delimited list of check-targets to pass to ninja."
+    value: ${{ steps.job-id.outputs.result }}
+
+runs:
+  using: "composite"
+  steps:
+    - uses: actions/github-script at 60a0d83039c74a4aee543508d2ffcb1c3799cdea #v7.0.1
+      id: job-id
+      with:
+        script: |
+          const job_data = await github.rest.actions.listJobsForWorkflowRun({
+            owner: context.repo.owner,
+            repo: context.repo.repo,
+            run_id: context.runId,
+          });
+
+          for (job of job_data.data.jobs) {
+            console.log(job)
+            if (job.name == "${{ inputs.job-name }}") {
+              return job.id
+            }
+          }
diff --git a/.github/workflows/libclc-tests.yml b/.github/workflows/libclc-tests.yml
deleted file mode 100644
index 23192f776a985..0000000000000
--- a/.github/workflows/libclc-tests.yml
+++ /dev/null
@@ -1,39 +0,0 @@
-name: libclc Tests
-
-permissions:
-  contents: read
-
-on:
-  workflow_dispatch:
-  push:
-    branches:
-      - 'release/**'
-    paths:
-      - 'libclc/**'
-      - '.github/workflows/libclc-tests.yml'
-      - '.github/workflows/llvm-project-tests.yml'
-      - '!clang/**'
-      - '!llvm/**'
-  pull_request:
-    branches:
-      - 'release/**'
-    paths:
-      - 'libclc/**'
-      - '.github/workflows/libclc-tests.yml'
-      - '.github/workflows/llvm-project-tests.yml'
-      - '!clang/**'
-      - '!llvm/**'
-
-concurrency:
-  # Skip intermediate builds: always.
-  # Cancel intermediate builds: only if it is a pull request build.
-  group: ${{...
[truncated]

``````````

</details>


https://github.com/llvm/llvm-project/pull/92058


More information about the llvm-commits mailing list