Repository navigation
docs: add cross-distro shell testing search aliases #58
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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/ |