diff --git a/.github/dependabot.config.yml b/.github/dependabot.config.yml new file mode 100644 index 00000000..6e322fe5 --- /dev/null +++ b/.github/dependabot.config.yml @@ -0,0 +1,59 @@ +# Human-editable source of truth for Dependabot configuration. +# Active release branches are populated from releases.md by hack/generate-dependabot.sh. +# Run ./hack/generate-dependabot.sh to regenerate .github/dependabot.yml. + +release-branches: + - release-v0.4.x + - release-v0.3.x +ecosystems: + - package-ecosystem: gomod + directory: / + schedule: + interval: daily + labels: + - ok-to-test + - dependencies + - release-note-none + - kind/misc + ignore: + - dependency-name: "k8s.io/*" + update-types: + - "version-update:semver-major" + - "version-update:semver-minor" + cooldown: + default-days: 7 + semver-major-days: 30 + semver-minor-days: 7 + semver-patch-days: 3 + - package-ecosystem: github-actions + directory: / + schedule: + interval: weekly + labels: + - ok-to-test + - dependencies + - release-note-none + - kind/misc + cooldown: + default-days: 7 + semver-major-days: 30 + semver-minor-days: 7 + semver-patch-days: 3 + - package-ecosystem: docker + directory: /tekton + schedule: + interval: weekly + labels: + - ok-to-test + - dependencies + - release-note-none + - kind/misc + groups: + all: + patterns: + - "*" + cooldown: + default-days: 7 + semver-major-days: 30 + semver-minor-days: 7 + semver-patch-days: 3 diff --git a/.github/dependabot.yml b/.github/dependabot.yml index fcf42579..e9d62c86 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -1,36 +1,196 @@ +# Generated file - DO NOT EDIT MANUALLY +# This file is generated by hack/generate-dependabot.sh +# +# To update this file: +# 1. Edit .github/dependabot.config.yml +# 2. Run: ./hack/generate-dependabot.sh +# version: 2 updates: - - package-ecosystem: "gomod" - directory: "/" + - package-ecosystem: gomod + directory: / schedule: - interval: "daily" + interval: daily labels: - - "ok-to-test" - - "dependencies" - - "release-note-none" - - "kind/misc" + - ok-to-test + - dependencies + - release-note-none + - kind/misc ignore: - - dependency-name: "k8s.io/*" - update-types: ["version-update:semver-major", "version-update:semver-minor"] - - package-ecosystem: "github-actions" - directory: "/" - schedule: - interval: "weekly" - labels: - - "ok-to-test" - - "dependencies" - - "release-note-none" - - "kind/misc" - - package-ecosystem: "docker" - directory: "/tekton" - schedule: - interval: "weekly" - labels: - - "ok-to-test" - - "dependencies" - - "release-note-none" - - "kind/misc" + - dependency-name: k8s.io/* + update-types: + - version-update:semver-major + - version-update:semver-minor + cooldown: + default-days: 7 + semver-major-days: 30 + semver-minor-days: 7 + semver-patch-days: 3 + - package-ecosystem: github-actions + directory: / + schedule: + interval: weekly + labels: + - ok-to-test + - dependencies + - release-note-none + - kind/misc + cooldown: + default-days: 7 + semver-major-days: 30 + semver-minor-days: 7 + semver-patch-days: 3 + - package-ecosystem: docker + directory: /tekton + schedule: + interval: weekly + labels: + - ok-to-test + - dependencies + - release-note-none + - kind/misc + groups: + all: + patterns: + - '*' + cooldown: + default-days: 7 + semver-major-days: 30 + semver-minor-days: 7 + semver-patch-days: 3 + - package-ecosystem: gomod + directory: / + target-branch: release-v0.4.x + schedule: + interval: daily + labels: + - ok-to-test + - dependencies + - release-note-none + - kind/misc + ignore: + - dependency-name: k8s.io/* + update-types: + - version-update:semver-major + - version-update:semver-minor + - dependency-name: '*' + update-types: + - version-update:semver-major + - version-update:semver-minor + cooldown: + default-days: 7 + semver-major-days: 30 + semver-minor-days: 7 + semver-patch-days: 3 + - package-ecosystem: github-actions + directory: / + target-branch: release-v0.4.x + schedule: + interval: weekly + labels: + - ok-to-test + - dependencies + - release-note-none + - kind/misc + ignore: + - dependency-name: '*' + update-types: + - version-update:semver-major + - version-update:semver-minor + cooldown: + default-days: 7 + semver-major-days: 30 + semver-minor-days: 7 + semver-patch-days: 3 + - package-ecosystem: docker + directory: /tekton + target-branch: release-v0.4.x + schedule: + interval: weekly + labels: + - ok-to-test + - dependencies + - release-note-none + - kind/misc + ignore: + - dependency-name: '*' + update-types: + - version-update:semver-major + - version-update:semver-minor + groups: + all: + patterns: + - '*' + cooldown: + default-days: 7 + semver-major-days: 30 + semver-minor-days: 7 + semver-patch-days: 3 + - package-ecosystem: gomod + directory: / + target-branch: release-v0.3.x + schedule: + interval: daily + labels: + - ok-to-test + - dependencies + - release-note-none + - kind/misc + ignore: + - dependency-name: k8s.io/* + update-types: + - version-update:semver-major + - version-update:semver-minor + - dependency-name: '*' + update-types: + - version-update:semver-major + - version-update:semver-minor + cooldown: + default-days: 7 + semver-major-days: 30 + semver-minor-days: 7 + semver-patch-days: 3 + - package-ecosystem: github-actions + directory: / + target-branch: release-v0.3.x + schedule: + interval: weekly + labels: + - ok-to-test + - dependencies + - release-note-none + - kind/misc + ignore: + - dependency-name: '*' + update-types: + - version-update:semver-major + - version-update:semver-minor + cooldown: + default-days: 7 + semver-major-days: 30 + semver-minor-days: 7 + semver-patch-days: 3 + - package-ecosystem: docker + directory: /tekton + target-branch: release-v0.3.x + schedule: + interval: weekly + labels: + - ok-to-test + - dependencies + - release-note-none + - kind/misc + ignore: + - dependency-name: '*' + update-types: + - version-update:semver-major + - version-update:semver-minor groups: all: patterns: - - "*" + - '*' + cooldown: + default-days: 7 + semver-major-days: 30 + semver-minor-days: 7 + semver-patch-days: 3 diff --git a/.github/workflows/dependabot-regen.yml b/.github/workflows/dependabot-regen.yml new file mode 100644 index 00000000..2b06ce36 --- /dev/null +++ b/.github/workflows/dependabot-regen.yml @@ -0,0 +1,114 @@ +name: Regenerate Dependabot Configuration + +"on": + schedule: + - cron: '0 9 * * 1' + workflow_dispatch: {} + +permissions: + contents: write + pull-requests: write + +jobs: + regenerate: + runs-on: ubuntu-latest + steps: + - name: Harden Runner + uses: step-security/harden-runner@9af89fc71515a100421586dfdb3dc9c984fbf411 # v2.19.4 + with: + egress-policy: audit + + - name: Checkout repository + uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 + with: + persist-credentials: false + + - name: Set up Go + uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0 + with: + go-version-file: 'go.mod' + + - name: Regenerate dependabot.yml + run: | + echo "Regenerating .github/dependabot.yml..." + ./hack/generate-dependabot.sh + + - name: Check for changes + id: check-changes + run: | + if git diff --quiet .github/dependabot.config.yml .github/dependabot.yml; then + echo "changed=false" >> $GITHUB_OUTPUT + echo "No changes detected in dependabot.yml" + else + echo "changed=true" >> $GITHUB_OUTPUT + echo "Changes detected in dependabot.yml" + fi + + - name: Create Pull Request + if: steps.check-changes.outputs.changed == 'true' + env: + GH_TOKEN: ${{ secrets.CHATOPS_TOKEN }} + WORKFLOW_NAME: ${{ github.workflow }} + EVENT_NAME: ${{ github.event_name }} + SERVER_URL: ${{ github.server_url }} + REPOSITORY: ${{ github.repository }} + RUN_ID: ${{ github.run_id }} + run: | + git config user.name "tekton-robot" + git config user.email "tekton-robot@users.noreply.github.com" + + # Create a new branch + BRANCH="dependabot-regen-$(date +%Y%m%d-%H%M%S)" + git checkout -b "$BRANCH" + + # Commit changes + git add .github/dependabot.config.yml .github/dependabot.yml + git commit -s -m "Regenerate dependabot.yml from config + + This automated PR regenerates .github/dependabot.yml from + .github/dependabot.config.yml to ensure the configuration + is up-to-date with the latest release branches. + + Generated by: ${WORKFLOW_NAME} + Triggered by: ${EVENT_NAME}" + + # Push branch (configure credentials only for this step) + git remote set-url origin "https://x-access-token:${GH_TOKEN}@github.com/${REPOSITORY}.git" + git push origin "$BRANCH" + + # Create PR + gh pr create \ + --title "Regenerate dependabot.yml configuration" \ + --body "## Automated Dependabot Configuration Update + + This PR regenerates \`.github/dependabot.yml\` from \`.github/dependabot.config.yml\`. + + ### Changes + The dependabot configuration has been regenerated to ensure it's in sync with: + - Release branches listed in \`.github/dependabot.config.yml\` + - Ecosystem configurations + + ### Review Checklist + - [ ] Verify that all active LTS release branches are included + - [ ] Check that main branch configurations look correct + - [ ] Ensure patch-only restrictions are applied to release branches + + --- + šŸ¤– This PR was automatically created by the \`${WORKFLOW_NAME}\` workflow. + **Triggered by**: ${EVENT_NAME} + **Run**: ${SERVER_URL}/${REPOSITORY}/actions/runs/${RUN_ID}" \ + --base main \ + --head "$BRANCH" \ + --label "dependencies" \ + --label "kind/misc" \ + --label "release-note-none" + + - name: Summary + env: + CHANGED: ${{ steps.check-changes.outputs.changed }} + run: | + if [ "${CHANGED}" = "true" ]; then + echo "āœ… Pull request created with updated dependabot.yml" + else + echo "āœ… No changes needed - dependabot.yml is up-to-date" + fi diff --git a/hack/generate-dependabot.go b/hack/generate-dependabot.go new file mode 100644 index 00000000..d0298a34 --- /dev/null +++ b/hack/generate-dependabot.go @@ -0,0 +1,186 @@ +// Copyright 2026 The Tekton Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//go:build ignore + +package main + +import ( + "bytes" + "fmt" + "os" + "path/filepath" + + "go.yaml.in/yaml/v3" +) + +// Config represents the dependabot configuration file structure +type Config struct { + ReleaseBranches []string `yaml:"release-branches"` + Ecosystems []Ecosystem `yaml:"ecosystems"` +} + +// Cooldown defines minimum age requirements before Dependabot opens a PR, +// reducing supply-chain risk by giving security vendors time to flag compromises. +type Cooldown struct { + DefaultDays int `yaml:"default-days,omitempty"` + SemverMajorDays int `yaml:"semver-major-days,omitempty"` + SemverMinorDays int `yaml:"semver-minor-days,omitempty"` + SemverPatchDays int `yaml:"semver-patch-days,omitempty"` +} + +// Ecosystem represents a package ecosystem configuration +type Ecosystem struct { + PackageEcosystem string `yaml:"package-ecosystem"` + Directory string `yaml:"directory"` + Schedule map[string]interface{} `yaml:"schedule"` + Labels []string `yaml:"labels"` + Ignore []map[string]interface{} `yaml:"ignore,omitempty"` + Groups map[string]interface{} `yaml:"groups,omitempty"` + Cooldown *Cooldown `yaml:"cooldown,omitempty"` +} + +// DependabotConfig represents the generated dependabot.yml structure +type DependabotConfig struct { + Version int `yaml:"version"` + Updates []Update `yaml:"updates"` +} + +// Update represents a single dependabot update configuration +type Update struct { + PackageEcosystem string `yaml:"package-ecosystem"` + Directory string `yaml:"directory"` + TargetBranch string `yaml:"target-branch,omitempty"` + Schedule map[string]interface{} `yaml:"schedule"` + Labels []string `yaml:"labels"` + Ignore []map[string]interface{} `yaml:"ignore,omitempty"` + Groups map[string]interface{} `yaml:"groups,omitempty"` + Cooldown *Cooldown `yaml:"cooldown,omitempty"` +} + +func main() { + if err := run(); err != nil { + fmt.Fprintf(os.Stderr, "Error: %v\n", err) + os.Exit(1) + } +} + +func run() error { + configPath := filepath.Join(".github", "dependabot.config.yml") + outputPath := filepath.Join(".github", "dependabot.yml") + + configData, err := os.ReadFile(configPath) + if err != nil { + return fmt.Errorf("failed to read config file: %w", err) + } + + var config Config + if err := yaml.Unmarshal(configData, &config); err != nil { + return fmt.Errorf("failed to parse config file: %w", err) + } + + fmt.Printf("Loading configuration from %s\n", configPath) + fmt.Printf(" - Found %d ecosystem(s)\n", len(config.Ecosystems)) + fmt.Printf(" - Found %d release branch(es)", len(config.ReleaseBranches)) + if len(config.ReleaseBranches) > 0 { + fmt.Printf(": %v", config.ReleaseBranches) + } + fmt.Println() + + // Generate dependabot config + dependabotConfig := generateDependabotConfig(config) + + // Write output with header + header := `# Generated file - DO NOT EDIT MANUALLY +# This file is generated by hack/generate-dependabot.sh +# +# To update this file: +# 1. Edit .github/dependabot.config.yml +# 2. Run: ./hack/generate-dependabot.sh +# +` + + var buf bytes.Buffer + enc := yaml.NewEncoder(&buf) + enc.SetIndent(2) + if err := enc.Encode(&dependabotConfig); err != nil { + return fmt.Errorf("failed to marshal output: %w", err) + } + enc.Close() + + fullOutput := header + buf.String() + if err := os.WriteFile(outputPath, []byte(fullOutput), 0644); err != nil { + return fmt.Errorf("failed to write output file: %w", err) + } + + fmt.Printf("\nāœ“ Generated %s\n", outputPath) + fmt.Printf(" - Main branch: %d ecosystems\n", len(config.Ecosystems)) + fmt.Printf(" - Release branches: %d branches\n", len(config.ReleaseBranches)) + fmt.Printf(" - Total update entries: %d\n", len(dependabotConfig.Updates)) + + return nil +} + +func generateDependabotConfig(config Config) DependabotConfig { + dependabotConfig := DependabotConfig{ + Version: 2, + Updates: []Update{}, + } + + // Add entries for main branch (no target-branch, uses existing ignore rules) + for _, ecosystem := range config.Ecosystems { + update := Update{ + PackageEcosystem: ecosystem.PackageEcosystem, + Directory: ecosystem.Directory, + Schedule: ecosystem.Schedule, + Labels: ecosystem.Labels, + Ignore: ecosystem.Ignore, + Groups: ecosystem.Groups, + Cooldown: ecosystem.Cooldown, + } + dependabotConfig.Updates = append(dependabotConfig.Updates, update) + } + + // Add entries for each release branch (with target-branch and patch-only) + for _, branch := range config.ReleaseBranches { + for _, ecosystem := range config.Ecosystems { + // Copy ignore rules from template + ignore := make([]map[string]interface{}, len(ecosystem.Ignore)) + copy(ignore, ecosystem.Ignore) + + // Add patch-only restriction for release branches + ignore = append(ignore, map[string]interface{}{ + "dependency-name": "*", + "update-types": []string{ + "version-update:semver-major", + "version-update:semver-minor", + }, + }) + + update := Update{ + PackageEcosystem: ecosystem.PackageEcosystem, + Directory: ecosystem.Directory, + TargetBranch: branch, + Schedule: ecosystem.Schedule, + Labels: ecosystem.Labels, + Ignore: ignore, + Groups: ecosystem.Groups, + Cooldown: ecosystem.Cooldown, + } + dependabotConfig.Updates = append(dependabotConfig.Updates, update) + } + } + + return dependabotConfig +} diff --git a/hack/generate-dependabot.sh b/hack/generate-dependabot.sh new file mode 100755 index 00000000..765e5337 --- /dev/null +++ b/hack/generate-dependabot.sh @@ -0,0 +1,40 @@ +#!/usr/bin/env bash + +# Copyright 2026 The Tekton Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Generate .github/dependabot.yml from .github/dependabot.config.yml + +set -o errexit +set -o nounset +set -o pipefail + +REPO_ROOT=$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd) +cd "${REPO_ROOT}" + +echo "Generating release branch list from releases.md active releases..." +yq -i '.release-branches = []' .github/dependabot.config.yml +awk '/^## Release$/{found=1; next} found && /^## /{exit} found && /^### v[0-9]+\.[0-9]+ \(LTS\)/{sub(/^### /, "release-"); sub(/ \(LTS\)\s*$/, ".x"); print}' releases.md | +while IFS= read -r branch; do + yq -i ".\"release-branches\" += [\"${branch}\"]" .github/dependabot.config.yml +done + +echo "Generating .github/dependabot.yml..." + +# Run the generator using go run +go run ./hack/generate-dependabot.go + +echo "" +echo "Done! Review the changes and commit if they look correct:" +echo " git diff .github/dependabot.yml" diff --git a/releases.md b/releases.md index 11ba7ca9..20a7d207 100644 --- a/releases.md +++ b/releases.md @@ -34,9 +34,18 @@ Further documentation available: - Standard for [release notes](https://github.com/tektoncd/community/blob/main/standards.md#release-notes) -## Releases +## Release -### v0.3 +### v0.4 (LTS) + +- **Latest Release**: [v0.4.0](https://github.com/tektoncd/pruner/releases/tag/v0.4.0) + (2026-04-15) + ([docs](https://github.com/tektoncd/pruner/tree/v0.4.0/docs), + [tutorials](https://github.com/tektoncd/pruner/tree/v0.4.0/docs/tutorials/README.md)) +- **Initial Release**: [v0.4.0](https://github.com/tektoncd/pruner/releases/tag/v0.4.0) + (2026-04-15) + +### v0.3 (LTS) - **Latest Release**: [v0.3.5](https://github.com/tektoncd/pruner/releases/tag/v0.3.5) (2025-12-23)