Skip to content

Latest commit

 

History

History
573 lines (468 loc) · 28.1 KB

File metadata and controls

573 lines (468 loc) · 28.1 KB

CI

Continuous Integration details for the Multicast project.

CI Service Providers


Continuous integration testing for the Multicast project is handled by GitHub Actions and the generous CircleCI service.

CI/CD Metrics

GitHub

GitHub Actions Metrics

CircleCI

CircleCI

Other Metrics

Many additional services are used for enhancing CI/CD with additional metrics, insights, and automated analysis.

DeepSource CodeCov OpenSSF Best Practices CodeRabbit Pull Request Reviews Average time to resolve an issue Percentage of issues still open

Triggering CI/CD


GitHub Actions

Triggers Workflows
push .github/workflows/bandit.yml, .github/workflows/CI-BUILD.yml, .github/workflows/codeql-analysis.yml, .github/workflows/makefile-lint.yml, .github/workflows/markdown-lint.yml, .github/workflows/shellcheck.yml, .github/workflows/yaml-lint.yml
workflow_run .github/workflows/CI-CHGLOG.yml, .github/workflows/CI-MATs.yml, .github/workflows/CI-DOCS.yml, .github/workflows/Tests.yml
pull_request .github/workflows/bandit.yml, .github/workflows/codeql-analysis.yml, .github/workflows/makefile-lint.yml, .github/workflows/markdown-lint.yml, .github/workflows/shellcheck.yml, .github/workflows/yaml-lint.yml
pull_request_target .github/workflows/Labeler.yml
schedule .github/dependabot.yml, .github/workflows/codeql-analysis.yml, .github/workflows/scorecard.yml
release .github/workflows/CD-PyPi.yml

CircleCI Pipelines

Triggers Pipelines
push (via a webhook) .circleci/config.yml

Appveyor Jobs

Caution

The Appveyor integration is still experimental, as the multicast module is not currently able to support running on Windows without Python socket support.

Triggers Jobs
pull_request (via a webhook) .appveyor.yml

Testing in CI/CD


Acceptance Testing with GitHub Actions

How on-workflow_run triggers propagate

%%{ init: { 'theme': 'base', 'themeVariables': { 'darkMode': true, 'primaryColor': '#3e3e3e', 'background': 'transparent', 'primaryBorderColor': 'Orange', 'lineColor': 'darkOrange', 'secondaryColor': 'transparent', 'tertiaryColor': '#030303' }} }%%
graph TD;
    PUSH-EVENT-->CI-Build.yml;
    CI-Build.yml-->multicast-build-*;
    CI-Build.yml-->BUILD-info.txt;
    CI-Build.yml-->Build-Summary-Artifact.txt;
    multicast-build-*-->CI-MATs.yml;
    multicast-build-*-->CI-CHGLOG.yml;
    BUILD-info.txt-->CI-MATs.yml;
    BUILD-info.txt-->CI-CHGLOG.yml;
    CI-CHGLOG.yml-->CHANGELOG.md;
    CI-CHGLOG.yml-->chglog-info.txt;
    CI-CHGLOG.yml-->chglog-Summary-Artifact.txt;
    CI-MATs.yml-->multicast-info-*;
    CI-MATs.yml-->MATs-Summary-Artifact.txt;
    multicast-build-*-->CI-Tests.yml;
    multicast-info-*-->CI-Tests.yml;
    CI-Tests.yml-->COVERAGE;
    CI-Tests.yml-->\*-Test-Report-\*-*;
    CI-Tests.yml-->Integration-Summary-Artifact.txt;
    multicast-build-*-->CI-DOCS.yml;
    multicast-info-*-->CI-DOCS.yml;
    CI-DOCS.yml-->Multicast-Documentation-*-ALL;
    CI-DOCS.yml-->DOCUMENTATION-Summary-Artifact.txt;
Loading
  1. PUSH-EVENT: This event triggers the entire Acceptance Testing CI/CD workflow.
  2. CI-Build.yml: The main configuration file for the build process, which generates several artifacts: A. multicast-build-{{ sha }}: The built package artifact. B. BUILD-info.txt: Contains essential details about the build execution, including: i. Build Run ID: A unique identifier for the build run. ii. Build Artifact's ID/URL/Name/Digest: Information about the generated artifact, such as its identifier, location, name, and digest for verification. iii. Git Commit Info: Details about the commit associated with the build, including the SHA, reference, and branch. C. Build-Summary-Artifact.txt (BUILD-COMMENT-BODY-{{ sha }}): A summary of the build process, highlighting key outcomes and metrics.
  3. CI-CHGLOG.yml: A configuration file that processes the build info to create: A. CHANGELOG.md (multicast-chglog-{{ build_sha }}): The generated CHANGELOG document. B. chglog-info.txt (multicast-chglog-info-{{ build_sha }}): Contains all the information from the "Build-Info.txt" along with additional details about the "CI-CHGLOG.yml" workflow run, including: i. CHANGELOG Workflow Run ID: A unique identifier for the MATs workflow run. ii. CHANGELOG Artifact's ID/URL/Name/Digest: Information about the generated CHANGELOG.md artifact, such as its identifier, location, name, and digest for verification. iii. Git Commit Info: Details about the commit associated with the build, including the nearest TAG (e.g., release or pre-release), and the previous release used for comparing changes. C. chglog-Summary-Artifact.txt: A summary of the CHANGELOG generation process, highlighting key outcomes and metrics.
  4. CI-MATs.yml: A configuration file that processes the build artifacts to create: A. multicast-info.txt (multicast-info-{{ build_sha }}): Contains all the information from the "Build-Info.txt" along with additional details about the "CI-MATs.yml" workflow run, including: i. MATs Workflow Run ID: A unique identifier for the MATs workflow run. ii. Conclusion Statuses: The outcomes of the Minimal Acceptance Tests. B. MATs-Summary-Artifact.txt (MATS-COMMENT-BODY-{{ build_sha }}): A summary of the Minimal Acceptance Tests conducted.
  5. CI-Tests.yml: A configuration file for executing tests, which processes the build artifacts to create: A. Coverage reports: Uploading various coverage reports for the tests executed to multiple services for analysis (e.g., codecov.io, coveralls.io, app.deepsource.io, etc.). B. Test-Results-Artifacts ({{ test-group }}-Test-Report-{{ matrix.os }}-{{ matrix.python-version }}): Contains the results of the tests grouped by coverage|doctests|integration, os and python-version. C. Integration-Summary-Artifact.txt (INTEGRATION-COMMENT-BODY-{{ build_sha }}): A summary of the test results.
  6. CI-DOCs.yml: A configuration file for generating documentation, which produces: A. Documentation-Artifact.zip (Multicast-Documentation-{{ build_sha }}-ALL): A zip file containing the generated documentation. B. DOCUMENTATION-Summary-Artifact.txt (DOCUMENTATION-COMMENT-BODY-{{ build_sha }}): A summary of the documentation results.

In summary, as the diagram illustrates, a GitHub Actions CI/CD workflow begins with a push event, leading to the building of artifacts, the execution of Minimal Acceptance Tests, and the generation of test reports. The workflow includes passing detailed information about the build process, such as the build run ID, artifact details, and associated git commit information, as well as comprehensive details about the Minimal Acceptance Tests, including the MATs workflow run ID and conclusion statuses, ensuring thorough traceability and accountability throughout the CI/CD pipeline.

Acceptance Testing with CircleCI

While the comprehensive results from the extensive GHA pipeline offer a detailed look at the state of the codebase, the process can take upwards of 30 minutes to complete. The Multicast Project also utilizes the much faster CircleCI offering to provide pass or fail status much earlier in CI/CD. While the underlying tests are the same for both GHA and CircleCI, they are only tested in a single environment on CircleCI, and typically perform faster.

How push triggers propagate on CircleCI

%%{ init: { 'theme': 'base', 'themeVariables': { 'darkMode': true, 'primaryColor': '#3e3e3e', 'background': 'transparent', 'primaryBorderColor': 'Orange', 'lineColor': 'darkOrange', 'secondaryColor': 'transparent', 'tertiaryColor': '#030303' }} }%%
graph TD;
  PUSH-EVENT-->config.yml;
  config.yml-->build;
  config.yml-->test;
  config.yml-->lint;
  config.yml-->pytest;
  build-->lint;
  build-->test;
  test-->pytest;

  build-->GH-Checks;
  test-->GH-Checks;
  lint-->GH-Checks;
  pytest-->GH-Checks;
  pytest-->Test-Results;
  Test-Results-->CircleCI-Metrics;
Loading
  1. PUSH-EVENT: This event triggers the entire Acceptance Testing CI/CD workflow.
  2. config.yml: The sole configuration file for the CircleCI jobs: A. build: Tests that the build process works without critical error, (albeit these quick builds are ephemeral and not attested) B. test: Tests that the Minimal Acceptance tests pass without failure, (albeit the test details are discarded, only the logs remain for a while on CircleCI) C. lint: Selectively lints (See Linting for details) the multicast python source (e.g., multicast/*.py), failing on any linter flagged issues or passing on none. D. pytest: Runs the now deprecated make test-pytest target to discover, and then run, unittests via the pytest testing framework. i. Test-Results: the produced test results. See Collect Tests with CircleCI for more.
  3. GH-Checks: Each CI/CD job will report back a GitHub Check run result.

In summary, as the diagram illustrates, a CircleCI pipeline CI/CD workflow begins with a push event, leading to the build, test, lint, and pytest jobs reporting back to GitHub Checks, indicating the status of each job. Additionally, the output from pytest generates some Test Results, which are then used to produce CircleCI Metrics.

How Integrations are triggered from Testing in CI/CD

Key integrations

There are many integrations with various service providers used in the Multicast project's CI/CD pipeline.

%%{ init: { 'theme': 'base', 'themeVariables': { 'darkMode': true, 'primaryColor': '#3e3e3e', 'background': 'transparent', 'primaryBorderColor': 'Orange', 'lineColor': 'darkOrange', 'secondaryColor': 'transparent', 'tertiaryColor': '#030303' }} }%%
graph TD;
  PUSH-EVENT["PUSH EVENT"];
  PUSH-EVENT-->CI-Build.yml;
  PUSH-EVENT-->config.yml;

  subgraph GHA
  multicast-build-*@{ shape: card };
  BUILD-info.txt@{ shape: card };
  Build-Summary-Artifact.txt@{ shape: card };
  CI-Build.yml-->multicast-build-* & BUILD-info.txt & Build-Summary-Artifact.txt;
  multicast-build-*-->CI-MATs.yml;
  multicast-build-*-->CI-CHGLOG.yml;
  BUILD-info.txt-->CI-MATs.yml;
  BUILD-info.txt-->CI-CHGLOG.yml;
  CHANGELOG.md@{ shape: card };
  chglog-info.txt@{ shape: card };
  chglog-Summary-Artifact.txt@{ shape: card };
  CI-CHGLOG.yml-->CHANGELOG.md;
  CI-CHGLOG.yml-->chglog-info.txt;
  CI-CHGLOG.yml-->chglog-Summary-Artifact.txt;
  multicast-info-*@{ shape: card };
  MATs-Summary-Artifact.txt@{ shape: card };
  CI-MATs.yml-->multicast-info-* & MATs-Summary-Artifact.txt;
  multicast-build-*-->CI-Tests.yml & CI-DOCS.yml;
  multicast-info-*-->CI-Tests.yml & CI-DOCS.yml;
  DOCUMENTATION-Summary-Artifact.txt@{ shape: card };
  Integration-Summary-Artifact.txt@{ shape: card };
  Multicast-Documentation-*-ALL@{ shape: card };
  \*-Test-Report-\*-*@{ shape: card };
  CI-Tests.yml-->Integration-Summary-Artifact.txt;
  CI-DOCS.yml-->DOCUMENTATION-Summary-Artifact.txt & Multicast-Documentation-*-ALL;
  CI-Tests.yml-->\*-Test-Report-\*-* & COVERAGE;
  PUSH-EVENT-->markdown-lint.yml & yaml-lint.yml;
  PUSH-EVENT-->bandit.yml & codeql-analysis.yml & flake8.yml & makefile-lint.yml;
  PUSH-EVENT-->shellcheck.yml;
  end

  subgraph "Github Attestations"
  multicast-build-*-->Attestations;
  end

  subgraph "Github Commit Comments"
  Build-Summary-Artifact.txt-->Comments;
  chglog-Summary-Artifact.txt-->Comments;
  MATs-Summary-Artifact.txt-->Comments;
  Integration-Summary-Artifact.txt-->Comments;
  DOCUMENTATION-Summary-Artifact.txt-->Comments;
  end

  subgraph "3rd-Party Integrations"

  subgraph "CodeCov service"
  CodeCov-->CodeCov-Metrics;
  end

  subgraph "DeepSource service"
  DeepSource-->DeepSource-Metrics;
  end

  subgraph "Coveralls service"
  Coveralls-->Coveralls-Metrics;
  end

  COVERAGE-->CodeCov & DeepSource & Coveralls;

  subgraph "GHA Marketplace"
  bandit.yml--oPython-Bandit-Scan;
  codeql-analysis.yml--ocodeql-action;
  flake8.yml--oflake8-cq;

  shellcheck.yml--oshellcheck-scan;
  end

  end

  subgraph "Github Checks"
  CI-Build.yml-->GH-Checks;
  CI-MATs.yml-->GH-Checks;
  CI-Tests.yml-->GH-Checks;
  CI-DOCS.yml-->GH-Checks;
  markdown-lint.yml-->GH-Checks;
  makefile-lint.yml-->GH-Checks;
  yaml-lint.yml-->GH-Checks;
  bandit.yml-->GH-Checks;
  codeql-analysis.yml-->GH-Checks;
  flake8.yml-->GH-Checks;
  shellcheck.yml-->GH-Checks;

  CodeCov-->GH-Checks;
  DeepSource-->GH-Checks;
  end

  subgraph "GitHub Code Scanning"
  Python-Bandit-Scan-->GH-Code-Scanning;
  codeql-action-->GH-Code-Scanning;
  flake8-cq-->GH-Code-Scanning;
  shellcheck-scan-->GH-Code-Scanning;
  end

  subgraph CircleCI
  config.yml-->build;
  config.yml-->test;
  config.yml-->lint;
  config.yml-->pytest;
  build-->lint;
  build-->test;
  test-->pytest;

  build-->GH-Checks;
  test-->GH-Checks;
  lint-->GH-Checks;
  pytest-->GH-Checks;
  pytest-->Test-Results;

  Test-Results-->CircleCI-Metrics;
  end

  subgraph PR
  PRC["GitHub Pull-Request Comments"]
  GH-Checks-->PRC;
  GH-Code-Scanning-->PRC;
  CodeCov-->PRC;
  DeepSource-->PRC;
  end
Loading

Linting in CI/CD

TL;DR Context of Linting

In the constantly evolving ecosystem of software development, where code quality and maintainability matter, the role of linters has become increasingly common practice. So it should be no surprise that various linters are used in the Multicast project's CI/CD workflows. By incorporating the linting directly into the CI/CD workflows, this automation alleviates the load on developers to manually check much of the code style and formatting across various languages, including Python, YAML, Makefile, Bash, and Markdown.

Some of the Multicast project styles and conventions are quite specific (e.g., custom locking conventions of CEP-5), and not yet automated. However, by leveraging linters, we not only ensure a level of maintainability but also foster a collaborative environment where developers can focus on writing effective code rather than getting bogged down by stylistic concerns.

Linting Design Overview

Most of the linting in CI/CD is performed by GitHub workflows with the exception of a minimal Flake-8 scan for python source-code performed via CircleCI by the aptly named Lint job. All of the linter reporting (e.g., anything more than pass/fail status) is from the GitHub linter workflows. There are two noteworthy forms of feedback from the various linting automation, code-scanning reports, and GitHub Annotated Messages. All linting workflows failures result in alerts that can be reviewed with the relevant PR via GitHub's UI, albeit with different levels of details per linter workflow and target branch.

Linting phases

The generalized design of linter workflows in the Multicast project CI/CD pipeline follows these same phases:

  • Initialization - Bootstraps environment and any initial setup automatically
  • Clone - git clone the Multicast Git Repository and any submodules needed
  • Linting - performs the actual linting on the resulting clone
  • Post-processing (optional) - any post-processing of the resulting linting results
  • Reporting - report any results and/or linting status

Important

This overview does not address the complexities of CI/CD timing, concurrency, or the various combinations of linter workflows that run simultaneously. Each linter workflow is separately triggered (e.g., push versus PR, etc.) and thus logically disjoint (See CI/CD Triggering for details). Each linter workflow varies in its exact implementation of the afore mentioned phases.

Logically (e.g., ignoring complexities of concurrency and trigger conditionals, etc.) the order of phases is sequential per single CI/CD linter workflow.

%%{ init: { 'theme': 'base', 'themeVariables': { 'darkMode': true, 'primaryColor': '#3e3e3e', 'background': 'transparent', 'primaryBorderColor': 'Orange', 'lineColor': 'darkOrange', 'secondaryColor': 'transparent', 'tertiaryColor': '#030303' }} }%%
sequenceDiagram
  participant Repo as Repository

  create participant GA as GitHub Actions
  Repo->>GA: Trigger
  GA-->>GA: Initialization
  GA->>GA: Clone
  create participant SC as Linter
  GA->>SC: Linting
  opt: Optional
    SC->>SC: Post-processing
  end
  destroy SC
  SC-->>GA: Scan Results
  destroy GA
  GA->>Repo: Reporting
Loading

Linting Workflows

Bandit
Property Value
Linter Python-Bandit-Scan
Workflow bandit.yml
Language Python
Category Security Linter
Badge Bandit
CodeQL
Property Value
Linter GitHub's CodeQL Analysis
Workflow codeql-analysis.yml
Languages Python, Javascript (github actions)
Category Security Linter
Badge CodeQL
Flake-8
Property Value
Linter flake8-cq
Workflow flake8.yml
Language Python
Category Style Linter
Badge Flake8 Analysis
Checkmake
Property Value
Linter checkmake
Workflow makefile-lint.yml
Language Makefile
Category Style Linter
Badge Makefile Lint
MarkdownLintCLI
Property Value
Linter MarkdownLint
Workflow markdown-lint.yml
Language Markdown
Category Format Linter
Badge Markdown Lint
Shellcheck-Scan

Caution

Shellcheck-Scan is intended ONLY for use in CI on GitHub Actions, because it is under different restrictions, please see its License for details.

Property Value
Linter Shellcheck-Scan
Workflow shellcheck.yml
Languages Bash, sh
Category Format Linter
Badge shellcheck
YAMLLint
Property Value
Linter YAMLLint
Workflow yaml-lint.yml
Languages YAML
Category Format Linter
Badge YAML Lint

How linting is triggered in CI/CD

Logically (e.g., ignoring complexities of concurrency and trigger conditionals, etc.) the various linters are all run independently per CI/CD linter workflow.

%%{ init: { 'theme': 'base', 'themeVariables': { 'darkMode': true, 'primaryColor': '#3e3e3e', 'background': 'transparent', 'primaryBorderColor': 'Orange', 'lineColor': 'darkOrange', 'secondaryColor': 'transparent', 'tertiaryColor': '#030303' }} }%%
graph TD;
    PUSH-EVENT-->bandit.yml;
    PUSH-EVENT-->codeql-analysis.yml;
    PUSH-EVENT-->flake8.yml;
    PUSH-EVENT-->makefile-lint.yml;
    PUSH-EVENT-->shellcheck.yml;
    PUSH-EVENT-->markdown-lint.yml;
    PUSH-EVENT-->yaml-lint.yml;
    flake8.yml--oflake8-cq;
    shellcheck.yml--oshellcheck-scan;
    bandit.yml-->Python-Bandit-Scan;
    codeql-analysis.yml-->codeql-action;
    flake8-cq-->GH-Code-Scanning;
    shellcheck-scan-->GH-Code-Scanning;
    Python-Bandit-Scan-->GH-Code-Scanning;
    codeql-action-->GH-Code-Scanning;
    makefile-lint.yml;
Loading

Configurable CI Variables

This section documents environment variables used across CI workflows to ensure consistency and simplify maintenance.

Python Version Variables

To standardize Python version management across all CI workflows, we use a set of environment variables defined at the top of each workflow file. This approach centralizes version definitions while maintaining separation between workflows, making future updates easier and ensuring consistency.

Standard Python Version Variables

Variable Purpose Example Value
PYTHON_DEFAULT The default Python version used for single-version jobs "3.12"
PYTHON_OLD_MIN Oldest/minimum Python version for cross-python portability testing "3.10"
PYTHON_OLD_EXTRA Additional Python version for coverage testing "3.11"
PYTHON_EXPERIMENTAL Future/experimental Python version for optional testing "3.13"

Usage Examples

Setting up Python with the default version
- uses: actions/setup-python@v6
  with:
    python-version: "${{ vars.PYTHON_DEFAULT }}"
Using matrix strategy for multi-version testing
jobs:
  test:
    strategy:
      fail-fast: false
      matrix:
        python-version: ["${{ vars.PYTHON_DEFAULT }}", "${{ vars.PYTHON_EXPERIMENTAL }}"]
    steps:
      - uses: actions/setup-python@v6
        with:
          python-version: ${{ matrix.python-version }}

Copyright (c) 2021-2026, Mr. Walls

License - MIT