rats.ci
¶
Commands for building and validating components.
The rats-ci
application provides a set of sub-commands that represent common operations done in
the typical CI pipeline. Wrapping the CI logic into a cli application allows us to run these same
checks locally during development, and reproduce any possible issues that fail the CI pipeline,
avoiding a long development loop. The rats-ci
command can be installed repo-wide in a monorepo,
but the commands should be run from within a component, where the pyproject.toml
file is located.
When using the rats-ci
application within a monorepo, we can give developers a common API while
adapting to the different technology choices within any given component.
CLI¶
The rats-ci
command is broken up into build-image
, check
, fix
, install
, and test
groups, which map to one or more default commands that can be customized by users. Any number of
the provided commands can be run in sequence, so rats-ci fix check test
is often used as a quick
way to fix any linting errors automatically, when possible; running the linting and typing checks,
as configured by the component being checked; and any unit tests, using pytest
by default.
Usage: rats-ci [OPTIONS] COMMAND1 [ARGS]... [COMMAND2 [ARGS]...]...
commands used during ci/cd
Options:
--help Show this message and exit.
Commands:
build-image Build a container image of the component.
check Run any configured linting & typing checks for the component.
config Show information about the configured command groups for active
component.
fix Run any configured auto-formatters for the component.
install Install the development environment for the component.
test Run any configured tests for the component.
Configuration¶
Info
The default configuration reflects the tools and options we use when developing rats.
However, we want the entire development team to use a common set of commands, like
rats-ci check
to run linting and other type checking rules, regardless of any differences
in language or configuration across components. Separating the implementation details from the
CI/CD concepts allows the team to contribute across a growing code base without needing to
memorize a new set of development commands; and without needing to force all components to
follow a very rigid set of commands.
Apart from configuring each group with the settings below, we can configure all groups in one operation using the rats.ci.AppConfigs.COMMAND_GROUPS service.
You can run rats-ci config
to see the current configuration for the ci commands within your
component. If you haven't modified the defaults, you should see the configuration below.
$ cd rats-apps
$ rats-ci config
component: rats-apps
install
poetry install
fix
ruff check --fix --unsafe-fixes
ruff format
check
ruff format --check
ruff check
pyright
test
pytest
install¶
We're currently using Poetry for dependency management, so the
rats-ci install
command maps simply to poetry install
by default. In simple cases, this command
might not be immediately necessary on most projects; but if installing all the development
dependencies in a component requires more than one command, or you have components other than
python packages, you can update the rats.ci.AppConfigs.INSTALL service to define your
installation steps.
fix¶
The rats-ci fix
command tries to make any linting or style fixes possible. Any kind of automated
formatting tools that can remove tedious process for maintaining a common style across the project,
and can avoid failing CI builds for uninteresting reasons that would create a long, annoying
feedback loop. By default, we run ruff check --fix --unsafe-fixes
and ruff format
, and expect
the component being fixed to have ruff installed and configured,
as usual. The default behavior can be updated by setting rats.ci.AppConfigs.FIX.
check¶
Any linting and typing errors that can't be automatically fixed with rats-ci fix
, can be detected
with rats-ci check
. We run ruff format --check
, ruff check
, and pyright
, but these defaults
can be changed with the rats.ci.AppConfigs.CHECK service.
test¶
We run our test suite with pytest
, but occasionally register additional commands to run
integration and end-to-end tests. The rats.ci.AppConfigs.TEST service can be provided to change
the configured test suite.
build-container¶
The rats-ci build-container
command builds and pushes a container image based on the value of
the DEVTOOLS_IMAGE_REGISTRY
and DEVTOOLS_IMAGE_TAG
environment variables. If
DEVTOOLS_IMAGE_TAG
is not defined, we use the rats.projects module to calculate a tag based
on the hash of all the files available to the build context. The image push can be disabled by
setting the DEVTOOLS_IMAGE_PUSH_ON_BUILD=0
environment variable.
$ cd rats-apps
$ rats-ci build-image
building docker image: example.azurecr.io/rats-apps:8b79a4344354…
[+] Building 2.5s (14/14) FINISHED
=> [internal] load build definition from Containerfile
=> => transferring dockerfile: 1.41kB
…
=> [1/9] FROM mcr.microsoft.com/mirror/docker/library/ubuntu:24.04
…
=> [9/9] COPY . /opt/rats
=> exporting to image
=> => exporting layers
=> => writing image sha256:2150f859e…
=> => naming to example.azurecr.io/rats-apps:8b79a434…
…
5f70bf18a086: Layer already exists
ef2fe6e1db4c: Pushed
b02f35d52f65: Pushed
…
8b79a4…aa69d: digest: sha256:a2c3356…4c9ca size: 2199
Info
For legacy reasons, the rats-ci build-container
command is not yet configurable in the same
way the others are, but we hope to address this in a future release.
__all__ = ['AppConfigs', 'AppServices', 'Application', 'CiCommandGroups', 'main']
module-attribute
¶
AppConfigs
¶
COMMAND_GROUPS = apps.ServiceId[CiCommandGroups]('command-groups')
class-attribute
instance-attribute
¶
Brings together the individual commands into a single config object.
Defining this service allows the entire configuration to be done in a single provider method, in case none of the defaults are desired.
from rats import apps, ci
class PluginContainer(apps.Container, apps.PluginMixin):
@apps.service(ci.AppConfigs.COMMAND_GROUPS)
def _cmd_groups(self) -> CiCommandGroups:
return CiCommandGroups(
install=tuple(
tuple(["uv", "sync"]),
),
fix=tuple(
tuple(["ruff", "check", "--fix"]),
),
check=tuple(
tuple(["ruff", "check"]),
),
test=tuple(
tuple(["pytest"]),
),
)
INSTALL = apps.ServiceId[Collection[str]]('install')
class-attribute
instance-attribute
¶
FIX = apps.ServiceId[Collection[str]]('fix')
class-attribute
instance-attribute
¶
CHECK = apps.ServiceId[Collection[str]]('check')
class-attribute
instance-attribute
¶
TEST = apps.ServiceId[Collection[str]]('test')
class-attribute
instance-attribute
¶
Application(app)
¶
Bases: apps.AppContainer
, cli.Container
, apps.PluginMixin
Main application for the rats-ci
cli commands.
Not typically used directly, but can be invoked using rats.apps.AppBundle within tests or in advanced workflows.
from rats import apps, ci
ci_app = apps.AppBundle(app_plugin=ci.Application)
ci_app.install()
ci_app.fix()
ci_app.check()
ci_app.test()
Warning
Calling ci_app.execute()
is unlikely to behave as expected, because sys.argv is
parsed by the click library.
Source code in rats/apps/_app_containers.py
config()
¶
Show information about the configured command groups for active component.
Refer to rats.ci for details on how to update these values.
Source code in src/rats/ci/_app.py
install()
¶
Install the development environment for the component.
Refer to rats.ci.AppConfigs.INSTALL for details on how to update these values.
Source code in src/rats/ci/_app.py
fix()
¶
Run any configured auto-formatters for the component.
Refer to rats.ci.AppConfigs.FIX for details on how to update these values.
Source code in src/rats/ci/_app.py
check()
¶
Run any configured linting & typing checks for the component.
Refer to rats.ci.AppConfigs.CHECK for details on how to update these values.
Source code in src/rats/ci/_app.py
test()
¶
Run any configured tests for the component.
Refer to rats.ci.AppConfigs.TEST for details on how to update these values.
Source code in src/rats/ci/_app.py
build_image()
¶
Build a container image of the component.
Source code in src/rats/ci/_app.py
AppServices
¶
Service IDs used by the rats.ci.Application class.
The rats-ci
application will move to using rats.apps.Executable classes to define
the behavior of the various commands. You can replace the default behavior of any of the given
commands by registering one or more executables to the appropriate service group. This approach
gives you more control over the logic of the commands, and works well when the exposed configs
in rats.ci.AppConfigs are not enough.
INSTALL_EXES = apps.ServiceId[apps.Executable]('install-exes')
class-attribute
instance-attribute
¶
Service group of executables to run with rats-ci install
.
FIX_EXES = apps.ServiceId[apps.Executable]('fix-exes')
class-attribute
instance-attribute
¶
Service group of executables to run with rats-ci fix
.
CHECK_EXES = apps.ServiceId[apps.Executable]('check-exes')
class-attribute
instance-attribute
¶
Service group of executables to run with rats-ci check
.
TEST_EXES = apps.ServiceId[apps.Executable]('test-exes')
class-attribute
instance-attribute
¶
Service group of executables to run with rats-ci test
.
BUILD_IMAGE_EXES = apps.ServiceId[apps.Executable]('build-image-exes')
class-attribute
instance-attribute
¶
Service group of executables to run with rats-ci build-image
.
CiCommandGroups
¶
Bases: NamedTuple
Main configuration object for the rats-ci
subcommands.
install
instance-attribute
¶
Set of commands meant to be run as part of rats-ci install
.
fix
instance-attribute
¶
Set of commands meant to be run as part of rats-ci fix
.
check
instance-attribute
¶
Set of commands meant to be run as part of rats-ci check
.
test
instance-attribute
¶
Set of commands meant to be run as part of rats-ci test
.
main()
¶
The main entry-point for the application, used to define the python script for `rats-ci.