diff --git a/.github/workflows/python-linting.yml b/.github/workflows/python-linting.yml new file mode 100644 index 0000000..0c4fdf0 --- /dev/null +++ b/.github/workflows/python-linting.yml @@ -0,0 +1,84 @@ +# Python Testing Workflow +# +# - Automatically runs tests on all supported versions of Python +name: Python - Linting + +on: + pull_request: + workflow_call: + inputs: + tool: + description: 'The tool to lint with' + type: string + default: 'ruff' + versions: + description: 'Python versions to test against' + type: string + # All Major versions of Python that are currently supported + default: '3.9,3.10,3.11,3.12' + +jobs: + python-versions: + runs-on: ubuntu-latest + outputs: + matrix: ${{ steps.set-matrix.outputs.matrix }} + steps: + - name: Set matrix + id: set-matrix + run: | + versions="${{ inputs.versions }}" + echo "Version Input :: $versions" + matrix=$(echo "$versions" | tr "," "\n" | awk '{print "\""$1"\""}' | paste -sd "," -) + echo "matrix :: [$matrix]" + echo "matrix=[$matrix]" >> "$GITHUB_OUTPUT" + + python-linting: + runs-on: ubuntu-latest + if: ${{ needs.python-versions.outputs.matrix != '[]' }} + needs: [ python-versions ] + strategy: + fail-fast: false + matrix: + python-version: ${{ fromJson(needs.python-versions.outputs.matrix) }} + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v5 + with: + python-version: ${{ matrix.python-version }} + + - name: Install dependencies + run: | + set -e + if [[ -f pyproject.toml ]]; then + python -m pip install --upgrade pip poetry + poetry install + elif [[ -f Pipfile ]]; then + python -m pip install --upgrade pip pipenv + pipenv sync -d + elif [[ -f requirements.txt ]]; then + python -m pip install --upgrade pip + pip install -r requirements.txt + elif [[ -f Makefile ]]; then + make install + else + echo "No manifest files found to install dependencies" + fi + + - name: Run linting + run: | + set -e + TOOL="${{ inputs.tool }}" + if [[ "$TOOL" == "ruff" ]]; then + pip install ruff + ruff check + elif [[ "$TOOL" == "flake8" ]]; then + pip install flake8 + flake8 . + elif [[ "$TOOL" == "black" ]]; then + pip install black + black --check . + fi diff --git a/.github/workflows/python-release.yml b/.github/workflows/python-release.yml new file mode 100644 index 0000000..ccbc234 --- /dev/null +++ b/.github/workflows/python-release.yml @@ -0,0 +1,65 @@ +# Python Releasing Workflow +name: Python - Release + +on: + push: + workflow_call: + inputs: + version: + description: 'Python main version to vendor' + type: string + # All Major versions of Python that are currently supported + default: '3.11' + +permissions: + contents: write + pull-requests: write + +jobs: + version-changes: + runs-on: ubuntu-latest + outputs: + release: ${{ steps.check_release.outputs.release }} + version: ${{ steps.check_release.outputs.version }} + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: "Check release" + id: check_release + env: + GH_TOKEN: ${{ github.token }} + run: | + set -e + + if [[ -f .release.yml ]]; then + pip install yq + current_version=$(cat .release.yml | yq -r ".version") + elif [[ -f pyproject.toml ]]; then + current_version=$(grep -oP '^version = "(.*)"$' pyproject.toml | cut -d '"' -f 2) + elif [[ -f setup.py ]]; then + current_version=$(grep -oP '^__version__ = "(.*)"$' setup.py | cut -d '"' -f 2) + else + echo "No version file found" + current_version="NA" + fi + + released_version=$(gh api -H "Accept: application/vnd.github+json" -H "X-GitHub-Api-Version: 2022-11-28" /repos/:owner/:repo/releases/latest | jq -r ".tag_name") + + if [[ "$current_version" == "NA" || "$current_version" == "$released_version" ]]; then + echo "No new release found" + echo "release=false" >> "$GITHUB_OUTPUT" + else + echo "New release found" + echo "version=$current_version" >> "$GITHUB_OUTPUT" + echo "release=true" >> "$GITHUB_OUTPUT" + fi + + github-release: + uses: advanced-security/reusable-workflows/.github/workflows/release.yml@main + needs: [ version-changes ] + if: ${{ needs.version-changes.outputs.release == 'true' }} + secrets: inherit + with: + version: ${{ needs.version-changes.outputs.version }} diff --git a/.github/workflows/python-testing.yml b/.github/workflows/python-testing.yml new file mode 100644 index 0000000..585c427 --- /dev/null +++ b/.github/workflows/python-testing.yml @@ -0,0 +1,85 @@ +# Python Testing Workflow +# +# - Automatically runs tests on all supported versions of Python +name: Python - Testing + +on: + pull_request: + workflow_call: + inputs: + versions: + description: 'Python versions to test against' + type: string + # All Major versions of Python that are currently supported + default: '3.9,3.10,3.11,3.12' + +jobs: + python-versions: + runs-on: ubuntu-latest + outputs: + matrix: ${{ steps.set-matrix.outputs.matrix }} + steps: + - name: Set matrix + id: set-matrix + run: | + versions="${{ inputs.versions }}" + echo "Version Input :: $versions" + matrix=$(echo "$versions" | tr "," "\n" | awk '{print "\""$1"\""}' | paste -sd "," -) + echo "matrix :: [$matrix]" + echo "matrix=[$matrix]" >> "$GITHUB_OUTPUT" + + python-testing: + # This workflow runs on the latest version of Ubuntu + runs-on: ubuntu-latest + if: ${{ needs.python-versions.outputs.matrix != '[]' }} + needs: [ python-versions ] + strategy: + fail-fast: false + matrix: + python-version: ${{ fromJSON(needs.python-versions.outputs.matrix) }} + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v5 + with: + python-version: ${{ matrix.python-version }} + + - name: Install dependencies + run: | + set -e + echo "Installing dependencies..." + if [[ -f pyproject.toml ]]; then + python -m pip install --upgrade pip poetry + poetry install + elif [[ -f Pipfile ]]; then + python -m pip install --upgrade pip pipenv + pipenv sync -d + elif [[ -f requirements.txt ]]; then + python -m pip install --upgrade pip + pip install -r requirements.txt + elif [[ -f Makefile ]]; then + make install + else + echo "No manifest files found to install dependencies" + fi + + - name: Run tests + run: | + set -e + echo "Running Python tests..." + if [[ -f pyproject.toml ]]; then + echo "Running poetry run test" + poetry run test + elif [[ -f Pipfile ]]; then + echo "Running pipenv run test" + pipenv run test + elif [[ -f Makefile ]]; then + echo "Running make test" + make test + else + echo "Unknown test runner..." + echo "Please contact the oss-maintainers team for help." + fi diff --git a/.github/workflows/python-vendor.yml b/.github/workflows/python-vendor.yml new file mode 100644 index 0000000..c7267d0 --- /dev/null +++ b/.github/workflows/python-vendor.yml @@ -0,0 +1,99 @@ +# Python Vendoring Workflow +name: Python - Vendoring + +on: + push: + pull_request: + workflow_call: + inputs: + custom-property: + description: 'Name of the custom property to get value from' + type: string + default: 'OSSType' + version: + description: 'Python main version to vendor' + type: string + # All Major versions of Python that are currently supported + default: '3.11' + +permissions: + contents: write + pull-requests: write + +jobs: + custom-property: + runs-on: ubuntu-latest + outputs: + osstype: ${{ steps.get_custom_property.outputs.osstype }} + + steps: + - name: Checkout + uses: actions/checkout@v4 + - name: "Get Custom Property" + id: get_custom_property + env: + GH_TOKEN: ${{ github.token }} + PROPERTY_NAME: ${{ inputs.custom-property }} + run: | + set -e + + PROPERTIES=$(gh api -H "Accept: application/vnd.github+json" -H "X-GitHub-Api-Version: 2022-11-28" /repos/:owner/:repo/properties/values) + echo "Properties: '$PROPERTIES'" + + REPOSITORY_TYPE=$(echo $PROPERTIES | jq -r ".[] | select(.property_name == \"$PROPERTY_NAME\") | .value") + echo "Repository type: '$REPOSITORY_TYPE'" + echo "osstype=$REPOSITORY_TYPE" >> "$GITHUB_OUTPUT" + + python-vendoring: + runs-on: ubuntu-latest + needs: [ custom-property ] + if: ${{ needs.custom-property.outputs.osstype == 'Actions' }} + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Set up Python ${{ inputs.version }} + uses: actions/setup-python@v5 + with: + python-version: ${{ inputs.version }} + + - name: "Install and Vendor dependencies" + id: vendoring + run: | + set -e + + if [[ -f Pipfile ]]; then + python -m pip install --upgrade pip pipenv + pipenv run vendor + elif [[ -f Makefile ]]; then + make vendor + elif [[ -f vendor/update.sh ]]; then + ./vendor/update.sh + else + echo "Unknown vendoring method" + fi + + CHANGES=$(git status --porcelain | wc -l) + echo "changes=$CHANGES" >> "$GITHUB_OUTPUT" + + - name: "Update vendored dependencies (Push)" + if: ${{ steps.vendoring.outputs.changes != 0 && (github.event_name == 'push' || github.event_name == 'workflow_dispatch') }} + uses: peter-evans/create-pull-request@v6 + with: + token: ${{ github.token }} + commit-message: "[chore]: Update vendored dependencies" + title: "[chore]: Update vendored dependencies" + branch: update-vendored-dependencies + base: ${{ github.event.before }} + labels: dependencies + body: | + This is an automated PR to update that vendored dependencies are up to date. + It was created by a GitHub workflow defined in `.github/workflows/python-vendor.yml`. + Please do not merge this PR manually. +
+ Details +

+ This PR was created by a workflow that runs on all pushes to the repository. + It installs dependencies and then verifies that the repository is clean. +

+
diff --git a/.github/workflows/python.yml b/.github/workflows/python.yml new file mode 100644 index 0000000..b9b7602 --- /dev/null +++ b/.github/workflows/python.yml @@ -0,0 +1,58 @@ +# Python Testing Workflow +# +# - Automatically runs tests on all supported versions of Python +name: Python + +on: + pull_request: + workflow_call: + inputs: + version: + description: 'Python main version to vendor' + type: string + # All Major versions of Python that are currently supported + default: '3.11' + versions: + description: 'Python versions to test against' + type: string + # All Major versions of Python that are currently supported + default: '3.9,3.10,3.11,3.12' + vendor: + description: 'Whether to vendor the dependencies' + type: string + default: 'true' + + +jobs: + # Run the tests on all supported versions of Python + testing: + uses: advanced-security/reusable-workflows/.github/workflows/python-testing.yml@main + secrets: inherit + with: + versions: ${{ inputs.versions }} + + # Run linters on the codebase + linting: + uses: advanced-security/reusable-workflows/.github/workflows/python-linting.yml@main + needs: [ testing ] + secrets: inherit + with: + versions: ${{ inputs.versions }} + + # Vendor the dependencies into the repository if needed + vendoring: + uses: advanced-security/reusable-workflows/.github/workflows/python-vendor.yml@main + needs: [ testing, linting ] + if: ${{ inputs.vendor == 'true' }} + secrets: inherit + with: + version: ${{ inputs.version }} + custom-property: 'OSSType' + + # Release a new version of the package + release: + uses: advanced-security/reusable-workflows/.github/workflows/python-release.yml@main + needs: [ testing, linting ] + secrets: inherit + with: + version: ${{ inputs.version }}