Sign inSign up

flywheel/qa-ci

By flywheel

•Updated about 17 hours ago

Flywheel QA/CI toolset

Image
0

500K+

flywheel/qa-ci repository overview

⁠QA/CI - pre-commit hooks and GitLab CI templates

Standardized development workflows and continuous integration pipelines using

  • pre-commit⁠ for running linters locally
  • GitLab CI⁠ for doing the same in CI then publishing artifacts and running further automation.

⁠Table of Contents

[TOC]

⁠Usage

  1. Ensure you have bash, docker and pre-commit installed:

    brew install bash docker pre-commit
    
  2. Create a .pre-commit-config.yaml in your project:
    This is the recommended hook configuration for containerized python apps.
    Check out the pre-commit⁠ section for details and options.

    repos:
      - repo: https://gitlab.com/flywheel-io/tools/etc/qa-ci
        rev: main
        hooks:
          - id: eolfix
          - id: hadolint
          - id: helmcheck
          - id: jsonlint
          - id: linkcheck
          - id: markdownlint
          - id: poetry_export
          - id: ruff
          - id: ruff_format
          - id: ruff_tests
          - id: shellcheck
          - id: yamllint
    
  3. Create a .gitlab-ci.yml in your project:
    This is the recommended CI configuration for containerized python apps.
    Check out the GitLab CI⁠ section for details and options.

    include:
      - project: flywheel-io/tools/etc/qa-ci
        ref: main
        file: ci/app.yml
    
  4. Update the qa-ci reference in both files from main to a non-mutable rev:
    The pre-commit and the gitlab-ci revs should always be pinned and in sync.

    pre-commit try-repo https://gitlab.com/flywheel-io/tools/etc/qa-ci autoupdate
    
  5. Profit! Your project can now be tested using pre-commit and CI is configured to run the same tests and to publish any project artifacts as needed.

    pre-commit run -a         # run all the hooks
    pre-commit install        # auto-run hooks before you commit
    

⁠pre-commit

Hooks help identifying issues before submission to code review. Running hooks before every commit allows pointing out problems like invalid YAML syntax, non-standard code formatting or broken tests. Fixing these before code review allows reviewers to focus on the architecture of the change while not wasting time on style nitpicks or worrying about whether the tests pass.

Using pre-commit provides a single, unified entry point for all building, linting and testing activities related to a project's development lifecycle, all driven from .pre-commit-config.yaml. Running the same command to invoke the same or similar tasks lowers friction when switching between projects and facilitates code standardization as well as CI automation.

⁠Hook configuration
  • Hooks are configured with .pre-commit-config.yaml.
    Projects using the py/docker/helm stack should use the recommended hooks listed in the Usage⁠ section above and documented in detail in the Supported hooks⁠ section below.

  • Hooks come with a recommended configuration to aid in code standardization across projects. You can override the defaults by passing your own hook args:

    hooks:
      - id: ruff
        args: [--select, "PL"]  # override qa-ci's default
    
  • You can inspect a CLI tools' help text to discover their available args:

    docker run -it --rm flywheel/qa-ci ruff --help
    
  • Hooks can be disabled by commenting them out, which is useful for adopting them gradually in existing projects:

    hooks:
    # - id: shellcheck  # disable shellcheck by commenting it out
    
  • Hooks can be extended with 3rd party hooks⁠ and custom local⁠ entries:

    # add 3rd party hook after the qa-ci ones:
    - repo: https://github.com/pre-commit/pre-commit-hooks
      rev: v4.3.0
      hooks:
        - id: trailing-whitespace
    
  • Finally, hooks can be removed if they are not relevant to your project.

⁠Supported hooks

This section describes the qa-ci hooks' behavior and configuration in detail. You can inspect the supported hook entries and their default arguments in .pre-commit-hooks.yaml⁠.
Qa-ci hooks are containerized to minimize dev environment setup time and to increase reproducibility across developer machines and CI runners.
Hooks may generate new files or reformat existing files in place. Eg.: ruff format may change whitespace in python code.
When this happens to tracked files, pre-commit will consider that hook failed. To fix this, simply commit that diff and re-run the hook.

⁠eolfix

Fix text files (i.e.: any source code) to enforce LF line endings and to ensure a single LF at EOF (no more, no less).

Links:

⁠hadolint

Lint Dockerfile to enforce best practices with hadolint. Uses shellcheck under the hood to lint the RUN instructions as well.

Links:

⁠helmcheck

Document, lint, test and security-scan helm charts with a custom qa-ci script helmcheck.sh. Runs helm-docs to generate the chart README, then renders the templates with test values to run yamllint, helm lint, kubeconform and kubesec on the rendered YAMLs.

Test values files are useful for templating charts that have required values and/or test-covering the templating logic on various if/else branches. Custom test values can be placed in the helm/<project>/tests/ dir, eg: helm/my-app/tests/test_nodeport.yaml If there are no custom tests, the chart will be tested using defaults. The overrides of skaffold.yaml (if present) are also used for testing.

Links:

⁠jsonlint

Lint JSON files for syntax, uniform indentation and style with jsonlint. Formats .json files in-place to consistently use 2 spaces for indentation.

Links:

⁠linkcheck

Check text files for dead links with a custom qa-ci script linkcheck.py.

Looks for HTTP links in any text file using regex and attempts to issue a HEAD request on all the URLs found. Ignores links

  • without a top level domain (eg. localhost)
  • with top level domain local and test
  • with domain helm.dev.flywheel.io and local.flywheel.io
  • matching any of the --ignore patterns passed as arguments

When checking links, strip URL fragments and consider:

  • 2xx, 401 and 403 as success (assume unauthorized responses are OK)
  • 503 as success for gitlab links (which return 503 on private repos)
  • everything else as failure

In addition to HTTP URLs, check markdown header / file references.

Links:

⁠markdownlint

Lint markdown files for syntax, line length, style and more with markdownlint. Re-formats .md files in-place to consistently use indentation and newlines.

  • The CLI arguments (hook args) can be used to enable/disable linter rules
  • To access all config options, you need to use a config file named .markdownlint-cli2.yaml
  • On projects without a config, defaults to the qa-ci config file that sets the max line length to 88 and allow inline HTML like <br/>.

Links:

⁠poetry_export

Export python dependencies from pyproject.toml to requirements.txt with poetry.

Python project dependencies should be managed with poetry. Exporting the required packages with their versions pinned into the simpler requirements.txt format allows installing them pip:

pip install -r requirements.txt

This can be useful for writing a Dockerfile without installing poetry for example, since it's a large, hard-to-containerize utility.

  • Prod dependencies will be exported into requirements.txt.
  • Dev-only dependencies will be exported into requirements-dev.txt.
  • Extras named all will also be included in requirements-dev.txt.
  • If there are any extras, all is required for this hook to work.

Links:

⁠ruff

Lint python code with static analyzer ruff. Supersedes isort, pylint and pydocstyle.

Links:

⁠ruff_format

Format python code with ruff to ensure uniform whitespace and style.

Links:

⁠ruff_tests

Lint python tests using less strict defaults with static analyzer ruff.

⁠shellcheck

Lint shell scripts with the static analyzer shellcheck.

Links:

⁠yamllint

Lint YAML files for syntax, uniform indentation and style with yamllint. Formats .yaml files in-place to consistently use 2 spaces as indentation and to enforce maximum line length 88 - among many other rules.

Links:

⁠GitLab CI

https://gitlab.com/flywheel-io/infrastructure/deployments/flywheel-build/build-cluster⁠

GitLab CI stages⁠ allow grouping jobs into different stages where jobs in the same stage are executed in parallell but the stages are run one after the other, making their order important.

All jobs defined in CI templates are assigned to a stage. The complete list of stages currently in use across the qa-ci templates are:

stages:
  - test     # run pre-commit
  - publish  # push artifacts (docker/helm/poetry/pages)
  - release  # automatic release mr and repo tagging using the bot
  - update   # automatic repo updates and external project triggers
⁠Pipelines

Qa-ci comes with full, off-the-shelf pipelines for application components, standalone docker images and python libraries.
Projects matching any of these use cases should use an off-the-shelf pipeline. Standardizing CI pipelines lowers friction when switching between projects and facilitates more and better automation.

⁠Flywheel application components

For python applications with a Dockerfile and a Helm chart that integrate into the Flywheel umbrella⁠ chart as a sub-compontent.
Source: ci/app.yml⁠

include:
  - project: flywheel-io/tools/etc/qa-ci
    ref: main
    file: ci/app.yml
⁠Docker base and utility images

For projects with a Dockerfile that are not tied to an application component, but contain utilities (or just useful layers) that are distributed as a docker image on Docker Hub⁠ under the flywheel repository.
Source: ci/img.yml⁠

include:
  - project: flywheel-io/tools/etc/qa-ci
    ref: main
    file: ci/img.yml
⁠Python libraries

For open-source python libraries published on PyPI⁠ and for private ones on GitLab Package Registry⁠.
Source: ci/lib.yml⁠

include:
  - project: flywheel-io/tools/etc/qa-ci
    ref: main
    file: ci/lib.yml
⁠Job templates

CI job templates allow selecting and/or customizing your jobs instead of relying on any set of jobs defined in one of the pipeline templates listed above.

To use a job template, include ci/templates.yml⁠ and extend it:

include:
  - project: flywheel-io/tools/etc/qa-ci
    ref: main
    file: ci/templates.yml

build:docker:
  extends: .build:docker
⁠.build:docker

Build the project's Docker image and push it to the GitLab container registry as $CI_REGISTRY_IMAGE:$CI_PIPELINE_ID. The registry feature must be enabled in the project settings General > Visibility, project features, permissions.
Runs on every MR, main branch commit and tag if a Dockerfile exists.

⁠.test:pre-commit

Run the project's pre-commit hooks as configured in the .pre-commit-config.yaml. The job is pre-configured to support pytest coverage reports.

⁠.publish:docker

Pull the build image from the GitLab registry and tag and push it to Docker Hub. Runs on every MR, main branch commit and tag if a Dockerfile exists. The images are tagged using the following patterns based on the commit source:

SourcePatternExampleType
MR<REF>FLYW-123-featrolling
mainlatestlatestrolling
main<REF>.<SHA>main.d34db33fimmutable
tag<TAG>1.2.3immutable

* <REF> is the branch name and <SHA> is the commit SHA.

Configuration:

VariableDefaultDescription
DOCKER_FILEDockerfileDockerfile name to build
DOCKER_IMAGEflywheel/<project>Image name to tag with
⁠.publish:helm

Build and push the project's helm chart to the Flywheel ChartMuseum⁠. Runs on every MR, main branch commit and tag if a helm/*/Chart.yaml exists. The chart is versioned using the following patterns based on the commit source:

SourcePatternExampleType
MR<VER>-<REF>1.2.3-FLYW-123-featrolling
main<VER>-latest1.2.3-latestrolling
main<VER>-<REF>.<DATE>.<BUILD>+<SHA>1.2.3-main.20220101.456+d34db33fimmutable
tag<TAG>1.2.3immutable

* <VER> is the last version and <BUILD> is the $CI_PIPELINE_ID.

Configuration:

VariableDefaultDescription
GIT_DEPTH100No. of commits to fetch from the history for <VER>
⁠.publish:pages

Publish static HTML project documentation from the public/ folder on GitLab pages⁠. Runs on every main branch commit and tag if the public/ dir exists.

Configuration:

TODO ...

⁠.publish:poetry

Publish a python library to PYPI, the Python Package Index.

⁠.release:mr

Create a release-X.Y.Z branch and MR with the project version bumped in all files referencing it like pyproject.toml and the helm chart. Runs on main and hotfix branches when manually triggering a pipeline with a RELEASE=X.Y.Z variable, where X.Y.Z is the desired version.

The MR description will hold a change-log based on the MRs merged since the last version and the list of JIRA tickets referenced across those changes. If FW_COMPONENT is set, it will also reference any open umbrella release MRs.

Edit the change-log in the MR description to adjust the upcoming project release docs and check/uncheck any umbrella release MRs to select which to bump.

Configuration:

VariableDefaultDescription
FW_COMPONENT""Set to true to enable umbrella version bumps
⁠.release:tag

Create an annotated tag.
Runs on main and hotfix branches when a release-X.Y.Z branch is merged.

The new tag will kick off further pipelines for publishing release artifacts.

⁠.update:deps

Create an update-repo branch and MR with common project files auto-updated. Runs on any branch if UPDATE=true is set.
It's recommended to run updates on the main branch every 2-4 weeks using a scheduled pipeline⁠ with a cron string like 0 0 * * sun%4 for every 4th Sunday.

FileDescription
DockerfileUpdate the base image in FROM
pyproject.tomlUpdate the build-system and loosen ^0.X pins
poetry.lockUpdate the lock file from pyproject.toml
requirements.txtUpdate requirements files
.pre-commit-config.yamlUpdate pre-commit repo references
.gitlab-ci.ymlUpdate gitlab-ci include references

Configuration:

VariableDefaultDescription
UPDATE_SKIP""Space-separated list of files not to update
⁠.update:release

Create a GitLab project release⁠ with the change-log and JIRA tickets from the release MR description.
If FW_COMPONENT is set and any umbrella releases were selected on the release MR description, then also bump the component version on those.
Runs on tags only.

⁠License

MIT

⁠Repository

flywheel-io/tools/etc/qa-ci⁠

Tag summary

Content type

Image

Digest

sha256:37d9e8a20…

Size

809.6 MB

Last updated

about 17 hours ago

docker pull flywheel/qa-ci:3.14-sse.7057c2b2.2898475772