Skip to content

Commit d646086

Browse files
committed
Check env var existence, add context class
1 parent 7d59bd5 commit d646086

1 file changed

Lines changed: 73 additions & 38 deletions

File tree

.github/scripts/merge_pr.php

Lines changed: 73 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,49 @@
22

33
declare(strict_types=1);
44

5+
class Context {
6+
public string $github_output;
7+
public string $pr_number;
8+
public string $pr_sha;
9+
public string $pr_ref;
10+
public string $pr_repo_url;
11+
public string $pr_title;
12+
public string $pr_description;
13+
public string $target_sha;
14+
public string $target_ref;
15+
/** @var list<string> */
16+
public array $release_branches;
17+
public string $pr_first_sha;
18+
}
19+
20+
function get_context(): Context {
21+
$context = new Context;
22+
23+
$env_mapping = [
24+
'PR_DESCRIPTION' => 'pr_description',
25+
'PR_NUMBER' => 'pr_number',
26+
'PR_REF' => 'pr_ref',
27+
'PR_REPO_URL' => 'pr_repo_url',
28+
'PR_SHA' => 'pr_sha',
29+
'PR_TITLE' => 'pr_title',
30+
'TARGET_REF' => 'target_ref',
31+
'TARGET_SHA' => 'target_sha',
32+
];
33+
34+
foreach ($env_mapping as $env_name => $prop_name) {
35+
$value = getenv($env_name);
36+
if ($value === false) {
37+
throw new InvalidArgumentException("Missing env var $env_name");
38+
}
39+
$context->{$prop_name} = $value;
40+
}
41+
42+
$context->release_branches = find_release_branches($context->target_ref);
43+
$context->pr_first_sha = trim(run_command("git log --reverse --format=%H {$context->target_sha}..{$context->pr_sha} | head -n1")->stdout);
44+
45+
return $context;
46+
}
47+
548
class ProcessResult {
649
public int $status = 0;
750
public string $stdout = '';
@@ -19,6 +62,9 @@ function run_command(string|array $cmd, ?string $failure_message = 'Unexpected e
1962
fwrite(STDERR, "::group::{$cmd}\n");
2063

2164
$process_handle = proc_open($cmd, $descriptor_spec, $pipes);
65+
if ($process_handle === false) {
66+
throw new RuntimeException("Failed to execute command `$cmd`");
67+
}
2268

2369
$stdin = $pipes[0];
2470
$stdout = $pipes[1];
@@ -122,20 +168,20 @@ function find_release_branches(string $target): array {
122168
return $branches;
123169
}
124170

125-
function merge_pr_into_target(string $pr_sha, string $pr_first_sha, string $target, string $message, string $description): string {
126-
$author = trim(run_command(['git', 'log', '-1', '--format=%an <%ae>', $pr_first_sha])->stdout);
171+
function merge_pr_into_target(Context $context, string $message): string {
172+
$author = trim(run_command(['git', 'log', '-1', '--format=%an <%ae>', $context->pr_first_sha])->stdout);
127173

128-
run(['git', 'checkout', '-B', $target, "refs/remotes/origin/$target"]);
129-
run(['git', 'merge', '--squash', $pr_sha],
130-
failure_message: "Failed to squash PR into $target.");
131-
run(['git', 'commit', "--author=$author", '-m', $message, '-m', wrap_commit_message($description)]);
174+
run(['git', 'checkout', '-B', $context->target_ref, "refs/remotes/origin/{$context->target_ref}"]);
175+
run(['git', 'merge', '--squash', $context->pr_sha],
176+
failure_message: "Failed to squash PR into {$context->target_ref}.");
177+
run(['git', 'commit', "--author=$author", '-m', $message, '-m', wrap_commit_message($context->pr_description)]);
132178
$squashed_sha = trim((string) shell_exec('git rev-parse HEAD'));
133179

134180
return $squashed_sha;
135181
}
136182

137-
/** @param list<string> $branches */
138-
function merge_upwards(array $branches): void {
183+
function merge_upwards(Context $context): void {
184+
$branches = $context->release_branches;
139185
for ($i = 1; $i < count($branches); $i++) {
140186
$prev = $branches[$i - 1];
141187
$current = $branches[$i];
@@ -151,8 +197,8 @@ enum PushPrBranchResult {
151197
case RemoteRejected;
152198
}
153199

154-
function push_pr_branch(string $url, string $branch, string $new_commit, string $expected_commit): PushPrBranchResult {
155-
$result = run_command(['git', 'push', "--force-with-lease=$branch:$expected_commit", $url, "$new_commit:refs/heads/$branch"], failure_message: null);
200+
function push_pr_branch(Context $context, string $new_commit): PushPrBranchResult {
201+
$result = run_command(['git', 'push', "--force-with-lease={$context->pr_ref}:{$context->pr_sha}", $context->pr_repo_url, "$new_commit:refs/heads/{$context->pr_ref}"], failure_message: null);
156202
if ($result->status === 0) {
157203
return PushPrBranchResult::Success;
158204
} else if (preg_match('(\[rejected\])', $result->stderr)) {
@@ -162,13 +208,12 @@ function push_pr_branch(string $url, string $branch, string $new_commit, string
162208
}
163209
}
164210

165-
/** @param list<string> $branches */
166-
function push_release_branches(array $branches): bool {
167-
return try_run(['git', 'push', '--atomic', 'origin', ...$branches]);
211+
function push_release_branches(Context $context): bool {
212+
return try_run(['git', 'push', '--atomic', 'origin', ...$context->release_branches]);
168213
}
169214

170-
function revert_pr_branch(string $url, string $branch, string $new_commit, string $expected_commit): void {
171-
run_command(['git', 'push', "--force-with-lease=$branch:$expected_commit", $url, "$new_commit:refs/heads/$branch"],
215+
function revert_pr_branch(Context $context, string $expected_commit): void {
216+
run_command(['git', 'push', "--force-with-lease={$context->pr_ref}:$expected_commit", $context->pr_repo_url, "{$context->pr_sha}:refs/heads/{$context->pr_ref}"],
172217
failure_message: 'Failed to push release branches. Reverting PR branch also failed.');
173218
}
174219

@@ -201,40 +246,30 @@ function wrap_commit_message(string $message, int $width = 80): string {
201246
}
202247

203248
function main(): int {
204-
$target_sha = getenv('TARGET_SHA');
205-
$target_ref = getenv('TARGET_REF');
206-
$pr_number = getenv('PR_NUMBER');
207-
$pr_sha = getenv('PR_SHA');
208-
$pr_ref = getenv('PR_REF');
209-
$pr_repo_url = getenv('PR_REPO_URL');
210-
$pr_title = getenv('PR_TITLE');
211-
$pr_description = getenv('PR_DESCRIPTION');
212249
$github_output = getenv('GITHUB_OUTPUT');
250+
if ($github_output === false) {
251+
throw new InvalidArgumentException('Missing env var GITHUB_OUTPUT');
252+
}
213253

214254
try {
215-
$release_branches = find_release_branches($target_ref);
216-
$pr_first_sha = trim(run_command("git log --reverse --format=%H $target_sha..$pr_sha | head -n1")->stdout);
255+
$context = get_context();
217256

218-
$squashed_sha = merge_pr_into_target($pr_sha, $pr_first_sha, $target_ref, "$pr_title (GH-$pr_number)", $pr_description);
219-
merge_upwards($release_branches);
220-
$push_pr_branch_result = push_pr_branch($pr_repo_url, $pr_ref, $squashed_sha, $pr_sha);
257+
$squashed_sha = merge_pr_into_target($context, "{$context->pr_title} (GH-{$context->pr_number})");
258+
merge_upwards($context);
259+
$push_pr_branch_result = push_pr_branch($context, $squashed_sha);
221260
if ($push_pr_branch_result === PushPrBranchResult::Rejected) {
222261
throw new RuntimeException('PR branch diverged.');
223262
} else if ($push_pr_branch_result === PushPrBranchResult::RemoteRejected) {
224-
if ($github_output !== false) {
225-
// Contributor likely unchecked the "Allow edits by maintainers"
226-
// checkbox. Resume and close PR manually.
227-
file_put_contents($github_output, "close_pr=1\n", FILE_APPEND);
228-
}
263+
// Contributor likely unchecked the "Allow edits by maintainers"
264+
// checkbox. Resume and close PR manually.
265+
file_put_contents($github_output, "close_pr=1\n", FILE_APPEND);
229266
}
230-
if (!push_release_branches($release_branches)) {
231-
revert_pr_branch($pr_repo_url, $pr_ref, $pr_sha, $squashed_sha);
267+
if (!push_release_branches($context)) {
268+
revert_pr_branch($context, $squashed_sha);
232269
throw new RuntimeException('Failed to push release branches.');
233270
}
234271
} catch (Throwable $e) {
235-
if ($github_output !== false) {
236-
file_put_contents($github_output, "fail_reason<<EOF\n{$e->getMessage()}\nEOF\n", FILE_APPEND);
237-
}
272+
file_put_contents($github_output, "fail_reason<<EOF\n{$e->getMessage()}\nEOF\n", FILE_APPEND);
238273
fwrite(STDERR, "::error::{$e->getMessage()}\n");
239274
return 1;
240275
}

0 commit comments

Comments
 (0)