Open one auto-merging PR per package from every sync workflow
sync-upstream.yml, sync-rebuilds.yml and track-branches.yml each opened one batch PR, so one package with a failing build held back every other update in it (#788, #837). All three now group their changes with package-pr-groups.sh and hand them to package-prs.yml, which opens a PR per package and arms auto-merge. Packages pinned from the same upstream branch still share one. Green packages land on their own and only the failures stay open; a red PR conflicting with master, and each lane's old batch PR, get closed. sync-upstream.yml loses its human-merged lane: it now pushes with the PAT like the other two, so its builds start without an approval hold and its PRs auto-merge when green. min_release_age still quarantines fresh releases. Its approve job, approve-sync-push.cjs, and auto-merge-pr.cjs's exception for auto/sync-upstream go with it.
This commit is contained in:
1 parent
a7f730d1e6
commit
ba7561a34c
11 files changed
+424
-467
No files matched your search
@@ -1,34 +0,0 @@
|
||||
const approvePrWorkflows = require('./approve-pr-workflows.cjs');
|
||||
|
||||
const BOT = 'github-actions[bot]';
|
||||
|
||||
// A sync workflow pushes its branch with GITHUB_TOKEN. GitHub holds the
|
||||
// resulting pull_request runs for approval and, unlike a person's push,
|
||||
// creates no pull_request_target run, so approve-pr.yml never sees it. The
|
||||
// sync workflow therefore releases the runs for the commit it just pushed,
|
||||
// under the same rule approve-pr.yml applies: only while build-approved is
|
||||
// on the PR. The sync applies that label itself, so its pushes build without
|
||||
// a maintainer. It acts only on its own bot-authored, same-repository PR for
|
||||
// the branch and commit it pushed.
|
||||
module.exports = async function approveSyncPush({ github, context, core,
|
||||
number, branch, headSha, since, approve = approvePrWorkflows, ...options }) {
|
||||
if (!Number.isInteger(number) || !branch || !headSha || !since) {
|
||||
throw new Error('Missing sync PR number, branch, head SHA or push time.');
|
||||
}
|
||||
const { data: pr } = await github.rest.pulls.get({ ...context.repo, pull_number: number });
|
||||
const repository = `${context.repo.owner}/${context.repo.repo}`;
|
||||
if (pr.user?.login !== BOT || pr.head.repo?.full_name !== repository ||
|
||||
pr.base.repo?.full_name !== repository || pr.head.ref !== branch) {
|
||||
throw new Error(`PR #${number} is not ${BOT}'s ${branch} PR in ${repository}; refusing to approve.`);
|
||||
}
|
||||
if (pr.state !== 'open' || pr.head.sha !== headSha) {
|
||||
core.info(`PR #${number} is closed or has moved past ${headSha}; nothing to approve.`);
|
||||
return;
|
||||
}
|
||||
if (!pr.labels.some(label => label.name === 'build-approved')) {
|
||||
core.info(`PR #${number} has no build-approved label; its runs stay held.`);
|
||||
return;
|
||||
}
|
||||
await approve({ github, context, core, vouchStatus: 'bot', pullRequest: pr,
|
||||
action: 'synchronize', since, ...options });
|
||||
};
|
||||
@@ -14,9 +14,6 @@
|
||||
// test.yml runs on PRs only; an existing test may also run on master
|
||||
// (builder-images.yml runs tests/build-isolation.sh with packages: write),
|
||||
// so editing one still needs a maintainer.
|
||||
// - Not the upstream sync. It labels its own PR build-approved to release
|
||||
// GitHub's hold on its pushes, which is no one's approval; it stays on the
|
||||
// reviewed lane.
|
||||
const PACKAGES = 'pkgbuilds/';
|
||||
const TESTS = 'tests/';
|
||||
const TEST_WORKFLOW = '.github/workflows/test.yml';
|
||||
@@ -38,7 +35,6 @@ function packageChange(file) {
|
||||
if (file.filename === TEST_WORKFLOW) return file.status === 'modified' && onlyRunsTests(file.patch);
|
||||
return false;
|
||||
}
|
||||
const REVIEWED_BRANCHES = /^auto\/sync-upstream(\/|$)/;
|
||||
|
||||
function decide({ pr, files, vouchStatus, repository }) {
|
||||
if (pr.state !== 'open') return { enable: false, reason: 'PR is not open' };
|
||||
@@ -55,10 +51,6 @@ function decide({ pr, files, vouchStatus, repository }) {
|
||||
return { enable: false, reason: `author not trusted to build (${vouchStatus || 'missing'}${labelled ? ', labelled' : ''})` };
|
||||
}
|
||||
|
||||
if (pr.head.repo?.full_name === repository && REVIEWED_BRANCHES.test(pr.head.ref)) {
|
||||
return { enable: false, reason: `${pr.head.ref} stays on the reviewed lane` };
|
||||
}
|
||||
|
||||
if (!files.length) return { enable: false, reason: 'PR changes no files' };
|
||||
const outside = files.filter(file => !packageChange(file));
|
||||
if (outside.length) {
|
||||
|
||||
Executable
+36
@@ -0,0 +1,36 @@
|
||||
#!/bin/bash
|
||||
# Usage: package-pr-groups.sh BRANCH_PREFIX PATCH_OUT
|
||||
#
|
||||
# Run from the repository root after a sync has rewritten recipes in the
|
||||
# working tree. Writes those changes to PATCH_OUT and prints, as one JSON
|
||||
# line, the PRs they split into: [{"branch": ..., "packages": "a b"}, ...].
|
||||
#
|
||||
# One PR per package, so a package whose build fails holds back only itself.
|
||||
# Packages pinned from the same upstream branch (omarchy-dev and
|
||||
# omarchy-settings-dev) share a PR: sync-upstream moves them in lockstep, and
|
||||
# merging one without the other would ship the pair from different commits.
|
||||
# Branch names come from sync-pr-branch.sh, so a scheduled run and a dispatch
|
||||
# naming the same packages update the same PR.
|
||||
set -euo pipefail
|
||||
|
||||
prefix=${1:?branch prefix required}
|
||||
patch=${2:?patch path required}
|
||||
scripts=$(dirname "$0")
|
||||
|
||||
git diff --binary -- pkgbuilds > "$patch"
|
||||
|
||||
declare -A members=()
|
||||
while IFS= read -r package; do
|
||||
key=$(jq -r '(.upstream.watch? | objects | select(has("git_branch")) | "\(.git_branch)#\(.branch)") // empty' \
|
||||
"pkgbuilds/$package/.omarchy/package.json" 2>/dev/null || true)
|
||||
members["${key:-$package}"]+="$package "
|
||||
done < <(git diff --name-only -- pkgbuilds | cut -d/ -f2 | sort -u)
|
||||
|
||||
groups='[]'
|
||||
for key in "${!members[@]}"; do
|
||||
read -r -a packages <<<"${members[$key]}"
|
||||
branch=$("$scripts/sync-pr-branch.sh" "$prefix" "${packages[@]}" | sed -n 's/^branch=//p')
|
||||
groups=$(jq -c --arg branch "$branch" --arg packages "${packages[*]}" \
|
||||
'. + [{branch: $branch, packages: $packages}]' <<<"$groups")
|
||||
done
|
||||
jq -c 'sort_by(.branch)' <<<"$groups"
|
||||
Reference in new issue
Block a user