Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
192 changes: 192 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,192 @@
name: CI

on:
push:
branches: [main]
pull_request:
branches: [main]

permissions:
contents: read

jobs:
commitlint:
runs-on: ubuntu-latest
strategy:
matrix:
python-version: ["3.11"] # TODO see https://github.com/mitre-attack/mitreattack-python/issues/176
steps:
- uses: actions/checkout@v6
with:
fetch-depth: 0

- name: Install the latest version of uv
uses: astral-sh/setup-uv@v7
with:
version: "latest"

- name: Set up Python
run: uv python install ${{ matrix.python-version }}

Comment on lines +23 to +30
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
- name: Install the latest version of uv
uses: astral-sh/setup-uv@v7
with:
version: "latest"
- name: Set up Python
run: uv python install ${{ matrix.python-version }}
- name: Install the latest version of uv
uses: astral-sh/setup-uv@v7
with:
python-version: ${{ matrix.python-version }}

- name: Install dependencies
run: uv sync --all-extras

- name: Check commit messages
run: |
if [ "${{ github.event_name }}" = "pull_request" ]; then
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I want to make sure we make it as easy as possible for external contributors to contribute. This makes me think of this FAQ from the Conventional Commits site.

https://www.conventionalcommits.org/en/v1.0.0/#do-all-my-contributors-need-to-use-the-conventional-commits-specification

Do all my contributors need to use the Conventional Commits specification?
No! If you use a squash based workflow on Git lead maintainers can clean up the commit messages as they’re merged—adding no workload to casual committers. A common workflow for this is to have your git system automatically squash commits from a pull request and present a form for the lead maintainer to enter the proper git commit message for the merge.

I think it might be better to squash commits from pull requests somehow instead and only validate commit messages that we ourselves write, to not make it an overly arduous process for external contribs.

uv run cz check --rev-range origin/${{ github.base_ref }}..HEAD
else
uv run cz check --rev-range HEAD~1..HEAD
fi

lint:
runs-on: ubuntu-latest
strategy:
matrix:
python-version: ["3.11"] # TODO see https://github.com/mitre-attack/mitreattack-python/issues/176
steps:
- uses: actions/checkout@v6

- name: Install the latest version of uv
uses: astral-sh/setup-uv@v7
with:
version: "latest"

- name: Set up Python
run: uv python install ${{ matrix.python-version }}

Comment on lines +50 to +57
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
- name: Install the latest version of uv
uses: astral-sh/setup-uv@v7
with:
version: "latest"
- name: Set up Python
run: uv python install ${{ matrix.python-version }}
- name: Install the latest version of uv
uses: astral-sh/setup-uv@v7
with:
python-version: ${{ matrix.python-version }}

- name: Install dependencies
run: uv sync --all-extras

- name: Lint with ruff
run: uv run ruff check --output-format github

- name: Check formatting with ruff
run: uv run ruff format --check

test:
runs-on: ubuntu-latest
strategy:
matrix:
python-version: ["3.11"] # TODO see https://github.com/mitre-attack/mitreattack-python/issues/176
steps:
- uses: actions/checkout@v6

- name: Install the latest version of uv
uses: astral-sh/setup-uv@v7
with:
version: "latest"

- name: Set up Python
run: uv python install ${{ matrix.python-version }}

Comment on lines +75 to +82
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
- name: Install the latest version of uv
uses: astral-sh/setup-uv@v7
with:
version: "latest"
- name: Set up Python
run: uv python install ${{ matrix.python-version }}
- name: Install the latest version of uv
uses: astral-sh/setup-uv@v7
with:
python-version: ${{ matrix.python-version }}

- name: Install dependencies
run: uv sync --all-extras

- name: Run pytest
run: uv run pytest --cov=mitreattack

release:
needs: [commitlint, lint, test]
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
strategy:
matrix:
python-version: ["3.11"] # TODO see https://github.com/mitre-attack/mitreattack-python/issues/176
runs-on: ubuntu-latest
# The concurrency block prevents multiple release jobs from running simultaneously for the same branch.
# This is particularly useful for releases since you typically want sequential deployments (finish
# current release before starting next) rather than canceling in-progress releases or running them
# in parallel.
concurrency:
# Creates a concurrency group keyed by workflow name + "release" + branch name (e.g., "Continuous Delivery-release-main")
group: ${{ github.workflow }}-release-${{ github.ref_name }}
# If a release is already running and a new push triggers another, the new job waits rather than canceling the running one
# If you changed cancel-in-progress to true, a new push would cancel the currently running release job.
cancel-in-progress: false

permissions:
contents: write

steps:
# Note: We checkout the repository at the branch that triggered the workflow.
# Python Semantic Release will automatically convert shallow clones to full clones
# if needed to ensure proper history evaluation. However, we forcefully reset the
# branch to the workflow sha because it is possible that the branch was updated
# while the workflow was running, which prevents accidentally releasing un-evaluated
# changes.
- name: Setup | Checkout Repository on Release Branch
uses: actions/checkout@v6
with:
fetch-depth: 0
ref: ${{ github.ref_name }}

- name: Setup | Force release branch to be at workflow sha
run: |
git reset --hard ${{ github.sha }}

- name: Setup | Install uv
uses: astral-sh/setup-uv@v5
with:
version: "latest"

- name: Setup | Install Python
run: uv python install ${{ matrix.python-version }}

Comment on lines +127 to +134
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
- name: Setup | Install uv
uses: astral-sh/setup-uv@v5
with:
version: "latest"
- name: Setup | Install Python
run: uv python install ${{ matrix.python-version }}
- name: Setup | Install uv
uses: astral-sh/setup-uv@v7
with:
python-version: ${{ matrix.python-version }}

- name: Setup | Install dependencies
run: uv sync --all-extras

- name: Semantic Release
id: release
uses: python-semantic-release/python-semantic-release@v10.5.3
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
# NOTE: git_committer_name and git_committer_email are optional
# We omit them because, if set, they must be associated with the provided token
# and we don't really care to have a specific committer for automated releases.

- name: Upload to GitHub Release Assets
uses: python-semantic-release/publish-action@v10.5.3
if: steps.release.outputs.released == 'true'
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
tag: ${{ steps.release.outputs.tag }}

- name: Upload distribution artifacts
uses: actions/upload-artifact@v6
if: steps.release.outputs.released == 'true'
with:
name: distribution-artifacts
path: dist
if-no-files-found: error

outputs:
released: ${{ steps.release.outputs.released || 'false' }}

publish:
# 1. Separate out the deploy step from the publish step to run each step at
# the least amount of token privilege
# 2. Also, deployments can fail, and its better to have a separate job if you need to retry
# and it won't require reversing the release.
needs: release
if: needs.release.outputs.released == 'true'
runs-on: ubuntu-latest
environment: release

permissions:
contents: read
id-token: write

steps:
- name: Download build artifacts
uses: actions/download-artifact@v4
Copy link
Contributor

@jondricek jondricek Dec 23, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

version 7.0.0 came out 2 weeks ago

https://github.com/actions/download-artifact

Suggested change
uses: actions/download-artifact@v4
uses: actions/download-artifact@v7

id: artifact-download
with:
name: distribution-artifacts
path: dist

- name: Publish to PyPI
uses: pypa/gh-action-pypi-publish@release/v1
with:
packages-dir: dist
print-hash: true
verbose: true
60 changes: 0 additions & 60 deletions .github/workflows/lint-publish.yml

This file was deleted.

15 changes: 15 additions & 0 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
repos:
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.14.10
hooks:
# Run the linter (disabled for now)
# - id: ruff-check
# args: [--fix]
# Run the formatter
- id: ruff-format

- repo: https://github.com/commitizen-tools/commitizen
rev: v4.10.1
hooks:
- id: commitizen
stages: [commit-msg]
12 changes: 8 additions & 4 deletions .readthedocs.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,15 @@ build:
os: ubuntu-24.04
tools:
python: "3.11"
# For details on how to customize the build process, see:
# https://docs.readthedocs.com/platform/stable/builds.html
# https://docs.readthedocs.com/platform/stable/build-customization.html
jobs:
post_create_environment:
- pip install poetry
post_install:
- VIRTUAL_ENV=$READTHEDOCS_VIRTUALENV_PATH poetry install --with docs
install:
- pip install uv
- uv sync --extra docs
build:
- uv run sphinx-build -b html docs $READTHEDOCS_OUTPUT/html

sphinx:
configuration: docs/conf.py
56 changes: 56 additions & 0 deletions justfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
# Default recipe to list all available commands
default:
@just --list

# Install development dependencies
install:
uv sync --all-extras

# Upgrade all uv dependencies
upgrade:
uv sync --all-extras --upgrade

# Install pre-commit hooks
setup-hooks:
uv run pre-commit install
uv run pre-commit install --hook-type commit-msg

# Run pre-commit hooks on all files
lint:
uv run pre-commit run --all-files

# Run ruff linter
ruff-check:
uv run ruff check

# Run ruff formatter check
ruff-format-check:
uv run ruff format --check

# Run ruff formatter (fix)
ruff-format:
uv run ruff format

# Run tests
test:
uv run pytest

# Run tests with coverage
test-cov:
uv run pytest --cov=mitreattack

# Check commit messages in range (default: last commit)
check-commits rev-range="HEAD~1..HEAD":
uv run cz check --rev-range {{ rev-range }}

# Dry run semantic release (no changes)
release-dry-run:
uv run semantic-release -v --noop version

# Build the package
build:
uv build

# Clean build artifacts
clean:
rm -rf dist/ build/ *.egg-info/
Loading
Loading