Conversation
These are trivial changes, and we generally don't run CI for them. Signed-off-by: James Le Cuirot <jlecuirot@microsoft.com>
Explicitly requesting `main` prevents us from being able to test these jobs from other branches before merging. It will use `main` by default when triggered by the scheduler. Signed-off-by: James Le Cuirot <jlecuirot@microsoft.com>
There was a problem hiding this comment.
Pull request overview
This PR refactors and extends the repository’s CI automation to reduce manual overhead (auto-updates pushed directly), improve PR visibility (posting image change reports), and add routing controls for which CI system runs (GHA vs Jenkins), while also clarifying the approval-gate flow.
Changes:
- Reworks PR CI orchestration to use an explicit approval gate and adds an optional Jenkins-trigger path via the
jenkins-cilabel. - Updates release automation workflows to push certain updates directly (mantle / ca-certs), and tags generated kernel PRs with
auto-ci. - Posts generated image-changes reports back onto pull requests as PR comments from the build workflow.
Reviewed changes
Copilot reviewed 7 out of 7 changed files in this pull request and generated 7 comments.
Show a summary per file
| File | Description |
|---|---|
| .github/workflows/pr-workflows.yaml | Introduces an explicit approval gate job and adds a Jenkins-triggered CI path based on PR labels. |
| .github/workflows/mantle-releases-main.yml | Switches mantle bump automation from PR creation to committing and pushing directly. |
| .github/workflows/kernel-release.yaml | Adjusts checkout behavior and adds auto-ci label to generated kernel PRs. |
| .github/workflows/common.sh | Adds a helper to push changes with a pull/rebase retry flow. |
| .github/workflows/ci.yaml | Adds a step to post image-changes reports as PR comments. |
| .github/workflows/cacerts-release.yaml | Removes PR creation step so the ca-certs workflow can push updates directly. |
| .github/workflows/cacerts-apply-patch.sh | Switches from “prepare outputs for PR creation” to pushing changes directly. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| # Skip the environment gate for auto-ci PRs from the bot to allow | ||
| # automatic triggering without manual approval. | ||
| environment: ${{ (github.actor != 'flatcar-infra' || !contains(github.event.pull_request.labels.*.name, 'auto-ci')) && 'development' || '' }} | ||
| steps: | ||
| - name: Set outputs | ||
| id: step1 | ||
| shell: bash | ||
| run: | | ||
| echo "sdk_changes=${{ contains(github.event.pull_request.body, '/update-sdk') }}" >> $GITHUB_OUTPUT | ||
| - run: 'true' |
There was a problem hiding this comment.
@copilot I already discussed this with you, and you thought it might work. Is there a way I can test it before merging? Or is there another way I can achieve the same thing without creating a redundant environment?
There was a problem hiding this comment.
There isn’t a reliable way to test the '' branch before merge here: environment can’t be conditionally omitted with an empty value, and github.actor is just a single login, so it can’t model @flatcar-infra team membership. The clean way to do this without a redundant environment is to split the gate into two jobs: one with environment: development, and one with no environment, then let downstream jobs continue when either gate succeeds. If you still want the @flatcar-infra exception, that ungated path needs a small pre-check job that queries team membership via the API and exposes it as an output.
| env: | ||
| WORK_SCRIPTS_DIR: "${{ github.workspace }}/work" | ||
| run: | | ||
| set -euo pipefail | ||
| source "${{ github.workspace }}/gha/.github/workflows/common.sh" | ||
| set -x |
| commit=${{ steps.fetch-latest-mantle.outputs.COMMIT }} | ||
| if ! grep -q "ghcr.io/flatcar/mantle:git-${commit}" sdk_container/.repo/manifests/mantle-container; then | ||
| echo "ghcr.io/flatcar/mantle:git-${commit}" > sdk_container/.repo/manifests/mantle-container | ||
| git add sdk_container/.repo/manifests/mantle-container | ||
| fi | ||
| - name: Create pull request for branch | ||
| if: ${{ steps.figure-out-branch.outputs.SKIP == 0 }} | ||
| uses: peter-evans/create-pull-request@v6 | ||
| with: | ||
| token: ${{ secrets.BOT_PR_TOKEN }} | ||
| base: ${{ steps.figure-out-branch.outputs.BRANCH }} | ||
| branch: mantle-update-${{ steps.figure-out-branch.outputs.BRANCH }} | ||
| author: Flatcar Buildbot <buildbot@flatcar-linux.org> | ||
| committer: Flatcar Buildbot <buildbot@flatcar-linux.org> | ||
| title: Upgrade mantle container image to latest HEAD in ${{ steps.figure-out-branch.outputs.BRANCH }} | ||
| commit-message: Update mantle container image to latest HEAD | ||
| delete-branch: true | ||
| signoff: true | ||
| echo "ghcr.io/flatcar/mantle:git-${commit}" > sdk_container/.repo/manifests/mantle-container | ||
| prepare_git_repo | ||
| git commit --signoff -m "Update mantle container image to latest HEAD" sdk_container/.repo/manifests/mantle-container | ||
| push_changes_with_rebase |
| const fs = require('fs'); | ||
| const glob = require('@actions/glob'); | ||
| const globber = await glob.create('scripts/image-changes-reports*.txt'); | ||
| let body = `### Image changes reports (${{ matrix.arch }})\n\n`; | ||
| for await (const file of globber.globGenerator()) { | ||
| const name = require('path').basename(file, '.txt'); | ||
| const content = fs.readFileSync(file, 'utf8').trim(); | ||
| if (content) { | ||
| body += `<details><summary>${name}</summary>\n\n\`\`\`\n${content}\n\`\`\`\n\n</details>\n\n`; | ||
| } | ||
| } | ||
| if (body.includes('<details>')) { | ||
| await github.rest.issues.createComment({ | ||
| owner: context.repo.owner, | ||
| repo: context.repo.repo, | ||
| issue_number: context.issue.number, | ||
| body: body, | ||
| }); | ||
| } |
| function push_changes_with_rebase() { | ||
| if ! git -C "${SDK_OUTER_TOPDIR}" push; then | ||
| cleanup_repo | ||
| git -C "${SDK_OUTER_TOPDIR}" pull --rebase | ||
| git -C "${SDK_OUTER_TOPDIR}" push | ||
| fi | ||
| } |
| - name: Check out main scripts branch for GitHub workflow scripts only | ||
| uses: actions/checkout@v4 | ||
| with: | ||
| token: ${{ secrets.BOT_PR_TOKEN }} | ||
| path: gha |
| - name: Check out main scripts branch for GitHub workflow scripts only | ||
| uses: actions/checkout@v4 | ||
| with: | ||
| token: ${{ secrets.BOT_PR_TOKEN }} | ||
| path: gha |
Saves us from having to fish them out and extract them, which is sooooooo annoying! Signed-off-by: James Le Cuirot <jlecuirot@microsoft.com>
Signed-off-by: James Le Cuirot <jlecuirot@microsoft.com>
Signed-off-by: James Le Cuirot <jlecuirot@microsoft.com>
This triggers the packages_all_arches job, which should be sufficient for all automated PRs and most others. It generates a version string like main-9999.0.X-github-Y where X is the unique run number (in case we trigger more than once) and Y is the pull request ID purely for reference. The Jenkins cause field links back to the GitHub action. This doesn't add any comment to indicate that Jenkins has been triggered, but our separate Checks API integration will provide feedback independently of this. Signed-off-by: James Le Cuirot <jlecuirot@microsoft.com>
| env: | ||
| WORK_SCRIPTS_DIR: "${{ github.workspace }}/work" | ||
| run: | | ||
| set -euo pipefail | ||
| source "${{ github.workspace }}/gha/.github/workflows/common.sh" |
| echo "ghcr.io/flatcar/mantle:git-${commit}" > sdk_container/.repo/manifests/mantle-container | ||
| prepare_git_repo | ||
| git commit --signoff -m "Update mantle container image to latest HEAD" sdk_container/.repo/manifests/mantle-container | ||
| push_changes_with_rebase |
| # Skip the environment gate for auto-ci PRs from the bot to allow | ||
| # automatic triggering without manual approval. | ||
| environment: ${{ (github.actor != 'flatcar-infra' || !contains(github.event.pull_request.labels.*.name, 'auto-ci')) && 'development' || '' }} |
| with: | ||
| token: ${{ secrets.BOT_PR_TOKEN }} | ||
| path: gha |
| with: | ||
| token: ${{ secrets.BOT_PR_TOKEN }} | ||
| path: gha |
Image changes reports (arm64)image-changes-reports-nightlyimage-changes-reports-release |
Image changes reports (amd64)image-changes-reports-nightlyimage-changes-reports-release |
Test report for 4734.0.0+nightly-20260617-2100 / amd64Platforms tested : qemu_uefi-amd64 🟢 ok bpf.ig; Succeeded: qemu_uefi-amd64 (1) 🟢 ok cl.basic; Succeeded: qemu_uefi-amd64 (1) 🟢 ok cl.cloudinit.basic; Succeeded: qemu_uefi-amd64 (1) 🟢 ok cl.cloudinit.multipart-mime; Succeeded: qemu_uefi-amd64 (1) 🟢 ok cl.cloudinit.script; Succeeded: qemu_uefi-amd64 (1) 🟢 ok cl.disk.raid0.data; Succeeded: qemu_uefi-amd64 (1) 🟢 ok cl.disk.raid0.root; Succeeded: qemu_uefi-amd64 (1) 🟢 ok cl.disk.raid1.data; Succeeded: qemu_uefi-amd64 (1) 🟢 ok cl.disk.raid1.root; Succeeded: qemu_uefi-amd64 (3); Failed: qemu_uefi-amd64 (1, 2) Diagnostic output for qemu_uefi-amd64, run 2Diagnostic output for qemu_uefi-amd64, run 1🟢 ok cl.etcd-member.discovery; Succeeded: qemu_uefi-amd64 (1) 🟢 ok cl.etcd-member.etcdctlv3; Succeeded: qemu_uefi-amd64 (1) 🟢 ok cl.etcd-member.v2-backup-restore; Succeeded: qemu_uefi-amd64 (1) 🟢 ok cl.filesystem; Succeeded: qemu_uefi-amd64 (1) 🟢 ok cl.flannel.udp; Succeeded: qemu_uefi-amd64 (1) 🟢 ok cl.flannel.vxlan; Succeeded: qemu_uefi-amd64 (1) 🟢 ok cl.ignition.instantiated.enable-unit; Succeeded: qemu_uefi-amd64 (1) 🟢 ok cl.ignition.kargs; Succeeded: qemu_uefi-amd64 (1) 🟢 ok cl.ignition.luks; Succeeded: qemu_uefi-amd64 (1) 🟢 ok cl.ignition.oem.indirect; Succeeded: qemu_uefi-amd64 (1) 🟢 ok cl.ignition.oem.indirect.new; Succeeded: qemu_uefi-amd64 (1) 🟢 ok cl.ignition.oem.regular; Succeeded: qemu_uefi-amd64 (1) 🟢 ok cl.ignition.oem.regular.new; Succeeded: qemu_uefi-amd64 (1) 🟢 ok cl.ignition.oem.reuse; Succeeded: qemu_uefi-amd64 (1) 🟢 ok cl.ignition.oem.wipe; Succeeded: qemu_uefi-amd64 (1) 🟢 ok cl.ignition.partition_on_boot_disk; Succeeded: qemu_uefi-amd64 (1) 🟢 ok cl.ignition.symlink; Succeeded: qemu_uefi-amd64 (1) 🟢 ok cl.ignition.translation; Succeeded: qemu_uefi-amd64 (1) 🟢 ok cl.ignition.v1.btrfsroot; Succeeded: qemu_uefi-amd64 (1) 🟢 ok cl.ignition.v1.ext4root; Succeeded: qemu_uefi-amd64 (1) 🟢 ok cl.ignition.v1.groups; Succeeded: qemu_uefi-amd64 (1) 🟢 ok cl.ignition.v1.once; Succeeded: qemu_uefi-amd64 (1) 🟢 ok cl.ignition.v1.sethostname; Succeeded: qemu_uefi-amd64 (1) 🟢 ok cl.ignition.v1.users; Succeeded: qemu_uefi-amd64 (1) 🟢 ok cl.ignition.v1.xfsroot; Succeeded: qemu_uefi-amd64 (1) 🟢 ok cl.ignition.v2.btrfsroot; Succeeded: qemu_uefi-amd64 (1) 🟢 ok cl.ignition.v2.ext4root; Succeeded: qemu_uefi-amd64 (1) 🟢 ok cl.ignition.v2.users; Succeeded: qemu_uefi-amd64 (1) 🟢 ok cl.ignition.v2.xfsroot; Succeeded: qemu_uefi-amd64 (1) 🟢 ok cl.ignition.v2_1.ext4checkexisting; Succeeded: qemu_uefi-amd64 (1) 🟢 ok cl.ignition.v2_1.swap; Succeeded: qemu_uefi-amd64 (1) 🟢 ok cl.ignition.v2_1.vfat; Succeeded: qemu_uefi-amd64 (1) 🟢 ok cl.install.cloudinit; Succeeded: qemu_uefi-amd64 (1) 🟢 ok cl.internet; Succeeded: qemu_uefi-amd64 (1) 🟢 ok cl.locksmith.cluster; Succeeded: qemu_uefi-amd64 (1) 🟢 ok cl.network.initramfs.second-boot; Succeeded: qemu_uefi-amd64 (1) 🟢 ok cl.network.iptables; Succeeded: qemu_uefi-amd64 (1) 🟢 ok cl.network.listeners; Succeeded: qemu_uefi-amd64 (1) 🟢 ok cl.network.nftables; Succeeded: qemu_uefi-amd64 (1) 🟢 ok cl.network.wireguard; Succeeded: qemu_uefi-amd64 (1) 🟢 ok cl.omaha.ping; Succeeded: qemu_uefi-amd64 (1) 🟢 ok cl.osreset.ignition-rerun; Succeeded: qemu_uefi-amd64 (1) 🟢 ok cl.overlay.cleanup; Succeeded: qemu_uefi-amd64 (1) 🟢 ok cl.swap_activation; Succeeded: qemu_uefi-amd64 (1) 🟢 ok cl.sysext.boot; Succeeded: qemu_uefi-amd64 (1) 🟢 ok cl.sysext.fallbackdownload # SKIP; Succeeded: qemu_uefi-amd64 (1) 🟢 ok cl.tang.nonroot; Succeeded: qemu_uefi-amd64 (1) 🟢 ok cl.tang.root; Succeeded: qemu_uefi-amd64 (1) 🟢 ok cl.toolbox.dnf-install; Succeeded: qemu_uefi-amd64 (1) 🟢 ok cl.tpm.eventlog; Succeeded: qemu_uefi-amd64 (1) 🟢 ok cl.tpm.nonroot; Succeeded: qemu_uefi-amd64 (1) 🟢 ok cl.tpm.root; Succeeded: qemu_uefi-amd64 (1) 🟢 ok cl.tpm.root-cryptenroll; Succeeded: qemu_uefi-amd64 (1) 🟢 ok cl.tpm.root-cryptenroll-pcr-noupdate; Succeeded: qemu_uefi-amd64 (1) 🟢 ok cl.tpm.root-cryptenroll-pcr-withupdate; Succeeded: qemu_uefi-amd64 (1) 🟢 ok cl.update.badverity; Succeeded: qemu_uefi-amd64 (1) 🟢 ok cl.update.reboot; Succeeded: qemu_uefi-amd64 (1) 🟢 ok cl.users.shells; Succeeded: qemu_uefi-amd64 (1) 🟢 ok cl.verity; Succeeded: qemu_uefi-amd64 (1) 🟢 ok confext.skiprefresh; Succeeded: qemu_uefi-amd64 (1) 🟢 ok coreos.auth.verify; Succeeded: qemu_uefi-amd64 (1) 🟢 ok coreos.ignition.groups; Succeeded: qemu_uefi-amd64 (1) 🟢 ok coreos.ignition.once; Succeeded: qemu_uefi-amd64 (1) 🟢 ok coreos.ignition.resource.local; Succeeded: qemu_uefi-amd64 (1) 🟢 ok coreos.ignition.resource.remote; Succeeded: qemu_uefi-amd64 (1) 🟢 ok coreos.ignition.resource.s3.versioned; Succeeded: qemu_uefi-amd64 (1) 🟢 ok coreos.ignition.security.tls; Succeeded: qemu_uefi-amd64 (1) 🟢 ok coreos.ignition.sethostname; Succeeded: qemu_uefi-amd64 (1) 🟢 ok coreos.ignition.systemd.enable-service; Succeeded: qemu_uefi-amd64 (1) 🟢 ok coreos.locksmith.reboot; Succeeded: qemu_uefi-amd64 (1) 🟢 ok coreos.locksmith.tls; Succeeded: qemu_uefi-amd64 (1) 🟢 ok coreos.selinux.boolean; Succeeded: qemu_uefi-amd64 (1) 🟢 ok coreos.selinux.enforce; Succeeded: qemu_uefi-amd64 (1) 🟢 ok coreos.tls.fetch-urls; Succeeded: qemu_uefi-amd64 (1) 🟢 ok coreos.update.badusr; Succeeded: qemu_uefi-amd64 (1) ❌ not ok devcontainer.docker; Failed: qemu_uefi-amd64 (1, 2, 3, 4, 5) Diagnostic output for qemu_uefi-amd64, run 5Diagnostic output for qemu_uefi-amd64, run 4Diagnostic output for qemu_uefi-amd64, run 3Diagnostic output for qemu_uefi-amd64, run 2Diagnostic output for qemu_uefi-amd64, run 1❌ not ok devcontainer.systemd-nspawn; Failed: qemu_uefi-amd64 (1, 2, 3, 4, 5) Diagnostic output for qemu_uefi-amd64, run 5Diagnostic output for qemu_uefi-amd64, run 4Diagnostic output for qemu_uefi-amd64, run 3Diagnostic output for qemu_uefi-amd64, run 2Diagnostic output for qemu_uefi-amd64, run 1🟢 ok docker.base; Succeeded: qemu_uefi-amd64 (1) 🟢 ok docker.btrfs-storage; Succeeded: qemu_uefi-amd64 (1) 🟢 ok docker.containerd-restart; Succeeded: qemu_uefi-amd64 (1) 🟢 ok docker.enable-service.sysext; Succeeded: qemu_uefi-amd64 (1) 🟢 ok docker.lib-coreos-dockerd-compat; Succeeded: qemu_uefi-amd64 (1) 🟢 ok docker.network-openbsd-nc; Succeeded: qemu_uefi-amd64 (1) 🟢 ok docker.selinux; Succeeded: qemu_uefi-amd64 (1) 🟢 ok docker.userns; Succeeded: qemu_uefi-amd64 (1) 🟢 ok kubeadm.v1.34.4.calico.base; Succeeded: qemu_uefi-amd64 (1) 🟢 ok kubeadm.v1.34.4.cilium.base; Succeeded: qemu_uefi-amd64 (1) 🟢 ok kubeadm.v1.34.4.flannel.base; Succeeded: qemu_uefi-amd64 (1) 🟢 ok kubeadm.v1.35.1.calico.base; Succeeded: qemu_uefi-amd64 (1) 🟢 ok kubeadm.v1.35.1.cilium.base; Succeeded: qemu_uefi-amd64 (1) 🟢 ok kubeadm.v1.35.1.flannel.base; Succeeded: qemu_uefi-amd64 (1) 🟢 ok kubeadm.v1.36.1.calico.base; Succeeded: qemu_uefi-amd64 (1) 🟢 ok kubeadm.v1.36.1.cilium.base; Succeeded: qemu_uefi-amd64 (1) 🟢 ok kubeadm.v1.36.1.flannel.base; Succeeded: qemu_uefi-amd64 (1) 🟢 ok linux.nfs.v3; Succeeded: qemu_uefi-amd64 (1) 🟢 ok linux.nfs.v4; Succeeded: qemu_uefi-amd64 (1) 🟢 ok linux.ntp; Succeeded: qemu_uefi-amd64 (1) 🟢 ok misc.fips; Succeeded: qemu_uefi-amd64 (1) 🟢 ok packages; Succeeded: qemu_uefi-amd64 (1) 🟢 ok sysext.custom-docker.sysext; Succeeded: qemu_uefi-amd64 (1) ❌ not ok sysext.custom-oem; Failed: qemu_uefi-amd64 (1, 2, 3, 4, 5) Diagnostic output for qemu_uefi-amd64, run 5Diagnostic output for qemu_uefi-amd64, run 4Diagnostic output for qemu_uefi-amd64, run 3Diagnostic output for qemu_uefi-amd64, run 2Diagnostic output for qemu_uefi-amd64, run 1🟢 ok sysext.disable-containerd; Succeeded: qemu_uefi-amd64 (1) 🟢 ok sysext.disable-docker; Succeeded: qemu_uefi-amd64 (1) 🟢 ok sysext.simple; Succeeded: qemu_uefi-amd64 (1) 🟢 ok systemd.journal.remote; Succeeded: qemu_uefi-amd64 (1) 🟢 ok systemd.journal.user; Succeeded: qemu_uefi-amd64 (1) 🟢 ok systemd.sysusers.gshadow; Succeeded: qemu_uefi-amd64 (1) |
In short this:
gh workflow run cacerts-release.yaml -r chewi/pr. main was updated in d4e008e. flatcar-4722 was updated in 0eb1eef.jenkins-cilabel is present.See each commit for details.
changelog/directory (user-facing change, bug fix, security fix, update) -- N/A/bootand/usrsize, packages, list files for any missing binaries, kernel modules, config files, kernel modules, etc. -- N/A