Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add --validate option for buildtest build #1729

Merged
merged 5 commits into from
Mar 16, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 1 addition & 4 deletions bash_completion.sh
Original file line number Diff line number Diff line change
Expand Up @@ -190,7 +190,7 @@ _buildtest ()
case "$next" in
build|bd)
local shortoption="-b -e -et -f -m -n -s -t -u -x -xt"
local longoption="--buildspec --dry-run --executor --executor-type --exclude --exclude-tags --filter --helpfilter --limit --maxpendtime --max-jobs --modules --module-purge --name --nodes --pollinterval --procs --profile --rerun --remove-stagedir --retry --save-profile --stage --tags --timeout --unload-modules"
local longoption="--buildspec --dry-run --executor --executor-type --exclude --exclude-tags --filter --helpfilter --limit --maxpendtime --max-jobs --modules --module-purge --name --nodes --pollinterval --procs --profile --rerun --remove-stagedir --retry --save-profile --tags --timeout --unload-modules --validate"
local allopts="${longoption} ${shortoption}"

COMPREPLY=( $( compgen -W "$allopts" -- "${cur}" ) )
Expand All @@ -199,9 +199,6 @@ _buildtest ()
-e|--executor)
COMPREPLY=( $( compgen -W "$(_avail_executors)" -- "${cur}" ) )
;;
-s|--stage)
COMPREPLY=( $( compgen -W "stage parse" -- "${cur}" ) )
;;
-et|--executor-type)
COMPREPLY=( $( compgen -W "local batch" -- "${cur}" ) )
;;
Expand Down
5 changes: 3 additions & 2 deletions buildtest/cli/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -943,9 +943,10 @@ def build_menu(self):
},
),
(
["-s", "--stage"],
["--validate"],
{
"help": "Control behavior of buildtest build to stop execution after 'parse' stage"
"action": "store_true",
"help": "Validate given buildspecs and control behavior of buildtest build to stop execution after parsing the YAML files.",
},
),
(
Expand Down
19 changes: 10 additions & 9 deletions buildtest/cli/build.py
Original file line number Diff line number Diff line change
Expand Up @@ -602,7 +602,7 @@ def __init__(
exclude_tags=None,
executors=None,
testdir=None,
stage=None,
validate=None,
dry_run=None,
filter_buildspecs=None,
rebuild=None,
Expand Down Expand Up @@ -641,7 +641,7 @@ def __init__(
exclude_tags (list, optional): list if tags to exclude specified via command line ``buildtest build --exclude-tags``
executors (list, optional): list of executors passed from command line ``buildtest build --executors``
testdir (str): Path to test directory where tests are written. This argument can be passed from command line ``buildtest build --testdir``
stage (str, optional): Stop build after parse or build stage which can be configured via ``buildtest build --stage`` option
validate (bool, optional): Validate given buildspecs and buildtest will stop after parse stage which can be configured via ``buildtest build --validate`` option
dry_run (bool, optional): Show a list of tests that will potentially be run without actually running them via ``buildtest build --dry-run``
filter_buildspecs (dict, optional): filters buildspecs and tests based on ``buildtest build --filter`` argument which is a key/value dictionary that can filter tests based on **tags**, **type**, and **maintainers**
rebuild (int, optional): Rebuild tests X times based on ``buildtest build --rebuild`` option.
Expand Down Expand Up @@ -691,7 +691,7 @@ def __init__(
raise BuildTestError(f"{arg_name} is not of type list")

# check for input arguments that are expected to be a string
for arg_name in [testdir, stage, save_profile, profile]:
for arg_name in [testdir, save_profile, profile]:
if arg_name and not isinstance(arg_name, str):
raise BuildTestError(f"{arg_name} is not of type str")

Expand Down Expand Up @@ -726,7 +726,7 @@ def __init__(
self.retry = retry
self.rerun = rerun
self.account = account
self.stage = stage
self.validate = validate
self.dry_run = dry_run
self.filter_buildspecs = filter_buildspecs
self.rebuild = rebuild
Expand Down Expand Up @@ -873,7 +873,7 @@ def load_rerun_file(self):
self.exclude_buildspecs = content["exclude_buildspecs"]
self.executors = content["executors"]
self.report_file = content["report_file"]
self.stage = content["stage"]
self.validate = content["validate"]
self.dry_run = content["dry_run"]
self.remove_stagedir = content["remove_stagedir"]
self.testdir = content["testdir"]
Expand Down Expand Up @@ -905,7 +905,7 @@ def save_rerun_file(self):
"executors": self.executors,
"report_file": self.report_file,
"dry_run": self.dry_run,
"stage": self.stage,
"validate": self.validate,
"remove_stagedir": self.remove_stagedir,
"testdir": self.testdir,
"maxpendtime": self.maxpendtime,
Expand Down Expand Up @@ -948,6 +948,7 @@ def save_profile_to_configuration(self):
"module": self.modules,
"unload-modules": self.unload_modules,
"module-purge": self.modulepurge,
"validate": self.validate,
"dry-run": self.dry_run,
"rebuild": self.rebuild,
"limit": self.limit,
Expand Down Expand Up @@ -1036,6 +1037,7 @@ def load_profile(self):
self.modules = profile_configuration.get("module")
self.unload_modules = profile_configuration.get("unload-modules")
self.modulepurge = profile_configuration.get("module-purge")
self.validate = profile_configuration.get("validate")
self.dry_run = profile_configuration.get("dry-run")
self.rebuild = profile_configuration.get("rebuild")
self.filter_buildspecs = profile_configuration.get("filter")
Expand Down Expand Up @@ -1097,9 +1099,8 @@ def build(self):
# is a builder object used for building test.
self.parse_buildspecs()

# if no builders found or --stage=parse set we return from method
# TODO remove buildtest build --stage=parse --> buildtest build --validate
if not self.builders or self.stage == "parse":
# if no builders found or buildtest build --validate set we return from method
if not self.builders or self.validate:
return

if self.limit:
Expand Down
4 changes: 4 additions & 0 deletions buildtest/cli/show.py
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,10 @@ def print_build_show():
"buildtest build --profile=python-profile",
"Run buildtest from profile name 'python-profile'",
)
table.add_row(
"buildtest build --validate -b <file>",
"Test will validate buildspecs and stop after parsing stage",
)
console.print(table)


Expand Down
2 changes: 1 addition & 1 deletion buildtest/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -170,7 +170,7 @@ def main():
exclude_tags=args.exclude_tags,
filter_buildspecs=args.filter,
rebuild=args.rebuild,
stage=args.stage,
validate=args.validate,
dry_run=args.dry_run,
testdir=args.testdir,
buildtest_system=system,
Expand Down
1 change: 1 addition & 0 deletions buildtest/schemas/settings.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -712,6 +712,7 @@
"module": {"type": "string"},
"unload-modules": {"type": "string"},
"module-purge": {"type": "boolean"},
"validate": {"type": "boolean", "description": "Validate given buildspecs and buildtest will stop after parse stage"},
"dry-run": {"type": "boolean", "description": "Show a list of tests that will potentially be run"},
"rebuild": {"type": "integer", "minimum": 1, "maximum": 50, "description": "Specify number of tests to rebuild"},
"limit": {"type": "integer", "minimum": 1, "description": "Limit number of tests to build"},
Expand Down
7 changes: 3 additions & 4 deletions docs/batch_support.rst
Original file line number Diff line number Diff line change
Expand Up @@ -609,10 +609,9 @@ resources and IBM BlueGene series. Cobalt resembles `PBS <https://community.alta
in terms of command line interface such as ``qsub``, ``qacct`` however they
slightly differ in their behavior.

Cobalt support has been tested on JLSE and `Theta <https://www.alcf.anl.gov/support-center/theta>`_
system. Cobalt directives are specified using ``#COBALT`` this can be specified
using ``cobalt`` property which accepts a list of strings. Shown below is an example
using cobalt property.
Cobalt support has been tested on JLSE and Theta system. Cobalt directives
are specified using ``#COBALT`` this can be specified using ``cobalt`` property
which accepts a list of strings. Shown below is an example using cobalt property.

.. code-block:: yaml
:emphasize-lines: 5
Expand Down
23 changes: 18 additions & 5 deletions docs/gettingstarted/buildingtest.rst
Original file line number Diff line number Diff line change
Expand Up @@ -337,17 +337,16 @@ Configure Build Stages
-----------------------

We can control behavior of ``buildtest build`` command to stop at certain phase
using ``--stage`` option. The **--stage** option accepts ``parse``, which
will instruct buildtest to stop at parse phase of the pipeline.
using ``--validate`` and ``--dry-run`` options.

Buildtest will validate all the buildspecs in the parse stage, so you can
instruct buildtest to stop at parse stage via ``--stage=parse``. This can be useful
instruct buildtest to stop at parse stage via ``--validate``. This can be useful
when debugging buildspecs that are invalid. In this example below, we instruct
buildtest to stop after parse stage.

.. dropdown:: ``buildtest build -b tutorials/vars.yml --stage=parse``
.. dropdown:: ``buildtest build -b tutorials/vars.yml --validate``

.. command-output:: buildtest build -b tutorials/vars.yml --stage=parse
.. command-output:: buildtest build -b tutorials/vars.yml --validate

.. _invalid_buildspecs:

Expand Down Expand Up @@ -375,6 +374,20 @@ where test failed to run since we provided invalid executor.
.. command-output:: buildtest build -b tutorials/invalid_executor.yml
:returncode: 1

Validate Tests (``buildtest build --validate``)
------------------------------------------------

When you use the **buildtest build** command, you have the option to enter a validate mode by
adding the ``--validate`` option. In this mode, the command will validate given buildspecs
and stop after the parse stage. It's particularly useful when you're creating or editing a
buildspec file and want to check its validity before entering the build stage.
For instance, in the following example, we demonstrate how to instruct buildtest to halt after
the parse stage.

.. dropdown:: ``buildtest build -b tutorials/vars.yml --validate``

.. command-output:: buildtest build -b tutorials/vars.yml --validate

Dry Run (``buildtest build --dry-run``)
----------------------------------------

Expand Down
4 changes: 2 additions & 2 deletions docs/scripting_examples/ex1.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,12 @@
configuration.detect_system()
configuration.validate()

# this will invoke buildtest build -b $BUILDTEST_ROOT/tutorials/vars.yml -b $BUILDTEST_ROOT/general_tests/configuration -x $BUILDTEST_ROOT/general_tests/configuration/ulimits.yml --stage=parse
# this will invoke buildtest build -b $BUILDTEST_ROOT/tutorials/vars.yml -b $BUILDTEST_ROOT/general_tests/configuration -x $BUILDTEST_ROOT/general_tests/configuration/ulimits.yml --validate
cmd = BuildTest(
configuration=configuration,
buildspecs=input_buildspecs,
exclude_buildspecs=exclude_buildspecs,
stage="parse",
validate=True,
buildtest_system=buildtest_system,
)
cmd.build()
Expand Down
2 changes: 1 addition & 1 deletion docs/troubleshooting.rst
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ file, the most convenient way is to run::
buildtest buildspec validate -b <file>

If your buildspec is valid, your next step is to run the test. You should check if test is generated properly,
this can be done by running ``buildtest build -b <file> --stage=build`` which will generate
this can be done by running ``buildtest build -b <file> --dry-run`` which will generate
the test and stop execution. Next you can navigate to the generated test and inspect
the content of test and run your test manually.

Expand Down
2 changes: 1 addition & 1 deletion tests/buildsystem/test_spack.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ def test_spack_examples():
cmd = BuildTest(
configuration=configuration,
tags=["spack"],
stage="build",
dry_run=True,
buildtest_system=system,
)
cmd.build()
14 changes: 5 additions & 9 deletions tests/cli/test_build.py
Original file line number Diff line number Diff line change
Expand Up @@ -344,19 +344,19 @@ def test_skip_field(self):
cmd.build()

@pytest.mark.cli
def test_build_by_stages(self):
# testing buildtest build --tags python --stage=parse
def test_build_validate(self):
# testing buildtest build --tags python --validate
cmd = BuildTest(
configuration=configuration,
tags=["python"],
stage="parse",
validate=True,
buildtest_system=self.system,
)
cmd.build()

@pytest.mark.cli
def test_build_dryrun(self):
# testing buildtest build --tags tutorials --dry-run
# testing buildtest build --tags python --dry-run
cmd = BuildTest(
configuration=configuration,
tags=["python"],
Expand Down Expand Up @@ -538,6 +538,7 @@ def test_save_profile(self):
modules="gcc/9.1.0",
unload_modules="gcc",
modulepurge=True,
validate=False,
dry_run=True,
limit=10,
rebuild=2,
Expand Down Expand Up @@ -650,11 +651,6 @@ def test_invalid_executors(self):
with pytest.raises(BuildTestError):
BuildTest(configuration=configuration, executors="generic.local.bash")

def test_invalid_stage(self):
# invalid type for stage argument, must be a string not list
with pytest.raises(BuildTestError):
BuildTest(configuration=configuration, tags=["pass"], stage=["parse"])

def test_invalid_type_for_testdir(self):
# invalid value for testdir argument, must be a str
with pytest.raises(BuildTestError):
Expand Down
Loading