diff options
-rw-r--r-- | bdep/buildfile | 2 | ||||
-rw-r--r-- | bdep/ci.cli | 18 | ||||
-rw-r--r-- | bdep/ci.cxx | 81 | ||||
-rwxr-xr-x | doc/cli.sh | 1 | ||||
-rw-r--r-- | tests/ci.testscript | 74 |
5 files changed, 170 insertions, 6 deletions
diff --git a/bdep/buildfile b/bdep/buildfile index cb701e8..2bbf1c3 100644 --- a/bdep/buildfile +++ b/bdep/buildfile @@ -150,7 +150,7 @@ if $cli.configured --keep-separator --generate-specifier --generate-modifier \ --generate-description --generate-parse --generate-merge \ --page-usage 'bdep::print_$name$_' --ansi-color --include-base-last \ ---suppress-undocumented --option-length 23 +--suppress-undocumented --option-length 24 cli.cxx{common-options}: cli.options += --short-usage --long-usage # Both. cli.cxx{bdep-options}: cli.options += --short-usage diff --git a/bdep/ci.cli b/bdep/ci.cli index 8befd82..a45828c 100644 --- a/bdep/ci.cli +++ b/bdep/ci.cli @@ -79,6 +79,12 @@ namespace bdep hierarchically so that the \cb{build-{include,exclude\}} overrides don't affect the \cb{builds} values. + If supported by the CI service, a package can be tested interactively + in a specific build configuration using the \c{\b{--interactive}|\b{-i}} + option. In this mode the CI service provides the login information for + the execution environment and pauses the testing at the specified + breakpoint. + While the exact interpretation of the CI request depends on the specific service, normally, the CI server will respond with a reference that can be used to query the results. See \l{brep#ci Package CI} for details on @@ -95,6 +101,18 @@ namespace bdep "Don't prompt for confirmation before submitting." } + string --interactive|-i + { + "<cf>[/<bp>]", + "Test the package interactively in the specified build configuration, + pausing the execution at the specified breakpoint. Valid breakpoint + values are \cb{error} (stop after first error), \cb{warning} (stop + after first warning), as well as the CI service-specific step ids + in which case the execution stops before performing the specified + step (see \l{bbot#arch-worker \cb{bbot} worker step ids}). If no + breakpoint is specified, then \cb{error} is assumed." + } + url --server { "<url>", diff --git a/bdep/ci.cxx b/bdep/ci.cxx index 797725f..18ebf7f 100644 --- a/bdep/ci.cxx +++ b/bdep/ci.cxx @@ -5,6 +5,7 @@ #include <sstream> +#include <libbutl/path-pattern.mxx> #include <libbutl/manifest-types.mxx> #include <libbpkg/manifest.hxx> @@ -176,17 +177,36 @@ namespace bdep { tracer trace ("ci"); - // Create the default override. + vector<manifest_name_value> overrides; + + auto override = [&overrides] (string n, string v) + { + overrides.push_back ( + manifest_name_value {move (n), move (v), // Name and value. + 0, 0, 0, 0, 0, 0, 0}); // Locations, etc. + }; + + // Add the default overrides. // - vector<manifest_name_value> overrides ({ - manifest_name_value {"build-email", "", // Name and value. - 0, 0, 0, 0, 0, 0, 0}}); // Locations, etc. + override ("build-email", ""); // Validate and append the specified overrides. // if (o.overrides_specified ()) try { + if (o.interactive_specified ()) + { + for (const manifest_name_value& nv: o.overrides ()) + { + if (nv.name == "builds" || + nv.name == "build-include" || + nv.name == "build-exclude") + fail << "'" << nv.name << "' override specified together with " + << "--interactive|-i"; + } + } + bpkg::package_manifest::validate_overrides (o.overrides (), "" /* name */); @@ -276,6 +296,49 @@ namespace bdep add_package (p.name); } + // Extract the interactive mode configuration and breakpoint from the + // --interactive|-i option value, reducing the former to the build + // manifest value overrides. + // + // Both are present in the interactive mode and are absent otherwise. + // + optional<string> icfg; + optional<string> ibpk; + + if (o.interactive_specified ()) + { + if (pkgs.size () > 1) + fail << "multiple packages specified with --interactive|-i"; + + const string& s (o.interactive ()); + validate_utf8_graphic (s, "--interactive|-i option value"); + + size_t p (s.find ('/')); + + if (p != string::npos) + { + icfg = string (s, 0, p); + ibpk = string (s, p + 1); + } + else + icfg = s; + + if (icfg->empty ()) + fail << "invalid --interactive|-i option value '" << s + << "': configuration name is empty"; + + if (path_pattern (*icfg)) + fail << "invalid --interactive|-i option value '" << s + << "': configuration name is a pattern"; + + override ("builds", "all"); + override ("build-include", *icfg); + override ("build-exclude", "**"); + + if (!ibpk) + ibpk = "error"; + } + // Get the server and repository URLs. // const url& srv (o.server_specified () ? o.server () : default_server); @@ -310,6 +373,13 @@ namespace bdep << " version: " << p.version; } + if (icfg) + { + assert (ibpk); + text << " config: " << *icfg << '\n' + << " b/point: " << *ibpk; + } + if (!yn_prompt ("continue? [y/n]")) return 1; } @@ -334,6 +404,9 @@ namespace bdep "package", p.name.string () + '/' + p.version.string ()}); + if (ibpk) + params.push_back ({parameter::text, "interactive", move (*ibpk)}); + try { ostringstream os; @@ -52,6 +52,7 @@ function compile () --link-regex '%bpkg([-.].+)%../../bpkg/doc/bpkg$1%' \ --link-regex '%bpkg(#.+)?%../../bpkg/doc/build2-package-manager-manual.xhtml$1%' \ --link-regex '%brep(#.+)?%../../brep/doc/build2-repository-interface-manual.xhtml$1%' \ +--link-regex '%bbot(#.+)?%../../bbot/doc/build2-build-bot-manual.xhtml$1%' \ --link-regex '%bdep(#.+)?%build2-project-manager-manual.xhtml$1%' \ --link-regex '%intro(#.+)?%../../build2-toolchain/doc/build2-toolchain-intro.xhtml$1%' \ ../bdep/$n.cli diff --git a/tests/ci.testscript b/tests/ci.testscript index 9aae4ea..d72d872 100644 --- a/tests/ci.testscript +++ b/tests/ci.testscript @@ -156,7 +156,7 @@ windows = ($cxx.target.class == 'windows') --override 'build-error-email: error@example.com' \ --override 'builds: &gcc' \ --override 'build-include: linux*' \ - --override 'build-exclude: *' 2>>~"%EOE%" + --override 'build-exclude: *' 2>>~%EOE% %CI request is queued.*% %reference: .+% EOE @@ -233,6 +233,67 @@ windows = ($cxx.target.class == 'windows') } } } + + : interactive + : + { + +$clone_root_prj + +$init -C @cfg &prj-cfg/*** + + test.options += --no-progress + + : valid + : + { + $clone_prj; + + $* --interactive 'linux_debian_8-gcc_4.9/warning' 2>>~%EOE% + %CI request is queued.*% + %reference: .+% + EOE + } + + : def-breakpoint + : + { + $clone_prj; + + $* --interactive 'linux_debian_8-gcc_4.9' 2>>~%EOE% + %CI request is queued.*% + %reference: .+% + EOE + } + + : config-empty + : + { + $clone_prj; + + $* --interactive '/warning' 2>>EOE != 0 + error: invalid --interactive|-i option value '/warning': configuration name is empty + EOE + } + + : config-pattern + : + { + $clone_prj; + + $* --interactive 'linux_debian_8-gcc_4.*' 2>>EOE != 0 + error: invalid --interactive|-i option value 'linux_debian_8-gcc_4.*': configuration name is a pattern + EOE + } + + : overrides + : + { + $clone_prj; + + $* --interactive 'linux_debian_8-gcc_4.9' --builds '&gcc' 2>>EOE != 0 + error: 'builds' override specified together with --interactive|-i + EOE + } + } } : multi-pkg @@ -288,6 +349,17 @@ windows = ($cxx.target.class == 'windows') EOE } + : interactive + : + { + $clone_prj; + $init -C @cfg &prj-cfg/***; + + $* --interactive 'linux_debian_8-gcc_4.9' 2>>EOE != 0 + error: multiple packages specified with --interactive|-i + EOE + } + : prompt : { |