quitsh

Define your build/CI tooling in a statically typed language. (supports Nix and component repositories - a.k.a. mono-repos)

https://github.com/sdsc-ordes/quitsh

Science Score: 44.0%

This score indicates how likely this project is to be science-related based on various indicators:

  • CITATION.cff file
    Found CITATION.cff file
  • codemeta.json file
    Found codemeta.json file
  • .zenodo.json file
    Found .zenodo.json file
  • DOI references
  • Academic publication links
  • Academic email domains
  • Institutional organization owner
  • JOSS paper metadata
  • Scientific vocabulary similarity
    Low similarity (18.4%) to scientific vocabulary

Keywords

automation ci cli component-based-development devenv go mono-repository monorepo nix
Last synced: 4 months ago · JSON representation ·

Repository

Define your build/CI tooling in a statically typed language. (supports Nix and component repositories - a.k.a. mono-repos)

Basic Info
  • Host: GitHub
  • Owner: sdsc-ordes
  • License: mit
  • Language: Go
  • Default Branch: main
  • Homepage:
  • Size: 694 KB
Statistics
  • Stars: 5
  • Watchers: 1
  • Forks: 0
  • Open Issues: 2
  • Releases: 6
Topics
automation ci cli component-based-development devenv go mono-repository monorepo nix
Created 9 months ago · Last pushed 4 months ago
Metadata Files
Readme Contributing License Code of conduct Citation

README.md

Coverage Current Release Package Pipeline Status License label


[!CAUTION]

This repository is in beta. The design space of this tool is still explored and breaking changes might occure. Documentation is incomplete.

The quitsh framework (/kwɪʧ/) is a build-tooling CLI framework designed to replace loosely-typed scripting languages (e.g., bash, python, and similar alternatives) with the statically-typed language Go. Its goal is to simplify tooling tasks while providing robust, extendable solutions for component repositories (mono-repositories).

quitsh is an opinionated framework born out of frustration with the lack of simple and extendable tooling for mono-repos. It is language-agnostic and toolchain-independent, allowing users to focus on their workflows without being constrained by specific technologies.

Quitsh can be used in two non-coupled ways (enhancing each other):

  • Build/use & extend the CLI quitsh for your tooling/CI/CD scripts in your repository. You write quitsh mycommand --do-it and decide what it does, using the library modules for running subprocesses, logging etc.

  • Use its component feature which gives you the ability to register your tooling scripts (build/lint/test etc.) as runners which can be reused across components. Since runners depend heavily on available executables in your PATH, runners run over a toolchain (currently Nix development shell etc.).

Key Features

Code-First Approach

  • All tooling logic is implemented in Go.
  • Tooling logic is defined primarily in code, avoiding declarative configurations or templated non-typed languages, which often add unnecessary complexity despite their flexibility. Note: Supporting configuration languages like jsonnet or "turing-complete" YAML etc. is particularly avoided. Everything stays strongly-typed and fast compiled.

Extendability

  • quitsh serves as a library to build your customized CLI tool for your specific tasks.
  • Users can add custom commands and specialized tooling features using libraries like cobra, quitsh mycommand --do-it.

Component System

  • Components (i.e., buildable units) are identified by placing a configuration file (default: .component.yaml) in the corresponding subdirectory.

Targets and Steps

  • Each component defines targets, which consist of multiple steps.
  • Targets can depend on other targets across the repository.
  • Input change sets can be specified for each target to track modifications and determine if the target is outdated.

Runner System

  • Steps within targets are executed by runners, which are written by you in Go and act as reusable replacements for traditional build/tooling scripts.
  • Runners can have custom YAML configuration options specified per component in .component.yaml.

Toolchain Dispatch

  • Runners are associated with specific toolchains.
  • By default, quitsh includes a Nix development shell dispatch, providing stable and reproducible environments.
  • While container-based dispatching is not a primary goal, it can be implemented by extending the dispatch interface.

  • The tool was built to replicate the same procedure one executes during local development and also in CI. Having CI align with what you execute locally is not a nice thing to have, its a necessity. Nix development shells (or containers) help with this. A Nix shell provides a simple and robust abstraction to pin a toolchain. The following visualization gives an overview about how quitsh is used:

quitsh-design

Built-in Libraries

The pkg folder offers utilities for common development needs, such as:

  • Command Execution: pkg/exec provides utilities for process execution and command chaining.
  • Structured Logging: pkg/log enables consistent and readable logging.
  • Error Handling: pkg/error facilitates contextual error management.
  • Dependency Graphs: Tools for managing and resolving dependency graphs across targets.
  • Some Go test runners (here as an example) for running Go tests (its used internally to test quitsh it-self).

Performance

  • Since all tooling is written in Go, quitsh provides type safety and fast performance by default.
  • Combined with a Nix-based toolchain dispatch and the ability to write tests easily, the framework significantly accelerates the "change, test, improve" workflow.

Nix Integration

  • A CLI tool built with quitsh can be seamlessly packaged into a Nix development shells, ensuring accessibility for all users of a given repository.

How To Use It?

Using this library follows instantiating the CLI (also demonstrated in this repository in main.go, e.g.:

```go args := cliconfig.New()

cli, err := cli.New( &args.Commands.Root, &args, cli.WithName("cli"), cli.WithDescription("This is the 🐔-🥚 CLI tool for 'quitsh', yes its built with 'quitsh'."), cli.WithCompFindOptions( query.WithFindOptions( fs.WithWalkDirFilterPatterns(nil, []string{"/test/repo/"}, true))), cli.WithStages("lint", "build", "test"), cli.WithTargetToStageMapperDefault(), cli.WithToolchainDispatcherNix( "tools/nix", func(c config.IConfig) *toolchain.DispatchArgs { cc := common.Cast*cliconfig.Config

  return &cc.Commands.DispatchArgs
},

), ) ```

You can now add runners and your own commands depending on the needs of your repository. For example in main.go:

go listcmd.AddCmd(cli, cli.RootCmd()) configcmd.AddCmd(cli.RootCmd(), &conf) exectarget.AddCmd(cli, cli.RootCmd()) execrunner.AddCmd(cli, cli.RootCmd(), &conf.Commands.DispatchArgs)

adds essential quitsh commands

  • listcmd to list all components etc: quitsh list.
  • configcmd to inspect/write the config file: quitsh config ....
  • exectarget to execute specific targets quitsh exec-target.
  • execrunner to let quitsh dispatch over toolchains (see cli.WithToolchainDispatcherNix above): quitsh exec-runner ...

There are lots of more useful commands in pkg/cli/cmd which you might use.

Useful References

A reference repository with commands and runner can be looked at here:

Config

Quitsh runs with global config YAML file which it loads (or defaults) at startup for any invocation. The above CLI instantiation constructs a new config with cliconfig.New() (this is custom for each usecase and can be adjusted and modified). The config defines global settings (output directories, logging etc.) and also various custom, use-case specific settings. These might include settings which runners (or custom commands) might use during execution. For example build runners might use a build.BuildType property which could be debug or release etc. The CLI does not care about your custom settings, they only need to be fully serializable to YAML (for toolchain dispatching) and you can override defaults from custom added commands for example.

Modifying Config Values

You have the ability to set the config file quitsh uses with --config or read it from stdin with --config - or set options (YAML) on the command line with --config-value. For example --config-value "build.buildType: release" would set the build.BuildType setting to release on startup.

Components

Quitsh builds around components. A component should be treated as an own compartment/Git repository or directory with its own independent source code and output.

A component in quitsh is defined by a .component.yaml (name is configurable):

```yaml

The name of the component: Must be a unique.

name: my-component

A semantic version.

This is useful for Nix packaging etc.

version: 0.2.1

A simple annotation (not used internally) what main language this component uses.

language: go

targets: # A target called test with two steps. my-test: # The stage to which this target belongs. Does not need to be provided # if the CLI is setup to map target names to stages. stage: test

steps:
  # Step 1: Using runner with ID (how it was registered).
  - runner-id: banana-project::my-test-runner
    config: # Your custom runner YAML config, (optional).

  # Step 2: Using a runner with registered key (stage: `test`, name `my-test`)
  - runner: my-test

# A target called build-all with one step. build-all: stage: build

# Defining when this target is considered changed:
# i.e. whenever `self::sources` input change set is changed.
# `self` maps to this component.
inputs: ["self::sources"]

# Defining dependencies on other targets such that this
# target is executed after target `my-test` above.
# You can also link to other components (e.g `other-comp::build`).
depends: ["self::my-test"]

steps:
  # Step 1: Using a runner with registered key (stage: `build`, name `my-test`)
  - runner: my-build
    config:
      tags: ["doit"]

lint: steps: - ... other steps ...

inputs: # An input change set with name sources which defines # patterns to match all source files. sources: # A regex which matches *.go files in ./src in the components folder. patterns: - '^./src/.*.go$' ```

Execution of Targets

The execution of steps by quitsh is done by reading a .component.yaml for each component. The .component.yaml file contains inputs and targets.

Quitsh's own .component.yaml looks like:

```yaml name: quitsh language: go

inputs: srcs: patterns: - "^.*$"

targets: test: stage: test steps: - runner: go - runner: go-bin config: # Build everything instrumented. # Execute the binaries via a go test provided in the following # pkg and with tags. buildPkg: test/cmd testPkg: test buildTags: ["integration"] testTags: ["integration"]

build: steps: - runner: go lint: steps: - runner: go ```

Each target defines is a set of steps which itself are further specified by the field runner. A runner is Go code applicable for a certain step which should work for all components.

A runner is registered in factory, for example here. Runners can be written by implementing the interface Runner inside ./pkg/runner/runners and registering them in [./pkg/runner/factory/init-runners.go], for example here.

[!NOTE]

You can execute targets in parallel with --parallel.

Runner Configuration

Runners can load independent YAML config under config to make them configurable, e.g. the go build runner loads the following config:

yaml steps: build: - runner: go config: version-module: "pkg/myversion-module" # defaults to `pkg/build`

Target Stages

Each target also maps to a stage which quitsh uses to group targets together if you want to find them and make gathering commands such as the example build here. It collects and runs all targets in the stage build.

How to Extend Functionality

For users using the quitsh CLI framework, it is suggested to follow the following points when thinking about new functionality in a repository which uses this library. If you need new functionality for CI and local development which you normally would write in bash/python follow the following steps:

  • If the functionality is a feature needed in an existing runner and step: Extend the runner and make it work with your new test/build/lint feature.

  • If the functionality is not related to a runner or the same for each component with that language: Extend quitsh by providing another subcommand which does what you need, see this example fix-hash.

  • If the functionality is for a certain language, e.g. go or python and applies to each component which is written in that language: consider adding a new runner for an already pre-defined stage, e.g. lint, build etc.

Example Applications

Understand what this framework does, is best accomplished by understanding how we use this framework in our components repo (mono-repo). Our major components are located in ./components.

Owner

  • Name: Swiss Data Science Center - ORD
  • Login: sdsc-ordes
  • Kind: organization
  • Location: Switzerland

Open Research Data team at the Swiss Data Science Center.

Citation (CITATION.cff)

cff-version: 1.2.0
message: "If you use this software, please cite it as below."
title: "quitsh"
authors:
  - family-names: Nützi
    given-names: Gabriel
    orcid: "https://orcid.org/0009-0008-8197-2851"
    affiliation: "SDSC - Swiss Data Science Center"
date-released: 2025-01-21
version: "0.14.0"
url: https://github.com/sdsc-ordes/quitsh
repository-code: https://github.com/sdsc-ordes/quitsh
keywords:
  - build-tooling
  - cli-framework
  - ci
  - go
  - nix
  - dependency-graph
  - build-targets
  - mono-repository
  - typed-scripting
  - devenv
  - automation
  - component-based-development
license: mit

GitHub Events

Total
  • Create event: 49
  • Release event: 4
  • Issues event: 1
  • Watch event: 6
  • Delete event: 31
  • Issue comment event: 29
  • Public event: 1
  • Push event: 132
  • Pull request review event: 1
  • Pull request event: 52
Last Year
  • Create event: 49
  • Release event: 4
  • Issues event: 1
  • Watch event: 6
  • Delete event: 31
  • Issue comment event: 29
  • Public event: 1
  • Push event: 132
  • Pull request review event: 1
  • Pull request event: 52

Issues and Pull Requests

Last synced: 4 months ago

All Time
  • Total issues: 1
  • Total pull requests: 5
  • Average time to close issues: N/A
  • Average time to close pull requests: 9 minutes
  • Total issue authors: 1
  • Total pull request authors: 1
  • Average comments per issue: 1.0
  • Average comments per pull request: 0.4
  • Merged pull requests: 3
  • Bot issues: 0
  • Bot pull requests: 0
Past Year
  • Issues: 1
  • Pull requests: 5
  • Average time to close issues: N/A
  • Average time to close pull requests: 9 minutes
  • Issue authors: 1
  • Pull request authors: 1
  • Average comments per issue: 1.0
  • Average comments per pull request: 0.4
  • Merged pull requests: 3
  • Bot issues: 0
  • Bot pull requests: 0
Top Authors
Issue Authors
  • gabyx (1)
Pull Request Authors
  • gabyx (31)
  • rmfranken (1)
Top Labels
Issue Labels
Pull Request Labels

Packages

  • Total packages: 1
  • Total downloads: unknown
  • Total dependent packages: 0
  • Total dependent repositories: 0
  • Total versions: 21
proxy.golang.org: github.com/sdsc-ordes/quitsh
  • Versions: 21
  • Dependent Packages: 0
  • Dependent Repositories: 0
Rankings
Dependent packages count: 5.7%
Average: 5.9%
Dependent repos count: 6.0%
Last synced: 4 months ago

Dependencies

.github/actions/setup-nix/action.yaml actions
  • cachix/cachix-action v15 composite
  • cachix/install-nix-action v30 composite
.github/workflows/format.yaml actions
  • ./.github/actions/setup-nix * composite
  • actions/checkout v4 composite
.github/workflows/normal.yaml actions
  • ./.github/actions/setup-nix * composite
  • actions/checkout v4 composite
go.mod go
  • deedles.dev/xiter v0.1.1
  • github.com/bmatcuk/doublestar/v4 v4.7.1
  • github.com/charlievieth/fastwalk v1.0.9
  • github.com/containers/image/v5 v5.33.0
  • github.com/containers/storage v1.56.0
  • github.com/creasty/defaults v1.8.0
  • github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc
  • github.com/gabriel-vasile/mimetype v1.4.7
  • github.com/go-playground/assert/v2 v2.2.0
  • github.com/go-playground/locales v0.14.1
  • github.com/go-playground/universal-translator v0.18.1
  • github.com/go-playground/validator/v10 v10.23.0
  • github.com/goccy/go-yaml v1.15.13
  • github.com/golang-cz/devslog v0.0.11
  • github.com/hashicorp/errwrap v1.1.0
  • github.com/hashicorp/go-multierror v1.1.1
  • github.com/hashicorp/go-version v1.7.0
  • github.com/huandu/go-clone v1.7.2
  • github.com/inconshreveable/mousetrap v1.1.0
  • github.com/leodido/go-urn v1.4.0
  • github.com/mattn/go-isatty v0.0.20
  • github.com/opencontainers/go-digest v1.0.0
  • github.com/otiai10/copy v1.14.0
  • github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2
  • github.com/spf13/cobra v1.8.1
  • github.com/spf13/pflag v1.0.5
  • github.com/stretchr/testify v1.10.0
  • golang.org/x/crypto v0.31.0
  • golang.org/x/mod v0.22.0
  • golang.org/x/net v0.33.0
  • golang.org/x/sync v0.10.0
  • golang.org/x/sys v0.28.0
  • golang.org/x/text v0.21.0
  • gopkg.in/yaml.v3 v3.0.1
go.sum go
  • deedles.dev/xiter v0.1.1
  • github.com/bmatcuk/doublestar/v4 v4.7.1
  • github.com/charlievieth/fastwalk v1.0.9
  • github.com/containers/image/v5 v5.33.0
  • github.com/containers/storage v1.56.0
  • github.com/cpuguy83/go-md2man/v2 v2.0.4
  • github.com/creasty/defaults v1.8.0
  • github.com/davecgh/go-spew v1.1.0
  • github.com/davecgh/go-spew v1.1.1
  • github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc
  • github.com/gabriel-vasile/mimetype v1.4.7
  • github.com/go-playground/assert/v2 v2.2.0
  • github.com/go-playground/locales v0.14.1
  • github.com/go-playground/universal-translator v0.18.1
  • github.com/go-playground/validator/v10 v10.23.0
  • github.com/goccy/go-yaml v1.15.13
  • github.com/golang-cz/devslog v0.0.11
  • github.com/hashicorp/errwrap v1.0.0
  • github.com/hashicorp/errwrap v1.1.0
  • github.com/hashicorp/go-multierror v1.1.1
  • github.com/hashicorp/go-version v1.7.0
  • github.com/huandu/go-assert v1.1.5
  • github.com/huandu/go-clone v1.7.2
  • github.com/inconshreveable/mousetrap v1.1.0
  • github.com/leodido/go-urn v1.4.0
  • github.com/mattn/go-isatty v0.0.20
  • github.com/opencontainers/go-digest v1.0.0
  • github.com/otiai10/copy v1.14.0
  • github.com/otiai10/mint v1.5.1
  • github.com/pmezard/go-difflib v1.0.0
  • github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2
  • github.com/russross/blackfriday/v2 v2.1.0
  • github.com/spf13/cobra v1.8.1
  • github.com/spf13/pflag v1.0.5
  • github.com/stretchr/objx v0.1.0
  • github.com/stretchr/testify v1.4.0
  • github.com/stretchr/testify v1.10.0
  • golang.org/x/crypto v0.31.0
  • golang.org/x/mod v0.22.0
  • golang.org/x/net v0.33.0
  • golang.org/x/sync v0.10.0
  • golang.org/x/sys v0.6.0
  • golang.org/x/sys v0.28.0
  • golang.org/x/text v0.21.0
  • gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405
  • gopkg.in/yaml.v2 v2.2.2
  • gopkg.in/yaml.v3 v3.0.1
test/repo/component-a/go.mod go
  • github.com/agnivade/levenshtein v1.1.1
test/repo/component-a/go.sum go
  • github.com/agnivade/levenshtein v1.1.1
  • github.com/arbovm/levenshtein v0.0.0-20160628152529-48b4e1c0c4d0
  • github.com/dgryski/trifles v0.0.0-20200323201526-dd97f9abfb48
tools/cli/go.mod go
  • ../.. *
  • deedles.dev/xiter v0.1.1
  • github.com/bmatcuk/doublestar/v4 v4.7.1
  • github.com/charlievieth/fastwalk v1.0.9
  • github.com/containers/image/v5 v5.33.0
  • github.com/containers/storage v1.56.0
  • github.com/creasty/defaults v1.8.0
  • github.com/gabriel-vasile/mimetype v1.4.7
  • github.com/go-playground/locales v0.14.1
  • github.com/go-playground/universal-translator v0.18.1
  • github.com/go-playground/validator/v10 v10.23.0
  • github.com/goccy/go-yaml v1.15.13
  • github.com/golang-cz/devslog v0.0.11
  • github.com/hashicorp/errwrap v1.1.0
  • github.com/hashicorp/go-multierror v1.1.1
  • github.com/hashicorp/go-version v1.7.0
  • github.com/huandu/go-clone v1.7.2
  • github.com/inconshreveable/mousetrap v1.1.0
  • github.com/leodido/go-urn v1.4.0
  • github.com/mattn/go-isatty v0.0.20
  • github.com/opencontainers/go-digest v1.0.0
  • github.com/otiai10/copy v1.14.0
  • github.com/spf13/cobra v1.9.1
  • github.com/spf13/pflag v1.0.6
  • golang.org/x/crypto v0.31.0
  • golang.org/x/mod v0.22.0
  • golang.org/x/net v0.33.0
  • golang.org/x/sync v0.10.0
  • golang.org/x/sys v0.28.0
  • golang.org/x/text v0.21.0
tools/cli/go.sum go
  • deedles.dev/xiter v0.1.1
  • github.com/bmatcuk/doublestar/v4 v4.7.1
  • github.com/charlievieth/fastwalk v1.0.9
  • github.com/containers/image/v5 v5.33.0
  • github.com/containers/storage v1.56.0
  • github.com/cpuguy83/go-md2man/v2 v2.0.6
  • github.com/creasty/defaults v1.8.0
  • github.com/davecgh/go-spew v1.1.0
  • github.com/davecgh/go-spew v1.1.1
  • github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc
  • github.com/gabriel-vasile/mimetype v1.4.7
  • github.com/go-playground/assert/v2 v2.2.0
  • github.com/go-playground/locales v0.14.1
  • github.com/go-playground/universal-translator v0.18.1
  • github.com/go-playground/validator/v10 v10.23.0
  • github.com/goccy/go-yaml v1.15.13
  • github.com/golang-cz/devslog v0.0.11
  • github.com/hashicorp/errwrap v1.0.0
  • github.com/hashicorp/errwrap v1.1.0
  • github.com/hashicorp/go-multierror v1.1.1
  • github.com/hashicorp/go-version v1.7.0
  • github.com/huandu/go-assert v1.1.5
  • github.com/huandu/go-clone v1.7.2
  • github.com/inconshreveable/mousetrap v1.1.0
  • github.com/leodido/go-urn v1.4.0
  • github.com/mattn/go-isatty v0.0.20
  • github.com/opencontainers/go-digest v1.0.0
  • github.com/otiai10/copy v1.14.0
  • github.com/otiai10/mint v1.5.1
  • github.com/pmezard/go-difflib v1.0.0
  • github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2
  • github.com/russross/blackfriday/v2 v2.1.0
  • github.com/spf13/cobra v1.9.1
  • github.com/spf13/pflag v1.0.6
  • github.com/stretchr/objx v0.1.0
  • github.com/stretchr/testify v1.4.0
  • github.com/stretchr/testify v1.10.0
  • golang.org/x/crypto v0.31.0
  • golang.org/x/mod v0.22.0
  • golang.org/x/net v0.33.0
  • golang.org/x/sync v0.10.0
  • golang.org/x/sys v0.6.0
  • golang.org/x/sys v0.28.0
  • golang.org/x/text v0.21.0
  • gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405
  • gopkg.in/yaml.v2 v2.2.2
  • gopkg.in/yaml.v3 v3.0.1