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

feature: stem installs to workflow name not rose-stem #180

Merged
Show file tree
Hide file tree
Changes from 3 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
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'
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]
wxtim marked this conversation as resolved.
Show resolved Hide resolved

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).
wxtim marked this conversation as resolved.
Show resolved Hide resolved
wxtim marked this conversation as resolved.
Show resolved Hide resolved

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"
wxtim marked this conversation as resolved.
Show resolved Hide resolved
"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"
wxtim marked this conversation as resolved.
Show resolved Hide resolved
"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."
wxtim marked this conversation as resolved.
Show resolved Hide resolved
),
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