зеркало из https://github.com/mozilla/gecko-dev.git
framework changes for bootstrap b=352230 r=preed
This commit is contained in:
Родитель
4b4a6b69ab
Коммит
a53b6f184e
|
@ -5,11 +5,14 @@
|
||||||
package Bootstrap::Step;
|
package Bootstrap::Step;
|
||||||
use MozBuild::Util;
|
use MozBuild::Util;
|
||||||
use Config::General;
|
use Config::General;
|
||||||
|
use POSIX qw(strftime);
|
||||||
|
|
||||||
|
my $DEFAULT_TIMEOUT = 3600;
|
||||||
|
|
||||||
# shared static config
|
# shared static config
|
||||||
my $conf = new Config::General("bootstrap.cfg");
|
my $conf = new Config::General("bootstrap.cfg");
|
||||||
if (not $conf) {
|
if (not $conf) {
|
||||||
die "Config is null: $!";
|
die "Config is null!";
|
||||||
}
|
}
|
||||||
|
|
||||||
sub new {
|
sub new {
|
||||||
|
@ -25,23 +28,32 @@ sub Shell {
|
||||||
my %args = @_;
|
my %args = @_;
|
||||||
my $cmd = $args{'cmd'};
|
my $cmd = $args{'cmd'};
|
||||||
my $dir = $args{'dir'};
|
my $dir = $args{'dir'};
|
||||||
my $timeout = $args{'timeout'};
|
my $timeout = $args{'timeout'} ? $args{'timeout'} : $DEFAULT_TIMEOUT;
|
||||||
|
my $logFile = $args{'logFile'};
|
||||||
my $rv = '';
|
my $rv = '';
|
||||||
|
|
||||||
if ($dir) {
|
if ($dir) {
|
||||||
chdir($dir) || die "Cannot chdir to $dir: $!";
|
$this->Log('msg' => 'Changing directory to ' . $dir);
|
||||||
|
chdir($dir) or die "Cannot chdir to $dir: $!";
|
||||||
$this->Log('msg' => 'Running shell command ' . $cmd . ' in dir ' . $dir);
|
$this->Log('msg' => 'Running shell command ' . $cmd . ' in dir ' . $dir);
|
||||||
} else {
|
} else {
|
||||||
$this->Log('msg' => 'Running shell command ' . $cmd);
|
$this->Log('msg' => 'Running shell command ' . $cmd);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$this->Log('msg' => 'Starting time is ' . $this->CurrentTime());
|
||||||
|
|
||||||
|
print "Timeout: $timeout\n";
|
||||||
|
|
||||||
if ($timeout) {
|
if ($timeout) {
|
||||||
$rv = MozBuild::Util::RunShellCommand(
|
$rv = MozBuild::Util::RunShellCommand(
|
||||||
'command' => "$cmd",
|
'command' => "$cmd",
|
||||||
'timeout' => "$timeout",
|
'timeout' => "$timeout",
|
||||||
|
'logfile' => "$logFile",
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
$rv = MozBuild::Util::RunShellCommand(
|
$rv = MozBuild::Util::RunShellCommand(
|
||||||
'command' => "$cmd",
|
'command' => "$cmd",
|
||||||
|
'logfile' => "$logFile",
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -49,28 +61,32 @@ sub Shell {
|
||||||
my $timedOut = $rv->{'timedOut'};
|
my $timedOut = $rv->{'timedOut'};
|
||||||
my $signalName = $rv->{'signalName'};
|
my $signalName = $rv->{'signalName'};
|
||||||
my $dumpedCore = $rv->{'dumpedCore'};
|
my $dumpedCore = $rv->{'dumpedCore'};
|
||||||
if ($exitValue) {
|
my $pid = $rv->{'pid'};
|
||||||
if ($exitValue != 0) {
|
print "Pid: $pid\n";
|
||||||
$this->Log('msg' => "output: $rv->{'output'}");
|
|
||||||
die("shell call returned bad exit code: $exitValue");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if ($timedOut) {
|
if ($timedOut) {
|
||||||
$this->Log('msg' => "output: $rv->{'output'}");
|
$this->Log('msg' => "output: $rv->{'output'}") if $rv->{'output'};
|
||||||
die("FAIL shell call timed out after $timeout seconds");
|
die("FAIL shell call timed out after $timeout seconds");
|
||||||
}
|
}
|
||||||
if ($signalName) {
|
if ($signalName) {
|
||||||
$this->Log('msg' => "output: $rv->{'output'}");
|
|
||||||
print ("WARNING shell recieved signal $signalName");
|
print ("WARNING shell recieved signal $signalName");
|
||||||
}
|
}
|
||||||
if ($dumpedCore) {
|
if ($dumpedCore) {
|
||||||
$this->Log('msg' => "output: $rv->{'output'}");
|
$this->Log('msg' => "output: $rv->{'output'}") if $rv->{'output'};
|
||||||
die("FAIL shell call dumped core");
|
die("FAIL shell call dumped core");
|
||||||
}
|
}
|
||||||
|
if ($exitValue) {
|
||||||
|
if ($exitValue != 0) {
|
||||||
|
$this->Log('msg' => "output: $rv->{'output'}") if $rv->{'output'};
|
||||||
|
die("shell call returned bad exit code: $exitValue");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if($rc->{'output'}) {
|
if ($rv->{'output'} && not defined($logFile)) {
|
||||||
$this->Log('msg' => "output: $rv->{'output'}");
|
$this->Log('msg' => "output: $rv->{'output'}");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# current time
|
||||||
|
$this->Log('msg' => 'Ending time is ' . $this->CurrentTime());
|
||||||
}
|
}
|
||||||
|
|
||||||
sub Log {
|
sub Log {
|
||||||
|
@ -89,8 +105,8 @@ sub Config {
|
||||||
|
|
||||||
my %config = $conf->getall();
|
my %config = $conf->getall();
|
||||||
|
|
||||||
if ($config{'app'}{'firefox'}{'release'}{'1.5.0.7'}{$var}) {
|
if ($config{'app'}{$var}) {
|
||||||
return $config{'app'}{'firefox'}{'release'}{'1.5.0.7'}{$var};
|
return $config{'app'}{$var};
|
||||||
} else {
|
} else {
|
||||||
die("No such config variable: $var\n");
|
die("No such config variable: $var\n");
|
||||||
}
|
}
|
||||||
|
@ -105,30 +121,41 @@ sub CheckLog {
|
||||||
my $checkFor = $args{'checkFor'};
|
my $checkFor = $args{'checkFor'};
|
||||||
my $checkForOnly = $args{'checkForOnly'};
|
my $checkForOnly = $args{'checkForOnly'};
|
||||||
|
|
||||||
open (FILE, "< $log") || die "Cannot open file $log: $!";
|
if (not defined($log)) {
|
||||||
|
die "No log file specified";
|
||||||
|
}
|
||||||
|
|
||||||
|
open (FILE, "< $log") or die "Cannot open file $log: $!";
|
||||||
my @contents = <FILE>;
|
my @contents = <FILE>;
|
||||||
close FILE || die "Cannot close file $log: $!";
|
close FILE or die "Cannot close file $log: $!";
|
||||||
|
|
||||||
if ($notAllowed) {
|
if ($notAllowed) {
|
||||||
my @errors = grep(/$notAllowed/i, @contents);
|
my @errors = grep(/$notAllowed/i, @contents);
|
||||||
if (@errors) {
|
if (@errors) {
|
||||||
die "Errors in log ($log): \n\n @errors \n $!";
|
die "Errors in log ($log): \n\n @errors \n";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ($checkFor) {
|
if ($checkFor) {
|
||||||
if (not grep(/$checkFor/i, @contents)) {
|
if (not grep(/$checkFor/i, @contents)) {
|
||||||
die "$checkFor is not present in file $log: $!";
|
die "$checkFor is not present in file $log \n";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ($checkForOnly) {
|
if ($checkForOnly) {
|
||||||
if (not grep(/$checkForOnly/i, @contents)) {
|
if (not grep(/$checkForOnly/i, @contents)) {
|
||||||
die "$checkForOnly is not present in file $log: $!";
|
die "$checkForOnly is not present in file $log \n";
|
||||||
}
|
}
|
||||||
my @errors = grep(!/$checkForOnly/i, @contents);
|
my @errors = grep(!/$checkForOnly/i, @contents);
|
||||||
if (@errors) {
|
if (@errors) {
|
||||||
die "Errors in log ($log): \n\n @errors \n $!";
|
die "Errors in log ($log): \n\n @errors \n";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sub CurrentTime() {
|
||||||
|
my $this = shift;
|
||||||
|
my $args = @_;
|
||||||
|
|
||||||
|
return strftime("%T %D", localtime());
|
||||||
|
}
|
||||||
|
|
||||||
1;
|
1;
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
package MozBuild::Util;
|
package MozBuild::Util;
|
||||||
|
use File::Path;
|
||||||
# Stolen from the code for bug 336463
|
|
||||||
|
|
||||||
my $EXEC_TIMEOUT = '600';
|
my $EXEC_TIMEOUT = '600';
|
||||||
|
|
||||||
sub RunShellCommand {
|
sub RunShellCommand {
|
||||||
my %args = @_;
|
my %args = @_;
|
||||||
my $shellCommand = $args{'command'};
|
my $shellCommand = $args{'command'};
|
||||||
|
my $logfile = $args{'logfile'};
|
||||||
|
|
||||||
# optional
|
# optional
|
||||||
my $timeout = exists($args{'timeout'}) ? $args{'timeout'} : $EXEC_TIMEOUT;
|
my $timeout = exists($args{'timeout'}) ? $args{'timeout'} : $EXEC_TIMEOUT;
|
||||||
|
@ -24,20 +24,31 @@ sub RunShellCommand {
|
||||||
my $dumpedCore;
|
my $dumpedCore;
|
||||||
my $timedOut;
|
my $timedOut;
|
||||||
my $output = '';
|
my $output = '';
|
||||||
|
my $pid;
|
||||||
|
|
||||||
eval {
|
eval {
|
||||||
local $SIG{'ALRM'} = sub { die "alarm\n" };
|
local $SIG{'ALRM'} = sub { die "alarm\n" };
|
||||||
alarm $timeout;
|
alarm $timeout;
|
||||||
|
|
||||||
if (! $redirectStderr || $shellCommand =~ "2>&1") {
|
if (! $redirectStderr or $shellCommand =~ "2>&1") {
|
||||||
open CMD, "$shellCommand |" or die "Could not run command $shellCommand: $!";
|
$pid = open CMD, "$shellCommand |" or die "Could not run command $shellCommand: $!";
|
||||||
} else {
|
} else {
|
||||||
open CMD, "$shellCommand 2>&1 |" or die "Could not close command $shellCommand: $!";
|
$pid = open CMD, "$shellCommand 2>&1 |" or die "Could not close command $shellCommand: $!";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (defined($logfile)) {
|
||||||
|
open(LOGFILE, ">> $logfile") or die "Could not open logfile $logfile: $!";
|
||||||
|
LOGFILE->autoflush(1);
|
||||||
|
}
|
||||||
while (<CMD>) {
|
while (<CMD>) {
|
||||||
$output .= $_;
|
$output .= $_;
|
||||||
print $_ if ($printOutputImmediately);
|
print $_ if ($printOutputImmediately);
|
||||||
|
if (defined($logfile)) {
|
||||||
|
print LOGFILE $_;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (defined($logfile)) {
|
||||||
|
close(LOGFILE) or die "Could not close logfile $logfile: $!";
|
||||||
}
|
}
|
||||||
|
|
||||||
close CMD;# or die "Could not close command: $!";
|
close CMD;# or die "Could not close command: $!";
|
||||||
|
@ -51,13 +62,14 @@ sub RunShellCommand {
|
||||||
if ($@) {
|
if ($@) {
|
||||||
if ($@ eq "alarm\n") {
|
if ($@ eq "alarm\n") {
|
||||||
$timedOut = 1;
|
$timedOut = 1;
|
||||||
|
kill(9, $pid) or die "Could not kill timed-out $pid: $!";
|
||||||
} else {
|
} else {
|
||||||
warn "Error running $shellCommand: $@\n";
|
warn "Error running $shellCommand: $@\n";
|
||||||
$output = $@;
|
$output = $@;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($exitValue || $timedOut || $dumpedCore || $signalNum) {
|
if ($exitValue or $timedOut or $dumpedCore or $signalNum) {
|
||||||
if ($timedOut) {
|
if ($timedOut) {
|
||||||
# callers expect exitValue to be non-zero if request timed out
|
# callers expect exitValue to be non-zero if request timed out
|
||||||
$exitValue = 1;
|
$exitValue = 1;
|
||||||
|
@ -68,7 +80,32 @@ sub RunShellCommand {
|
||||||
exitValue => $exitValue,
|
exitValue => $exitValue,
|
||||||
sigName => $sigName,
|
sigName => $sigName,
|
||||||
output => $output,
|
output => $output,
|
||||||
dumpedCore => $dumpedCore };
|
dumpedCore => $dumpedCore,
|
||||||
|
pid => $pid,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
## This is a wrapper function to get easy true/false return values from a
|
||||||
|
## mkpath()-like function. mkpath() *actually* returns the list of directories
|
||||||
|
## it created in the pursuit of your request, and keeps its actual success
|
||||||
|
## status in $@.
|
||||||
|
|
||||||
|
sub MkdirWithPath
|
||||||
|
{
|
||||||
|
my %args = @_;
|
||||||
|
|
||||||
|
my $dirToCreate = $args{'dir'};
|
||||||
|
my $printProgress = $args{'printProgress'};
|
||||||
|
my $dirMask = $args{'dirMask'};
|
||||||
|
|
||||||
|
die "ASSERT: MkdirWithPath() needs an arg" if not defined($dirToCreate);
|
||||||
|
|
||||||
|
## Defaults based on what mkpath does...
|
||||||
|
$printProgress = defined($printProgress) ? $printProgress : 0;
|
||||||
|
$dirMask = defined($dirMask) ? $dirMask : 0777;
|
||||||
|
|
||||||
|
eval { mkpath($dirToCreate, $printProgress, $dirMask) };
|
||||||
|
return defined($@);
|
||||||
}
|
}
|
||||||
|
|
||||||
1;
|
1;
|
||||||
|
|
|
@ -4,10 +4,33 @@ Bootstrap Release
|
||||||
Bootstrap is a release automation tool.
|
Bootstrap is a release automation tool.
|
||||||
Use "release -h" for help.
|
Use "release -h" for help.
|
||||||
|
|
||||||
Tools run first
|
Pre-flight Checklist
|
||||||
-----------------
|
-----------------
|
||||||
* checklist/config generator
|
There are a number of manual steps that must be performed, so a default
|
||||||
* version bump tool
|
end-to-end run will generally not work.
|
||||||
|
|
||||||
|
Before any steps:
|
||||||
|
|
||||||
|
* verify shipped-locales
|
||||||
|
* edit bootstrap.cfg
|
||||||
|
* edit tinder-config.pl/mozconfig
|
||||||
|
* version bump
|
||||||
|
|
||||||
|
After Build and Repack steps:
|
||||||
|
|
||||||
|
* rsync builds to candidates dir
|
||||||
|
|
||||||
|
After the Update step:
|
||||||
|
|
||||||
|
* edit patcher config
|
||||||
|
* edit mozilla/testing/release/updates/updates.cfg
|
||||||
|
|
||||||
|
After Sign step:
|
||||||
|
|
||||||
|
* create bouncer links
|
||||||
|
* rsync builds to mirrors
|
||||||
|
* wait 12 hours for mirrors to catch up
|
||||||
|
* rsync production AUS config
|
||||||
|
|
||||||
Steps are in dependency order. The process may be restarted at any step as
|
Steps are in dependency order. The process may be restarted at any step as
|
||||||
long as all previous steps are satisfied.
|
long as all previous steps are satisfied.
|
||||||
|
@ -16,53 +39,46 @@ PASS/FAIL verification is run after every step.
|
||||||
|
|
||||||
Steps
|
Steps
|
||||||
-----------------
|
-----------------
|
||||||
1) tag
|
1) Tag
|
||||||
2) build
|
2) Build
|
||||||
2.1) push
|
2.1) Push
|
||||||
2.2) announce
|
2.2) Announce
|
||||||
3) source
|
3) Source
|
||||||
4) repack
|
4) Repack
|
||||||
4.1) push
|
4.1) Push
|
||||||
4.2) announce
|
4.2) Announce
|
||||||
5) updates
|
5) Updates
|
||||||
5.1) push
|
5.1) Push
|
||||||
5.2) announce
|
5.2) Announce
|
||||||
6) stage
|
6) Stage
|
||||||
6.1) merge
|
6.1) Merge
|
||||||
6.2) announce
|
6.2) Announce
|
||||||
7) sign
|
7) Sign
|
||||||
8) release
|
|
||||||
8.1) announce
|
|
||||||
|
|
||||||
Details
|
Details
|
||||||
-----------------
|
-----------------
|
||||||
tag
|
Tag
|
||||||
_RELEASE and _RCn for mozilla and talkback
|
_RELEASE and _RCn for mozilla, l10n and talkback
|
||||||
build
|
Build
|
||||||
en-US build from source (based on tag)
|
en-US build from source (based on tag)
|
||||||
push to stage
|
push to stage
|
||||||
announce
|
announce
|
||||||
source
|
Source
|
||||||
bz2 archive based on tag
|
bz2 archive (based on tag)
|
||||||
push to stage
|
push to stage
|
||||||
repack
|
Repack
|
||||||
repack l10n, uses en-US build
|
repack l10n, uses en-US build (based on tag)
|
||||||
push to stage
|
push to stage
|
||||||
announce
|
announce
|
||||||
updates
|
Updates
|
||||||
uses patcher
|
uses patcher
|
||||||
generate partials and AUS config ("snippets")
|
generate partials and AUS config ("snippets")
|
||||||
push to stage
|
push to stage
|
||||||
announce
|
announce
|
||||||
stage
|
Stage
|
||||||
uses groom-files
|
uses groom-files
|
||||||
create release directory/filename structure
|
create release directory/filename structure
|
||||||
merge updates
|
merge updates
|
||||||
announce
|
announce
|
||||||
sign
|
Sign
|
||||||
manual
|
manual
|
||||||
release
|
|
||||||
create bouncer links
|
|
||||||
rsync builds to mirrors
|
|
||||||
rsync production AUS config
|
|
||||||
announce
|
|
||||||
|
|
|
@ -1,13 +1,23 @@
|
||||||
<app firefox>
|
<app>
|
||||||
<release 1.5.0.7>
|
productTag = FIREFOX_1_6_0_7
|
||||||
productTag = FIREFOX_1_5_0_7
|
branchTag = MOZILLA_1_8_0_BRANCH
|
||||||
branchTag = MOZILLA_1_8_0_7
|
pullDate = 2006-11-03 12:00 PDT
|
||||||
pullDate = 2006-09-06 18:00 PDT
|
rc = 1
|
||||||
rc = 1
|
version = 1.6.0.7
|
||||||
version = 1.5.0.7
|
oldVersion = 1.5.0.7
|
||||||
appName = browser
|
appName = browser
|
||||||
product = firefox
|
product = firefox
|
||||||
buildDir = /builds/tinderbox/
|
buildDir = /builds/tinderbox/Fx-Mozilla1.8.0-Release
|
||||||
pushDate = 2006090601
|
l10n-buildDir = /builds/tinderbox/Fx-Mozilla1.8.0-l10n-Release
|
||||||
</release>
|
pushDate = 2006-10-30-22
|
||||||
|
logDir = /builds/release/logs
|
||||||
|
mozillaCvsroot = /builds/cvsmirror/cvsroot
|
||||||
|
l10nCvsroot = /builds/cvsmirror/l10n
|
||||||
|
mofoCvsroot = /builds/cvsmirror/mofo
|
||||||
|
stageHome = /data/cltbld
|
||||||
|
updateDir = /builds/updates
|
||||||
|
verifyDir = /builds/verify
|
||||||
|
patcherConfig = moz180-branch-patcher2.cfg
|
||||||
|
tagDir = /builds/tags
|
||||||
|
buildPlatform = Linux_2.4.21-37.EL_Depend
|
||||||
</app>
|
</app>
|
||||||
|
|
|
@ -33,7 +33,7 @@ sub main {
|
||||||
sub ProcessArgs {
|
sub ProcessArgs {
|
||||||
GetOptions(
|
GetOptions(
|
||||||
\%config,
|
\%config,
|
||||||
"step|s=s", "only|o=s", "list|l", "help|h",
|
"step|s=s", "only|o=s", "list|l", "help|h", "execute|e", "verify|v",
|
||||||
);
|
);
|
||||||
|
|
||||||
if ($config{'list'}) {
|
if ($config{'list'}) {
|
||||||
|
@ -45,10 +45,12 @@ sub ProcessArgs {
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($config{'help'}) {
|
if ($config{'help'}) {
|
||||||
print "Usage: release [-l] [-s Step] [-o Step] [-h]\n";
|
print "Usage: release [-l] [-s Step] [-o Step] [-e | v] [-h]\n";
|
||||||
print " -l list all Steps\n";
|
print " -l list all Steps\n";
|
||||||
print " -s start at Step\n";
|
print " -s start at Step\n";
|
||||||
print " -o only run one Step\n";
|
print " -o only run one Step\n";
|
||||||
|
print " -e only run Execute\n";
|
||||||
|
print " -v only run Verify\n";
|
||||||
print " -h this usage message\n";
|
print " -h this usage message\n";
|
||||||
exit(0);
|
exit(0);
|
||||||
}
|
}
|
||||||
|
@ -103,8 +105,16 @@ sub PerformStep {
|
||||||
print "Bootstrap running $stepName\n";
|
print "Bootstrap running $stepName\n";
|
||||||
my $step = "Bootstrap::Step::$stepName"->new();
|
my $step = "Bootstrap::Step::$stepName"->new();
|
||||||
eval {
|
eval {
|
||||||
$step->Execute();
|
if (defined($config{'execute'})) {
|
||||||
$step->Verify();
|
print "Bootstrap only running Execute\n";
|
||||||
|
$step->Execute();
|
||||||
|
} elsif (defined($config{'verify'})) {
|
||||||
|
print "Bootstrap only running Verify\n";
|
||||||
|
$step->Verify();
|
||||||
|
} else {
|
||||||
|
$step->Execute();
|
||||||
|
$step->Verify();
|
||||||
|
}
|
||||||
};
|
};
|
||||||
if ($@)
|
if ($@)
|
||||||
{
|
{
|
||||||
|
|
|
@ -12,7 +12,7 @@ sub Execute {
|
||||||
}
|
}
|
||||||
|
|
||||||
eval {
|
eval {
|
||||||
$this->Shell( 'cmd' => 'true' );
|
$this->Shell( 'cmd' => 'true', logFile => 't/test.log' );
|
||||||
};
|
};
|
||||||
|
|
||||||
if ($@) {
|
if ($@) {
|
||||||
|
@ -20,7 +20,7 @@ sub Execute {
|
||||||
}
|
}
|
||||||
|
|
||||||
eval {
|
eval {
|
||||||
$this->Shell( 'cmd' => 'false' );
|
$this->Shell( 'cmd' => 'false', logFile => 't/test.log' );
|
||||||
};
|
};
|
||||||
|
|
||||||
if (not $@) {
|
if (not $@) {
|
||||||
|
@ -63,7 +63,7 @@ sub Execute {
|
||||||
|
|
||||||
sub Verify {
|
sub Verify {
|
||||||
my $this = shift;
|
my $this = shift;
|
||||||
$this->Shell('cmd' => 'echo Verify tag');
|
$this->Shell('cmd' => 'echo Verify tag', logFile => 't/test.log');
|
||||||
$this->Log('msg' => 'finished');
|
$this->Log('msg' => 'finished');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,3 +2,10 @@ success
|
||||||
failed
|
failed
|
||||||
success
|
success
|
||||||
failed
|
failed
|
||||||
|
Verify tag
|
||||||
|
Verify tag
|
||||||
|
Verify tag
|
||||||
|
Verify tag
|
||||||
|
Verify tag
|
||||||
|
Verify tag
|
||||||
|
Verify tag
|
||||||
|
|
Загрузка…
Ссылка в новой задаче