diff --git a/.cookiecutter-replay.json b/.cookiecutter-replay.json index 74af62b..108e9bb 100644 --- a/.cookiecutter-replay.json +++ b/.cookiecutter-replay.json @@ -8,6 +8,7 @@ "keywords": "rust, python", "github_org": "frequenz-floss", "license": "MIT", + "private_repo": "no", "author_name": "Frequenz Energy-as-a-Service GmbH", "author_email": "floss@frequenz.com", "python_package": "frequenz.resampling", @@ -34,6 +35,10 @@ "MIT", "Proprietary" ], + "private_repo": [ + "{{ 'yes' if cookiecutter.license == 'Proprietary' else 'no' }}", + "{{ 'no' if cookiecutter.license == 'Proprietary' else 'yes' }}" + ], "author_name": "Frequenz Energy-as-a-Service GmbH", "author_email": "floss@frequenz.com", "python_package": "{{cookiecutter | python_package}}", diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 19232b7..2deb13c 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -29,6 +29,7 @@ updates: exclude-patterns: # pydoclint has shipped breaking changes in patch updates often - "pydoclint" + - "isort" minor: update-types: - "minor" @@ -44,6 +45,7 @@ updates: - "mkdocstrings[python]" - "pydoclint" - "pytest-asyncio" + - "isort" # We group repo-config updates as it uses optional dependencies that are # considered different dependencies otherwise, and will create one PR for # each if we don't group them. diff --git a/.github/workflows/auto-dependabot.yaml b/.github/workflows/auto-dependabot.yaml index a4b920e..7b47101 100644 --- a/.github/workflows/auto-dependabot.yaml +++ b/.github/workflows/auto-dependabot.yaml @@ -23,7 +23,8 @@ jobs: if: | github.actor == 'dependabot[bot]' && !contains(github.event.pull_request.title, 'the repo-config group') && - !contains(github.event.pull_request.title, 'Bump black from ') + !contains(github.event.pull_request.title, 'Bump black from ') && + !contains(github.event.pull_request.title, 'Bump isort from ') runs-on: ubuntu-slim steps: - name: Generate GitHub App token diff --git a/.github/workflows/black-migration.yaml b/.github/workflows/black-migration.yaml index 3dc86fb..7116acd 100644 --- a/.github/workflows/black-migration.yaml +++ b/.github/workflows/black-migration.yaml @@ -66,7 +66,7 @@ jobs: # Read/update pull request metadata and labels. permission-pull-requests: write - name: Migrate - uses: frequenz-floss/gh-action-dependabot-migrate@eb100d3cf732b4808a7776eee8f303521efd494b # v1.2.1 + uses: frequenz-floss/gh-action-dependabot-migrate@27763fb5eb56476d91abe00132e8a0614171f92f # v1.2.0 with: migration-script: | import os @@ -81,6 +81,7 @@ jobs: subprocess.run([sys.executable, "-Im", "black", "."], check=True) token: ${{ steps.create-app-token.outputs.token }} auto-merge-on-changes: "false" + version-iteration: "false" sign-commits: "true" auto-merged-label: "tool:auto-merged" migrated-label: "tool:black:migration:executed" diff --git a/.github/workflows/isort-migration.yaml b/.github/workflows/isort-migration.yaml new file mode 100644 index 0000000..fde6c0c --- /dev/null +++ b/.github/workflows/isort-migration.yaml @@ -0,0 +1,92 @@ +# Automatic isort migration for Dependabot PRs +# +# When Dependabot upgrades isort, this workflow installs the new version and +# runs `isort .` so the PR already contains any import-ordering changes +# introduced by the upgrade, while leaving the PR open for review. +# +# isort follows SemVer but its release policy +# (https://github.com/PyCQA/isort/blob/main/docs/major_releases/release_policy.md) +# explicitly allows intentional formatting changes in minor releases, and +# patch releases may also adjust output in smaller bug-fix ways. Because of +# that, isort is excluded from the regular `patch` and `minor` Dependabot +# groups: every isort bump produces an individual `Bump isort from …` PR and +# is routed through this migration workflow. +# +# The companion auto-dependabot workflow skips those PRs so they're handled +# exclusively by this migration workflow. +# +# XXX: !!! SECURITY WARNING !!! +# pull_request_target has write access to the repo, and can read secrets. +# This is required because Dependabot PRs are treated as fork PRs: the +# GITHUB_TOKEN is read-only and secrets are unavailable with a plain +# pull_request trigger. The action mitigates the risk by: +# - Never executing code from the PR (the migration script is embedded +# in this workflow file on the base branch, not taken from the PR). +# - Gating migration steps on github.actor == 'dependabot[bot]'. +# - Running checkout with persist-credentials: false and isolating +# push credentials from the migration script environment. +# For more details read: +# https://securitylab.github.com/research/github-actions-preventing-pwn-requests/ + +name: isort Migration + +on: + merge_group: # To allow using this as a required check for merging + pull_request_target: + types: [opened, synchronize, reopened, labeled, unlabeled] + +permissions: + # Commit reformatted files back to the PR branch. + contents: write + # Create and normalize migration state labels. + issues: write + # Read/update pull request metadata and comments. + pull-requests: write + +jobs: + isort-migration: + name: Migrate isort + # Skip if it was triggered by the merge queue. We only need the workflow to + # be executed to meet the "Required check" condition for merging, but we + # don't need to actually run the job, having the job present as Skipped is + # enough. + if: | + github.event_name == 'pull_request_target' && + github.actor == 'dependabot[bot]' && + contains(github.event.pull_request.title, 'Bump isort from ') + runs-on: ubuntu-24.04 + steps: + - name: Generate token + id: create-app-token + uses: actions/create-github-app-token@1b10c78c7865c340bc4f6099eb2f838309f1e8c3 # v3.1.1 + with: + app-id: ${{ secrets.FREQUENZ_AUTO_DEPENDABOT_APP_ID }} + private-key: ${{ secrets.FREQUENZ_AUTO_DEPENDABOT_APP_PRIVATE_KEY }} + # Push reformatted files to the PR branch. + permission-contents: write + # Create and normalize migration state labels. + permission-issues: write + # Read/update pull request metadata and labels. + permission-pull-requests: write + - name: Migrate + uses: frequenz-floss/gh-action-dependabot-migrate@27763fb5eb56476d91abe00132e8a0614171f92f # v1.2.0 + with: + migration-script: | + import os + import subprocess + import sys + + version = os.environ["MIGRATION_VERSION"].lstrip("v") + subprocess.run( + [sys.executable, "-Im", "pip", "install", f"isort=={version}"], + check=True, + ) + subprocess.run([sys.executable, "-Im", "isort", "."], check=True) + token: ${{ steps.create-app-token.outputs.token }} + auto-merge-on-changes: "false" + version-iteration: "false" + sign-commits: "true" + auto-merged-label: "tool:auto-merged" + migrated-label: "tool:isort:migration:executed" + intervention-pending-label: "tool:isort:migration:intervention-pending" + intervention-done-label: "tool:isort:migration:intervention-done" diff --git a/.github/workflows/repo-config-migration.yaml b/.github/workflows/repo-config-migration.yaml index 8ab5e01..9608e91 100644 --- a/.github/workflows/repo-config-migration.yaml +++ b/.github/workflows/repo-config-migration.yaml @@ -58,12 +58,14 @@ jobs: # Allow pushes when migration changes workflow files. permission-workflows: write - name: Migrate - uses: frequenz-floss/gh-action-dependabot-migrate@eb100d3cf732b4808a7776eee8f303521efd494b # v1.2.1 + uses: frequenz-floss/gh-action-dependabot-migrate@27763fb5eb56476d91abe00132e8a0614171f92f # v1.2.0 with: script-url-template: >- https://raw.githubusercontent.com/frequenz-floss/frequenz-repo-config-python/{version}/cookiecutter/migrate.py token: ${{ steps.create-app-token.outputs.token }} migration-token: ${{ secrets.REPO_CONFIG_MIGRATION_TOKEN }} + version-iteration: "minor" + if-no-iterations: "pass" sign-commits: "true" auto-merged-label: "tool:auto-merged" migrated-label: "tool:repo-config:migration:executed" diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 66c9d01..7d90f59 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -50,14 +50,14 @@ pytest tests/test_*.py Or you can use `nox`: ```sh -nox -R -s pytest -- test/test_*.py +nox -R -s pytest -- tests/test_*.py ``` The same appliest to `pylint` or `mypy` for example: ```sh -nox -R -s pylint -- test/test_*.py -nox -R -s mypy -- test/test_*.py +nox -R -s pylint -- tests/test_*.py +nox -R -s mypy -- tests/test_*.py ``` ### Building the documentation diff --git a/pyproject.toml b/pyproject.toml index 298d2b4..17c2480 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ [build-system] requires = [ "maturin>=1.7,<2.0", - "frequenz-repo-config[lib] == 0.17.0", + "frequenz-repo-config[lib] == 0.18.0", ] build-backend = "maturin" @@ -58,7 +58,7 @@ dev-mkdocs = [ "mkdocs-material == 9.7.6", "mkdocstrings[python] == 1.0.4", "mkdocstrings-python == 2.0.3", - "frequenz-repo-config[lib] == 0.17.0", + "frequenz-repo-config[lib] == 0.18.0", ] dev-mypy = [ "mypy == 2.1.0", @@ -68,7 +68,7 @@ dev-mypy = [ ] dev-noxfile = [ "nox == 2026.4.10", - "frequenz-repo-config[lib] == 0.17.0", + "frequenz-repo-config[lib] == 0.18.0", ] dev-pylint = [ # dev-pytest already defines a dependency to pylint because of the examples @@ -80,7 +80,7 @@ dev-pytest = [ "pylint == 4.0.5", # We need this to check for the examples "pandas == 3.0.3", "pandas-stubs == 3.0.3.260530", - "frequenz-repo-config[extra-lint-examples] == 0.17.0", + "frequenz-repo-config[extra-lint-examples] == 0.18.0", "pytest-mock == 3.15.1", "pytest-asyncio == 1.4.0", "async-solipsism == 0.9",