From f6e2c47331c3157116be2e34f529e45a20b0bb0b Mon Sep 17 00:00:00 2001 From: Douglas Myers-Turnbull Date: Fri, 12 Jul 2024 14:00:04 -0700 Subject: [PATCH] feat: add draft next-gen Python workflows --- draft/python/README.md | 3 + draft/python/_py-test.yaml | 292 +++++++++++++++++++++++++ draft/python/py-check-pr-metadata.yaml | 77 +++++++ draft/python/py-deploy-docs.yaml | 56 +++++ draft/python/py-deploy-packages.yaml | 209 ++++++++++++++++++ draft/python/py-format-pr.yaml | 91 ++++++++ draft/python/py-test-pr.yaml | 42 ++++ draft/python/py-update-coverage.yaml | 100 +++++++++ draft/python/py_bump-version.yaml | 66 ++++++ draft/python/release.yaml | 41 ++++ 10 files changed, 977 insertions(+) create mode 100644 draft/python/README.md create mode 100644 draft/python/_py-test.yaml create mode 100644 draft/python/py-check-pr-metadata.yaml create mode 100644 draft/python/py-deploy-docs.yaml create mode 100644 draft/python/py-deploy-packages.yaml create mode 100644 draft/python/py-format-pr.yaml create mode 100644 draft/python/py-test-pr.yaml create mode 100644 draft/python/py-update-coverage.yaml create mode 100644 draft/python/py_bump-version.yaml create mode 100644 draft/python/release.yaml diff --git a/draft/python/README.md b/draft/python/README.md new file mode 100644 index 0000000..8d55a3b --- /dev/null +++ b/draft/python/README.md @@ -0,0 +1,3 @@ +# Advanced python workflows + +**Keep these outside of `.github` to ensure they cannot run by mistake.** diff --git a/draft/python/_py-test.yaml b/draft/python/_py-test.yaml new file mode 100644 index 0000000..6f9cbb2 --- /dev/null +++ b/draft/python/_py-test.yaml @@ -0,0 +1,292 @@ +# SPDX-FileCopyrightText: Copyright 2024, the RCSB PDB, University of California, Rutgers University, and contributors +# SPDX-FileCopyrightText: Copyright 2020-2024, Contributors to CICD +# SPDX-PackageHomePage: https://github.com/dmyersturnbull/cicd +# SPDX-License-Identifier: Apache-2.0 +# SPDX-FileCopyrightText: Copyright 2020-2023, Contributors to Tyrannosaurus +# SPDX-PackageHomePage: https://github.com/dmyersturnbull/tyrannosaurus +# SPDX-License-Identifier: Apache-2.0 + +# This workflow is designed to run various types of tests and analyses on the codebase. +# It is triggered from other workflows using `workflow_call`, with specific ref inputs. +# Different jobs cover tests across multiple operating systems (Ubuntu, Windows, macOS) and Python versions. +# Some jobs are conditional, triggered only by specific comments on pull requests or specific events, +# such as '/please-review', '/please-run-tests', '/please-check-docker-build', etc. +# TODO: Allow tests after failure to run as long as not cancelled + +name: Test +run-name: > + ${{ github.workflow }} \ + ${{ github.ref_name }} \ + (triggered by ${{ github.ref_type }}) + +on: + workflow_call: + inputs: + ref: + type: string + description: Ref to check out + default: main + +permissions: + contents: read + statuses: write + actions: read + security-events: write + +jobs: + + preliminary: + name: Start Markdown table + runs-on: ubuntu-latest + steps: + - run: + echo "\n| Test | Outcome |\n| --- | --- |" >> ${GITHUB_STEP_SUMMARY} + + pytest: + # This job runs unit tests on multiple operating systems (Ubuntu, Windows, macOS) with Python 3.12. + # It is triggered by pull requests, specific comments ('/please-review', '/please-run-tests'), + # or when called directly from another workflow. + # The job uploads coverage reports as artifacts for each combination of OS and Python version. + if: > + github.event_name == 'pull_request' || + github.event.comment.body == '/please-review' || + github.event.comment.body == '/please-run-tests' || + github.event_name == 'workflow_call' + strategy: + matrix: + os: + - ubuntu-latest + - windows-latest + - macos-latest + python: + - '3.12' + name: Run tests for ${{ matrix.os }}, Python ${{ matrix.python }} + runs-on: ${{ matrix.os }} + steps: + - uses: actions/checkout@v4 + with: + ref: ${{ github.event.inputs.ref || github.ref }} + - uses: actions/setup-python@v5 + with: + python-version: ${{ matrix.python }} + - name: Install dependencies and run tests + id: test + run: | + pip install hatch~=1.12 + hatch run test + echo "\ + | Pytest on ${os}, Python ${python} \ + | $( (( $? == 0 )) && echo ✅ || echo ❌ ) \ + |\ + " >> ${GITHUB_STEP_SUMMARY} + - name: Upload coverage report + uses: actions/upload-artifact@v4 + with: + name: coverage-${{ matrix.os }}-${{ matrix.python }} + path: coverage.json + if-no-files-found: error + + docker: + # This job builds Docker images on Ubuntu and Windows if a Dockerfile is present. + # It is triggered by pull requests, specific comments ('/please-review', '/please-check-docker-build'), + # or when called directly from another workflow. + # macOS is not included due to known limitations with Docker on macOS. + if: > + github.event_name == 'pull_request' || + github.event.comment.body == '/please-review' || + github.event.comment.body == '/please-check-docker-build' || + github.event_name == 'workflow_call' + strategy: + matrix: + os: + - ubuntu-latest + - windows-latest + runs-on: ${{ matrix.os }} + steps: + - uses: actions/checkout@v4 + with: + ref: ${{ github.event.inputs.ref || github.ref }} + - name: Check for Dockerfile + id: check-docker + run: | + [[ -f Dockerfile ]]; echo "found=$?" >> ${GITHUB_ENV} + - name: Build Docker image + if: env.found == '0' + run: | + docker build . + echo "\ + | **Docker build** on ${os} \ + | $( (( $? == 0 )) && echo ✅ || echo ❌ ) \ + |\ + " >> ${GITHUB_STEP_SUMMARY} + + codeql: + # This job runs CodeQL analysis for code quality and security checks. + # It is triggered by pull requests, specific comments ('/please-review', '/please-check-code-quality'), + # or when called directly from another workflow. + if: > + github.event_name == 'pull_request' || + github.event.comment.body == '/please-review' || + github.event.comment.body == '/please-check-code-quality' || + github.event_name == 'workflow_call' + name: Analyze with CodeQL + continue-on-error: true + runs-on: ubuntu-latest + steps: + - name: Check out repository + uses: actions/checkout@v4 + with: + ref: ${{ github.event.inputs.ref || github.ref }} + - name: Run ruff --no-fix + id: ruff + run: + pip install hatch~=1.12 + hatch run check + - name: Run CodeQL init + uses: github/codeql-action/init@v3 + - name: Run CodeQL autobuild + uses: github/codeql-action/autobuild@v3 + - name: Run CodeQL analyze + id: codeql + uses: github/codeql-action/analyze@v3 + - name: Log Ruff outcome + run: | + v=[[ ${{ steps.ruff.outcome }} == success ]] + echo "\ + | **Ruff linting** \ + | $( (( ${v} == 0 )) && echo ✅ || echo ⚠️ ) \ + |\ + " >> ${GITHUB_STEP_SUMMARY} + - name: Log CodeQL outcome + run: | + v=[[ ${{ steps.codeql.outcome }} == success ]] + echo "\ + | **CodeQL linting** \ + | $( (( ${v} == 0 )) && echo ✅ || echo ⚠️ ) \ + |\ + " >> ${GITHUB_STEP_SUMMARY} + + security: + # This job runs security linters (Bandit) to check for security issues in the codebase. + # It is triggered by pull requests, specific comments ('/please-review', '/please-check-security'), + # or when called directly from another workflow. + if: > + github.event_name == 'pull_request' || + github.event.comment.body == '/please-review' || + github.event.comment.body == '/please-check-security' || + github.event_name == 'workflow_call' + name: Run security linters + runs-on: ubuntu-latest + outputs: + test_result: ${{ steps.bandit.outcome }} + steps: + - name: Check out code + uses: actions/checkout@v4 + with: + ref: ${{ github.event.inputs.ref || github.ref }} + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: '3.12' + - name: Run Bandit security linter + id: bandit + run: | + pip install hatch~=1.12 + hatch run check-security + echo "\ + | **Security checks** \ + | $( (( $? == 0 )) && echo ✅ || echo ❌ ) \ + |\ + " >> ${GITHUB_STEP_SUMMARY} + + docs: + # This job tests building the documentation to ensure there are no errors. + # It is triggered by pull requests and the comments '/please-review' and '/please-check-docs'. + if: > + github.event_name == 'pull_request' || + github.event.comment.body == '/please-review' || + github.event.comment.body == '/please-check-docs' || + github.event_name == 'workflow_call' + name: Test building docs + runs-on: ubuntu-latest + steps: + - name: Check out code + uses: actions/checkout@v4 + with: + ref: ${{ github.event.inputs.ref || github.ref }} + - uses: actions/setup-python@v5 + with: + python-version: '3.12' + - name: Install dependencies and build docs + id: build_docs + run: | + pip install hatch~=1.12 + # Use ⚠️ if there were warnings. + mkdocs_output=$( hatch run build-docs 2>&1 ) + emoji=$( + (( $? != 0 )) + && echo "❌" + || ( echo "${mkdocs_output}" | grep --quiet "^WARNING " && echo"⚠️" || echo "✅" ) + ) + echo "\ + | **Documentation build** \ + | ${emoji} \ + |\ + " >> ${GITHUB_STEP_SUMMARY} + echo "${mkdocs_output}" + + links: + # This job runs a link checker (linkspector) to verify that all links in the documentation are valid. + # It is triggered by pull requests and the comments '/please-review' and '/please-check-links'. + # Failures will NOT cause the workflow run to fail. + # Note that it uses Reviewdog and will leave a PR review. + name: Check for broken links + if: > + github.event_name == 'pull_request' || + github.event.comment.body == '/please-review' || + github.event.comment.body == '/please-check-links' || + github.event_name == 'workflow_call' + runs-on: ubuntu-latest + continue-on-error: true + steps: + - name: Check out code + uses: actions/checkout@v4 + - name: Run linkspector + id: linkspector + uses: umbrelladocs/action-linkspector@v1 + with: + github_token: ${{ secrets.github_token }} + filter_mode: added + reporter: ${{ github.event_type == 'schedule' && 'github-check' || 'github-pr-review' }} + - name: Log + run: | + v=${{ steps.linkspector.outcome }} + echo "\ + | Markdown links \ + | $( [[ ${v} == success ]] && echo ✅ || echo ⚠️ ) \ + |\ + " >> ${GITHUB_STEP_SUMMARY} + + quick-test: + # This job performs a quick test run for fast feedback. + # **IMPORTANT:** This job is ONLY triggered via /please-check-quickly ! + if: github.event.comment.body == '/please-check-quickly' + name: Quick test on Ubuntu, Python 3.12 + runs-on: ubuntu-latest + steps: + - name: Check out code + uses: actions/checkout@v4 + with: + ref: ${{ github.event.inputs.ref || github.ref }} + - uses: actions/setup-python@v5 + with: + python-version: '3.12' + - name: Run quick tests + run: | + pip install hatch~=1.12 + hatch run test + echo "\ + | Pytest on ubuntu-latest, Python 3.12 \ + | $( (( $? == 0 )) && echo ✅ || echo ❌ ) \ + |\ + " >> ${GITHUB_STEP_SUMMARY} diff --git a/draft/python/py-check-pr-metadata.yaml b/draft/python/py-check-pr-metadata.yaml new file mode 100644 index 0000000..12a00da --- /dev/null +++ b/draft/python/py-check-pr-metadata.yaml @@ -0,0 +1,77 @@ +# SPDX-FileCopyrightText: Copyright 2024, the RCSB PDB, University of California, Rutgers University, and contributors + +# TODO: This is not complete. + +name: Validate PR metadata +run-name: ${{ github.workflow }} on ${{ github.ref_name }} + +on: + pull_request: + types: + - ready_for_review + - edited + issue_comment: + types: + - created + +jobs: + + commitizen-check: + runs-on: ubuntu-latest + + steps: + + - name: Check out repository + uses: actions/checkout@v4 + + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: '3.12' + + - name: Install Commitizen + run: pip install commitizen~=3.27 + + - name: Check if comment contains /please-check-pr-metadata + if: github.event_name == 'issue_comment' + id: check-comment + run: | + exit [[ "${{ github.event.comment.body }}" == *"/please-check-pr-metadata"* ]] + + - name: Validate proposed commit message with Commitizen + id: validate-commit-message + run: | + commit_message=$(jq --raw-output '.pull_request.title' "${GITHUB_EVENT_PATH}") + commit_body=$(jq --raw-output '.pull_request.body' "${GITHUB_EVENT_PATH}") + commit_message="${commit_message}\n\n${commit_body}" + cz_output=$(echo "${commit_message}" | cz check 2>&1) && { + echo "**✅** The PR title+description meets commit message requirements.\n\n" \ + >> ${GITHUB_STEP_SUMMARY} + } || { + echo "fail_msg=The PR title+description do not meet commit message requirements: ${cz_output}" \ + >> ${GITHUB_ENV} + echo "\ + **❌** The PR title+description does not meet commit message requirements: \ + \n```\n${cz_output}\n```\n\n" \ + >> ${GITHUB_STEP_SUMMARY} + exit 1 + } + + - name: Set validation status + if: always() + uses: actions/github-script@v7 + with: + script: | + const { context, github } = require('@actions/github'); + const status = context.job === 'success' ? 'success' : 'failure'; + const description = status === 'success' ? + 'Validation passed' + : 'Validation failed: ' + process.env.fail_msg; + await github.repos.createCommitStatus({ + owner: context.repo.owner, + repo: context.repo.repo, + sha: context.payload.pull_request.head.sha, + state: status, + description: status === 'success' ? 'Validation passed' : 'Validation failed', + context: 'PR Metadata Validation' + }); diff --git a/draft/python/py-deploy-docs.yaml b/draft/python/py-deploy-docs.yaml new file mode 100644 index 0000000..ed2f858 --- /dev/null +++ b/draft/python/py-deploy-docs.yaml @@ -0,0 +1,56 @@ +# SPDX-FileCopyrightText: Copyright 2024, the RCSB PDB, University of California, Rutgers University, and contributors +# SPDX-FileCopyrightText: Copyright 2020-2024, Contributors to CICD +# SPDX-PackageHomePage: https://github.com/dmyersturnbull/cicd +# SPDX-License-Identifier: Apache-2.0 +# SPDX-FileCopyrightText: Copyright 2020-2023, Contributors to Tyrannosaurus +# SPDX-PackageHomePage: https://github.com/dmyersturnbull/tyrannosaurus +# SPDX-License-Identifier: Apache-2.0 + +# This deploys documentation to GitHub Pages. + +name: Deploy docs +run-name: ${{ github.workflow }} for ${{ github.ref_name }} +# Deploys mkdocs documentation to GitHub Pages +# Mike (https://pypi.org/project/mike/) is used to maintain multiple versions + +on: + push: + tags: + # Mike handles the 'latest' tag + - '^v(\d+)\.(\d+)\.(\d+)(?:-(alpha|beta|rc))?$' # match all semver, including prerelease + - '^v(\d+)\.(\d+)\.(\d+)$' # match all non-prerelease semver + #- '^v(\d+)\.([1-9]\d*)\.(\d+)$' # OR: match only 0.1.0+ (non-prerelease) + #- '^(v[1-9]\d*)\.(\d+)\.(\d+)$' # OR: match only 1.0.0+ (non-prerelease) + +concurrency: + group: ${{ github.workflow }}-${{ github.sha }} + cancel-in-progress: false + +permissions: + contents: write + pages: write + id-token: write + +jobs: + deploy-docs: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + ref: ${{ github.ref }} + - uses: actions/setup-python@v5 + with: + python-version: '3.12' + - name: Install dependencies + run: | + pip install hatch~=1.12 + - name: Deploy docs for ${{ github.ref_name }} + run: | + hatch run x-deploy-docs ${{ github.ref_name }} --push + - name: Upload artifact + uses: actions/upload-pages-artifact@v3 + with: + path: . + - name: Deploy to GitHub Pages + id: deployment + uses: actions/deploy-pages@v4 diff --git a/draft/python/py-deploy-packages.yaml b/draft/python/py-deploy-packages.yaml new file mode 100644 index 0000000..4e06ef1 --- /dev/null +++ b/draft/python/py-deploy-packages.yaml @@ -0,0 +1,209 @@ +# SPDX-FileCopyrightText: Copyright 2024, the RCSB PDB, University of California, Rutgers University, and contributors +# SPDX-FileCopyrightText: Copyright 2020-2024, Contributors to CICD +# SPDX-PackageHomePage: https://github.com/dmyersturnbull/cicd +# SPDX-License-Identifier: Apache-2.0 +# SPDX-FileCopyrightText: Copyright 2020-2023, Contributors to Tyrannosaurus +# SPDX-PackageHomePage: https://github.com/dmyersturnbull/tyrannosaurus +# SPDX-License-Identifier: Apache-2.0 + +# This workflow automates a software release, deploying packages to four targets. +# These targets are GitHub releases, PyPi, the GitHub Container Registry, and Docker Hub. +# Additionally, it updates "moving" tags: "latest", which is always updated, and, e.g., "v1", "v2" for the latest release per major version. +# The workflow is triggered by pushes of tags matching "latest" or a semver version prefixed by "v". +# These secrets are needed: +# DOCKERHUB_USERNAME +# DOCKERHUB_TOKEN +# PYPI_TOKEN +# GITHUB_TOKEN (provided automatically by GitHub Actions) +# Note that Docker Hub will not be included as a target if DOCKERHUB_USERNAME is not set. +# Notes about container registries: +# - QEMU is set up for cross-platform builds. +# - Docker Buildx is used for advanced Docker image building and pushing. +# - Docker metadata action extracts metadata such as tags and labels for the images. +# - Cosign is used to sign the Docker images to ensure their integrity and authenticity. + +name: Deploy packages +run-name: ${{ github.workflow }} for ${{ github.ref_name }} + +on: + push: + tags: + # Mike handles the 'latest' tag + - '^v(\d+)\.(\d+)\.(\d+)(?:-(alpha|beta|rc))?$' # match all semver, including prerelease + - '^v(\d+)\.(\d+)\.(\d+)$' # match all non-prerelease semver + #- '^v(\d+)\.([1-9]\d*)\.(\d+)$' # OR: match only 0.1.0+ (non-prerelease) + #- '^(v[1-9]\d*)\.(\d+)\.(\d+)$' # OR: match only 1.0.0+ (non-prerelease) + +concurrency: + group: ${{ github.workflow }}-${{ github.sha }} + cancel-in-progress: false + +permissions: + contents: write + id-token: write + packages: write + attestations: write + +jobs: + + tag-latest: + # This job tags the release as 'latest' and 'v', where is its major version + runs-on: ubuntu-latest + steps: + - uses: Actions-R-Us/actions-tagger@v2 + with: + publish_latest_tag: true + token: ${{ secrets.PAT }} + + build-dist: + # This job builds the Hatch distribution artifacts (wheels and sdist). + runs-on: ubuntu-latest + steps: + - name: Check out code + uses: actions/checkout@v4 + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: '3.12' + - name: Install Hatch and build artifacts + run: | + pip install hatch~=1.12 + hatch build + - name: Upload Hatch artifacts + uses: actions/upload-artifact@v4 + with: + name: dist + path: dist/ + + check-dockerfile-exists: + # This job checks whether the Dockerfile exists. + runs-on: ubuntu-latest + needs: build-dist + outputs: + docker_tags: ${{ steps.check-dockerfile.outputs.found }} + steps: + - name: Check out code + uses: actions/checkout@v4 + - name: Check for Dockerfile + id: check-dockerfile + run: | + if [[ -f Dockerfile ]]; then + echo "Dockerfile exists." + echo "found=true" >> ${GITHUB_OUTPUT} + else + echo "Dockerfile does not exist." + echo "found=false" >> ${GITHUB_OUTPUT} + fi + + publish-github-release: + # This job publishes the release on GitHub. + runs-on: ubuntu-latest + needs: build-dist + steps: + - name: Download artifacts + uses: actions/download-artifact@v4 + with: + name: dist + - name: Publish GitHub release + uses: softprops/action-gh-release@v1 + with: + draft: false + generate_release_notes: true + fail_on_unmatched_files: true + token: ${{ secrets.github_token }} + files: dist/* + + publish-pypi: + # This job publishes the package to PyPI. + name: Publish to PyPi + needs: build-dist + runs-on: ubuntu-latest + steps: + - name: Download artifacts + uses: actions/download-artifact@v4 + with: + name: dist + - name: Install Hatch + run: | + pip install hatch~=1.12 + - name: Publish to PyPi + run: | + hatch publish + env: + HATCH_INDEX_USER: __token__ + HATCH_INDEX_AUTH: ${{ secrets.PYPI_TOKEN }} + if: secrets.PYPI_TOKEN != '' + + publish-docker: + name: Publish to Docker container registries + needs: + - bump + runs-on: ${{ os }} + steps: + # https://github.com/sigstore/cosign-installer + - name: Install cosign + uses: sigstore/cosign-installer@v3 + - name: Download Docker image + uses: actions/download-artifact@v4 + with: + name: docker + - name: Set up QEMU + uses: docker/setup-qemu-action@v3 + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + - name: Extract Docker metadata + id: meta + uses: docker/metadata-action@v5 + with: + images: ${{ GITHUB_REPOSITORY }} + - name: Log in to Docker Hub + uses: docker/login-action@v3 + env: + dockerhub_username: ${{ secrets.DOCKERHUB_USERNAME }} + dockerhub_token: ${{ secrets.DOCKERHUB_TOKEN }} + with: + username: ${{ env.dockerhub_username }} + password: ${{ env.dockerhub_token }} + if: ${{ env.dockerhub_username != '' }} + - name: Log in to GHCR + uses: docker/login-action@v3 + env: + ghcr_username: ${{ github.actor }} + ghcr_password: ${{ github.token }} + with: + registry: ghcr.io + - name: Push Docker image + id: push + uses: docker/build-push-action@v6 + with: + context: . + push: ${{ github.event_name != 'pull_request' }} + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} + cache-from: type=gha + # type=gha,mode=max is meant to maximize cache hits. + cache-to: type=gha,mode=max + # Sign the resulting Docker image digest except on PRs. + # This will only write to the public Rekor transparency log when the Docker + # repository is public to avoid leaking data. + # To publish transparency data even for private images, pass --force to cosign. + # https://github.com/sigstore/cosign + - name: Sign the published Docker image + env: + # https://docs.github.com/en/actions/security-guides/security-hardening-for-github-actions#using-an-intermediate-environment-variable + TAGS: ${{ steps.docker-meta.outputs.tags }} + DIGEST: ${{ steps.build-and-push.outputs.digest }} + # This step uses the identity token to provision an ephemeral certificate + # against the sigstore community Fulcio instance. + run: | + echo "${TAGS}" \ + | xargs \ + --replace _ \ + cosign sign --yes _@${DIGEST} + + #- name: Generate artifact attestation + # uses: actions/attest-build-provenance@v1 + # with: + # subject-name: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME}} + # subject-digest: ${{ steps.push.outputs.digest }} + # push-to-registry: true diff --git a/draft/python/py-format-pr.yaml b/draft/python/py-format-pr.yaml new file mode 100644 index 0000000..b727be7 --- /dev/null +++ b/draft/python/py-format-pr.yaml @@ -0,0 +1,91 @@ +# SPDX-FileCopyrightText: Copyright 2024, the RCSB PDB, University of California, Rutgers University, and contributors +# SPDX-FileCopyrightText: Copyright 2020-2024, Contributors to CICD +# SPDX-PackageHomePage: https://github.com/dmyersturnbull/cicd +# SPDX-License-Identifier: Apache-2.0 + +# TODO: This is not complete. + +name: Format PR + +on: + pull_request_target: + types: + - synchronize + - opened + - reopened + issue_comment: + types: + - created + +jobs: + format: + if: > + github.event_name == 'pull_request_target' || + (github.event_name == 'issue_comment' && contains(github.event.comment.body, '/please-format')) + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@v4 + with: + ref: ${{ github.event.pull_request.head.ref || github.event.issue.pull_request.head.ref }} + token: ${{ secrets.GITHUB_TOKEN }} + + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: '3.12' + + - name: Install dependencies + run: | + pip pip install 'ruff >=0.4.8' + npm install --global prettier '>=3.0.0' + + - name: Run Ruff format + continue-on-error: true + # Format Python + run: | + ruff format . + + - name: Run Prettier + continue-on-error: true + # for Python projects, we're mostly formatting YAML and Markdown + run: | + prettier --write . + + - name: Run pre-commit hooks + # do not continue on error because we should already be formatted + # we're mostly checking the other things, like that shebangs are executable + run: | + pre-commit run --all-files + + - name: Commit changes + run: | + git config --global user.name 'github-actions[bot]' + git config --global user.email 'github-actions[bot]@users.noreply.github.com' + git add . + git commit -m "style: auto-format" + continue-on-error: true + + - name: Push changes + if: success() && steps.commit.outputs.commit != '' + run: | + git push origin ${{ github.event.pull_request.head.ref || github.event.issue.pull_request.head.ref }} + + merge: + needs: + - format + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@v4 + with: + ref: ${{ github.event.pull_request.head.ref }} + token: ${{ secrets.GITHUB_TOKEN }} + + - name: Merge PR + run: gh pr merge \ + ${{ github.event.pull_request.number }} \ + --merge \ + --admin + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/draft/python/py-test-pr.yaml b/draft/python/py-test-pr.yaml new file mode 100644 index 0000000..a80bb26 --- /dev/null +++ b/draft/python/py-test-pr.yaml @@ -0,0 +1,42 @@ +# SPDX-FileCopyrightText: Copyright 2024, the RCSB PDB, University of California, Rutgers University, and contributors +# SPDX-FileCopyrightText: Copyright 2020-2024, Contributors to CICD +# SPDX-PackageHomePage: https://github.com/dmyersturnbull/cicd +# SPDX-License-Identifier: Apache-2.0 + +# This workflow runs tests for pull requests and issue comments. +# It is triggered by pull request events (ready for review, synchronize, edited) +# and issue comments (created). +# The tests are conditional based on the state of the pull request (not in draft) +# and specific events. + +name: Test PR +run-name: ${{ github.workflow }} ${{ github.ref_name }} + +on: + pull_request: + types: + - ready_for_review + - synchronize + - edited + issue_comment: + types: + - created + +jobs: + test: + name: Run tests for PR and issue comments + # Run tests if the PR is ready for review, synchronized (and not in draft), or edited (and not in draft), + # or if an issue comment is created. + if: > + github.event_name == 'pull_request' && + github.event.action == 'ready_for_review' || + github.event_name == 'pull_request' && + github.event.action == 'synchronize' && + github.event.pull_request.draft == false || + github.event_name == 'pull_request' && + github.event.action == 'edited' && + github.event.pull_request.draft == false || + github.event_name == 'issue_comment' && + github.event.action == 'created' + uses: ./.github/workflows/_py-test.yaml + secrets: inherit diff --git a/draft/python/py-update-coverage.yaml b/draft/python/py-update-coverage.yaml new file mode 100644 index 0000000..6044f9b --- /dev/null +++ b/draft/python/py-update-coverage.yaml @@ -0,0 +1,100 @@ +# SPDX-FileCopyrightText: Copyright 2024, the RCSB PDB, University of California, Rutgers University, and contributors +# SPDX-FileCopyrightText: Copyright 2020-2024, Contributors to CICD +# SPDX-PackageHomePage: https://github.com/dmyersturnbull/cicd +# SPDX-License-Identifier: Apache-2.0 +# SPDX-FileCopyrightText: Copyright 2020-2023, Contributors to Tyrannosaurus +# SPDX-PackageHomePage: https://github.com/dmyersturnbull/tyrannosaurus +# SPDX-License-Identifier: Apache-2.0 + +# This workflow updates the code coverage reports and sends them to Coveralls and Codecov. +# It is triggered by pushes to the main branch and release branches. +# The workflow runs tests on multiple operating systems (Ubuntu, Windows, macOS) and Python version 3.12, +# and sends the coverage reports to Coveralls and Codecov. + +name: Update coverage +run-name: ${{ github.workflow }} on ${{ github.ref_name }} + +on: + push: + branches: + - main + - master + - 'releases/**' + +permissions: + contents: write + statuses: write + actions: write + security-events: write + +concurrency: + group: > + ${{ github.workflow }}\ + -${{ github.event.pull_request.number || github.sha }} + cancel-in-progress: true + +jobs: + + test: + # This job runs the tests and generates coverage reports. + name: Run tests + uses: ./.github/workflows/_test.yaml + secrets: inherit + + send-to-coveralls: + name: Update coveralls + needs: test + strategy: + matrix: + os: + - ubuntu-latest + - windows-latest + - macos-latest + python: + - '3.12' + runs-on: ${{ matrix.os }} + steps: + - name: Download coverage artifact for ${{ matrix.os }} / Python ${{ matrix.python }} + uses: actions/download-artifact@v4 + with: + name: coverage-${{ matrix.os }}-${{ matrix.python }} + - name: Send coverage to Coveralls + uses: coverallsapp/github-action@v2 + with: + flag-name: run-${{ matrix.os }}-py${{ matrix.python }} + parallel: true + + send-to-codecov: + name: Update coveralls and codecov + needs: test + continue-on-error: true + #if: !cancelled() + strategy: + matrix: + os: + - ubuntu-latest + - windows-latest + - macos-latest + python: + - '3.12' + runs-on: ${{ matrix.os }} + steps: + - name: Send coverage to Codecov + uses: codecov/codecov-action@v3 + with: + env_vars: matrix.os,matrix.python + fail_ci_if_error: true + + finalize-codecov-send: + # This job sends final data to Coveralls to mark the parallel runs as finished. + # Will not run if the 'send-to-codecov' job was not cancelled + needs: send-to-codecov + continue-on-error: true + #if: !cancelled() + runs-on: ubuntu-latest + steps: + - name: Send final data to Coveralls + uses: coverallsapp/github-action@v2 + with: + parallel-finished: true + file: coverage.json diff --git a/draft/python/py_bump-version.yaml b/draft/python/py_bump-version.yaml new file mode 100644 index 0000000..df89ac6 --- /dev/null +++ b/draft/python/py_bump-version.yaml @@ -0,0 +1,66 @@ +# SPDX-FileCopyrightText: Copyright 2024, the RCSB PDB, University of California, Rutgers University, and contributors +# SPDX-FileCopyrightText: Copyright 2020-2024, Contributors to CICD +# SPDX-PackageHomePage: https://github.com/dmyersturnbull/cicd +# SPDX-License-Identifier: Apache-2.0 + +# + +name: Bump version +run-name: ${{ github.workflow }} to ${{ github.ref_name }} +# Manually called workflow that uses Commitizen to bump the version. +# Adds a commit of type 'release' + +on: + # `gh workflow run bump-version.yaml --prerelease=${prerelease} + workflow_dispatch: + inputs: + prerelease: + type: choice + required: true + description: Pre-release type + options: + - alpha + - beta + - rc + - none + +concurrency: + group: ${{ github.workflow }}-${{ github.sha }} + cancel-in-progress: false + +permissions: + contents: write + +jobs: + + bump: + name: Bump version with commitizen + runs-on: ubuntu-latest + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + steps: + + - uses: actions/checkout@v4 + - name: Import GPG key + id: gpg + uses: crazy-max/ghaction-import-gpg@v5 + with: + gpg_private_key: ${{ secrets.GPG_PRIVATE_KEY }} + passphrase: ${{ secrets.GPG_PASSPHRASE }} + git_user_signingkey: true + git_commit_gpgsign: true + + - id: cz-release + name: Perform bump + uses: commitizen-tools/commitizen-action@v0.2 + with: + github_token: ${{ secrets.github_token }} + git_name: ${{ steps.gpg.outputs.name }} + git_email: ${{ steps.gpg.outputs.email }} + gpg_sign: true + prerelease: ${{ github.event.inputs.prerelease }} # https://github.com/commitizen-tools/commitizen/pull/1162 + changelog: false + debug: true + + - name: Print version + run: echo "Bumped to version ${{ steps.cz-release.outputs.version }}" diff --git a/draft/python/release.yaml b/draft/python/release.yaml new file mode 100644 index 0000000..b4098aa --- /dev/null +++ b/draft/python/release.yaml @@ -0,0 +1,41 @@ +# SPDX-FileCopyrightText: Copyright 2020-2024, Contributors to CICD +# SPDX-PackageHomePage: https://github.com/dmyersturnbull/cicd +# SPDX-License-Identifier: Apache-2.0 + +changelog: + exclude: + labels: + - 'type: chore' + - 'type: style' + - 'exclude' + categories: + - title: '💥 Breaking changes' + labels: + - 'breaking' + - title: '🗑️ Deprecation' + labels: + - 'type: deprecation' + - title: '🔒️ Security' + labels: + - 'type: security' + - title: '✨ Features' + labels: + - 'type: feature' + - title: '🐛 Fixes' + labels: + - 'type: fix' + - title: '⚡️ Performance' + labels: + - 'type: performance' + - title: '📝 Documentation' + labels: + - 'type: docs' + - title: '🔧 Build' + labels: + - 'type: build' + - title: '🍒 Miscellaneous' + labels: + - 'type: refactor' + - 'type: test' + - 'type: ci' + - 'include'