Skip to content

Commit

Permalink
feature: stem installs to workflow name not rose-stem (#180)
Browse files Browse the repository at this point in the history
* make rose stem install to a sensible name workflow
  • Loading branch information
wxtim authored Oct 21, 2022
1 parent d909df7 commit 9974e2b
Show file tree
Hide file tree
Showing 4 changed files with 109 additions and 44 deletions.
8 changes: 8 additions & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,14 @@ creating a new release entry be sure to copy & paste the span tag with the
`actions:bind` attribute, which is used by a regex to find the text to be
updated. Only the first match gets replaced, so it's fine to leave the old
ones in. -->

## __cylc-rose-1.1.2 (<span actions:bind='release-date'>Upcoming</span>)__

### Fixes

[#180](https://github.com/cylc/cylc-rose/pull/180) - Rose stem gets stem
suite's basename to use as workflow name when not otherwise set.

## __cylc-rose-1.1.1 (<span actions:bind='release-date'>Released 2022-09-14</span>)__

### Fixes
Expand Down
2 changes: 1 addition & 1 deletion cylc/rose/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -205,4 +205,4 @@
"""

__version__ = '1.1.1'
__version__ = '1.1.1.dev'
84 changes: 43 additions & 41 deletions cylc/rose/stem.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,22 +19,24 @@
# -----------------------------------------------------------------------------
"""rose stem [options] [path]
Install a rose stem workflow with a specified set of source tree(s).
This command acts as a wrapper to "cylc install" by defining a number of
additional Jinja2 variables.
Install a suitable suite with a specified set of source tree(s).
The path to the workflow source directory can be specified using the
"path" argument. Otherwise it must be provided in a directory named
"rose-stem" in the first source tree.
To run a rose-stem suite use "cylc play".
Default values of some of these settings are suite-dependent, specified
in the `rose-suite.conf` file.
Examples
rose stem --group=developer
rose stem --source=/path/to/source --source=/other/source --group=mygroup
rose stem --source=foo=/path/to/source --source=bar=fcm:bar_tr@head
Jinja2 Variables
Note that `<project>` refers to the FCM keyword name of the repository in
upper case.
Default values of some of these settings are suite-dependent, specified
in the `rose-suite.conf` file.
HOST_SOURCE_<project>
The complete list of source trees for a given project. Working copies
in this list have their hostname prefixed, e.g. `host:/path/wc`.
Expand All @@ -56,12 +58,6 @@
SOURCE_<project>_REV
The revision of the project specified on the command line. This
is intended to specify the revision of `fcm-make` config files.
Usage examples
rose stem --group=developer
rose stem --source=/path/to/source --source=/other/source --group=mygroup
rose stem --source=foo=/path/to/source --source=bar=fcm:bar_tr@head
rose stem --source=A=
"""

from ansimarkup import parse as cparse
Expand Down Expand Up @@ -367,10 +363,11 @@ def _generate_name(self):
try:
basedir = self._ascertain_project(os.getcwd())[1]
except ProjectNotFoundException:
if self.opts.source:
basedir = os.path.abspath(self.opts.source)
if self.opts.workflow_conf_dir:
basedir = os.path.abspath(self.opts.workflow_conf_dir)
else:
basedir = os.getcwd()
basedir = os.path.dirname(os.path.abspath(os.getcwd()))

name = os.path.basename(basedir)
self.reporter(NameSetEvent(name))
return name
Expand All @@ -384,12 +381,17 @@ def _this_suite(self):
basedir = self.opts.stem_sources[0]
else:
basedir = self._ascertain_project(os.getcwd())[1]

suitedir = os.path.join(basedir, DEFAULT_TEST_DIR)
suitefile = os.path.join(suitedir, "rose-suite.conf")

if not os.path.isfile(suitefile):
raise RoseSuiteConfNotFoundException(suitedir)

self.opts.suite = suitedir

self._check_suite_version(suitefile)

return suitedir

def _read_auto_opts(self):
Expand Down Expand Up @@ -482,10 +484,10 @@ def process(self):
elements[0], '"' + elements[1] + '"')

# Change into the suite directory
if getattr(self.opts, 'source', None):
self.reporter(SuiteSelectionEvent(self.opts.source))
if getattr(self.opts, 'workflow_conf_dir', None):
self.reporter(SuiteSelectionEvent(self.opts.workflow_conf_dir))
self._check_suite_version(
os.path.join(self.opts.source, 'rose-suite.conf'))
os.path.join(self.opts.workflow_conf_dir, 'rose-suite.conf'))
else:
thissuite = self._this_suite()
self.fs_util.chdir(thissuite)
Expand All @@ -499,7 +501,8 @@ def process(self):


def get_source_opt_from_args(opts, args):
"""Convert sourcedir given as arg or implied by no arg to opts.source.
"""Convert sourcedir given as arg or implied by no arg to
opts.workflow_conf_dir.
Possible outcomes:
No args given:
Expand All @@ -514,14 +517,14 @@ def get_source_opt_from_args(opts, args):
"""
if len(args) == 0:
# sourcedir not given:
opts.source = None
opts.workflow_conf_dir = None
return opts
elif os.path.isabs(args[-1]):
# sourcedir given, and is abspath:
opts.source = args[-1]
opts.workflow_conf_dir = args[-1]
else:
# sourcedir given and is not abspath
opts.source = str(Path.cwd() / args[-1])
opts.workflow_conf_dir = str(Path.cwd() / args[-1])

return opts

Expand All @@ -536,28 +539,27 @@ def main():
# opts.group is stored by the --task option.
rose_stem_options = OptionGroup(parser, 'Rose Stem Specific Options')
rose_stem_options.add_option(
"--task", "--group", '-t', '-g',
"--task", "--group", "-t", "-g",
help=(
"Specify a group of tasks to run. "
"Additional groups can be "
"specified with further `--group` arguments. "
"Rose stem adds group names to the RUN_NAMES template variable "
"which a workflow can use to enable groups of tasks."
"Specify a group name to run. Additional groups can be specified"
" with further `--group` arguments. The suite will then convert"
" the groups into a series of tasks to run."
),
action="append",
metavar="PATH/TO/FLOW",
default=[],
dest="stem_groups")
rose_stem_options.add_option(
"--source", "-s",
"--source", '-s',
help=(
"Specify a source tree to include in a rose-stem suite. "
"Defaults to \".\" if unspecified. "
"You can use --source more than once to "
"specify any number of sources. "
"The first --source argument must be a working "
"copy which should contain a workflow definition "
"in the rose-stem subdirectory."
"Specify a source tree to include in a rose-stem suite. The first"
" source tree must be a working copy, as the location of the suite"
" and fcm-make config files are taken from it. Further source"
" trees can be added with additional `--source` arguments."
" The project which is associated with a given source is normally"
" automatically determined using FCM, however the project can"
" be specified as '<project-name>=<project-path>'."
" Defaults to `.` if not specified."
),
action="append",
metavar="PATH/TO/FLOW",
Expand All @@ -582,8 +584,8 @@ def main():
opts = StemRunner(opts).process()

# call cylc install
if hasattr(opts, 'source'):
cylc_install(parser, opts, opts.source)
if opts.workflow_conf_dir:
cylc_install(parser, opts, opts.workflow_conf_dir)
else:
cylc_install(parser, opts)

Expand Down
59 changes: 57 additions & 2 deletions tests/unit/test_rose_stem_units.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,11 @@
"""Functional tests for top-level function record_cylc_install_options and
"""

import os
import pytest
from types import SimpleNamespace

from cylc.rose.stem import get_source_opt_from_args
from cylc.rose.stem import get_source_opt_from_args, StemRunner


@pytest.mark.parametrize(
Expand Down Expand Up @@ -48,9 +49,63 @@ def test_get_source_opt_from_args(tmp_path, monkeypatch, args, expect):
monkeypatch.chdir(tmp_path)
opts = SimpleNamespace()

result = get_source_opt_from_args(opts, args).source
result = get_source_opt_from_args(opts, args).workflow_conf_dir

if expect is None:
assert result == expect
else:
assert result == expect.format(tmp_path=str(tmp_path))


class Test_generate_name:
"""Try 3 paths in StemRunner._generate_name.
Contains a setup function for each path.
"""
EXPECT = 'bar'
MSG = 'Suite is named bar'

@staticmethod
def name_from_fcm(monkeypatch):
"""It gets the name from _ascertain_project.
"""
class MonkeyStemRunner(StemRunner):
def _ascertain_project(self, x):
return ['foo', '/foo/bar']
return MonkeyStemRunner(SimpleNamespace, reporter=print)

@staticmethod
def source_set(monkeypatch):
"""It gets the name from the source opt.
equivalent of using:
rose stem /foo/bar/rose-stem
"""
opts = SimpleNamespace()
opts.workflow_conf_dir = '/foo/bar'
stemrunner = StemRunner(opts, reporter=print)
return stemrunner

@staticmethod
def source_unset(monkeypatch):
"""It gets the name from the file path.
equivalent of using:
rose stem
"""
opts = SimpleNamespace()
opts.workflow_conf_dir = ''
monkeypatch.setattr(os, "getcwd", lambda: "/foo/bar/rose-stem")
stemrunner = StemRunner(opts, reporter=print)
return stemrunner

@pytest.mark.parametrize(
'setup', [
'source_set', 'source_unset', 'name_from_fcm'])
def test__generate_name(self, capsys, monkeypatch, setup):
"""Tests StemRunner._generate_name for fake stemrunner
returned by each test case method.
"""
result = getattr(self, setup)(monkeypatch)._generate_name()
assert result == self.EXPECT
assert self.MSG in capsys.readouterr().out

0 comments on commit 9974e2b

Please sign in to comment.