-
Notifications
You must be signed in to change notification settings - Fork 22
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add GitHub action for cloning an openQA job mentioned in a PR descrip…
…tion This GitHub action allows to clone a job when creating a PR by mentioning it in the PR description via `@openqa: Clone https://…`. Related ticket: https://progress.opensuse.org/issues/130934
- Loading branch information
Showing
6 changed files
with
172 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
--- | ||
name: 'Clone job' | ||
description: 'Clone openQA job mentioned in PR description' | ||
|
||
runs: | ||
using: composite | ||
image: registry.opensuse.org/devel/openqa/containers/tumbleweed:client | ||
steps: | ||
- uses: actions/checkout@v4 | ||
with: | ||
repository: os-autoinst/scripts | ||
path: scripts | ||
- name: Clone and monitor job mentioned in PR description | ||
run: scripts/openqa-clone-and-monitor-job-from-pr |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,106 @@ | ||
#!/usr/bin/env perl | ||
# Copyright SUSE LLC | ||
|
||
=head1 NAME | ||
openqa-clone-and-monitor-job-from-pr | ||
=head1 SYNOPSIS | ||
Clones and monitors openQA jobs mentioned in a PR description as CI action. This | ||
script is supposed to be used via the GitHub action defined in | ||
C<actions/clone-job/action.yaml> like this: | ||
=begin text | ||
--- | ||
name: Run openQA tests | ||
on: | ||
pull_request_target: | ||
workflow_dispatch: | ||
env: | ||
OPENQA_HOST: ${{ secrets.OPENQA_URL }} | ||
OPENQA_API_KEY: ${{ secrets.OPENQA_API_KEY }} | ||
OPENQA_API_SECRET: ${{ secrets.OPENQA_API_SECRET }} | ||
GH_REPO: ${{ github.event.pull_request.head.repo.full_name }} | ||
GH_REF: ${{ github.event.pull_request.head.ref }} | ||
GH_PR_BODY: ${{ github.event.pull_request.body }} | ||
jobs: | ||
clone_and_monitor_job_from_pr: | ||
steps: | ||
- uses: os-autoinst/scripts/clone-job@master | ||
=end text | ||
It will then clone and monitor an openQA job when a PR mentioning one via e.g. | ||
C<@openqa: Clone https://openqa.opensuse.org/tests/123456> is created. By | ||
default it will clone the job on o3 into the "Development / GitHub" group. To | ||
use a different openQA instance and group, set the environment variables | ||
C<OPENQA_HOST> and C<OPENQA_SCHEDULE_GROUP_ID> accordingly. | ||
For local testing you may also invoke the script manually. Have a look at the | ||
handling of environment variables at the beginning of the script code as you | ||
need to set certain additional environment variables that are normally supplied | ||
by GitHub. | ||
=back | ||
=cut | ||
|
||
package openqa_clone_and_monitor_job_from_pr; # for testing | ||
|
||
use Mojo::Base -strict, -signatures; | ||
use Mojo::JSON qw(decode_json); | ||
|
||
my $expected_url = $ENV{OPENQA_HOST} // 'https://openqa.opensuse.org'; | ||
my $group_id = $ENV{OPENQA_SCHEDULE_GROUP_ID} // 118; | ||
my $pr_body = $ENV{GH_PR_BODY} // ''; | ||
my $gh_repo = $ENV{GH_REPO} or die 'GH_REPO must be set'; | ||
my $gh_ref = $ENV{GH_REF} or die 'GH_REF must be set'; | ||
my $gh_srv = $ENV{GITHUB_SERVER_URL} or die 'GITHUB_SERVER_URL must be set'; | ||
my $api_key = $ENV{OPENQA_API_KEY} or die 'OPENQA_API_KEY must be set'; | ||
my $api_secret = $ENV{OPENQA_API_SECRET} or die 'OPENQA_API_SECRET must be set'; | ||
my @secrets = ('--apikey', $api_key, '--apisecret', $api_secret); | ||
my @vars = ("BUILD=$gh_repo.git#$gh_ref", "_GROUP_ID=$group_id", "CASEDIR=$gh_srv/$gh_repo.git#$gh_ref"); | ||
|
||
sub _parse_urls ($text) { | ||
my @urls; | ||
while ($text =~ /(\@openqa:?\s+Clone\s+(https?:[^\s]+))/ig) { | ||
push @urls, $2 if index($2, $expected_url) == 0; | ||
} | ||
return \@urls if @urls; | ||
print 'No test cloned; the PR description does not contain '; # uncoverable statement | ||
print "a command like '\@openqa: Clone $expected_url/tests/<JOB_ID>'.\n"; # uncoverable statement | ||
exit 0; | ||
} | ||
|
||
sub _handle_cmd_error ($command, @args) { | ||
if ($? == -1) { die "Failed to execute '$command @args': $!\n" } | ||
elsif ($? & 127) { die sprintf("'$command' received signal %d\n", $? & 127) } | ||
elsif ($? >> 8) { die sprintf("'$command' exited with non-zero exist status %d\n", $? >> 8) } | ||
} | ||
|
||
sub _run_cmd ($command, @args) { system $command, @args; _handle_cmd_error $command, @args } | ||
|
||
sub _run_cmd_capturing_output ($command, @args) { | ||
open my $fh, '-|', $command, @args or die "Failed to execute '$command @args': $!\n"; | ||
my $output = do { local $/; <$fh> }; | ||
close $fh; | ||
_handle_cmd_error $command, @args; | ||
return $output; | ||
} | ||
|
||
sub _clone_job ($url) { | ||
my @args = (@secrets, qw(--json-output --skip-chained-deps --within-instance), $url, @vars); | ||
my $json = _run_cmd_capturing_output 'openqa-clone-job', @args; | ||
return values %{decode_json($json)}; | ||
} | ||
|
||
sub run () { | ||
my $urls = _parse_urls($pr_body); | ||
my @job_ids = map { _clone_job $_ } @$urls; | ||
my @quoted_url_list = join(', ', map { "'$_'" } @$urls); | ||
my @job_url_list = map { "- $expected_url/tests/$_\n" } @job_ids; | ||
print "Cloned @quoted_url_list into:\n @job_url_list"; | ||
_run_cmd 'openqa-cli', 'monitor', '--host', $expected_url, @secrets, @job_ids; | ||
} | ||
|
||
run unless caller; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
#!/usr/bin/env perl | ||
|
||
use Mojo::Base -strict, -signatures; | ||
|
||
use FindBin; | ||
use Test::More; | ||
use Test::Output qw(combined_like); | ||
use Test::MockModule; | ||
|
||
$ENV{GH_REPO} = 'foo'; | ||
$ENV{GH_REF} = 'bar'; | ||
$ENV{OPENQA_HOST} = 'http://127.0.0.1:9526'; | ||
$ENV{OPENQA_API_KEY} = 'key'; | ||
$ENV{OPENQA_API_SECRET} = 'secret'; | ||
$ENV{GITHUB_SERVER_URL} = 'gh-srv-url'; | ||
$ENV{GH_PR_BODY} = 'Merge my changes | ||
@openqa: Clone http://127.0.0.1:9526/tests/4240 | ||
@openqa: Clone http://127.0.0.1:9526/tests/4239 | ||
footnote'; | ||
|
||
require "$FindBin::RealBin/../openqa-clone-and-monitor-job-from-pr"; | ||
|
||
my $mock = Test::MockModule->new('openqa_clone_and_monitor_job_from_pr', no_auto => 1); | ||
my @invoked_commands; | ||
my @clone_responses = ('{"4240" : 4246}', '{"4239" : 4245}'); | ||
$mock->redefine(_run_cmd => sub ($command, @args) { | ||
push @invoked_commands, [$command, @args]; | ||
$mock->original('_run_cmd')->('echo', @args); | ||
}); | ||
$mock->redefine(_run_cmd_capturing_output => sub ($command, @args) { | ||
push @invoked_commands, [$command, @args]; | ||
$mock->original('_run_cmd_capturing_output')->('echo', shift @clone_responses); | ||
}); | ||
|
||
combined_like { openqa_clone_and_monitor_job_from_pr::run() } | ||
qr(Cloned.*4240.*4239.*into:.*monitor --host http://127\.0\.0\.1:9526 --apikey key --apisecret secret 4246 4245)s, | ||
'monitor command invoked as expected'; | ||
|
||
my @expected_secrets = qw(--apikey key --apisecret secret); | ||
my @expected_clone_options = (@expected_secrets, qw(--json-output --skip-chained-deps --within-instance)); | ||
my @expected_vars = ('BUILD=foo.git#bar', '_GROUP_ID=118', 'CASEDIR=gh-srv-url/foo.git#bar'); | ||
my @expected_invocations; | ||
push @expected_invocations, [qw(openqa-clone-job), @expected_clone_options, "http://127.0.0.1:9526/tests/$_", @expected_vars] for 4240, 4239; | ||
push @expected_invocations, [qw(openqa-cli monitor --host http://127.0.0.1:9526), @expected_secrets, 4246, 4245]; | ||
is_deeply \@invoked_commands, \@expected_invocations, 'expected commands invoked' or diag explain \@invoked_commands; | ||
|
||
done_testing; |