forked from lix-project/hydra
hydra: add Coverity Scan plugin
This adds a Hydra plugin for users to submit their open source projects to the Coverity Scan system for analysis. First, add a <coverityscan> section to your Hydra config, including the access token, project name, and email, and a regex specifying jobs to upload: <coverityscan> project = testrix jobs = foobar:.*:coverity.* email = aseipp@pobox.com token = ${builtins.readFile ./coverity-token} </coverityscan> This will upload the scan results for any job whose name matches 'coverity.*' in any jobset in the Hydra 'foobar' project, for the Coverity Scan project named 'testrix'. Note that one upload will occur per job matched by the regular expression - so be careful with how many builds you upload. The jobs which are matched by the jobs specification must have a file in their output path of the form: $out/tarballs/...-cov-int.(xz|lzma|zip|bz2|tgz) The file must have the 'cov-int' directory produced by `cov-build` in the root. (You can also output something into $out/nix-support/hydra-build-products for the Hydra UI.) This file will be found in the store, and uploaded to the service directly using your access credentials. Note the exact extension: don't use .tar.xz, only use .xz specifically. Signed-off-by: Austin Seipp <aseipp@pobox.com>
This commit is contained in:
parent
6c6ce7a781
commit
4166974657
122
src/lib/Hydra/Plugin/CoverityScan.pm
Normal file
122
src/lib/Hydra/Plugin/CoverityScan.pm
Normal file
|
@ -0,0 +1,122 @@
|
||||||
|
package Hydra::Plugin::CoverityScan;
|
||||||
|
|
||||||
|
use strict;
|
||||||
|
use feature 'switch';
|
||||||
|
use parent 'Hydra::Plugin';
|
||||||
|
use File::Basename;
|
||||||
|
use LWP::UserAgent;
|
||||||
|
use Hydra::Helper::CatalystUtils;
|
||||||
|
|
||||||
|
sub buildFinished {
|
||||||
|
my ($self, $b, $dependents) = @_;
|
||||||
|
|
||||||
|
my $cfg = $self->{config}->{coverityscan};
|
||||||
|
my @config = defined $cfg ? ref $cfg eq "ARRAY" ? @$cfg : ($cfg) : ();
|
||||||
|
|
||||||
|
# Scan the job and see if it matches any of the Coverity Scan projects
|
||||||
|
my $proj;
|
||||||
|
my $jobName = showJobName $b;
|
||||||
|
foreach my $p (@config) {
|
||||||
|
next unless $jobName =~ /^$p->{jobs}$/;
|
||||||
|
|
||||||
|
# If build is cancelled or aborted, do not upload build
|
||||||
|
next if $b->buildstatus == 4 || $b->buildstatus == 3;
|
||||||
|
|
||||||
|
# Otherwise, select this Coverity project
|
||||||
|
$proj = $p; last;
|
||||||
|
}
|
||||||
|
|
||||||
|
# Bail if there's no matching project
|
||||||
|
return unless defined $proj;
|
||||||
|
|
||||||
|
# Compile submission information
|
||||||
|
my $project = $proj->{project};
|
||||||
|
my $email = $proj->{email};
|
||||||
|
my $token = $proj->{token};
|
||||||
|
my $scanurl = $proj->{scanurl} || "http://scan5.coverity.com/cgi-bin/upload.py";
|
||||||
|
|
||||||
|
# Sanity checks
|
||||||
|
die "coverity project name not configured" unless defined $project;
|
||||||
|
die "email must be specified for Coverity project '".$project."'"
|
||||||
|
unless defined $email;
|
||||||
|
die "access token must be specified for Coverity project '".$project."'"
|
||||||
|
unless defined $token;
|
||||||
|
|
||||||
|
# Get tarball locations
|
||||||
|
my $storePath = ($b->buildoutputs)[0]->path;
|
||||||
|
my $tarballs = "$storePath/tarballs";
|
||||||
|
my $covTarball;
|
||||||
|
|
||||||
|
opendir TARBALLS, $tarballs or die;
|
||||||
|
while (readdir TARBALLS) {
|
||||||
|
next unless $_ =~ /.*-coverity-int\.(tgz|lzma|xz|bz2|zip)$/;
|
||||||
|
$covTarball = "$tarballs/$_"; last;
|
||||||
|
}
|
||||||
|
closedir TARBALLS;
|
||||||
|
|
||||||
|
unless (defined $covTarball) {
|
||||||
|
print STDERR "CoverityScan.pm: Coverity tarball not found in $tarballs; skipping upload...\n";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
# Find the file mimetype
|
||||||
|
my @exts = qw(.xz .bz2 .lzma .zip .tgz);
|
||||||
|
my ($dir, $file, $ext) = fileparse($covTarball, @exts);
|
||||||
|
my $mimetype;
|
||||||
|
given ($ext) {
|
||||||
|
when ('.xz') { $mimetype = "application/x-xz"; }
|
||||||
|
when ('.lzma') { $mimetype = "application/x-xz"; }
|
||||||
|
when ('.zip') { $mimetype = "application/zip"; }
|
||||||
|
when ('.bz2') { $mimetype = "application/x-bzip2"; }
|
||||||
|
when ('.tgz') { $mimetype = "application/x-gzip"; }
|
||||||
|
default { die "couldn't parse extension of $covTarball"; }
|
||||||
|
}
|
||||||
|
|
||||||
|
die "couldn't detect mimetype of $covTarball" unless defined $mimetype;
|
||||||
|
|
||||||
|
# Parse version number from tarball
|
||||||
|
my $pkgNameRE = "(?:(?:[A-Za-z0-9]|(?:-[^0-9]))+)";
|
||||||
|
my $versionRE = "(?:[A-Za-z0-9\.\-]+)";
|
||||||
|
|
||||||
|
my $shortName = basename($covTarball);
|
||||||
|
my $version = $2 if $shortName =~ /^($pkgNameRE)-($versionRE)-coverity-int.*$/;
|
||||||
|
|
||||||
|
die "CoverityScan.pm: Couldn't parse build version for upload! ($shortName)"
|
||||||
|
unless defined $version;
|
||||||
|
|
||||||
|
# Submit build
|
||||||
|
my $jobid = $b->id;
|
||||||
|
my $desc = "Hydra Coverity Build ($jobName) - $jobid:$version";
|
||||||
|
|
||||||
|
print STDERR "uploading $desc ($shortName) to Coverity Scan\n";
|
||||||
|
|
||||||
|
my $ua = LWP::UserAgent->new();
|
||||||
|
my $resp = $ua->post($scanurl,
|
||||||
|
Content_Type => 'form-data',
|
||||||
|
Content => [
|
||||||
|
project => $project,
|
||||||
|
email => $email,
|
||||||
|
token => $token,
|
||||||
|
version => $version,
|
||||||
|
description => $desc,
|
||||||
|
file => [ $covTarball, $shortName,
|
||||||
|
Content_Type => $mimetype,
|
||||||
|
],
|
||||||
|
],
|
||||||
|
);
|
||||||
|
|
||||||
|
# The Coverity HTTP endpoint doesn't handle errors very well, and always
|
||||||
|
# returns a 200 :(
|
||||||
|
my $results = $resp->decoded_content;
|
||||||
|
if ($results =~ /ERROR!/) {
|
||||||
|
print STDERR "CoverityScan.pm: upload error - ", $resp->decoded_content, "\n";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
# Just for sanity, in case things change later
|
||||||
|
unless ($results =~ /Your request has been submitted/) {
|
||||||
|
print STDERR "CoverityScan.pm: upload error, didn't find expected response - ", $resp->decoded_content, "\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
1;
|
Loading…
Reference in a new issue