diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml new file mode 100644 index 0000000..36ef346 --- /dev/null +++ b/.github/workflows/CI.yml @@ -0,0 +1,21 @@ +name: CI + +on: + push: + branches: + - main + - 'releases/**' + workflow_call: + workflow_dispatch: + +permissions: {} + +jobs: + check_actions: + name: Check actions + uses: ./.github/workflows/check_actions.yml + permissions: + security-events: write + check_docs: + name: Check docs + uses: ./.github/workflows/check_docs.yml diff --git a/.github/workflows/PR.yml b/.github/workflows/PR.yml new file mode 100644 index 0000000..1522824 --- /dev/null +++ b/.github/workflows/PR.yml @@ -0,0 +1,22 @@ +name: PR + +on: + pull_request: + branches: + - main + - 'releases/**' + workflow_call: + workflow_dispatch: + +permissions: {} + +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true + +jobs: + run_ci: + name: Run CI + uses: ./.github/workflows/CI.yml + permissions: + security-events: write diff --git a/.github/workflows/check_actions.yml b/.github/workflows/check_actions.yml new file mode 100644 index 0000000..edc83dd --- /dev/null +++ b/.github/workflows/check_actions.yml @@ -0,0 +1,21 @@ +name: Check actions + +on: + workflow_call: + workflow_dispatch: + +permissions: {} + +jobs: + zizmor: + name: Run zizmor + runs-on: ubuntu-latest + permissions: + security-events: write + steps: + - name: Check out repo + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + persist-credentials: false + - name: Run zizmor + uses: zizmorcore/zizmor-action@5f14fd08f7cf1cb1609c1e344975f152c7ee938d # v0.5.6 diff --git a/.github/workflows/check_docs.yml b/.github/workflows/check_docs.yml new file mode 100644 index 0000000..2e8f154 --- /dev/null +++ b/.github/workflows/check_docs.yml @@ -0,0 +1,35 @@ +name: Sync docs config mirror + +on: + workflow_call: + workflow_dispatch: + +jobs: + validate-docs: + runs-on: ubuntu-latest + + steps: + - name: Check out repository + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + persist-credentials: false + + - name: Generate docs mirror + shell: bash + run: | + bash .github/workflows/sync-docs.sh + + - name: Verify docs mirror is clean + shell: bash + run: | + set -euo pipefail + if grep -R "local>ni/python-renovate-config" docs; then + echo "Found unresolved local preset references in docs/" >&2 + exit 1 + fi + + if ! git diff --quiet -- docs; then + echo "docs/ is out of sync with the source configs; regenerate it (by running .github/workflows/sync-docs.sh) and commit the updated docs/ output." >&2 + git --no-pager diff -- docs >&2 + exit 1 + fi diff --git a/.github/workflows/sync-docs.sh b/.github/workflows/sync-docs.sh new file mode 100644 index 0000000..961defa --- /dev/null +++ b/.github/workflows/sync-docs.sh @@ -0,0 +1,18 @@ +#!/usr/bin/env bash + +set -euo pipefail + +docs_dir="docs" +pages_base_url="https://ni.github.io/python-renovate-config" + +mkdir -p "${docs_dir}/presets/group" "${docs_dir}/presets/packages" +find "${docs_dir}" -type f -name '*.json' -delete + +cp default.json recommended.json "${docs_dir}/" +cp presets/*.json "${docs_dir}/presets/" +cp presets/group/*.json "${docs_dir}/presets/group/" +cp presets/packages/*.json "${docs_dir}/presets/packages/" + +find "${docs_dir}" -type f -name '*.json' -print0 | xargs -0 sed -E -i \ + -e "s|local>ni/python-renovate-config:([A-Za-z0-9_-]+)|${pages_base_url}/\\1.json|g" \ + -e "s|local>ni/python-renovate-config//([A-Za-z0-9_./-]+)|${pages_base_url}/\\1.json|g" diff --git a/README.md b/README.md index 516fa69..c23bb86 100644 --- a/README.md +++ b/README.md @@ -50,6 +50,23 @@ which some project owners may want to configure differently. detected and pulled from the repository before we try to upgrade. This should not affect security vulnerability alerts. +## Using Outside of GitHub repos + +If Renovate is running somewhere that cannot resolve this repository's `local>` preset references, +use the generated mirror under `docs/` instead of referencing the repository root files directly. + +Example: + +```jsonc +{ + "extends": [ + "https://ni.github.io/python-renovate-config/recommended.json" + ] +} +``` + +PR builds validate that `docs/` is in sync, and a script is provided to keep it in sync. + ## Presets ### `presets/enableGitSubmodules.json` diff --git a/docs/README.md b/docs/README.md new file mode 100644 index 0000000..14c8db7 --- /dev/null +++ b/docs/README.md @@ -0,0 +1,8 @@ +# Generated Config Mirror + +`.github/workflows/sync-docs.sh` populates this directory by copying the config files and rewriting internal `local>` references to the GitHub Pages URLs rooted at: + +`https://ni.github.io/python-renovate-config/` + +Use `docs/recommended.json` from this directory when a Renovate host cannot resolve GitHub-local +preset references directly. The JSON files in this directory are generated and should be updated using the script rather than edited by hand. \ No newline at end of file diff --git a/docs/default.json b/docs/default.json new file mode 100644 index 0000000..69a10ee --- /dev/null +++ b/docs/default.json @@ -0,0 +1,8 @@ +{ + "$schema": "https://docs.renovatebot.com/renovate-schema.json", + "extends": [ + "config:recommended" + ], + "branchPrefix": "users/renovate/", + "timezone": "US/Central" +} \ No newline at end of file diff --git a/docs/presets/enableGitSubmodules.json b/docs/presets/enableGitSubmodules.json new file mode 100644 index 0000000..3ee5c2e --- /dev/null +++ b/docs/presets/enableGitSubmodules.json @@ -0,0 +1,7 @@ +{ + "$schema": "https://docs.renovatebot.com/renovate-schema.json", + "description": "Update Git submodules.", + "git-submodules": { + "enabled": true + } +} \ No newline at end of file diff --git a/docs/presets/enableVulnerabilityAlerts.json b/docs/presets/enableVulnerabilityAlerts.json new file mode 100644 index 0000000..ad23f8f --- /dev/null +++ b/docs/presets/enableVulnerabilityAlerts.json @@ -0,0 +1,8 @@ +{ + "$schema": "https://docs.renovatebot.com/renovate-schema.json", + "description": "Raise PR when vulnerability alerts are detected (including OSV alerts).", + "extends": [ + ":enableVulnerabilityAlerts" + ], + "osvVulnerabilityAlerts": true +} \ No newline at end of file diff --git a/docs/presets/group/githubActions.json b/docs/presets/group/githubActions.json new file mode 100644 index 0000000..6fa90a9 --- /dev/null +++ b/docs/presets/group/githubActions.json @@ -0,0 +1,13 @@ +{ + "$schema": "https://docs.renovatebot.com/renovate-schema.json", + "description": "Group GitHub Actions together.", + "packageRules": [ + { + "matchManagers": [ + "github-actions" + ], + "groupName": "GitHub Actions", + "groupSlug": "github-actions" + } + ] +} \ No newline at end of file diff --git a/docs/presets/group/python.json b/docs/presets/group/python.json new file mode 100644 index 0000000..e313168 --- /dev/null +++ b/docs/presets/group/python.json @@ -0,0 +1,20 @@ +{ + "$schema": "https://docs.renovatebot.com/renovate-schema.json", + "description": "Group Python packages together.", + "packageRules": [ + { + "matchCategories": [ + "python" + ], + "matchUpdateTypes": [ + "major", + "minor", + "patch", + "rollback", + "replacement" + ], + "groupName": "Python packages", + "groupSlug": "python" + } + ] +} \ No newline at end of file diff --git a/docs/presets/packages/niPython.json b/docs/presets/packages/niPython.json new file mode 100644 index 0000000..2e2f158 --- /dev/null +++ b/docs/presets/packages/niPython.json @@ -0,0 +1,14 @@ +{ + "$schema": "https://docs.renovatebot.com/renovate-schema.json", + "description": "All NI Python packages.", + "packageRules": [ + { + "matchDatasources": [ + "pypi" + ], + "matchPackageNames": [ + "ni**" + ] + } + ] +} \ No newline at end of file diff --git a/docs/recommended.json b/docs/recommended.json new file mode 100644 index 0000000..0847541 --- /dev/null +++ b/docs/recommended.json @@ -0,0 +1,49 @@ +{ + "$schema": "https://docs.renovatebot.com/renovate-schema.json", + "extends": [ + "https://ni.github.io/python-renovate-config/default.json", + "https://ni.github.io/python-renovate-config/presets/enableVulnerabilityAlerts.json", + "helpers:pinGitHubActionDigestsToSemver", + // Run lock file maintenance monthly in order to upgrade indirect + // dependencies that are not covered by the weekly update, such as + // `certifi` or `typing_extensions`. + ":maintainLockFilesMonthly", + ":rebaseStalePrs" + ], + // Do not upgrade to new package versions as soon as they are released. If + // an upstream package is compromised, delaying makes it more likely that + // the compromised version will be detected and pulled from the repository + // before we try to upgrade. This should not affect security vulnerability + // alerts. + "minimumReleaseAge": "14 days", + "packageRules": [ + { + "description": "Update GitHub Actions on Sundays.", + "extends": [ + "https://ni.github.io/python-renovate-config/presets/group/githubActions.json" + ], + "schedule": ["* * * * 0"] + }, + { + "description": "Update Python packages on Sundays.", + "extends": [ + "https://ni.github.io/python-renovate-config/presets/group/python.json" + ], + "schedule": ["* * * * 0"] + }, + { + "description": "Set minimumReleaseAge to 1 day for ni/python-actions.", + "matchPackageNames": [ + "ni/python-actions" + ], + "minimumReleaseAge": "1 day" + }, + { + "description": "Set minimumReleaseAge to 1 day for NI Python packages.", + "extends": [ + "https://ni.github.io/python-renovate-config/presets/packages/niPython.json" + ], + "minimumReleaseAge": "1 day" + } + ] +} \ No newline at end of file