Skip to content

Commit

Permalink
make rose stem install to a sensible name workflow
Browse files Browse the repository at this point in the history
  • Loading branch information
wxtim committed Oct 4, 2022
1 parent 4be1f74 commit 0ab9119
Show file tree
Hide file tree
Showing 4 changed files with 113 additions and 48 deletions.
11 changes: 8 additions & 3 deletions CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,17 @@ 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.1 (<span actions:bind='release-date'>Released 2022-09-14</span>)__

## __cylc-rose-1.1.1 (<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.

[#171](https://github.com/cylc/cylc-rose/pull/171) - Fix bug where Cylc Rose
passed `rose-suite.conf` items commented with `!` or `!!` to Cylc regardless.

[#172](https://github.com/cylc/cylc-rose/pull/172) - Allow getting a workflow
name when source is not an SVN repo.

## __cylc-rose-1.1.0 (<span actions:bind='release-date'>Released 2022-07-28</span>)__

Expand All @@ -32,6 +34,9 @@ a database locking issue with the `rose_prune` built-in app.

### Fixes

[#172](https://github.com/cylc/cylc-rose/pull/172) - Allow getting a workflow
name when source is not an SVN repo.

[#139](https://github.com/cylc/cylc-rose/pull/139) - Make `rose stem` command
work correctly with changes made to `cylc install` in
[cylc-flow PR #4823](https://github.com/cylc/cylc-flow/pull/4823)
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'
89 changes: 47 additions & 42 deletions cylc/rose/stem.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,24 +17,28 @@
# You should have received a copy of the GNU General Public License
# along with Rose. If not, see <http://www.gnu.org/licenses/>.
# -----------------------------------------------------------------------------
"""rose stem [options] [path]
"""rose stem [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 rose-stem suite using cylc install.
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".
Install a suitable suite with a specified set of source tree(s).
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 +60,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 +365,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 +383,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 +486,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 +503,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 +519,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 +541,28 @@ 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 by putting the project name as the first part of "
"this argument separated by an equals sign as in the third "
"example above. Defaults to `.` if not specified."
),
action="append",
metavar="PATH/TO/FLOW",
Expand All @@ -582,8 +587,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 0ab9119

Please sign in to comment.