mirror of
https://github.com/containers/podman.git
synced 2025-07-04 01:48:28 +08:00
Merge pull request #15722 from edsantiago/treadmill_improvements
[CI:DOCS] Buildah treadmill script: various fixes
This commit is contained in:
@ -38,10 +38,6 @@ our $Treadmill_PR_Title = 'DO NOT MERGE: buildah vendor treadmill';
|
|||||||
# Github API; this is where we query to find out the active treadmill PR
|
# Github API; this is where we query to find out the active treadmill PR
|
||||||
our $API_URL = 'https://api.github.com/graphql';
|
our $API_URL = 'https://api.github.com/graphql';
|
||||||
|
|
||||||
# Temporary file used to preserve current treadmill patches. This file
|
|
||||||
# should only exist very briefly while we perform branch operations.
|
|
||||||
our $Patch_File = "0000-$ME.patch";
|
|
||||||
|
|
||||||
# Use colors if available and if stdout is a tty
|
# Use colors if available and if stdout is a tty
|
||||||
our $C_Highlight = '';
|
our $C_Highlight = '';
|
||||||
our $C_Warning = '';
|
our $C_Warning = '';
|
||||||
@ -66,14 +62,14 @@ eval '
|
|||||||
|
|
||||||
sub usage {
|
sub usage {
|
||||||
print <<"END_USAGE";
|
print <<"END_USAGE";
|
||||||
Usage: $ME [OPTIONS] [--sync | --pick | --reset ]
|
Usage: $ME [OPTIONS] [--sync | --pick [PR] | --reset ]
|
||||||
|
|
||||||
$ME is (2022-04-20) **EXPERIMENTAL**
|
$ME is (2022-04-20) **EXPERIMENTAL**
|
||||||
|
|
||||||
$ME is intended to solve the problem of vendoring
|
$ME is intended to solve the problem of vendoring
|
||||||
buildah into podman.
|
buildah into podman.
|
||||||
|
|
||||||
Call me with one of two options:
|
Call me with one of three options:
|
||||||
|
|
||||||
--sync The usual case. Mostly used by Ed. Called from a
|
--sync The usual case. Mostly used by Ed. Called from a
|
||||||
development branch, this just updates everything so
|
development branch, this just updates everything so
|
||||||
@ -81,7 +77,8 @@ Call me with one of two options:
|
|||||||
latest-podman (main). With a few sanity checks.
|
latest-podman (main). With a few sanity checks.
|
||||||
|
|
||||||
--pick Used for really-truly vendoring in a new buildah; will
|
--pick Used for really-truly vendoring in a new buildah; will
|
||||||
cherry-pick a commit on your buildah-vendor working branch
|
cherry-pick a commit on your buildah-vendor working branch.
|
||||||
|
Optional PR arg is the ID of the treadmill PR on github.
|
||||||
|
|
||||||
--reset Used after vendoring buildah into main, when there
|
--reset Used after vendoring buildah into main, when there
|
||||||
really aren't any buildah patches to keep rolling.
|
really aren't any buildah patches to keep rolling.
|
||||||
@ -103,6 +100,7 @@ END_USAGE
|
|||||||
our %action;
|
our %action;
|
||||||
our $debug = 0;
|
our $debug = 0;
|
||||||
our $force_old_main = 0; # in --pick, proceeds even if main is old
|
our $force_old_main = 0; # in --pick, proceeds even if main is old
|
||||||
|
our $force_retry = 0; # in --sync, continue despite saved checkpoint
|
||||||
our $force_testing = 0; # in --sync, test even no podman/buildah changes
|
our $force_testing = 0; # in --sync, test even no podman/buildah changes
|
||||||
our $verbose = 0;
|
our $verbose = 0;
|
||||||
our $NOT = ''; # print "blahing the blah$NOT\n" if $debug
|
our $NOT = ''; # print "blahing the blah$NOT\n" if $debug
|
||||||
@ -114,6 +112,7 @@ sub handle_opts {
|
|||||||
'reset' => sub { $action{reset}++ },
|
'reset' => sub { $action{reset}++ },
|
||||||
|
|
||||||
'force-old-main' => \$force_old_main,
|
'force-old-main' => \$force_old_main,
|
||||||
|
'force-retry' => \$force_retry,
|
||||||
'force-testing' => \$force_testing,
|
'force-testing' => \$force_testing,
|
||||||
|
|
||||||
'debug!' => \$debug,
|
'debug!' => \$debug,
|
||||||
@ -140,11 +139,6 @@ sub main {
|
|||||||
# and there's no clean way to make it use @_.
|
# and there's no clean way to make it use @_.
|
||||||
handle_opts(); # will set package globals
|
handle_opts(); # will set package globals
|
||||||
|
|
||||||
# Fetch command-line arguments. Barf if too many.
|
|
||||||
# FIXME: if called with arg, that's the --sync branch?
|
|
||||||
# FIXME: if called with --pick + arg, that's the PR?
|
|
||||||
die "$ME: Too many arguments; try $ME --help\n" if @ARGV;
|
|
||||||
|
|
||||||
my @action = keys(%action);
|
my @action = keys(%action);
|
||||||
die "$ME: Please invoke me with one of --sync or --pick\n"
|
die "$ME: Please invoke me with one of --sync or --pick\n"
|
||||||
if ! @action;
|
if ! @action;
|
||||||
@ -158,13 +152,15 @@ sub main {
|
|||||||
# that repo is clean. None of our actions can be run on a dirty repo.
|
# that repo is clean. None of our actions can be run on a dirty repo.
|
||||||
assert_clean_repo();
|
assert_clean_repo();
|
||||||
|
|
||||||
$handler->();
|
$handler->(@ARGV);
|
||||||
}
|
}
|
||||||
|
|
||||||
###############################################################################
|
###############################################################################
|
||||||
# BEGIN sync and its helpers
|
# BEGIN sync and its helpers
|
||||||
|
|
||||||
sub do_sync {
|
sub do_sync {
|
||||||
|
die "$ME: --sync takes no arguments; try $ME --help\n" if @_;
|
||||||
|
|
||||||
# Preserve current branch name, so we can come back after switching to main
|
# Preserve current branch name, so we can come back after switching to main
|
||||||
my $current_branch = git_current_branch();
|
my $current_branch = git_current_branch();
|
||||||
|
|
||||||
@ -188,11 +184,13 @@ sub do_sync {
|
|||||||
pull_main();
|
pull_main();
|
||||||
git('checkout', '-q', $current_branch);
|
git('checkout', '-q', $current_branch);
|
||||||
|
|
||||||
# Preserve local patches. --always will generate empty patches (e.g.,
|
# Make a temporary copy of this branch
|
||||||
# after a buildah vendor when everything is copacetic); --no-signature
|
my $temp_branch = strftime("__buildah-treadmill-checkpoint/%Y%m%d-%H%M%S", localtime);
|
||||||
# prevents a buildup of "-- 2.35" (git version) lines at the end.
|
git('branch', $temp_branch, $current_branch);
|
||||||
git('format-patch', '--always', '--no-signature', "--output=$Patch_File", 'HEAD^');
|
progress("Current branch preserved as $temp_branch");
|
||||||
progress("Treadmill patches saved to $Patch_File");
|
|
||||||
|
# Get the hash of the top (treadmill) commit, to cherry-pick later
|
||||||
|
my $treadmill_commit = git('rev-parse', 'HEAD');
|
||||||
|
|
||||||
#
|
#
|
||||||
# Danger Will Robinson! This is where it gets scary: a failure here
|
# Danger Will Robinson! This is where it gets scary: a failure here
|
||||||
@ -207,7 +205,11 @@ This is not something I can recover from. Your human judgment is needed.
|
|||||||
You will need to recover from this manually. Your best option is to
|
You will need to recover from this manually. Your best option is to
|
||||||
look at the source code for this script.
|
look at the source code for this script.
|
||||||
|
|
||||||
Your treadmill patches are here: $Patch_File
|
Treadmill branch copy is preserved in $temp_branch
|
||||||
|
|
||||||
|
To restore state to where you were before this sync:
|
||||||
|
\$ git checkout main
|
||||||
|
\$ git branch -f $current_branch $treadmill_commit
|
||||||
END_FAIL_INSTRUCTIONS
|
END_FAIL_INSTRUCTIONS
|
||||||
|
|
||||||
exit 1;
|
exit 1;
|
||||||
@ -260,12 +262,34 @@ END_FAIL_INSTRUCTIONS
|
|||||||
git_commit_buildah($buildah_new);
|
git_commit_buildah($buildah_new);
|
||||||
|
|
||||||
# And, finally, this has the highest possibility of failing
|
# And, finally, this has the highest possibility of failing
|
||||||
progress('Reapplying preserved patches');
|
local $SIG{__DIE__} = sub {
|
||||||
git('am', '--empty=keep', $Patch_File);
|
print STDERR $C_Warning, "@_", <<"END_FAIL_INSTRUCTIONS";
|
||||||
|
|
||||||
# It worked! Clean up: remove our local die() handler and the patch file
|
This is not something I can recover from. Your human judgment is needed.
|
||||||
|
|
||||||
|
Chances are, you might be able to run 'git status', look for
|
||||||
|
merge conflicts, manually resolve those, 'git add', then
|
||||||
|
'git cherry-pick --continue'. If that works, run this script
|
||||||
|
again (you will probably need the --force-retry option).
|
||||||
|
|
||||||
|
If that DOES NOT work, your only option is to look at the source code
|
||||||
|
for this script. Sorry. There's only so much that can be done automatically.
|
||||||
|
|
||||||
|
Treadmill branch copy is preserved in $temp_branch
|
||||||
|
|
||||||
|
To restore state to where you were before this sync:
|
||||||
|
\$ git checkout main
|
||||||
|
\$ git branch -f $current_branch $treadmill_commit
|
||||||
|
END_FAIL_INSTRUCTIONS
|
||||||
|
|
||||||
|
exit 1;
|
||||||
|
};
|
||||||
|
progress('Reapplying treadmill patches');
|
||||||
|
git('cherry-pick', '--allow-empty', $treadmill_commit);
|
||||||
|
|
||||||
|
# It worked! Clean up: remove our local die() handler and the saved branch
|
||||||
undef $SIG{__DIE__};
|
undef $SIG{__DIE__};
|
||||||
unlink $Patch_File;
|
git('branch', '-D', $temp_branch);
|
||||||
|
|
||||||
# if buildah is unchanged, and we did not pull main, exit cleanly
|
# if buildah is unchanged, and we did not pull main, exit cleanly
|
||||||
my $change_message = '';
|
my $change_message = '';
|
||||||
@ -295,6 +319,13 @@ END_FAIL_INSTRUCTIONS
|
|||||||
|
|
||||||
progress("All OK. It's now up to you to 'git push --force'");
|
progress("All OK. It's now up to you to 'git push --force'");
|
||||||
progress(" --- Reminder: $change_message");
|
progress(" --- Reminder: $change_message");
|
||||||
|
|
||||||
|
# Kind of kludgy. If user had to retry a prior failed attempt, and
|
||||||
|
# things are now successful, remind them to delete old checkpoints.
|
||||||
|
# ($force_retry is a 'git branch -D' command string at this point.)
|
||||||
|
if ($force_retry) {
|
||||||
|
progress(" --- Retry worked! You may now $force_retry");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
###############
|
###############
|
||||||
@ -429,8 +460,9 @@ sub do_pick {
|
|||||||
assert_buildah_vendor_commit('HEAD');
|
assert_buildah_vendor_commit('HEAD');
|
||||||
progress("HEAD is a buildah vendor commit. Good.");
|
progress("HEAD is a buildah vendor commit. Good.");
|
||||||
|
|
||||||
# Identify and pull the treadmill PR
|
# Identify and pull the treadmill PR.
|
||||||
my $treadmill_pr = treadmill_pr();
|
my $treadmill_pr = shift || treadmill_pr();
|
||||||
|
|
||||||
my $treadmill_branch = "$ME/pr$treadmill_pr/tmp$$";
|
my $treadmill_branch = "$ME/pr$treadmill_pr/tmp$$";
|
||||||
progress("Fetching treadmill PR $treadmill_pr into $treadmill_branch");
|
progress("Fetching treadmill PR $treadmill_pr into $treadmill_branch");
|
||||||
git('fetch', '-q', git_upstream(), "pull/$treadmill_pr/head:$treadmill_branch");
|
git('fetch', '-q', git_upstream(), "pull/$treadmill_pr/head:$treadmill_branch");
|
||||||
@ -465,6 +497,26 @@ sub do_pick {
|
|||||||
# treadmill_pr # Returns ID of open podman PR with the desired subject
|
# treadmill_pr # Returns ID of open podman PR with the desired subject
|
||||||
##################
|
##################
|
||||||
sub treadmill_pr {
|
sub treadmill_pr {
|
||||||
|
# Github API (or maybe just the search endpoint???) is restricted.
|
||||||
|
my $token = $ENV{GITHUB_TOKEN}
|
||||||
|
or do {
|
||||||
|
warn <<"END_NEED_PR";
|
||||||
|
$ME: Cannot proceed without PR ID.
|
||||||
|
|
||||||
|
If you have a github API token, please: export GITHUB_TOKEN=.......
|
||||||
|
and re-run me.
|
||||||
|
|
||||||
|
If you do not have a github API token, please go here:
|
||||||
|
|
||||||
|
https://github.com/containers/podman/pulls?q=is%3Apr+is%3Aopen+%22buildah+vendor+treadmill%22
|
||||||
|
|
||||||
|
...then reinvoke me, adding that PR ID to the command line args.
|
||||||
|
|
||||||
|
As of 2022-09-12 the treadmill PR is 13808, but that may change over time.
|
||||||
|
END_NEED_PR
|
||||||
|
exit 1;
|
||||||
|
};
|
||||||
|
|
||||||
my $query = <<'END_QUERY';
|
my $query = <<'END_QUERY';
|
||||||
{
|
{
|
||||||
search(
|
search(
|
||||||
@ -481,16 +533,10 @@ END_QUERY
|
|||||||
$ua->agent("$ME " . $ua->agent); # Identify ourself
|
$ua->agent("$ME " . $ua->agent); # Identify ourself
|
||||||
|
|
||||||
my %headers = (
|
my %headers = (
|
||||||
|
'Authorization' => "bearer $token",
|
||||||
'Accept' => "application/vnd.github.antiope-preview+json",
|
'Accept' => "application/vnd.github.antiope-preview+json",
|
||||||
'Content-Type' => "application/json",
|
'Content-Type' => "application/json",
|
||||||
);
|
);
|
||||||
|
|
||||||
# Use github token if available, but don't require it. (All it does is
|
|
||||||
# bump up our throttling limit, which shouldn't be an issue) (unless
|
|
||||||
# someone invokes this script hundreds of times per minute).
|
|
||||||
if (my $token = $ENV{GITHUB_TOKEN}) {
|
|
||||||
$headers{Authorization} = "bearer $token";
|
|
||||||
}
|
|
||||||
$ua->default_header($_ => $headers{$_}) for keys %headers;
|
$ua->default_header($_ => $headers{$_}) for keys %headers;
|
||||||
|
|
||||||
# Massage the query: escape quotes, put it all in one line, collapse spaces
|
# Massage the query: escape quotes, put it all in one line, collapse spaces
|
||||||
@ -503,7 +549,9 @@ END_QUERY
|
|||||||
print $postquery, "\n" if $debug;
|
print $postquery, "\n" if $debug;
|
||||||
my $res = $ua->post($API_URL, Content => $postquery);
|
my $res = $ua->post($API_URL, Content => $postquery);
|
||||||
if ((my $code = $res->code) != 200) {
|
if ((my $code = $res->code) != 200) {
|
||||||
print $code, " ", $res->message, "\n";
|
warn "$ME: GraphQL request failed on $API_URL:\n";
|
||||||
|
print STDERR " ", $code, " ", $res->message, "\n";
|
||||||
|
warn "Cannot continue.\n";
|
||||||
exit 1;
|
exit 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -621,8 +669,8 @@ from the buildah vendor treadmill PR, #%s
|
|||||||
EOF
|
EOF
|
||||||
|
|
||||||
# Strip the "DO NOT MERGE" header from the treadmill PR, print only
|
# Strip the "DO NOT MERGE" header from the treadmill PR, print only
|
||||||
# the "Changes as of YYYY-MM-DD" and subsequent lines
|
# the "Changes since YYYY-MM-DD" and subsequent lines
|
||||||
sed -ne '/^Changes as of/,$ p' <$msgfile >>$tmpfile
|
sed -ne '/^Changes since /,$ p' <$msgfile >>$tmpfile
|
||||||
mv $tmpfile $msgfile
|
mv $tmpfile $msgfile
|
||||||
|
|
||||||
END_EDIT_SCRIPT
|
END_EDIT_SCRIPT
|
||||||
@ -639,6 +687,8 @@ END_EDIT_SCRIPT
|
|||||||
# BEGIN reset and its helpers
|
# BEGIN reset and its helpers
|
||||||
|
|
||||||
sub do_reset {
|
sub do_reset {
|
||||||
|
die "$ME: --sync takes no arguments; try $ME --help\n" if @_;
|
||||||
|
|
||||||
my $current_branch = git_current_branch();
|
my $current_branch = git_current_branch();
|
||||||
|
|
||||||
# Make sure side branch == main (i.e., there are no commits on the branch)
|
# Make sure side branch == main (i.e., there are no commits on the branch)
|
||||||
@ -681,21 +731,47 @@ sub progress {
|
|||||||
# assert_clean_repo # Don't even think of running with local changes
|
# assert_clean_repo # Don't even think of running with local changes
|
||||||
#######################
|
#######################
|
||||||
sub assert_clean_repo {
|
sub assert_clean_repo {
|
||||||
# Our patch file should only exist for brief moments during a sync run.
|
# During --sync we create a temporary copy of the treadmill branch,
|
||||||
# If it exists at any other time, something has gone very wrong.
|
# in case something goes wrong. The branch is deleted on success.
|
||||||
if (-e $Patch_File) {
|
# If one exists, it means we may have lost work.
|
||||||
|
my @relics = grep {
|
||||||
|
m!^__buildah-treadmill-checkpoint/\d+-\d+$!
|
||||||
|
} git('branch', '--list', '--format=%(refname:lstrip=2)');
|
||||||
|
if (@relics) {
|
||||||
|
if ($force_retry) {
|
||||||
warn <<"END_WARN";
|
warn <<"END_WARN";
|
||||||
$ME: File exists: $Patch_File
|
$ME: WARNING: leftover checkpoint(s): @relics
|
||||||
|
|
||||||
|
...continuing due to --force-retry.
|
||||||
|
|
||||||
|
If things work out, you can 'git branch -D @relics'
|
||||||
|
END_WARN
|
||||||
|
|
||||||
|
# OK, ugly override of a binary flag, but it's OK because
|
||||||
|
# it helps with user-friendliness: offer a reminder upon
|
||||||
|
# successful completion of the script.
|
||||||
|
$force_retry = "git branch -D @relics";
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
warn <<"END_WARN";
|
||||||
|
$ME: FATAL: leftover checkpoint: @relics
|
||||||
|
|
||||||
This means that something went very wrong during an earlier sync run.
|
This means that something went very wrong during an earlier sync run.
|
||||||
Your git branch may be in an inconsistent state. Your work to date
|
Your git branch may be in an inconsistent state. Your work to date
|
||||||
may be lost. This file may be your only hope of recovering it.
|
may be lost. This branch may be your only hope of recovering it.
|
||||||
|
|
||||||
This is not something a script can resolve. You need to look at this
|
This is not something a script can resolve. You need to look at this
|
||||||
file, compare to your git HEAD, and manually reconcile any differences.
|
branch, compare to your git HEAD, and manually reconcile any differences.
|
||||||
|
|
||||||
|
If you really know what you're doing, i.e., if you've reconciled
|
||||||
|
merge conflicts and have a pretty secure branch structure, try
|
||||||
|
rerunning me with --force-retry. Or, if that checkpoint is a
|
||||||
|
remnant from a past run, and you're ultra-certain that you don't
|
||||||
|
need it, you can git branch -D @relics
|
||||||
END_WARN
|
END_WARN
|
||||||
exit 1;
|
exit 1;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
# OK so far. Now check for modified files.
|
# OK so far. Now check for modified files.
|
||||||
if (my @changed = git('status', '--porcelain', '--untracked=no')) {
|
if (my @changed = git('status', '--porcelain', '--untracked=no')) {
|
||||||
@ -727,7 +803,15 @@ sub git_current_branch() {
|
|||||||
# git_forkpoint # Hash at which branch (default: cur) branched from main
|
# git_forkpoint # Hash at which branch (default: cur) branched from main
|
||||||
###################
|
###################
|
||||||
sub git_forkpoint {
|
sub git_forkpoint {
|
||||||
return git('merge-base', '--fork-point', 'main', @_);
|
# '--fork-point vendor-branch' fails silently on Paul's git tree,
|
||||||
|
# but plain merge-base works fine. My head hurts from trying to
|
||||||
|
# understand the docs, so I give up. Just try fork-point first,
|
||||||
|
# and if it fails, try without. #cargocult #gitishard
|
||||||
|
my $forkpoint = eval { git('merge-base', '--fork-point', 'main', @_) };
|
||||||
|
if ($@) {
|
||||||
|
$forkpoint = git('merge-base', 'main', @_);
|
||||||
|
}
|
||||||
|
return $forkpoint;
|
||||||
}
|
}
|
||||||
|
|
||||||
#####################
|
#####################
|
||||||
|
Reference in New Issue
Block a user