# file      : tests/publish.testscript
# license   : MIT; see accompanying LICENSE file

.include common.testscript project.testscript

# bdep-publish requirements for the minimum supported git version are higher
# then the default 2.1.0 (see bdep/publish.cxx for details).
#
+if! ($git_version_major >  2 || \
      $git_version_major == 2 && $git_version_minor >= 11)
  exit
end

repository = $config.bdep.tests.publish.repository

+if ("$repository" == '')
  exit
end

test.arguments += --repository "$repository"  --yes \
 --author-name user --author-email user@example.com

config_cxx = [cmdline] cc config.cxx=$quote($recall($cxx.path) $cxx.config.mode, true)

new  += --vcs git,branch=master 2>!
init += $config_cxx -d prj 2>! &prj/**/bootstrap/***

windows = ($cxx.target.class == 'windows')

g = [cmdline] git -C prj >! 2>!

# Note that using the same package name and version for tests may result in
# duplicate submissions. We will use unique version for each test,
# incrementing the patch version for 1.0.X.
#
# Next version to use: 1.0.22
#

# Normally we disable the progress indication that complicates stderr output
# validation. We also disable the progress indication test on Windows, as
# curl's progress is not always properly terminated there, messing up with
# the subsequent output.
#
: submit
:
{
  test.arguments += --control 'none'

  +$clone_prj

  : single-pkg
  :
  {
    test.arguments += --force=uncommitted --simulate 'success'

    : single-cfg
    :
    {
      $clone_root_prj;
      $init -C @cfg &prj-cfg/***;
      sed -i -e 's/^(version:) .*$/\1 1.0.1/' prj/manifest;

      $* --no-progress 2>>~%EOE%
        synchronizing:
          upgrade prj/1.0.1
        %package submission is queued(: \.*prj/1.0.1)?%d
        %reference: .{12}%
        EOE
    }

    : progress
    :
    if! $windows
    {
      $clone_root_prj;
      $init -C @cfg &prj-cfg/***;
      sed -i -e 's/^(version:) .*$/\1 1.0.19/' prj/manifest;

      $* 2>>~%EOE%
        synchronizing:
          upgrade prj/1.0.19
        submitting prj-1.0.19.tar.gz
        %.*
        %package submission is queued(: \.*prj/1.0.19)?%d
        %reference: .{12}%
        EOE
    }

    : no-cfg
    :
    {
      $clone_root_prj;

      $* 2>>~%EOE% != 0
        %error: no default configuration in project .+%
          info: use (@<cfg-name> | --config|-c <cfg-dir> | --all|-a) to specify configuration explicitly
        EOE
    }

    : multi-cfg
    :
    {
      $clone_root_prj;
      $init -C @cfg1 &prj-cfg1/***;
      $init -C @cfg2 &prj-cfg2/***;

      $* --all 2>>EOE != 0
        error: package prj is initialized in multiple specified configurations
          info: @cfg1
          info: @cfg2
        EOE
    }

    : snapshot
    :
    {
      $clone_root_prj;
      $init -C @cfg &prj-cfg/***;
      sed -i -e 's/^(version:) .*$/\1 1.0.15-a.0.z/' prj/manifest;

      $* 2>>EOE != 0;
        synchronizing:
          upgrade prj/1.0.15-a.0.19700101000000
        error: package prj version 1.0.15-a.0.19700101000000 is a snapshot
        EOE

      $* --force=snapshot 2>>~%EOE% != 0
        error: package prj version 1.0.15-a.0.19700101000000 is a snapshot
        EOE
    }

    : non-standard-version
    :
    : Test publishing a package with the non-standard version from a
    : non-bdep-initialized project, using the forwarded build2 configuration.
    :
    {
      $new --no-init --no-amalgamation prj 2>- &prj/***;
      sed -i -e 's/^(version:) .*$/\1 12345/' prj/manifest;

      sed -i \
          -e 's/^(amalgamation =.*)$/\1\nversion = 12345\ndist.package = $project-$version/' \
          -e 's/^using version$//' \
          prj/build/bootstrap.build;

      $build 'configure:' prj/@prj-cfg/,forward &prj/build/bootstrap/*** 2>!;

      $* --no-progress --forward --section alpha 2>>~%EOE%
        %package submission is queued(: .*prj/12345)?%
        %reference: .{12}%
        EOE
    }
  }

  : multi-pkg
  :
  {
    test.options += --no-progress
    test.arguments += --force=uncommitted --simulate 'success'

    +$new -t empty prj &prj/***
    +$new --package -t lib libprj -d prj
    +$new --package -t exe prj    -d prj

    : both
    :
    {
      $clone_prj;
      sed -i -e 's/^(version:) .*$/\1 1.0.2/' prj/libprj/manifest;
      sed -i -e 's/^(version:) .*$/\1 1.0.2/' prj/prj/manifest;
      $init -C @cfg &prj-cfg/***;

      $* 2>>~%EOE%
        %package submission is queued(: \.*libprj/1.0.2)?%d
        %reference: .{12}%
        %package submission is queued(: \.*prj/1.0.2)?%d
        %reference: .{12}%
        EOE
    }

    : diff-configs
    :
    {
      $clone_prj;
      sed -i -e 's/^(version:) .*$/\1 1.0.20/' prj/libprj/manifest;
      sed -i -e 's/^(version:) .*$/\1 1.0.20/' prj/prj/manifest;

      $init -C @cfg1                    -d prj/libprj &prj-cfg1/***;
      $init -C @cfg2 --config-type host -d prj/prj    &prj-cfg2/***;

      $* 2>>~%EOE%
        %package submission is queued(: \.*libprj/1.0.20)?%d
        %reference: .{12}%
        %package submission is queued(: \.*prj/1.0.20)?%d
        %reference: .{12}%
        EOE
    }

    : diff-configs-forward
    :
    {
      $clone_prj;
      sed -i -e 's/^(version:) .*$/\1 1.0.21/' prj/libprj/manifest;
      sed -i -e 's/^(version:) .*$/\1 1.0.21/' prj/prj/manifest;

      $init -C @cfg1                    --no-default --forward -d prj/libprj &prj-cfg1/***;
      $init -C @cfg2 --config-type host --no-default --forward -d prj/prj    &prj-cfg2/***;

      $* --forward 2>>~%EOE%
        %package submission is queued(: \.*libprj/1.0.21)?%d
        %reference: .{12}%
        %package submission is queued(: \.*prj/1.0.21)?%d
        %reference: .{12}%
        EOE
    }

    : single
    :
    {
      $clone_prj;
      sed -i -e 's/^(version:) .*$/\1 1.0.3/' prj/libprj/manifest;
      $init -C @cfg &prj-cfg/***;

      # Publish the single libprj package rather than the whole prj project.
      #
      test.arguments = $regex.apply($test.arguments, '^(prj)$', '\1/libprj');

      $* 2>>~%EOE%
        %package submission is queued(: \.*prj/1.0.3)?%d
        %reference: .{12}%
        EOE
    }

    : prompt
    :
    {
      $clone_prj;
      sed -i -e 's/^(version:) .*$/\1 1.0.4/' prj/libprj/manifest;
      sed -i -e 's/^(version:) .*$/\1 1.0.4/' prj/prj/manifest;
      $init -C @cfg &prj-cfg/***;

      # Suppress the --yes option.
      #
      test.arguments = $regex.apply($test.arguments, '^(--yes)$', '');

      $* <'y' 2>>~"%EOE%"
        publishing:
          to:      $repository
        %  as:      .+@.+%

          package: libprj
          version: 1.0.4
          project: prj
          section: stable

          package: prj
          version: 1.0.4
          project: prj
          section: stable
        %warning: publishing using staged build2 toolchain%?
        %continue\\?\\.+ package submission is queued\(: \\.*libprj/1.0.4\)?%d
        %reference: .{12}%
        %package submission is queued\(: \\.*prj/1.0.4\)?%d
        %reference: .{12}%
        EOE
    }
  }

  : commited-prj
  :
  {
    test.options += --no-progress
    test.arguments += --simulate 'success'

    clone_prj = [cmdline] cp --no-cleanup -pr ../prj ./ &prj/***

    +$clone_prj

    +$g config user.name  'Test Script'
    +$g config user.email 'testscript@example.com'
    +$g add '*'
    +$g commit -m 'Create' --no-verify

    : final
    :
    {
      $clone_prj;
      $init -C @cfg &prj-cfg/***;
      sed -i -e 's/^(version:) .*$/\1 1.0.16/' prj/manifest;

      $* 2>>~%EOE% != 0;
        synchronizing:
          upgrade prj/1.0.16
        error: project directory has uncommitted changes
          info: run 'git status' for details
          info: use 'git stash' to temporarily hide the changes
          info: use --force=uncommitted to publish anyway
        EOE

      $g commit -a -m 'Version';

      $* 2>>~%EOE%
        %package submission is queued(: \.*prj/1.0.16)?%d
        %reference: .{12}%
        EOE
    }

    : snapshot
    :
    {
      $clone_prj;
      $init -C @cfg &prj-cfg/***;
      sed -i -e 's/^(version:) .*$/\1 1.0.17-a.0.z/' prj/manifest;

      $* 2>>~%EOE% != 0;
        synchronizing:
        %  upgrade prj/1.0.17-a.0.\.+%d
        error: project directory has uncommitted changes
          info: run 'git status' for details
          info: use 'git stash' to temporarily hide the changes
          info: use --force=uncommitted to publish anyway
        EOE

      # Note that the uncomitted snapshot sn is the previous commit time + 1
      # and the commited snapshot sn is the commit time. That's why let's
      # sleep a bit to make sure that the package version increases with the
      # commit.
      #
      sleep 1;

      $g commit -a -m 'Version';

      $* 2>>~%EOE% != 0;
        synchronizing:
        %  upgrade prj/1.0.17-a.0.\.+%d
        %error: package prj version 1.0.17-a.0.\.+ is a snapshot%d
          info: use --force=snapshot to publish anyway
        EOE

      $* --force=snapshot 2>>~%EOE%
        %package submission is queued(: \.*prj/1.0.17-a.0.\.+)?%d
        %reference: .{12}%
        EOE
    }
  }

  : non-vsc-prj
  :
  {
    test.options += --no-progress
    test.arguments += --simulate 'success'

    clone_prj = [cmdline] cp --no-cleanup -pr ../prj ./ &prj/***;

    $clone_prj;
    rm -rf prj/.git;

    $init -C @cfg &prj-cfg/***;
    sed -i -e 's/^(version:) .*$/\1 1.0.18/' prj/manifest;

    $* 2>>~%EOE%
      synchronizing:
        upgrade prj/1.0.18
      %package submission is queued(: \.*prj/1.0.18)?%d
      %reference: .{12}%
      EOE
  }

  : failure
  :
  {
    test.options += --no-progress
    test.arguments += --force=uncommitted

    : duplicate-archive
    :
    {
      test.arguments += --simulate 'duplicate-archive'

      $clone_root_prj;
      $init -C @cfg &prj-cfg/***;
      sed -i -e 's/^(version:) .*$/\1 1.0.5/' prj/manifest;

      $* 2>>~%EOE% != 0
        synchronizing:
          upgrade prj/1.0.5
        error: duplicate submission
        %  info: reference: .{12}%?
        EOE
    }

    : internal-error-text
    :
    {
      test.arguments += --simulate 'internal-error-text'

      $clone_root_prj;
      $init -C @cfg &prj-cfg/***;
      sed -i -e 's/^(version:) .*$/\1 1.0.6/' prj/manifest;

      $* 2>>~%EOE% != 0
        synchronizing:
          upgrade prj/1.0.6
        error: submission handling failed
        %  info: consider reporting this to .+ maintainers%
        EOE
    }

    : internal-error-html
    :
    {
      test.arguments += --simulate 'internal-error-html'

      $clone_root_prj;
      $init -C @cfg &prj-cfg/***;
      sed -i -e 's/^(version:) .*$/\1 1.0.7/' prj/manifest;

      $* 2>>~%EOE% != 0
        synchronizing:
          upgrade prj/1.0.7
        error: HTTP status code 500 (internal server error)
        %  info: consider reporting this to .+ maintainers%
        EOE
    }
  }
}

: control
:
{
  # The control repository URL doesn't really matter for the submission
  # simulation. We specify it to enable the control branch-related
  # functionality.
  #
  test.arguments += --force=uncommitted --simulate 'success' \
--control 'http://example.com/rep.git'

  # Create the remote repository.
  #
  +mkdir --no-cleanup prj.git
  +git -C prj.git -c init.defaultBranch=master init --bare --quiet &prj.git/***

  +$clone_prj

  +$g config user.name  'Test Script'
  +$g config user.email 'testscript@example.com'

  clone_rep = [cmdline] cp --no-cleanup -r ../prj.git ./ &prj.git/***
  clone_prj = [cmdline] cp --no-cleanup -r ../prj     ./ &prj/***

  : success
  :
  {
    # Setup the remote repository.
    #
    rep = "file://($windows ? "$regex.replace($~, '\\', '/')" : "$~")/prj.git"
    $clone_rep;

    # Setup the local repository/project.
    #
    $clone_prj;
    $init -C @cfg &prj-cfg/***;
    $g remote add origin "$rep";

    # Publish when neither local nor remote-tracking build2-control branches
    # are present.
    #
    sed -i -e 's/^(version:) .*$/\1 1.0.8/' prj/manifest;

    $* >&2 2>>~%EOE%;
      synchronizing:
        upgrade prj/1.0.8
      pushing branch build2-control
      %.*
      submitting prj-1.0.8.tar.gz
      %.+
      %reference: .{12}%
      EOE

    test.options += --no-progress;

    # Publish when both local and remote-tracking build2-control branches are
    # present.
    #
    sed -i -e 's/^(version:) .*$/\1 1.0.9/' prj/manifest;

    $* 2>>~%EOE%;
      synchronizing:
        upgrade prj/1.0.9
      %package submission is queued(: \.*prj/1.0.9)?%d
      %reference: .{12}%
      EOE

    # Publish when the local build2-control branch is not present while the
    # remote-tracking branch is.
    #
    sed -i -e 's/^(version:) .*$/\1 1.0.10/' prj/manifest;

    $g branch -D build2-control;

    $* 2>>~%EOE%;
      synchronizing:
        upgrade prj/1.0.10
      %package submission is queued(: \.*prj/1.0.10)?%d
      %reference: .{12}%
      EOE

    # Check for the build2-control branch commits presence and the files they
    # add.
    #
    $g checkout build2-control;
    $g log --name-only --pretty='format:%s' >>:~%EOO%
      Add prj/1.0.10 publish authorization
      %submit/.{16}%

      Add prj/1.0.9 publish authorization
      %submit/.{16}%

      Add prj/1.0.8 publish authorization
      %submit/.{16}%

      Start
      EOO
  }

  : failure
  :
  {
    g2 = [cmdline] git -C prj2 >! 2>!

    # Setup the remote repository.
    #
    rep = "file://($windows ? "$regex.replace($~, '\\', '/')" : "$~")/prj.git"
    $clone_rep;

    # Setup the local repository/project.
    #
    $clone_prj;
    $init -C @cfg &prj-cfg/***;
    $g remote add origin "$rep";

    # Publish successfully.
    #
    sed -i -e 's/^(version:) .*$/\1 1.0.11/' prj/manifest;

    $* >! 2>!;

    # Push into the build2-control branch from another local repository,
    # making the subsequent publish of prj package impossible until the next
    # fetch.
    #
    # Convert specific warnings to infos as we expect them to appear. This, in
    # particular, prevents bbot workers to set task result status to warning.
    #
    git clone "$rep" prj2 &prj2/*** 2>&1 | \
    sed -e 's/warning: (remote HEAD refers to nonexistent .*)/info: \1/' >&2 2>!;

    $g2 config user.name  'Test Script';
    $g2 config user.email 'testscript@example.com';
    $g2 checkout -b build2-control --track origin/build2-control;
    $g2 commit --allow-empty -m 'Dummy1';
    $g2 push;

    sed -i -e 's/^(version:) .*$/\1 1.0.12/' prj/manifest;

    # Fail to publish (see above for details).
    #
    $* 2>>~%EOE% != 0;
      synchronizing:
        upgrade prj/1.0.12
      pushing branch build2-control
      %.*
      error: unable to push build2-control branch
        info: run 'git fetch' and try again
      EOE

    test.options += --no-progress;

    # Publish successfully after the fetch.
    #
    $g fetch;

    $* 2>>~%EOE%;
      %package submission is queued(: \.*prj/1.0.12)?%d
      %reference: .{12}%
      EOE

    sed -i -e 's/^(version:) .*$/\1 1.0.13/' prj/manifest;

    # Reproduce the situation when the local build2-control branch exists but
    # the remote-tracking one doesn't (see brep/publish.cxx for details).
    #
    $g branch -Dr origin/build2-control;

    # Note that the push operation is fixed in git 2.32.0 not to print "Branch
    # set up to track ..."  in the quiet mode.
    #
    $* >&2 2>>~%EOE%;
      synchronizing:
        upgrade prj/1.0.13
      %Branch '?build2-control'? set up to track remote branch '?build2-control'? from '?origin'?.%d?
      %package submission is queued(: \.*prj/1.0.13)?%d
      %reference: .{12}%
      EOE

    # Test publishing after implicit fetches.
    #
    # Push again into the build2-control branch from another local repository
    # (see above for details).
    #
    $g2 pull --ff-only;
    $g2 commit --allow-empty -m 'Dummy2';
    $g2 push;

    sed -i -e 's/^(version:) .*$/\1 1.0.14/' prj/manifest;

    # Note that the prj repository master branch push doesn't implicitly fetch
    # the build2-control branch, so the subsequent publishing fails.
    #
    $g add '*';
    $g commit -m 'Create' --no-verify;
    $g push --set-upstream origin master;

    $* 2>>~%EOE% != 0;
      synchronizing:
        upgrade prj/1.0.14
      %.*
      error: unable to push build2-control branch
        info: run 'git fetch' and try again
      EOE

    # Note that the prj repository master branch pull fetches the
    # build2-control branch implicitly, so the subsequent publishing succeeds.
    #
    $g pull --ff-only;

    $* 2>>~%EOE%;
      %package submission is queued(: \.*prj/1.0.14)?%d
      %reference: .{12}%
      EOE

    # Check the build2-control branch commits presence and the files they add.
    #
    $g checkout build2-control;
    $g log --name-only --pretty='format:%s' >>:~%EOO%
      %.*
      Add prj/1.0.14 publish authorization
      %submit/.{16}%

      Dummy2
      Add prj/1.0.13 publish authorization
      %submit/.{16}%

      Add prj/1.0.12 publish authorization
      %submit/.{16}%

      Dummy1
      Add prj/1.0.11 publish authorization
      %submit/.{16}%

      Start
      EOO
  }
}
