#! /usr/bin/perl

# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# package Tmp version 1.0
#
# Create temporary files/directories and ensures they are removed at
# program end.
#
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
{
  package Tmp;

  use File::Temp;
  use strict 'vars';

  sub new
  {
    my $self = {};
    my $save_tmp = shift;

    bless $self;

    my $x = $0;
    $x =~ s#.*/##;
    $x =~ s/(\s+|"|\\|')/_/;
    $x = 'tmp' if$x eq "";

    my $t = File::Temp::tempdir("/tmp/$x.XXXXXXXX", CLEANUP => $save_tmp ? 0 : 1);

    $self->{base} = $t;

    if(!$save_tmp) {
      my $s_t = $SIG{TERM};
      $SIG{TERM} = sub { File::Temp::cleanup; &$s_t if $s_t };

      my $s_i = $SIG{INT};
      $SIG{INT} = sub { File::Temp::cleanup; &$s_i if $s_i };
    }

    return $self
  }

  sub dir
  {
    my $self = shift;
    my $dir = shift;
    my $t;

    if($dir ne "" && !-e("$self->{base}/$dir")) {
      $t = "$self->{base}/$dir";
      die "error: mktemp failed\n" unless mkdir $t, 0755;
    }
    else {
      chomp ($t = `mktemp -d $self->{base}/XXXX`);
      die "error: mktemp failed\n" if $?;
    }

    return $t;
  }

  sub file
  {
    my $self = shift;
    my $file = shift;
    my $t;

    if($file ne "" && !-e("$self->{base}/$file")) {
      $t = "$self->{base}/$file";
      open my $f, ">$t";
      close $f;
    }
    else {
      chomp ($t = `mktemp $self->{base}/XXXX`);
      die "error: mktemp failed\n" if $?;
    }

    return $t;
  }

  # helper function
  sub umount
  {
    my $mp = shift;

    if(open(my $f, "/proc/mounts")) {
      while(<$f>) {
        if((split)[1] eq $mp) {
          # print STDERR "umount $mp\n";
          ::susystem("umount $mp");
          return;
        }
      }
      close $f;
    }
  }

  sub mnt
  {
    my $self = shift;
    my $dir = shift;

    my $t = $self->dir($dir);

    if($t ne '') {
      eval 'END { umount $t }';

      my $s_t = $SIG{TERM};
      $SIG{TERM} = sub { umount $t; &$s_t if $s_t };

      my $s_i = $SIG{INT};
      $SIG{INT} = sub { umount $t; &$s_i if $s_i };
    }

    return $t;
  }
}


# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
use strict;

use Getopt::Long;

use Data::Dumper;
$Data::Dumper::Sortkeys = 1;
$Data::Dumper::Terse = 1;
$Data::Dumper::Indent = 1;

our $VERSION = "1.5";

sub usage;
sub get_rc;
sub get_git_branch_and_tags;
sub get_git_package;
sub get_target;
sub update_spec;
sub update_changelog;
sub update_tag;
sub do_sr;


# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
my $config;

my $opt_sr;
my $opt_wait;
my $opt_save_temp;
my $opt_try;
my $opt_delay = 30;
my $opt_target;
my $opt_from;
my $opt_spec;
my $opt_obs;
my $opt_no_tag;

GetOptions(
  'sr=s'        => \$opt_sr,
  'wait-for-ok' => \$opt_wait,
  'delay=i'     => \$opt_delay,
  'try'         => \$opt_try,
  'target=s'    => \$opt_target,
  'from=s'      => \$opt_from,
  'spec=s'      => \$opt_spec,
  'obs=s'       => \$opt_obs,
  'no-tag'      => \$opt_no_tag,
  'save-temp'   => \$opt_save_temp,
  'version'     => sub { print "$VERSION\n"; exit 0 },
  'help'        => sub { usage 0 },
) || usage 1;

$opt_from = $opt_target if $opt_from eq "";

my $tmp = Tmp::new($opt_save_temp);   

my $tmpdir_to = $tmp->dir('to_package');
my $tmpdir_from = $tmp->dir('from_package');

$ENV{PATH} = "$ENV{HOME}/bin:/usr/bin:/bin:/usr/sbin:/sbin";

get_rc;
get_target;

exit do_sr if $opt_sr;

if($config->{to_prj} eq $config->{from_prj} && $config->{to_bs} eq $config->{from_bs}) {
  $config->{single} = 1;
  $tmpdir_from = $tmpdir_to;
}
else {
  $config->{single} = 0;
}

get_git_branch_and_tags;

chomp($config->{version} = `git2log --version`);
die "no version info\n" if $config->{version} eq "";

my @s = map { s#^[^/]*/##; $_ } glob("package/*");
@s = grep { !/\.changes$/ } @s;
die "no source files; maybe run 'make archive'\n" if !@s;

$config->{archive} = "$config->{package}-$config->{version}.tar";
for (sort @s) {
  $config->{archive} = $_, last if /^$config->{archive}/;
}
die "package/$config->{archive}: archive missing\n" unless -f "package/$config->{archive}";

@s = grep { $_ ne $config->{archive} } @s;
$config->{sources}{$_} = 1 for @s;

print "       Package: $config->{package}\n";
print "       Version: $config->{version}\n";
print "    GIT Branch: $config->{branch}\n";
print "     Spec File: $opt_spec\n" if $opt_spec;
print "   OBS Sources: $opt_obs\n" if $opt_obs;
if($config->{to_prj} eq $config->{from_prj}) {
  print "       Project: $config->{to_prj}\n";
}
else {
  print "Source Project: $config->{from_prj}\n";
  print "Target Project: $config->{to_prj}\n";
}
print "    Maintainer: $config->{email}\n";
if($config->{to_bs} eq $config->{from_bs}) {
  print "            BS: $config->{to_bs}\n";
}
else {
  print "     Source BS: $config->{from_bs}\n";
  print "     Target BS: $config->{to_bs}\n";
}
print "         TMP Dir: $tmp->{base}\n";

print "Checking out $config->{from_prj}/$config->{package}...\n";
system "cd $tmpdir_from ; osc -A https://$config->{from_bs} co -c $config->{from_prj}/$config->{package} >/dev/null";
system "ls -og $tmpdir_from/$config->{package} | tail -n +2";

if(!$config->{single}) {
  print "Checking out $config->{to_prj}/$config->{package}...\n";
  system "cd $tmpdir_to ; osc -A https://$config->{to_bs} co -c $config->{to_prj}/$config->{package} >/dev/null 2>1";
  if(! -d "$tmpdir_to/$config->{package}") {
    print "Target package missing - will be automatically created later.\n";
    $config->{create_target} = 1;
  }
  else {
    system "ls -og $tmpdir_to/$config->{package} | tail -n +2";
  }
}

my @specs = map { s#.*/##; s#\.spec$##; $_ } glob("$tmpdir_from/$config->{package}/*.spec");
if(@specs) {
  $config->{spec_name} = $specs[0];
  print "Package has several spec files; using $config->{spec_name} as base\n" if @specs > 1;
}

if($opt_spec) {
  if(open my $f, $opt_spec) {
    $config->{spec_file_alt} = [ <$f> ];
    close $f;
  }
}
elsif($opt_obs) {
  if(open my $f, "$opt_obs/$config->{spec_name}.spec") {
    $config->{spec_file_alt} = [ <$f> ];
    close $f;
  }
  else {
    die "spec file missing: $opt_obs/$config->{spec_name}.spec\n";
  }
}

if(open my $f, "$tmpdir_from/$config->{package}/$config->{spec_name}.spec") {
  $config->{spec_file} = [ <$f> ];
  close $f;
}

die "missing spec file\n" if !defined $config->{spec_file};

if(open my $f, "$tmpdir_from/$config->{package}/$config->{spec_name}.changes") {
  $config->{changes} = [ <$f> ];
  close $f;
}

die "missing changes\n" if !defined $config->{changes};

# copy OBS files
if($opt_obs) {
  system "cp $opt_obs/* $tmpdir_from/$config->{package}/";
  # keep only one spec file
  for my $s (glob "$tmpdir_from/$config->{package}/*spec") {
    unlink $s if $s !~ /\/$config->{spec_name}.spec$/;
  }
}

update_spec;

# write new spec file
if(open my $f, ">$tmpdir_from/$config->{package}/$config->{spec_name}.spec") {
  print $f @{$config->{spec_file}};
  close $f;
}

update_changelog;

my $new_changelog = "$tmpdir_from/$config->{package}/$config->{spec_name}.changes";

# write new changes file
if(open my $f, ">$new_changelog") {
  print $f @{$config->{changes}};
  close $f;
}

# delete obsolete files
for ($config->{rm_archive}, keys %{$config->{rm_sources}}, keys %{$config->{rm_patches}}) {
  # print "unlink $tmpdir_from/$config->{package}/$_\n";
  unlink "$tmpdir_from/$config->{package}/$_";
}

# copy new files except *.changes (we would overwrite our newly generated one)
rename $new_changelog, "$new_changelog.tmp";
system "cp package/* $tmpdir_from/$config->{package}/";
rename "$new_changelog.tmp", $new_changelog;

# copy changes and specs
if(@specs > 1) {
  my $base = shift @specs;
  my $theme = $base;
  $theme =~ s/.*-//;
  for my $s (@specs) {
    my $stheme = $s;
    $stheme =~ s/.*-//;
    system "cp $tmpdir_from/$config->{package}/$base.changes $tmpdir_from/$config->{package}/$s.changes";
    system "perl -ple 's/^%define\\s+(\\S+)\\s+$theme\\s*\$/%define \$1 $stheme/' $tmpdir_from/$config->{package}/$base.spec > $tmpdir_from/$config->{package}/$s.spec";
  }
}

# create new tag if needed
update_tag;

if(!$config->{single}) {
  if($config->{create_target}) {
    if(!$opt_try) {
      my $tmp_d = $tmp->dir('create');
      system "cd $tmp_d ; osc -A https://$config->{to_bs} init $config->{to_prj}";
      system "cd $tmp_d ; osc -A https://$config->{to_bs} mkpac $config->{package}";
      system "cd $tmp_d ; osc -A https://$config->{to_bs} ci -n";
      system "cd $tmpdir_to ; osc -A https://$config->{to_bs} co -c $config->{to_prj}/$config->{package} >/dev/null";
    }
    else {
      mkdir "$tmpdir_to/$config->{package}";
    }
  }

  system "rm -f $tmpdir_to/$config->{package}/*";
  system "cp -a $tmpdir_from/$config->{package}/* $tmpdir_to/$config->{package}";
}

system "cd $tmpdir_to/$config->{package} ; osc -A https://$config->{to_bs} addremove" unless $config->{create_target} && $opt_try;
print "Submitting changes to $config->{to_prj}/$config->{package}...\n";
system "cd $tmpdir_to/$config->{package} ; osc -A https://$config->{to_bs} ci -m '- release $config->{version}'" if !$opt_try;
system "ls -og $tmpdir_to/$config->{package} | tail -n +2";


# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# usage($exit_code)
#
# Print help text and exit.
#
sub usage
{
  print <<"= = = = = = = =";
Usage: tobs [OPTIONS]
Submit from git to build system.

General options:

  --target TARGET           Submit to TARGET.
                            TARGET has the form BS://PROJECT[/PACKAGE], where:
                            BS is the section name of the open build service api server,
                            as specified in .tobsrc,
                            PROJECT ist the project name,
                            PACKAGE is the (optional) package name - in case it does not
                            match the git project name.
  --from SOURCE             If specified, submit from SOURCE to TARGET. If this options
                            is not used, SOURCE = TARGET is assumed.
  --spec FILE               Use FILE as spec file template instead of the spec file from
                            the build service project.
  --obs DIR                 Commit everything in DIR to OBS. Note that *.changes is still
                            automatically created.
  --no-tag                  Don\'t create new git tag.
  --try                     Don\'t actually do anything.
  --version                 Show tobs version.
  --save-temp               Keep temporary files.
  --help                    Write this help text.

Create submit request:

  --sr BS://PROJECT         Create submit request.
  --wait-for-ok             Wait until package has built ok on at least one architecture
                            in devel project.
  --delay N                 Wait N seconds between polling for build results (default: 30).
  --package PACKAGE         Set package name to PACKAGE. If this option is missing, the
                            package name is determined from the checked out git repository.
                            If you use this option you must also specify a TARGET with
                            the --target option.

Note: You are expected to create the necessary files running 'make archive' before
using tobs.

Configuration file:

  \$HOME/.tobsrc

  Typical .ini style with entries in key=value form and section names in brackets ('[]').

  Section names are used for the BS part in the TARGET specification.
  See README for some config entry examples.

Examples:

  # submit from current git dir to foo:bar:devel project
  tobs --target obs://foo:bar:devel

  # the same, but don't actually submit the package
  tobs --try --target obs://foo:bar:devel

  # create submit request from devel project foo:bar:devel to openSUSE:Factory
  tobs --target obs://foo:bar:devel --sr obs://openSUSE:Factory

= = = = = = = =

  exit shift;
}


# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
sub get_rc
{
  my $sec;

  if(open my $f, "$ENV{HOME}/.tobsrc") {
    while(<$f>) {
      if(/^\s*\[(\S+)\]/) {
        $sec = {};
        $config->{rc}{$1} = $sec;
        next;
      }

      next unless $sec;

      if(/^\s*(\S+)\s*=\s*(\S+)/) {
        my $key = $1;
        my $val = $2;
        if($key =~ /^(\S+)\[(\S+)\]$/) {
          $sec->{$1}{$2} = $val;
        }
        else {
          $sec->{$key} = $val;
        }
      }
    }

    close $f;
  }
}


# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
sub get_git_branch_and_tags
{
  die "no git repository found\n" unless -d '.git';

  my $branch = `git2log --branch`;

  chomp $branch;

  die "failed to determine branch\n" if !$branch;

  $config->{branch} = $branch;

  if(open my $p, "git tag 2>/dev/null |") {
    while(<$p>) {
      s/\/?\s*$//;
      $config->{tags}{$_} = 1 if $_ ne "";
    }
    close $p;
  }
}


# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
sub get_git_package
{
  die "no git repository found\n" unless -d '.git';

  my $pack = `git config --get remote.origin.url 2>/dev/null`;

  if($pack =~ m#([^/.]+)\.git\s*$#) {
    $pack = $1;
  }
  elsif($pack =~ m#([^/.]+?)\s*$#) {
    $pack = $1;
  }

  $config->{package} = $pack if $pack ne "";
}


# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
sub get_target
{
  die "target spec missing; use --target option\n" if !$opt_target;

  my $bs_name;

  $config->{package} = $2 if $opt_sr =~ s#([^/])/([^/]+)$#$1#;
  $config->{package} = $2 if $opt_from =~ s#([^/])/([^/]+)$#$1#;
  $config->{package} = $2 if $opt_target =~ s#([^/])/([^/]+)$#$1#;

  $opt_sr = $config->{rc}{aliases}{$opt_sr} if $config->{rc}{aliases}{$opt_sr};
  $opt_target = $config->{rc}{aliases}{$opt_target} if $config->{rc}{aliases}{$opt_target};
  $opt_from = $config->{rc}{aliases}{$opt_from} if $config->{rc}{aliases}{$opt_from};

  if($opt_target =~ m#^([^:]+)://([^/]+)$#) {
    $bs_name = $1;
    $config->{to_bs} = $config->{rc}{$bs_name}{api};
    $config->{to_prj} = $2;
  }
  else {
    die "invalid target spec: $opt_target\n";
  }

  if($opt_from =~ m#^([^:]+)://([^/]+)$#) {
    $bs_name = $1;
    $config->{from_bs} = $config->{rc}{$bs_name}{api};
    $config->{from_prj} = $2;
  }
  else {
    die "invalid target spec: $opt_from\n";
  }

  if($opt_sr =~ m#^([^:]+)://([^/]+)$#) {
    $config->{sr}{api} = $config->{rc}{$1}{api};
    my $pref = $config->{rc}{$1}{prefix}{$bs_name};
    $config->{sr}{prefix} = "$pref:" if defined $pref;
    $config->{sr}{prj} = $2;
  }

  get_git_package if !$config->{package};

  if(!$config->{package} || !$config->{to_prj} || !$config->{to_bs} || !$config->{from_prj} || !$config->{from_bs}) {
    die "incomplete config\n  package = $config->{package}\n  dst project = $config->{to_prj}\n  dst api = $config->{to_bs}\n  src project = $config->{from_prj}\n  src api = $config->{from_bs}\n";
  }

  if($ENV{USER_NAME}) {
    $config->{email} = $ENV{USER_NAME};
  }
  elsif(open my $p, "osc -A https://$config->{from_bs} maintainer -e -B $config->{from_prj} $config->{package} |") {
    while (<$p>) {
      s/^\s+//;
      s/,.*$//;
      s/\s*$//;
      if(/\@/) {
        $config->{email} = $_;
        last;
      }
    }
    close $p;
  }

  $config->{email} = (getpwuid $<)[0] if !$config->{email};
  $config->{email} .= "\@suse.com" if $config->{email} !~ /\@/;
}


# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
sub update_spec
{
  my $spec_version;
  my $spec_name;
  my $setup = 0;

  # If the user has specified an alternative spec file source we still have
  # to scan the 'real' spec file to get the version info (to know which log
  # entries to add to the changelog).
  if($config->{spec_file_alt}) {
    for (@{$config->{spec_file}}) {
      last if /^%package\s+\-n/;

      if(/^Version:(\s*)(\S+)/) {
        $spec_version = $config->{spec_version} = $2;
        last;
      }
    }

    # the original spec is no longer needed
    $config->{spec_file} = $config->{spec_file_alt};
    delete $config->{spec_file_alt};
  }

  for (@{$config->{spec_file}}) {
    last if /^%package\s+\-n/;

    if(/^Version:(\s*)(\S+)/) {
      $spec_version = $config->{spec_version} = $2 unless defined $spec_version;
      $_ = "Version:$1$config->{version}\n";
    }

    if(/^Name:(\s*)(\S+)/) {
      # Be careful: if there are several 'Name:' lines don't do fancy stuff
      # as we are not sure which one is correct (think of %if's in the
      # spec).
      if(defined $spec_name) {
        $spec_name = '';
      }
      else {
        $spec_name = $2;
      }
    }

    if(/^Source:(\s*)((\S+)\.tar\.(bz2|gz|xz))/) {
      $config->{rm_archive} = $2;
      my $s = $1;
      my $n = $config->{archive};
      $config->{rm_archive} =~ s/%\{name\}/$spec_name/g if $spec_name ne '';
      $config->{rm_archive} =~ s/%\{version\}/$spec_version/g;
      $n =~ s/^$spec_name\-/%\{name\}-/ if $spec_name ne '';
      $n =~ s/\-$config->{version}\.tar/-%\{version\}.tar/ if $spec_version ne "";
      $_ = "Source:$s$n\n";
      my $i = 1;
      chop $s;
      for my $x (sort keys %{$config->{sources}}) {
        $_ .= "Source$i:$s$x\n";
        $i++;
      }
    }

    if(/^Source\d+:(\s*)((\S+)\.tar\.(bz2|gz|xz))/) {
      $config->{rm_sources}{$2} = 1;
      undef $_;
    }

    if(/^Patch(\d*):\s*(\S+)/) {
      $config->{rm_patches}{$2} = 1;
      print "Dropping patch: $2\n";
      undef $_;
    }

    if(/^%patch/) {
      undef $_;
    }

    if(/^%setup/) {
      if($setup) {
        undef $_;
      }
      else {
        $setup = 1;
      }
    }
  }

  $config->{spec_file} = [ grep defined, @{$config->{spec_file}} ];

  for(my $i = 1; $i < @{$config->{spec_file}}; $i++) {
    $config->{spec_file}[$i] = $config->{spec_file}[$i - 1] = undef if $config->{spec_file}[$i] =~ /^%endif/ && $config->{spec_file}[$i - 1] =~ /%ifarch\s/;
  }
}


# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
sub update_changelog
{
  my $changelog;

  if($config->{version} ne $config->{spec_version}) {
    $changelog = `git2log --changelog --format=obs --start=$config->{spec_version}`;

    die "Version $config->{spec_version} not found in changelog\n" if $changelog eq "";
  }

  my $log;

  for (sort keys %{$config->{sources}}) {
    $log .= "- adding $_\n" if !$config->{rm_sources}{$_};
  }

  for (sort keys %{$config->{rm_sources}}) {
    $log .= "- removing $_\n" if !$config->{sources}{$_};
  }

  for (sort keys %{$config->{rm_patches}}) {
    $log .= "- removing patch $_\n";
  }

  # insert at the end of the first log entry
  if($log) {
    $changelog =~ s/(\n-[^\n]*\n)\n/$1$log\n/;
  }

  if($changelog) {
    unshift @{$config->{changes}}, $changelog;

    print "New changelog entry:\n", $changelog;
  }
}


# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
sub update_tag
{
  my $tag = "$config->{branch}-$config->{version}";
  $tag =~ s/^master-//;

  if(!$config->{tags}{$tag} && !$opt_no_tag) {
    print "Creating tag $tag\n";
    system "git tag $tag ; git push origin tags/$tag" if !$opt_try;
  }
}


# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# Wait for OBS build results and submit package if we got a positive result.
#
# We loop until we see a positive build result or we're sure the OBS is not
# building anymore.
#
# The package build is considered ok if there's at least a single positive
# build at this point. If not, it has failed.
#
# Note that failed builds do not worry us as many projects are set up to
# build several targets and not all of them are expected to work.
#
sub do_sr
{
  my $sr = $config->{sr};

  print "      Package: $config->{package}\n";
  print "      Project: $sr->{prefix}$config->{to_prj}\n";
  print "    Submit To: $sr->{prj}\n";
  print "   Maintainer: $config->{email}\n";
  print "           BS: $sr->{api}\n";

  if($sr->{api} ne $config->{to_bs} && !$sr->{prefix}) {
    die "submitting from $config->{to_bs} to $sr->{api} not possible\n";
  }

  my $err = 0;

  if($opt_wait) {
    my $ok;
    my $failed;
    my $building;
    my $delay = $opt_delay;

    print "Waiting for build results of $config->{to_prj}/$config->{package}...\n";
    $| = 1;

    do {
      sleep $delay;
      if(open my $p, "osc -A https://$sr->{api} r --csv $sr->{prefix}$config->{to_prj} $config->{package} |") {
        # sample line:
        #
        # old: openSUSE_Factory|x86_64|unpublished|False|succeeded|
        # new: "openSUSE_Factory","x86_64","hwinfo","unpublished","False","succeeded",""
        #
        # field 0, 1, 2, 3: not relevant
        # field 4: False or True; if True, state is going to change
        # field 5: status
        # field 6: sometimes a 7th field is added with the real state
        #
        while (<$p>) {
          chomp;
          my @i = split /,/;
          s/^"|"$//g for @i;

          if(
            $i[4] eq "False" &&
            (
              $i[5] eq "succeeded" ||
              $i[5] eq "finished" && $i[6] eq "succeeded"
            )
          ) {
            $ok = 1;
          }
          elsif(
            $i[4] eq "False" &&
            (
              $i[5] eq "failed" ||
              $i[5] eq "unresolvable" ||
              $i[5] eq "broken" ||
              $i[5] eq "finished" && $i[6] eq "failed"
            )
          ) {
            $failed = 1;
          }
          elsif(
            $i[4] eq "False" &&
            !(
              $i[5] eq "excluded" ||
              $i[5] eq "disabled"
            )
          ) {
            $building = 1;
          }
        }
        $failed = 1 if !$building;
        close $p;
      }
      else {
        last;
      }
    } while(!$ok && $building);

    if(!$ok && $failed) {
      print "Build failed\n";

      return 1;
    }

    print "Build ok\n";
  }

  print "Creating submit request to $sr->{prj}\n";

  if(!$opt_try) {
    my $sr_resp = $tmp->file();
    my $user = $config->{email};
    $user =~ s/\@.*$//;
    system "echo y | osc -A https://$sr->{api} sr -m 'submitted by $user via jenkins' --yes --nodevelproject $sr->{prefix}$config->{to_prj} $config->{package} $sr->{prj} >$sr_resp 2>&1";
    $err = $? >> 8;

    my $resp_msg;

    if(open my $f, $sr_resp) {
      local $/ = undef;
      $resp_msg = <$f>;
      close $f;
    }

    if($err) {
      if($resp_msg =~ /The request contains no actions./) {
        $resp_msg =~ s/^.*HTTP Error 400:.*\n//m;
        $resp_msg .= "no request created\nFinished: SUCCESS\n";
        $err = 0;
      }
    }
    else {
      if($resp_msg =~ /created request id (\d+)/) {
        my $url = "$sr->{api}/request/show/$1";
        $url =~ s#^api\.#https://build.#;
        print "Submit request URL: $url\n";
      }
    }

    print $resp_msg;
  }

  return $err;
}

