Writing Scripts

Overview

Workflow deinitions are text files in YAML format, that are read, compiled, and executed by the Task Runner.

Note

Unless you are a Python programmer, you may have to get used to the fact that whitespace matters in YAML files:
Make sure you indent uniformly. Don’t mix tabs and spaces. We recommend to use an editor that supports the YAML syntax (e.g. VS Code).

A simple confuguration script may look like this:
yabs.yaml:

 1# Yabs Workflow Definition
 2# See https://github.com/mar10/yabs
 3file_version: yabs#1
 4
 5config:
 6  repo: 'mar10/test-release-tool'
 7  version:
 8    - type: __version__
 9      file: src/test_release_tool/__init__.py
10  branches: main  # or master?
11
12
13tasks:
14  # The following tools are available. They are executed in the order
15  # listed here
16
17  # 'check': Assert preconditons and fail otherwise
18  - task: check
19    build: true             # dist/ folder exists
20    can_push: true          # Test if 'git push' would/would not succeed
21    clean: true             # Repo must/must not contain modifications
22    python: ">=3.9"         # SemVer specifier
23    twine: true             # `twine` is available
24    up_to_date: true        # everything pulled from remote
25    venv: true              # running inside a virtual environment
26    version: true           # `setup.py --version` returns the configured version
27    # winget: true            # `wingetcreate` is available
28    yabs: ">=0.5"           # SemVer specifier
29
30  # 'exec': Run arbitrary shell command
31  - task: exec
32    args: ["tox", "-e", "lint"]     # shell command and optional arguments
33    always: true            # `true`: run even in dry-run mode
34
35  # 'bump': Increment project version (requires argument: `yabs run --inc INC`)
36  - task: bump
37    inc: null               # Use value passed as 'yabs run --inc INC'
38
39  # 'commit': Commit modified files
40  - task: commit
41    add_known: true         # Commit with -a flag
42    message: |
43      Bump version to {version}
44
45  # 'tag': Create an annotated tag
46  - task: tag
47    name: v{version}
48    message: |
49      Version {version}
50
51  # 'push': Push changes and tags
52  - task: push
53    tags: true
54
55  # 'pypi_release': Create a release on PyPI using `twine`
56  - task: pypi_release
57    build:
58      - sdist
59      - bdist_wheel
60    upload: true
61
62  # 'github_release': Create a release on GitHub
63  - task: github_release
64    draft: false
65
66  # Bump 'v1.2.3' => 'v1.2.4-a1'
67  - task: bump
68    inc: "postrelease"
69
70  # Commit using '[ci skip]' as part of the message to prevent CI testing
71  - task: commit
72    add_known: true
73    message: |
74      Bump prerelease ({version}) [ci skip]
75
76  # Push to GitHub
77  - task: push

See yabs.yaml for a complete configuration with all available options and defaults.

Note

To get started, run yabs init inside your project’s directory. This will prompt for a few details and create a fresh yabs.yaml file.

Task Types

See also

See Script Reference for a list of all tasks and options
and yabs.yaml for a complete configuration file with all available tasks.

Template Macros

Some tasks have string options such as tag names, commit messges, etc. These strings may contain inline macros that will be expanded.

Typical macros are version, tag_name, repo, …
Macro names must be embedded in curly braces, for example:

- task: github_release
  name: 'v{version}'
  message: |
    Released {version}

    [Changelog](https://github.com/{repo}/blob/master/CHANGELOG.md),
    [Commit details](https://github.com/{repo}/compare/{org_tag_name}...{tag_name}).

All attributes of the task context are available as macros:

{inc}

Value of the --inc argument.

{org_tag_name}

The repo’s latest tag name (before ‘bump’).

{org_version}

Latest version (before ‘bump’).

{repo}

GitHub repo name, e.g. ‘USER/PROJECT’.

{tag_name}

The current tag name (after ‘bump’).

{version}

Current version (after ‘bump’).

See TaskContext for a complete list.

Version Locations

Note

Currently only a small subset is implemented.
Please open an issue if you need another one and are ready to help with testing.

(TODO: verify this section.)

Although there seems to be consent that Python projects should have a version number that is stored at one central location, the community has not agreed upon that location yet.

In order to find and bump this versions, we need to pass a hint in the configuration yabs.yaml like so:

file_version: yabs#1
config:
  ...
  version:
    - type: __version__  # Example!
      file: src/my_project/__init__.py
...

Yabs supports some common approaches.
Following some typical patterns how Python projects store version numbers.

Note

Currently we would recommend this variant (unless Poetry is used):
Store the version in __init__.py of the project’s root folder:

__version__ = "1.2.3"

Then reference this in setup.cfg:

[metadata]
name = my_package
version = attr: my_project.__version__

This would then configured in yabs.yaml like so:

config:
  version:
    - type: __version__
      file: my_project/__init__.py

See below for details about the different use cases.

Poetry

Todo

Not yet implemented.

Poetry stores the version number in its own section in pyproject.toml (defined in PEP-518):

pyproject.toml:

[project]
...
[tool.poetry]
name = "my_project"
version =  "1.2.3"

yabs.yaml:

config:
  version:
    - type: poetry

flit

Todo

Not yet implemented.

__init__.py of the project’s root package

__init__.py:

__version__ = "1.2.3"

yabs.yaml:

config:
  version:
    - type: __version__
      file: src/my_project/__init__.py

Or a variant the mimics Python’s sys.version_info style:

__init__.py:

version_info = (1, 2, 3)
version = ".".join(str(c) for c in version_info)

yabs.yaml:

config:
  version:
    # TODO

Plain Text File

For example a _version.txt file in the project’s src folder containing:

_version.txt:

1.2.3

yabs.yaml:

config:
  version:
    # TODO

setup.cfg

See also PEP-396 and setuptools .

setup.cfg in the project’s root folder:

[metadata]
name = my_package
version = 1.2.3

yabs.yaml:

config:
  version:
    # TODO

The follwing two examples for setup.cfg use the special attr: and file: directives that where introduced with setuptools v39.2 ).

Note: This assumes that the version is stored in a separate text- or Python file, which is covered in the examples above.

[metadata]
name = my_package
version = attr: my_project.__version__
[metadata]
name = my_package
version = file: path/to/file

The follwing two examples for setup.cfg use the special version-file and version-from-file options that where proposed for distutils2.

Note: This assumes that the version is stored in a separate text- or Python file, which is covered in the examples above.

[metadata]
# The entire contents of the file contains the version number
version-file = version.txt
[metadata]
# The version number is contained within a larger file, e.g. of Python code,
# such that the file must be parsed to extract the version
version-from-file = elle.py

Debugging

Use the --verbose (short -v) option to generate more console logging.
Use the --dry-run (short -n) option to run all tasks in a simulation mode:

$ yabs run --inc patch -vn