Skip to content

docs: add cross-distro shell testing search aliases #58

docs: add cross-distro shell testing search aliases

docs: add cross-distro shell testing search aliases #58

Workflow file for this run

name: Build and Release
on:
push:
branches:
- main
tags:
- 'v*'
workflow_dispatch:
concurrency:
group: opsscript-gate-release
cancel-in-progress: false
queue: max
permissions:
contents: read
jobs:
test:
name: Run Test Suite
runs-on: ubuntu-latest
steps:
- name: Checkout Code
uses: actions/checkout@v7
- name: Set up Python
uses: actions/setup-python@v7
with:
python-version: '3.12'
- name: Install Dependencies
run: |
python -m pip install --upgrade pip
pip install -e .[test]
- name: Run Tests
run: |
pytest -v -m "not integration"
integration:
name: Docker Integration Tests
runs-on: ubuntu-latest
steps:
- name: Checkout Code
uses: actions/checkout@v7
- name: Set up Python
uses: actions/setup-python@v7
with:
python-version: '3.12'
- name: Install Dependencies
run: |
python -m pip install --upgrade pip
pip install -e .[test]
- name: Verify Docker Available
run: docker version
- name: Run Docker Integration Tests
run: |
pytest -v -m integration
build:
name: Build Distribution Packages
needs: [test, integration]
runs-on: ubuntu-latest
permissions:
contents: write
outputs:
is_new_release: ${{ steps.release-check.outputs.is_new_release }}
should_tag: ${{ steps.release-check.outputs.should_tag }}
release_tag: ${{ steps.release-check.outputs.release_tag }}
steps:
- name: Checkout Code
uses: actions/checkout@v7
with:
fetch-depth: 0
- name: Set up Python
uses: actions/setup-python@v7
with:
python-version: '3.12'
- name: Determine Release Readiness
id: release-check
shell: bash
run: |
set -euo pipefail
TOML_VERSION=$(python -c "import tomllib; f=open('pyproject.toml', 'rb'); print(tomllib.load(f)['project']['version'])")
INIT_VERSION=$(python -c "import sys; sys.path.insert(0, 'src'); import opsscript_gate; print(opsscript_gate.__version__)")
echo "pyproject.toml version: $TOML_VERSION"
echo "opsscript_gate version: $INIT_VERSION"
if [ "$TOML_VERSION" != "$INIT_VERSION" ]; then
echo "::error::Version mismatch: pyproject.toml ($TOML_VERSION) != __init__.py ($INIT_VERSION)"
exit 1
fi
TARGET_TAG="v$TOML_VERSION"
echo "Target release tag: $TARGET_TAG"
echo "Triggering ref: ${{ github.ref }}"
echo "Triggering SHA: ${{ github.sha }}"
echo "Triggering event: ${{ github.event_name }}"
IS_NEW_RELEASE="false"
SHOULD_TAG="false"
if [[ "${{ github.ref }}" =~ ^refs/tags/v ]]; then
TAG_VERSION="${GITHUB_REF_NAME#v}"
echo "Triggered via explicit Git tag: $GITHUB_REF_NAME (version: $TAG_VERSION)"
if [ "$TAG_VERSION" != "$TOML_VERSION" ]; then
echo "::error::Tag mismatch: Git tag $GITHUB_REF_NAME does not match project version $TOML_VERSION"
exit 1
fi
IS_NEW_RELEASE="true"
SHOULD_TAG="false"
elif [ "${{ github.ref }}" = "refs/heads/main" ]; then
if git rev-parse -q --verify "refs/tags/$TARGET_TAG" >/dev/null; then
TAG_SHA=$(git rev-list -n 1 "$TARGET_TAG")
echo "Tag $TARGET_TAG already exists, pointing to commit: $TAG_SHA"
if [ "$TAG_SHA" = "${{ github.sha }}" ]; then
echo "Tag $TARGET_TAG points to current commit (${{ github.sha }}). Treating as retry/resume of release."
IS_NEW_RELEASE="true"
SHOULD_TAG="false"
else
echo "Tag $TARGET_TAG was released from earlier commit ($TAG_SHA != ${{ github.sha }}). Skipping release."
IS_NEW_RELEASE="false"
SHOULD_TAG="false"
fi
else
echo "Target tag $TARGET_TAG does not exist. Scheduling new release for commit ${{ github.sha }}."
IS_NEW_RELEASE="true"
SHOULD_TAG="true"
fi
else
echo "Workflow triggered on unsupported ref (${{ github.ref }}). Release is strictly prohibited."
IS_NEW_RELEASE="false"
SHOULD_TAG="false"
fi
echo "is_new_release=$IS_NEW_RELEASE" >> "$GITHUB_OUTPUT"
echo "should_tag=$SHOULD_TAG" >> "$GITHUB_OUTPUT"
echo "release_tag=$TARGET_TAG" >> "$GITHUB_OUTPUT"
- name: Install build tools
if: steps.release-check.outputs.is_new_release == 'true'
run: |
python -m pip install --upgrade pip
pip install build twine
- name: Build sdist and wheel
if: steps.release-check.outputs.is_new_release == 'true'
run: |
python -m build
- name: Verify Package Metadata
if: steps.release-check.outputs.is_new_release == 'true'
run: |
python -m twine check dist/*
- name: Upload dist artifacts
if: steps.release-check.outputs.is_new_release == 'true'
uses: actions/upload-artifact@v4
with:
name: dist
path: dist/
retention-days: 7
- name: Create and push Git tag
if: steps.release-check.outputs.is_new_release == 'true' && steps.release-check.outputs.should_tag == 'true'
shell: bash
run: |
TARGET_TAG="${{ steps.release-check.outputs.release_tag }}"
echo "Creating and pushing Git tag: $TARGET_TAG pointing to commit $GITHUB_SHA"
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"
git tag "$TARGET_TAG" "$GITHUB_SHA"
git push origin "$TARGET_TAG"
- name: Create GitHub Release and Upload Assets
uses: softprops/action-gh-release@v3
if: steps.release-check.outputs.is_new_release == 'true'
with:
tag_name: ${{ steps.release-check.outputs.release_tag }}
target_commitish: ${{ github.sha }}
files: dist/*
generate_release_notes: true
- name: Check Marketplace listing freshness
if: steps.release-check.outputs.is_new_release == 'true'
shell: bash
env:
RELEASE_TAG: ${{ steps.release-check.outputs.release_tag }}
run: |
set -euo pipefail
listing_url="https://github.com/marketplace/actions/opsscript-gate"
listing="$(curl -fsSL "$listing_url")"
if grep -Fq "$RELEASE_TAG" <<<"$listing"; then
echo "Marketplace listing references $RELEASE_TAG."
exit 0
fi
echo "::warning::Marketplace listing is not yet showing $RELEASE_TAG. GitHub requires the release UI checkbox to publish an Action release."
{
echo "## Marketplace publication"
echo
echo "The release **$RELEASE_TAG** is live, but the Marketplace page has not caught up."
echo "Open the release editor, enable **Publish this Action to the GitHub Marketplace**, choose the categories, and save it."
echo
echo "[Open release editor](https://github.com/Mresyzz/opsscript-gate/releases/edit/${{ steps.release-check.outputs.release_tag }})"
} >> "$GITHUB_STEP_SUMMARY"
publish-pypi:
name: Publish to PyPI via OIDC
needs: [test, build]
if: needs.build.outputs.is_new_release == 'true'
runs-on: ubuntu-latest
environment:
name: pypi
url: https://pypi.org/p/opsscript-gate
permissions:
id-token: write
steps:
- name: Download dist artifacts
uses: actions/download-artifact@v4
with:
name: dist
path: dist
- name: Publish package distributions to PyPI
uses: pypa/gh-action-pypi-publish@release/v1
with:
packages-dir: dist/