Skip to content

Fix secrets detector model dump counting (#65) #44

Fix secrets detector model dump counting (#65)

Fix secrets detector model dump counting (#65) #44

name: Release Rust Python Package Plugin
on:
push:
tags:
- "*-v*"
workflow_call:
inputs:
tag:
description: "Release tag in the form <slug>-v<version>"
required: true
type: string
repository:
description: "Target package repository"
required: true
type: string
publish_enabled:
description: "Whether to run the publish job"
required: false
default: false
type: boolean
workflow_dispatch:
inputs:
tag:
description: "Release tag in the form <slug>-v<version>"
required: true
type: string
repository:
description: "Target package repository"
required: true
default: testpypi
type: choice
options:
- testpypi
- pypi
permissions:
contents: read
jobs:
resolve:
runs-on: ubuntu-latest
outputs:
plugin: ${{ steps.resolve.outputs.plugin }}
slug: ${{ steps.resolve.outputs.plugin }}
plugin_path: ${{ steps.resolve.outputs.plugin_path }}
wheel_matrix: ${{ steps.resolve.outputs.wheel_matrix }}
publish_env: ${{ steps.resolve.outputs.publish_env }}
publish_enabled: ${{ steps.resolve.outputs.publish_enabled }}
checkout_ref: ${{ steps.resolve.outputs.checkout_ref }}
tag_on_main: ${{ steps.resolve.outputs.tag_on_main }}
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd
- uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405
with:
python-version: "3.12"
- name: Validate plugin catalog
run: python3 tools/plugin_catalog.py validate .
- id: resolve
shell: bash
env:
TAG_INPUT: ${{ inputs.tag }}
REPOSITORY_INPUT: ${{ inputs.repository }}
PUBLISH_ENABLED: ${{ inputs.publish_enabled }}
run: |
set -euo pipefail
git fetch --force origin "refs/heads/main:refs/remotes/origin/main"
if [[ -n "${TAG_INPUT}" ]]; then
tag="${TAG_INPUT}"
repository="${REPOSITORY_INPUT}"
if git ls-remote --exit-code --tags origin "refs/tags/${tag}" >/dev/null 2>&1; then
git fetch --force origin "refs/tags/${tag}:refs/tags/${tag}"
git show-ref --verify --quiet "refs/tags/${tag}"
checkout_ref="refs/tags/${tag}"
tag_ref="refs/tags/${tag}"
elif [[ "${GITHUB_EVENT_NAME}" == "pull_request" && "${PUBLISH_ENABLED}" == "false" ]]; then
checkout_ref="${GITHUB_SHA}"
tag_ref="${GITHUB_SHA}"
else
echo "Release tag ${tag} does not exist" >&2
exit 1
fi
else
tag="${GITHUB_REF_NAME}"
repository="pypi"
checkout_ref="${GITHUB_REF}"
tag_ref="${GITHUB_REF}"
fi
if git merge-base --is-ancestor "${tag_ref}" "refs/remotes/origin/main"; then
tag_on_main=true
else
tag_on_main=false
fi
release_info="$(python3 tools/plugin_catalog.py release-info . "${tag}")"
plugin="$(printf '%s' "${release_info}" | python3 -c 'import json, sys; print(json.load(sys.stdin)["slug"])')"
plugin_path="$(printf '%s' "${release_info}" | python3 -c 'import json, sys; print(json.load(sys.stdin)["path"])')"
if [[ -n "${TAG_INPUT}" ]]; then
wheel_matrix="$(python3 -c 'import json; print(json.dumps([{"runner":"ubuntu-latest","platform":"linux-x86_64"},{"runner":"ubuntu-24.04-arm","platform":"linux-aarch64"},{"runner":"ubuntu-24.04-s390x","platform":"linux-s390x"},{"runner":"ubuntu-24.04-ppc64le","platform":"linux-ppc64le"},{"runner":"macos-latest","platform":"macos-arm64"},{"runner":"windows-latest","platform":"windows-x86_64"}]))')"
else
wheel_matrix="$(printf '%s' "${release_info}" | python3 -c 'import json, sys; print(json.dumps(json.load(sys.stdin)["release_wheel_matrix"]))')"
fi
{
echo "plugin=${plugin}"
echo "plugin_path=${plugin_path}"
echo "wheel_matrix=${wheel_matrix}"
echo "checkout_ref=${checkout_ref}"
echo "tag_on_main=${tag_on_main}"
if [[ "${PUBLISH_ENABLED}" == "false" ]]; then
echo "publish_enabled=false"
else
echo "publish_enabled=true"
fi
if [[ "${repository}" == "testpypi" ]]; then
echo "publish_env=testpypi"
else
echo "publish_env=pypi"
fi
} >> "$GITHUB_OUTPUT"
preflight:
needs: resolve
runs-on: ubuntu-latest
defaults:
run:
shell: bash
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd
with:
ref: ${{ needs.resolve.outputs.checkout_ref }}
- uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405
with:
python-version: "3.12"
- name: Verify Rust toolchain
run: |
rustc --version
cargo --version
- name: Generate stubs
working-directory: ${{ needs.resolve.outputs.plugin_path }}
run: cargo run --bin stub_gen
- name: Verify generated stubs are checked in
working-directory: ${{ needs.resolve.outputs.plugin_path }}
run: git diff --exit-code
build-wheel:
needs: [resolve, preflight]
strategy:
fail-fast: false
matrix:
include: ${{ fromJson(needs.resolve.outputs.wheel_matrix) }}
runs-on: ${{ matrix.runner }}
defaults:
run:
shell: bash
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd
with:
ref: ${{ needs.resolve.outputs.checkout_ref }}
- uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405
if: ${{ matrix.runner != 'ubuntu-24.04-s390x' && matrix.runner != 'ubuntu-24.04-ppc64le' }}
with:
python-version: "3.12"
- name: Install system Python on partner runners
if: ${{ matrix.runner == 'ubuntu-24.04-s390x' || matrix.runner == 'ubuntu-24.04-ppc64le' }}
run: |
sudo apt-get update
sudo apt-get install -y python3.12 python3.12-dev python3.12-venv python3-pip
sudo apt-get clean
sudo rm -rf /var/lib/apt/lists/*
python_bin_dir="${RUNNER_TEMP}/python-bin"
mkdir -p "${python_bin_dir}"
ln -sf "$(which python3.12)" "${python_bin_dir}/python"
export PATH="${python_bin_dir}:$PATH"
echo "${python_bin_dir}" >> "$GITHUB_PATH"
python --version
python -m pip --version
- name: Verify Rust toolchain
run: |
rustc --version
cargo --version
- name: Install uv
run: python -m pip install uv==0.9.30 maturin==1.12.6
- name: Build wheel
working-directory: ${{ needs.resolve.outputs.plugin_path }}
run: uv run maturin build --release --out dist
- name: Upload wheel artifact
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f
with:
name: wheel-${{ matrix.platform }}
path: ${{ needs.resolve.outputs.plugin_path }}/dist/*.whl
- name: Test built wheel in isolated virtualenv
working-directory: ${{ needs.resolve.outputs.plugin_path }}
run: |
tmpdir="$(mktemp -d)"
python -m venv "${tmpdir}/venv"
venv_python="${tmpdir}/venv/bin/python"
if [[ ! -f "${venv_python}" ]]; then
venv_python="${tmpdir}/venv/Scripts/python.exe"
fi
"${venv_python}" -m pip install dist/*.whl pytest pytest-asyncio PyYAML
if [[ -d "${GITHUB_WORKSPACE}/plugins/tests/${{ needs.resolve.outputs.slug }}" ]]; then
mkdir -p "${tmpdir}/tests"
cp -R "${GITHUB_WORKSPACE}/plugins/tests/${{ needs.resolve.outputs.slug }}" "${tmpdir}/tests/${{ needs.resolve.outputs.slug }}"
cp "${GITHUB_WORKSPACE}/plugins/tests/conftest.py" "${tmpdir}/tests/conftest.py"
cp "${GITHUB_WORKSPACE}/plugins/tests/plugin_hooks.py" "${tmpdir}/tests/plugin_hooks.py"
cp "${GITHUB_WORKSPACE}/plugins/tests/pytest.ini" "${tmpdir}/pytest.ini"
cd "${tmpdir}"
export CPEX_TEST_PLUGIN_HOOKS=1
export PYTHONPATH="${tmpdir}/tests"
"${venv_python}" -m pytest \
-c "${tmpdir}/pytest.ini" \
"${tmpdir}/tests/${{ needs.resolve.outputs.slug }}" -v
fi
build-sdist:
needs: [resolve, preflight]
runs-on: ubuntu-latest
defaults:
run:
shell: bash
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd
with:
ref: ${{ needs.resolve.outputs.checkout_ref }}
- uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405
with:
python-version: "3.12"
- name: Install uv
run: python -m pip install uv==0.9.30 maturin==1.12.6
- name: Build sdist
working-directory: ${{ needs.resolve.outputs.plugin_path }}
run: uv run maturin sdist --out dist
- name: Upload sdist artifact
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f
with:
name: sdist
path: ${{ needs.resolve.outputs.plugin_path }}/dist/*.tar.gz
- name: Test built sdist in isolated virtualenv
working-directory: ${{ needs.resolve.outputs.plugin_path }}
run: |
tmpdir="$(mktemp -d)"
python -m venv "${tmpdir}/venv"
venv_python="${tmpdir}/venv/bin/python"
if [[ ! -f "${venv_python}" ]]; then
venv_python="${tmpdir}/venv/Scripts/python.exe"
fi
"${venv_python}" -m pip install dist/*.tar.gz pytest pytest-asyncio PyYAML
if [[ -d "${GITHUB_WORKSPACE}/plugins/tests/${{ needs.resolve.outputs.slug }}" ]]; then
mkdir -p "${tmpdir}/tests"
cp -R "${GITHUB_WORKSPACE}/plugins/tests/${{ needs.resolve.outputs.slug }}" "${tmpdir}/tests/${{ needs.resolve.outputs.slug }}"
cp "${GITHUB_WORKSPACE}/plugins/tests/conftest.py" "${tmpdir}/tests/conftest.py"
cp "${GITHUB_WORKSPACE}/plugins/tests/plugin_hooks.py" "${tmpdir}/tests/plugin_hooks.py"
cp "${GITHUB_WORKSPACE}/plugins/tests/pytest.ini" "${tmpdir}/pytest.ini"
cd "${tmpdir}"
export CPEX_TEST_PLUGIN_HOOKS=1
export PYTHONPATH="${tmpdir}/tests"
"${venv_python}" -m pytest \
-c "${tmpdir}/pytest.ini" \
"${tmpdir}/tests/${{ needs.resolve.outputs.slug }}" -v
fi
publish:
if: ${{ needs.resolve.outputs.publish_enabled == 'true' && (needs.resolve.outputs.publish_env != 'pypi' || needs.resolve.outputs.tag_on_main == 'true') }}
needs: [resolve, build-wheel, build-sdist]
runs-on: ubuntu-latest
environment: ${{ needs.resolve.outputs.publish_env }}
permissions:
id-token: write
steps:
- name: Download all artifacts
uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131
with:
path: dist
merge-multiple: true
- name: Publish distributions to TestPyPI
if: needs.resolve.outputs.publish_env == 'testpypi'
uses: pypa/gh-action-pypi-publish@ed0c53931b1dc9bd32cbe73a98c7f6766f8a527e
with:
packages-dir: dist/
repository-url: https://test.pypi.org/legacy/
skip-existing: true
- name: Publish distributions to PyPI
if: needs.resolve.outputs.publish_env == 'pypi'
uses: pypa/gh-action-pypi-publish@ed0c53931b1dc9bd32cbe73a98c7f6766f8a527e
with:
packages-dir: dist/
skip-existing: true