hydra-notify: move StepFinished processing to an Event

[?]
Aug 12, 2021, 2:28 PM
LQEYBAEL73DCWQMK4PM6GOKIADZMHAL7O7KIIBNXN756CVOGOKDAC

Dependencies

  • [2] GE7LFZHQ hydra-notify: move buildFinished query in to the function impl
  • [3] OPSWSU4L hydra-notify: move BuildStarted processing to an Event
  • [4] GQGQEMMA Event.pm: add a new_event helper to parse and construct an Event
  • [5] OEQQ6CVT Set notificationpendingsince for dependent builds
  • [6] NTEDD7T4 Provide a plugin hook for when build steps finish
  • [7] FCTX433O Add buildStarted plugin hook
  • [8] 32KJOERM Turn hydra-notify into a daemon
  • [9] EKHD4I44 Event: init structure and parse existing messages
  • [10] IE2PRAQU hydra-queue-runner: Send build notifications
  • [11] CQZQE32V Improve handling of Perl's block eval errors
  • [12] 7Q2PXRZA hydra-notify step-finished: Don't barf if the step has no log file
  • [13] PXTSKX4G Add buildQueued plugin hook
  • [14] 4ZCUCACY hydra-notify: Fix processing notifications

Change contents

  • replacement in src/lib/Hydra/Event/StepFinished.pm at line 26
    [4.2086][4.2086:2195]()
    return bless { "build_id" => $build_id, "step_number" => $step_number, "log_path" => $log_path }, $self;
    [4.2086]
    [4.2195]
    $log_path = undef if $log_path eq "-";
    return bless {
    "build_id" => $build_id,
    "step_number" => $step_number,
    "log_path" => $log_path,
    "step" => undef,
    }, $self;
    }
    sub load {
    my ($self, $db) = @_;
    if (!defined($self->{"step"})) {
    my $build = $db->resultset('Builds')->find($self->{"build_id"})
    or die "build $self->{'build_id'} does not exist\n";
    $self->{"step"} = $build->buildsteps->find({stepnr => $self->{"step_number"}})
    or die "step $self->{'step_number'} does not exist\n";
    }
    }
    sub execute {
    my ($self, $db, $plugin) = @_;
    $self->load($db);
    $plugin->stepFinished($self->{"step"}, $self->{"log_path"});
    return 1;
  • edit in src/script/hydra-notify at line 77
    [4.4018][4.4018:4019](),[4.4019][4.2066:2128]()
    sub stepFinished {
    my ($buildId, $stepNr, $logPath) = @_;
  • edit in src/script/hydra-notify at line 78
    [4.474][4.2129:2236](),[4.2236][4.4230:4231](),[4.4230][4.4230:4231](),[4.59][4.4302:4411](),[4.4302][4.4302:4411](),[4.4411][4.2237:2279](),[4.131][4.4449:4486](),[4.2279][4.4449:4486](),[4.4449][4.4449:4486](),[4.4486][4.1034:1201](),[4.1201][4.4618:4634](),[4.4618][4.4618:4634](),[4.1903][4.3830:3833](),[4.4634][4.3830:3833](),[4.3830][4.3830:3833]()
    my $build = $db->resultset('Builds')->find($buildId)
    or die "build $buildId does not exist\n";
    my $step = $build->buildsteps->find({stepnr => $stepNr})
    or die "step $stepNr does not exist\n";
    $logPath = undef if $logPath eq "-";
    foreach my $plugin (@plugins) {
    eval {
    $plugin->stepFinished($step, $logPath);
    1;
    } or do {
    print STDERR "error with $plugin->stepFinished: $@\n";
    }
    }
    }
  • replacement in src/script/hydra-notify at line 101
    [4.235][4.235:286]()
    if ($channelName eq "build_started") {
    [4.235]
    [3.451]
    if ($channelName eq "build_started" || $channelName eq "step_finished" ) {
  • edit in src/script/hydra-notify at line 107
    [2.233][4.633:755](),[4.633][4.633:755]()
    } elsif ($channelName eq "step_finished") {
    stepFinished(int($payload[0]), int($payload[1]));
  • file addition: StepFinished.t (----------)
    [3.587]
    use strict;
    use Setup;
    my %ctx = test_init();
    require Hydra::Schema;
    require Hydra::Model::DB;
    use Hydra::Event;
    use Hydra::Event::BuildStarted;
    use Test2::V0;
    use Test2::Tools::Exception;
    use Test2::Tools::Mock qw(mock_obj);
    my $db = Hydra::Model::DB->new;
    hydra_setup($db);
    my $project = $db->resultset('Projects')->create({name => "tests", displayname => "", owner => "root"});
    my $jobset = createBaseJobset("basic", "basic.nix", $ctx{jobsdir});
    ok(evalSucceeds($jobset), "Evaluating jobs/basic.nix should exit with return code 0");
    is(nrQueuedBuildsForJobset($jobset), 3, "Evaluating jobs/basic.nix should result in 3 builds");
    for my $build (queuedBuildsForJobset($jobset)) {
    ok(runBuild($build), "Build '".$build->job."' from jobs/basic.nix should exit with return code 0");
    }
    subtest "Parsing step_finished" => sub {
    like(
    dies { Hydra::Event::parse_payload("step_finished", "") },
    qr/three arguments/,
    "empty payload"
    );
    like(
    dies { Hydra::Event::parse_payload("step_finished", "abc123") },
    qr/three arguments/,
    "one argument"
    );
    like(
    dies { Hydra::Event::parse_payload("step_finished", "abc123\tabc123") },
    qr/three arguments/,
    "two arguments"
    );
    like(
    dies { Hydra::Event::parse_payload("step_finished", "abc123\tabc123\tabc123\tabc123") },
    qr/three arguments/,
    "four arguments"
    );
    like(
    dies { Hydra::Event::parse_payload("step_finished", "abc123\t123\t/path/to/log") },
    qr/should be an integer/,
    "not an integer: first position"
    );
    like(
    dies { Hydra::Event::parse_payload("step_finished", "123\tabc123\t/path/to/log") },
    qr/should be an integer/,
    "not an integer: second argument"
    );
    is(
    Hydra::Event::parse_payload("step_finished", "123\t456\t/path/to/logfile"),
    Hydra::Event::StepFinished->new(123, 456, "/path/to/logfile")
    );
    };
    subtest "load" => sub {
    my $step = $db->resultset('BuildSteps')->search(
    { },
    { limit => 1 }
    )->next;
    my $build = $step->build;
    my $event = Hydra::Event::StepFinished->new($build->id, $step->stepnr, "/foo/bar/baz");
    $event->load($db);
    is($event->{"step"}->get_column("build"), $build->id, "The build record matches.");
    # Create a fake "plugin" with a stepFinished sub, the sub sets this
    # "global" passedStep, passedLogPath variables.
    my $passedStep;
    my $passedLogPath;
    my $plugin = {};
    my $mock = mock_obj $plugin => (
    add => [
    "stepFinished" => sub {
    my ($self, $step, $log_path) = @_;
    $passedStep = $step;
    $passedLogPath = $log_path;
    }
    ]
    );
    $event->execute($db, $plugin);
    is($passedStep->get_column("build"), $build->id, "The plugin's stepFinished hook is called with a step from the expected build");
    is($passedStep->stepnr, $step->stepnr, "The plugin's stepFinished hook is called with the proper step of the build");
    is($passedLogPath, "/foo/bar/baz", "The plugin's stepFinished hook is called with the proper log path");
    };
    done_testing;
  • edit in t/Event.t at line 4
    [4.3066][4.3066:3098]()
    use Hydra::Event::StepFinished;
  • edit in t/Event.t at line 15
    [4.3773][4.3773:4960]()
    subtest "Payload type: step_finished" => sub {
    like(
    dies { Hydra::Event::parse_payload("step_finished", "") },
    qr/three arguments/,
    "empty payload"
    );
    like(
    dies { Hydra::Event::parse_payload("step_finished", "abc123") },
    qr/three arguments/,
    "one argument"
    );
    like(
    dies { Hydra::Event::parse_payload("step_finished", "abc123\tabc123") },
    qr/three arguments/,
    "two arguments"
    );
    like(
    dies { Hydra::Event::parse_payload("step_finished", "abc123\tabc123\tabc123\tabc123") },
    qr/three arguments/,
    "four arguments"
    );
    like(
    dies { Hydra::Event::parse_payload("step_finished", "abc123\t123\t/path/to/log") },
    qr/should be an integer/,
    "not an integer: first position"
    );
    like(
    dies { Hydra::Event::parse_payload("step_finished", "123\tabc123\t/path/to/log") },
    qr/should be an integer/,
    "not an integer: second argument"
    );
    is(
    Hydra::Event::parse_payload("step_finished", "123\t456\t/path/to/logfile"),
    Hydra::Event::StepFinished->new(123, 456, "/path/to/logfile")
    );
    };