diff --git a/.github/renovate.json5 b/.github/renovate.json5 index 31055da9f..c9b6ceff4 100644 --- a/.github/renovate.json5 +++ b/.github/renovate.json5 @@ -1,25 +1,38 @@ { // Configuration file for RenovateBot: https://docs.renovatebot.com/configuration-options - extends: ["config:base"], - ignoreDeps: [ - "mypy", // 1.5 removed Python 3.7 support https://github.com/canonical/craft-parts/issues/603 - "pydantic", // We'll update Pydantic for all repositories simultaneously. - "types-requests", // Don't update until we can support urllib3 >= 2.0 - "urllib3", // Can't update, see setup.py - ], + extends: ["config:recommended"], labels: ["dependencies"], // For convenient searching in GitHub + baseBranches: ["$default", "/^hotfix\\/.*/"], pip_requirements: { - fileMatch: ["^tox.ini$", "(^|/)requirements([\\w-]*)\\.txt$"] - }, - pip_setup: { - fileMatch: ["^pyproject.toml$", "(^|/)setup\\.py$"] + fileMatch: ["^tox.ini$", "(^|/)requirements([\\w-]*)\\.txt$", "^.pre-commit-config.yaml$"] }, packageRules: [ + { + // Internal package minor patch updates get top priority, with auto-merging + groupName: "internal package minor releases", + matchPackagePatterns: ["^craft-.*"], + matchUpdateTypes: ["minor", "patch", "pin", "digest"], + prPriority: 10, + automerge: true, + minimumReleaseAge: "0 seconds", + schedule: ["at any time"], + matchBaseBranches: ["$default"], // Only do minor releases on main + }, + { + // Same as above, but for hotfix branches, only for patch, and without auto-merging. + groupName: "internal package patch releases (hotfix)", + matchPackagePatterns: ["^craft-.*"], + matchUpdateTypes: ["patch", "pin", "digest"], + prPriority: 10, + minimumReleaseAge: "0 seconds", + schedule: ["at any time"], + matchBaseBranches: ["/^hotfix/.*/"], // All hotfix branches + }, { // Automerge patches, pin changes and digest changes. // Also groups these changes together. groupName: "bugfixes", - excludePackageNames: ["ruff"], + excludeDepPatterns: ["lint/.*", "types/.*"], matchUpdateTypes: ["patch", "pin", "digest"], prPriority: 3, // Patches should go first! automerge: true @@ -27,37 +40,49 @@ { // Update all internal packages in one higher-priority PR groupName: "internal packages", - matchPackagePrefixes: ["craft-", "snap-"], - matchLanguages: ["python"], - prPriority: 2 + matchDepPatterns: ["craft-.*", "snap-.*"], + matchCategories: ["python"], + prPriority: 2, + matchBaseBranches: ["$default"], // Not for hotfix branches }, { - // GitHub Actions are higher priority to update than most dependencies. + // GitHub Actions are higher priority to update than most dependencies since they don't tend to break things. groupName: "GitHub Actions", matchManagers: ["github-actions"], - prPriority: 1 + prPriority: 1, + automerge: true, }, // Everything not in one of these rules gets priority 0 and falls here. + { + //Do all pydantic-related updates together + groupName: "pydantic etc.", + matchPackagePatterns: ["^pydantic"], + }, { // Minor changes can be grouped and automerged for dev dependencies, but are also deprioritised. - groupName: "development dependencies (minor and patch)", + groupName: "development dependencies (non-major)", groupSlug: "dev-dependencies", - matchPackageNames: [ - "black", - "codespell", - "coverage", - "mypy", - "pydocstyle", - "pytest", - "ruff", - "tox", + matchDepPatterns: [ + "dev/.*", + "lint/.*", + "types/.*" ], matchPackagePatterns: [ - ".*-mock$" - ], - matchPackagePrefixes: [ - "pytest-", - "types-", + // Brought from charmcraft. May not be complete. + // This helps group dependencies in requirements-dev.txt files. + "^(.*/)?autoflake$", + "^(.*/)?black$", + "^(.*/)?flake8$", + "^(.*/)?hypothesis$", + "^(.*/)?pycodestyle$", + "^(.*/)?pyfakefs$", + "^(.*/)?pyflakes$", + "^(.*/)?pylint$", + "^(.*/)?pytest", + "^(.*/)?responses$", + "^(.*/)?ruff$", + "^(.*/)?twine$", + "^(.*/)?types-" ], matchUpdateTypes: ["minor", "patch", "pin", "digest"], prPriority: -1, @@ -67,13 +92,16 @@ // Documentation related updates groupName: "documentation dependencies", groupSlug: "doc-dependencies", - matchPackageNames: ["Sphinx"], - matchPackagePatterns: ["^[Ss]phinx.*$", "^furo$"] + matchPackageNames: ["Sphinx", "furo"], + matchPackagePatterns: ["[Ss]phinx.*$"], + matchDepPatterns: ["docs/.*"], + matchBaseBranches: ["$default"], // Not for hotfix branches }, { // Other major dependencies get deprioritised below minor dev dependencies. matchUpdateTypes: ["major"], - prPriority: -2 + prPriority: -2, + matchBaseBranches: ["$default"], // Not for hotfix branches }, { // Major dev dependencies are stone last, but grouped. @@ -81,30 +109,46 @@ groupSlug: "dev-dependencies", matchDepTypes: ["devDependencies"], matchUpdateTypes: ["major"], - prPriority: -3 + prPriority: -3, + matchBaseBranches: ["$default"], // Not for hotfix branches }, { - // Ruff is still unstable, so update it separately. - matchPackageNames: ["ruff"], - prPriority: -3 + // Pyright makes regular breaking changes in patch releases, so we separate these + // and do them independently. + matchPackageNames: ["pyright", "types/pyright"], + prPriority: -4, + matchBaseBranches: ["$default"], // Not for hotfix branches } ], - regexManagers: [ + customManagers: [ { // tox.ini can get updates too if we specify for each package. fileMatch: ["tox.ini"], + customType: "regex", depTypeTemplate: "devDependencies", matchStrings: [ - "# renovate: datasource=(?\\S+)\n\\s+(?.*?)(\\[[\\w]*\\])*[=><~]=(?.*?)\n" + "# renovate: datasource=(?\\S+)\n\\s+(?.*?)(\\[[\\w]*\\])*[=><]=?(?.*?)\n" + ] + }, + { + // .pre-commit-config.yaml version updates + fileMatch: [".pre-commit-config.yaml"], + customType: "regex", + datasourceTemplate: "pypi", + depTypeTemplate: "lint", + matchStrings: [ + "- repo: .*/<(?\\S+)\\s*\\n\\s*rev:\s+\"?v?(?\\S*)\"?", ] } ], timezone: "Etc/UTC", - automergeSchedule: ["every weekend"], schedule: ["every weekend"], prConcurrentLimit: 2, // No more than 2 open PRs at a time. + branchConcurrentLimit: 20, // No more than 20 open branches at a time. prCreation: "not-pending", // Wait until status checks have completed before raising the PR prNotPendingHours: 4, // ...unless the status checks have been running for 4+ hours. prHourlyLimit: 1, // No more than 1 PR per hour. - stabilityDays: 2 // Wait 2 days from release before updating. + minimumReleaseAge: "2 days", + automergeStrategy: "squash", // Squash & rebase when auto-merging. + semanticCommitType: "build" // use `build` as commit header type (i.e. `build(deps): `) } diff --git a/.github/workflows/check-renovate.yaml b/.github/workflows/check-renovate.yaml new file mode 100644 index 000000000..7d13cfbf2 --- /dev/null +++ b/.github/workflows/check-renovate.yaml @@ -0,0 +1,40 @@ +name: Renovate check +on: + pull_request: + paths: + - ".github/workflows/check-renovate.yaml" + - ".github/renovate.json5" + + # Allows triggering the workflow manually from the Actions tab + workflow_dispatch: + inputs: + enable_ssh_access: + type: boolean + description: 'Enable ssh access' + required: false + default: false + +jobs: + renovate: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + - name: Install node + uses: actions/setup-node@v4 + with: + node-version: 22 + - name: Install renovate + run: npm install --global renovate + - name: Enable ssh access + uses: mxschmitt/action-tmate@v3 + if: ${{ inputs.enable_ssh_access }} + with: + limit-access-to-actor: true + - name: Check renovate config + run: renovate-config-validator .github/renovate.json5 + - name: Renovate dry-run + run: renovate --dry-run --autodiscover + env: + RENOVATE_TOKEN: ${{ secrets.GITHUB_TOKEN }} + RENOVATE_USE_BASE_BRANCH_CONFIG: ${{ github.ref }}