diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000000..0792b6fd6f --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,92 @@ +# Dependabot configuration for automated dependency updates +# This helps keep dependencies secure and up-to-date +version: 2 +updates: + # Enable version updates for Go modules + - package-ecosystem: "gomod" + directory: "/" + schedule: + interval: "weekly" + day: "monday" + time: "09:00" + open-pull-requests-limit: 5 + labels: + - "dependencies" + - "go" + commit-message: + prefix: "chore(deps)" + groups: + go-dependencies: + patterns: + - "*" + update-types: + - "minor" + - "patch" + + # Enable version updates for npm (web directory) + - package-ecosystem: "npm" + directory: "/web" + schedule: + interval: "weekly" + day: "monday" + time: "09:00" + open-pull-requests-limit: 5 + labels: + - "dependencies" + - "javascript" + commit-message: + prefix: "chore(deps)" + groups: + npm-dependencies: + patterns: + - "*" + update-types: + - "minor" + - "patch" + + # Enable version updates for npm (docs directory) + - package-ecosystem: "npm" + directory: "/docs" + schedule: + interval: "weekly" + day: "monday" + time: "09:00" + open-pull-requests-limit: 5 + labels: + - "dependencies" + - "javascript" + - "documentation" + commit-message: + prefix: "chore(deps)" + + # Enable version updates for GitHub Actions + - package-ecosystem: "github-actions" + directory: "/" + schedule: + interval: "weekly" + day: "monday" + time: "09:00" + open-pull-requests-limit: 5 + labels: + - "dependencies" + - "github-actions" + commit-message: + prefix: "chore(deps)" + groups: + github-actions: + patterns: + - "*" + + # Enable version updates for Docker + - package-ecosystem: "docker" + directory: "/" + schedule: + interval: "weekly" + day: "monday" + time: "09:00" + open-pull-requests-limit: 3 + labels: + - "dependencies" + - "docker" + commit-message: + prefix: "chore(deps)" diff --git a/.github/release-drafter.yml b/.github/release-drafter.yml new file mode 100644 index 0000000000..240752f771 --- /dev/null +++ b/.github/release-drafter.yml @@ -0,0 +1,81 @@ +name-template: 'v$RESOLVED_VERSION' +tag-template: 'v$RESOLVED_VERSION' + +categories: + - title: '๐Ÿš€ Features' + labels: + - 'kind/feature' + - 'enhancement' + - 'kind/enhancement' + - title: '๐Ÿ› Bug Fixes' + labels: + - 'kind/bug' + - 'bug' + - 'fix' + - title: '๐Ÿ“š Documentation' + labels: + - 'documentation' + - 'docs' + - title: '๐Ÿ”’ Security' + labels: + - 'security' + - title: 'โšก Performance' + labels: + - 'performance' + - title: '๐Ÿงน Maintenance' + labels: + - 'chore' + - 'dependencies' + - 'refactor' + +change-template: '- $TITLE @$AUTHOR (#$NUMBER)' +change-title-escapes: '\<*_&' + +version-resolver: + major: + labels: + - 'major' + - 'breaking' + minor: + labels: + - 'minor' + - 'kind/feature' + patch: + labels: + - 'patch' + - 'kind/bug' + default: patch + +exclude-labels: + - 'skip-changelog' + - 'not-auto-close' + +autolabeler: + - label: 'documentation' + files: + - '*.md' + - 'docs/**/*' + - label: 'kind/bug' + branch: + - '/fix\/.+/' + title: + - '/fix/i' + - label: 'kind/feature' + branch: + - '/feat(ure)?\/.+/' + title: + - '/feat(ure)?/i' + - label: 'dependencies' + files: + - 'go.mod' + - 'go.sum' + - 'package.json' + - 'package-lock.json' + - 'yarn.lock' + +template: | + ## What's Changed + + $CHANGES + + **Full Changelog**: https://github.com/$OWNER/$REPOSITORY/compare/$PREVIOUS_TAG...v$RESOLVED_VERSION diff --git a/.github/workflows/auto-assign-reviewers.yaml b/.github/workflows/auto-assign-reviewers.yaml new file mode 100644 index 0000000000..09cd54e9df --- /dev/null +++ b/.github/workflows/auto-assign-reviewers.yaml @@ -0,0 +1,89 @@ +name: auto-assign-reviewers + +on: + pull_request: + types: [opened, ready_for_review] + branches: + - master + - 'release-v*' + +permissions: + contents: read + pull-requests: write + +jobs: + assign-reviewers: + runs-on: ubuntu-24.04 + if: github.event.pull_request.draft == false + steps: + - name: Checkout repository + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + + - name: Auto-assign reviewers based on changed files + uses: actions/github-script@v7 + with: + script: | + const { owner, repo } = context.repo; + const prNumber = context.payload.pull_request.number; + + // Get changed files + const { data: files } = await github.rest.pulls.listFiles({ + owner, + repo, + pull_number: prNumber + }); + + const reviewers = new Set(); + const teamReviewers = new Set(); + + // Analyze changed files and assign appropriate reviewers + const hasGoChanges = files.some(f => f.filename.endsWith('.go')); + const hasWebChanges = files.some(f => f.filename.startsWith('web/')); + const hasWorkflowChanges = files.some(f => f.filename.startsWith('.github/workflows/')); + const hasDocChanges = files.some(f => f.filename.endsWith('.md')); + const hasManifestChanges = files.some(f => f.filename.startsWith('manifests/')); + + // Add team reviewers based on changes + if (hasWebChanges) { + teamReviewers.add('pipecd-approvers-web'); + } + + // Always add general approvers for significant changes + if (hasGoChanges || hasWorkflowChanges || hasManifestChanges) { + teamReviewers.add('pipecd-approvers'); + } + + // Assign reviewers if any were identified + if (teamReviewers.size > 0) { + try { + await github.rest.pulls.requestReviewers({ + owner, + repo, + pull_number: prNumber, + team_reviewers: Array.from(teamReviewers) + }); + + console.log(`Assigned team reviewers: ${Array.from(teamReviewers).join(', ')}`); + } catch (error) { + console.log('Could not assign team reviewers:', error.message); + } + } + + // Add helpful labels + const labels = []; + if (hasGoChanges) labels.push('area/go'); + if (hasWebChanges) labels.push('area/web'); + if (hasWorkflowChanges) labels.push('area/build'); + if (hasDocChanges) labels.push('kind/documentation'); + if (hasManifestChanges) labels.push('area/manifests'); + + if (labels.length > 0) { + await github.rest.issues.addLabels({ + owner, + repo, + issue_number: prNumber, + labels + }); + + console.log(`Added labels: ${labels.join(', ')}`); + } diff --git a/.github/workflows/auto-merge-dependabot.yaml b/.github/workflows/auto-merge-dependabot.yaml new file mode 100644 index 0000000000..eb7cc0fff0 --- /dev/null +++ b/.github/workflows/auto-merge-dependabot.yaml @@ -0,0 +1,64 @@ +name: auto-merge-dependabot + +on: + pull_request: + types: [opened, synchronize, reopened] + +permissions: + contents: write + pull-requests: write + +jobs: + auto-merge-dependabot: + runs-on: ubuntu-24.04 + if: github.actor == 'dependabot[bot]' + steps: + - name: Fetch Dependabot metadata + id: metadata + uses: dependabot/fetch-metadata@v2 + with: + github-token: "${{ secrets.GITHUB_TOKEN }}" + + - name: Auto-approve minor and patch updates + if: steps.metadata.outputs.update-type == 'version-update:semver-patch' || steps.metadata.outputs.update-type == 'version-update:semver-minor' + run: | + gh pr review --approve "${{ github.event.pull_request.html_url }}" + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + - name: Enable auto-merge for safe updates + if: steps.metadata.outputs.update-type == 'version-update:semver-patch' || steps.metadata.outputs.update-type == 'version-update:semver-minor' + run: | + gh pr merge --auto --squash "${{ github.event.pull_request.html_url }}" + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + - name: Comment on major updates + if: steps.metadata.outputs.update-type == 'version-update:semver-major' + uses: actions/github-script@v7 + with: + script: | + const { owner, repo } = context.repo; + const prNumber = context.payload.pull_request.number; + + const comment = `## โš ๏ธ Major Version Update Detected + +This Dependabot PR contains a **major version update** for: +- **${context.payload.pull_request.title}** + +**Action required:** +- Manual review needed for breaking changes +- Check changelog and migration guides +- Update code if necessary +- Run full test suite before merging + +**Update type:** \`${process.env.UPDATE_TYPE}\``; + + await github.rest.issues.createComment({ + owner, + repo, + issue_number: prNumber, + body: comment + }); + env: + UPDATE_TYPE: ${{ steps.metadata.outputs.update-type }} diff --git a/.github/workflows/benchmark.yaml b/.github/workflows/benchmark.yaml new file mode 100644 index 0000000000..c8fc1df164 --- /dev/null +++ b/.github/workflows/benchmark.yaml @@ -0,0 +1,77 @@ +name: benchmark + +on: + push: + branches: + - master + pull_request: + branches: + - master + paths: + - '**.go' + - 'go.mod' + - 'go.sum' + - '.github/workflows/benchmark.yaml' + +# Only run the latest benchmark for each PR +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +env: + GO_VERSION: 1.25.0 + +jobs: + benchmark: + runs-on: ubuntu-24.04 + steps: + - name: Checkout repository + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + + - name: Set up Go + uses: actions/setup-go@v5 + with: + go-version: ${{ env.GO_VERSION }} + cache: true + + - name: Run benchmarks + run: | + # Run benchmarks and save results + go test -bench=. -benchmem -run=^$ ./... | tee benchmark_results.txt + + - name: Upload benchmark results + uses: actions/upload-artifact@v4 + with: + name: benchmark-results + path: benchmark_results.txt + retention-days: 30 + + - name: Compare benchmarks (PR only) + if: github.event_name == 'pull_request' + uses: benchmark-action/github-action-benchmark@v1 + with: + tool: 'go' + output-file-path: benchmark_results.txt + github-token: ${{ secrets.GITHUB_TOKEN }} + comment-on-alert: true + alert-threshold: '150%' + fail-on-alert: false + auto-push: false + + - name: Comment benchmark results + if: github.event_name == 'pull_request' + uses: actions/github-script@v7 + with: + script: | + const fs = require('fs'); + const results = fs.readFileSync('benchmark_results.txt', 'utf8'); + + // Extract summary (first 1000 chars) + const summary = results.substring(0, 1000); + + await github.rest.issues.createComment({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: context.issue.number, + body: `## ๐Ÿ“Š Benchmark Results\n\n\`\`\`\n${summary}\n...\n\`\`\`\n\nFull results are available in the workflow artifacts.` + }); diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index dee768c3ba..6e2af601ab 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -12,6 +12,11 @@ on: - 'release-v*' - 'feat/*' +# Cancel in-progress runs for the same workflow and ref +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + env: GO_VERSION: 1.25.0 NODE_VERSION: 18.12.0 diff --git a/.github/workflows/changelog.yaml b/.github/workflows/changelog.yaml new file mode 100644 index 0000000000..490bbf7c4f --- /dev/null +++ b/.github/workflows/changelog.yaml @@ -0,0 +1,43 @@ +name: changelog + +on: + push: + branches: + - master + workflow_dispatch: + +permissions: + contents: write + pull-requests: read + +jobs: + update-changelog: + runs-on: ubuntu-24.04 + steps: + - name: Checkout repository + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + with: + fetch-depth: 0 + + - name: Generate changelog + id: changelog + uses: orhun/git-cliff-action@v4 + with: + config: cliff.toml + args: --verbose + env: + OUTPUT: CHANGELOG.md + + - name: Commit changelog + run: | + git config user.name 'github-actions[bot]' + git config user.email 'github-actions[bot]@users.noreply.github.com' + + # Only commit if there are changes + if [[ $(git diff --stat) != '' ]]; then + git add CHANGELOG.md + git commit -m "docs: update CHANGELOG.md" + git push + else + echo "No changes to CHANGELOG.md" + fi diff --git a/.github/workflows/ci-failure-analyzer.yaml b/.github/workflows/ci-failure-analyzer.yaml new file mode 100644 index 0000000000..1b67b13fe6 --- /dev/null +++ b/.github/workflows/ci-failure-analyzer.yaml @@ -0,0 +1,164 @@ +name: ci-failure-analyzer + +on: + workflow_run: + workflows: ["build", "test", "lint"] + types: [completed] + +permissions: + actions: read + checks: read + pull-requests: write + +jobs: + analyze-failure: + runs-on: ubuntu-24.04 + if: github.event.workflow_run.conclusion == 'failure' + steps: + - name: Analyze CI failure and comment + uses: actions/github-script@v7 + with: + script: | + const { owner, repo } = context.repo; + const workflowRun = context.payload.workflow_run; + + // Get associated PRs + const prs = workflowRun.pull_requests; + if (prs.length === 0) { + console.log('No PRs associated with this workflow run'); + return; + } + + const prNumber = prs[0].number; + + // Get workflow jobs + const { data: jobs } = await github.rest.actions.listJobsForWorkflowRun({ + owner, + repo, + run_id: workflowRun.id + }); + + const failedJobs = jobs.jobs.filter(job => job.conclusion === 'failure'); + + if (failedJobs.length === 0) { + return; + } + + // Analyze failure patterns + let failureAnalysis = `## ๐Ÿ”ด CI Failure Analysis\n\n`; + failureAnalysis += `Workflow: **${workflowRun.name}**\n`; + failureAnalysis += `Failed jobs: **${failedJobs.length}**\n\n`; + + const failurePatterns = { + test: [], + lint: [], + build: [], + timeout: [], + dependency: [], + other: [] + }; + + for (const job of failedJobs) { + const jobName = job.name.toLowerCase(); + const steps = job.steps.filter(s => s.conclusion === 'failure'); + + failureAnalysis += `### โŒ ${job.name}\n`; + + for (const step of steps) { + const stepName = step.name.toLowerCase(); + + // Categorize failures + if (stepName.includes('test')) { + failurePatterns.test.push({ job: job.name, step: step.name }); + } else if (stepName.includes('lint') || stepName.includes('format')) { + failurePatterns.lint.push({ job: job.name, step: step.name }); + } else if (stepName.includes('build') || stepName.includes('compile')) { + failurePatterns.build.push({ job: job.name, step: step.name }); + } else if (stepName.includes('timeout')) { + failurePatterns.timeout.push({ job: job.name, step: step.name }); + } else if (stepName.includes('dependencies') || stepName.includes('install')) { + failurePatterns.dependency.push({ job: job.name, step: step.name }); + } else { + failurePatterns.other.push({ job: job.name, step: step.name }); + } + + failureAnalysis += `- Step: \`${step.name}\`\n`; + } + + failureAnalysis += `- [View logs](${job.html_url})\n\n`; + } + + // Add helpful suggestions + failureAnalysis += `## ๐Ÿ’ก Suggested Actions\n\n`; + + if (failurePatterns.test.length > 0) { + failureAnalysis += `**Test Failures (${failurePatterns.test.length}):**\n`; + failureAnalysis += `- Review test output in the logs\n`; + failureAnalysis += `- Run tests locally: \`make test\`\n`; + failureAnalysis += `- Check for flaky tests\n\n`; + } + + if (failurePatterns.lint.length > 0) { + failureAnalysis += `**Linting Issues (${failurePatterns.lint.length}):**\n`; + failureAnalysis += `- Run linter locally: \`make lint\`\n`; + failureAnalysis += `- Auto-fix where possible: \`make fmt\`\n`; + failureAnalysis += `- Review [coding standards](https://github.com/pipe-cd/pipecd/blob/master/CONTRIBUTING.md)\n\n`; + } + + if (failurePatterns.build.length > 0) { + failureAnalysis += `**Build Failures (${failurePatterns.build.length}):**\n`; + failureAnalysis += `- Build locally: \`make build\`\n`; + failureAnalysis += `- Check for compilation errors\n`; + failureAnalysis += `- Verify all dependencies are available\n\n`; + } + + if (failurePatterns.dependency.length > 0) { + failureAnalysis += `**Dependency Issues (${failurePatterns.dependency.length}):**\n`; + failureAnalysis += `- Update dependencies: \`make update/go-deps\` or \`make update/web-deps\`\n`; + failureAnalysis += `- Clear caches and retry\n\n`; + } + + if (failurePatterns.timeout.length > 0) { + failureAnalysis += `**Timeout Issues (${failurePatterns.timeout.length}):**\n`; + failureAnalysis += `- Check for infinite loops or hanging processes\n`; + failureAnalysis += `- Review test performance\n\n`; + } + + failureAnalysis += `---\n`; + failureAnalysis += `**Quick actions:**\n`; + failureAnalysis += `- ๐Ÿ”„ Re-run failed workflows\n`; + failureAnalysis += `- ๐Ÿ“– Check [CI troubleshooting guide](https://github.com/pipe-cd/pipecd/blob/master/CONTRIBUTING.md#development)\n`; + failureAnalysis += `- ๐Ÿ’ฌ Ask in [Slack](https://cloud-native.slack.com/archives/C01B27F9T0X) if you need help\n`; + + // Check if we already commented + const { data: comments } = await github.rest.issues.listComments({ + owner, + repo, + issue_number: prNumber + }); + + const existingComment = comments.find(c => + c.user.type === 'Bot' && + c.body.includes('CI Failure Analysis') && + c.body.includes(workflowRun.id.toString()) + ); + + if (existingComment) { + // Update existing comment + await github.rest.issues.updateComment({ + owner, + repo, + comment_id: existingComment.id, + body: failureAnalysis + `\n\nWorkflow run: ${workflowRun.id}` + }); + } else { + // Create new comment + await github.rest.issues.createComment({ + owner, + repo, + issue_number: prNumber, + body: failureAnalysis + `\n\nWorkflow run: ${workflowRun.id}` + }); + } + + console.log(`Posted failure analysis for PR #${prNumber}`); diff --git a/.github/workflows/dependency-review.yaml b/.github/workflows/dependency-review.yaml new file mode 100644 index 0000000000..36a8ef703d --- /dev/null +++ b/.github/workflows/dependency-review.yaml @@ -0,0 +1,28 @@ +name: dependency-review + +on: + pull_request: + branches: + - master + - 'release-v*' + +permissions: + contents: read + pull-requests: write + +jobs: + dependency-review: + runs-on: ubuntu-24.04 + steps: + - name: Checkout repository + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + + - name: Dependency Review + uses: actions/dependency-review-action@v4 + with: + # Fail the build if there are any vulnerabilities + fail-on-severity: moderate + # Comment on the PR with the dependency review results + comment-summary-in-pr: always + # Allow licenses + allow-licenses: Apache-2.0, MIT, BSD-2-Clause, BSD-3-Clause, ISC diff --git a/.github/workflows/issue-triage-automation.yaml b/.github/workflows/issue-triage-automation.yaml new file mode 100644 index 0000000000..abd98e077e --- /dev/null +++ b/.github/workflows/issue-triage-automation.yaml @@ -0,0 +1,142 @@ +name: issue-triage-automation + +on: + issues: + types: [opened, labeled] + issue_comment: + types: [created] + +permissions: + issues: write + pull-requests: write + +jobs: + triage-new-issue: + runs-on: ubuntu-24.04 + if: github.event_name == 'issues' && github.event.action == 'opened' + steps: + - name: Auto-label and triage new issues + uses: actions/github-script@v7 + with: + script: | + const { owner, repo } = context.repo; + const issue = context.payload.issue; + const issueNumber = issue.number; + const title = issue.title.toLowerCase(); + const body = issue.body?.toLowerCase() || ''; + + const labels = []; + + // Auto-detect issue type from title/body + if (title.includes('bug') || body.includes('bug')) { + labels.push('kind/bug'); + } + if (title.includes('feature') || title.includes('enhancement') || body.includes('feature request')) { + labels.push('kind/feature'); + } + if (title.includes('question') || title.includes('help') || title.includes('how to')) { + labels.push('kind/question'); + } + if (title.includes('doc') || title.includes('documentation')) { + labels.push('kind/documentation'); + } + + // Auto-detect area from keywords + if (body.includes('kubernetes') || body.includes('k8s')) { + labels.push('area/kubernetes'); + } + if (body.includes('terraform')) { + labels.push('area/terraform'); + } + if (body.includes('web') || body.includes('ui') || body.includes('frontend')) { + labels.push('area/web'); + } + if (body.includes('pipeline') || body.includes('deployment')) { + labels.push('area/deployment'); + } + if (body.includes('security') || body.includes('vulnerability') || body.includes('cve')) { + labels.push('security'); + } + + // Add triage label + labels.push('needs-triage'); + + // Add labels + if (labels.length > 0) { + await github.rest.issues.addLabels({ + owner, + repo, + issue_number: issueNumber, + labels + }); + + console.log(`Auto-labeled issue #${issueNumber} with: ${labels.join(', ')}`); + } + + // Welcome message for first-time contributors + const { data: issueCreator } = await github.rest.issues.listForRepo({ + owner, + repo, + creator: issue.user.login, + state: 'all' + }); + + if (issueCreator.length === 1) { + const welcomeComment = `๐Ÿ‘‹ Welcome to PipeCD, @${issue.user.login}! + +Thank you for opening your first issue. A maintainer will review this soon. + +**While you wait:** +- Check our [documentation](https://pipecd.dev/docs/) +- Join our [Slack community](https://cloud-native.slack.com/archives/C01B27F9T0X) +- Review our [contributing guide](https://github.com/pipe-cd/pipecd/blob/master/CONTRIBUTING.md) + +We appreciate your contribution! ๐ŸŽ‰`; + + await github.rest.issues.createComment({ + owner, + repo, + issue_number: issueNumber, + body: welcomeComment + }); + } + + check-inactive-issues: + runs-on: ubuntu-24.04 + if: github.event_name == 'issue_comment' + steps: + - name: Remove needs-info label when author responds + uses: actions/github-script@v7 + with: + script: | + const { owner, repo } = context.repo; + const issue = context.payload.issue; + const comment = context.payload.comment; + + // If issue author responds, remove needs-info label + if (comment.user.login === issue.user.login) { + const { data: labels } = await github.rest.issues.listLabelsOnIssue({ + owner, + repo, + issue_number: issue.number + }); + + if (labels.some(l => l.name === 'needs-info')) { + await github.rest.issues.removeLabel({ + owner, + repo, + issue_number: issue.number, + name: 'needs-info' + }).catch(() => {}); + + // Add needs-triage back + await github.rest.issues.addLabels({ + owner, + repo, + issue_number: issue.number, + labels: ['needs-triage'] + }); + + console.log(`Removed needs-info from issue #${issue.number} after author response`); + } + } diff --git a/.github/workflows/link-check.yaml b/.github/workflows/link-check.yaml new file mode 100644 index 0000000000..92c33c56b9 --- /dev/null +++ b/.github/workflows/link-check.yaml @@ -0,0 +1,28 @@ +name: link-check + +on: + pull_request: + branches: + - master + - 'release-v*' + paths: + - '**.md' + - 'docs/**' + schedule: + # Run weekly on Monday at 00:00 UTC + - cron: '0 0 * * 1' + workflow_dispatch: + +jobs: + markdown-link-check: + runs-on: ubuntu-24.04 + steps: + - name: Checkout repository + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + + - name: Check links in markdown files + uses: gaurav-nelson/github-action-markdown-link-check@v1 + with: + config-file: '.markdown-link-check.json' + use-quiet-mode: 'yes' + use-verbose-mode: 'no' diff --git a/.github/workflows/lint.yaml b/.github/workflows/lint.yaml index db70d646f4..6f676301e3 100644 --- a/.github/workflows/lint.yaml +++ b/.github/workflows/lint.yaml @@ -10,6 +10,11 @@ on: - "release-v*" - "feat/*" +# Cancel in-progress runs for the same workflow and ref +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + env: GO_VERSION: 1.25.0 NODE_VERSION: 18.12.0 diff --git a/.github/workflows/pr-size-labeler.yaml b/.github/workflows/pr-size-labeler.yaml new file mode 100644 index 0000000000..f4ad853ff5 --- /dev/null +++ b/.github/workflows/pr-size-labeler.yaml @@ -0,0 +1,130 @@ +name: pr-size-labeler + +on: + pull_request: + types: [opened, synchronize, reopened] + +permissions: + contents: read + pull-requests: write + +jobs: + label-pr-size: + runs-on: ubuntu-24.04 + steps: + - name: Checkout repository + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + with: + fetch-depth: 0 + + - name: Label PR by size and complexity + uses: actions/github-script@v7 + with: + script: | + const { owner, repo } = context.repo; + const prNumber = context.payload.pull_request.number; + + // Get PR files + const { data: files } = await github.rest.pulls.listFiles({ + owner, + repo, + pull_number: prNumber, + per_page: 100 + }); + + // Calculate total changes + let additions = 0; + let deletions = 0; + let filesChanged = files.length; + + files.forEach(file => { + additions += file.additions; + deletions += file.deletions; + }); + + const totalChanges = additions + deletions; + + // Remove old size labels + const { data: currentLabels } = await github.rest.issues.listLabelsOnIssue({ + owner, + repo, + issue_number: prNumber + }); + + const sizeLabels = ['size/XS', 'size/S', 'size/M', 'size/L', 'size/XL', 'size/XXL']; + const labelsToRemove = currentLabels + .filter(label => sizeLabels.includes(label.name)) + .map(label => label.name); + + for (const label of labelsToRemove) { + await github.rest.issues.removeLabel({ + owner, + repo, + issue_number: prNumber, + name: label + }).catch(() => {}); + } + + // Determine size label + let sizeLabel; + if (totalChanges < 10) { + sizeLabel = 'size/XS'; + } else if (totalChanges < 50) { + sizeLabel = 'size/S'; + } else if (totalChanges < 200) { + sizeLabel = 'size/M'; + } else if (totalChanges < 500) { + sizeLabel = 'size/L'; + } else if (totalChanges < 1000) { + sizeLabel = 'size/XL'; + } else { + sizeLabel = 'size/XXL'; + } + + // Add new size label + await github.rest.issues.addLabels({ + owner, + repo, + issue_number: prNumber, + labels: [sizeLabel] + }); + + // Add comment for large PRs + if (totalChanges > 500) { + const comment = `## โš ๏ธ Large PR Detected + +This PR has **${totalChanges}** total changes across **${filesChanged}** files. + +**Recommendations for large PRs:** +- Consider breaking this into smaller, focused PRs +- Ensure comprehensive testing +- Add detailed description of changes +- Request review from multiple maintainers + +**Current changes:** +- โž• ${additions} additions +- โž– ${deletions} deletions +- ๐Ÿ“ ${filesChanged} files changed`; + + // Check if we already commented + const { data: comments } = await github.rest.issues.listComments({ + owner, + repo, + issue_number: prNumber + }); + + const hasComment = comments.some(c => + c.user.type === 'Bot' && c.body.includes('Large PR Detected') + ); + + if (!hasComment) { + await github.rest.issues.createComment({ + owner, + repo, + issue_number: prNumber, + body: comment + }); + } + } + + console.log(`Labeled PR #${prNumber} as ${sizeLabel} (${totalChanges} changes)`); diff --git a/.github/workflows/release-notes.yaml b/.github/workflows/release-notes.yaml new file mode 100644 index 0000000000..95571038d8 --- /dev/null +++ b/.github/workflows/release-notes.yaml @@ -0,0 +1,65 @@ +name: release-notes + +on: + release: + types: [published] + +permissions: + contents: write + +jobs: + generate-release-notes: + runs-on: ubuntu-24.04 + steps: + - name: Checkout repository + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + with: + fetch-depth: 0 + + - name: Generate Release Notes + id: generate_notes + uses: release-drafter/release-drafter@v6 + with: + config-name: release-drafter.yml + publish: true + tag: ${{ github.event.release.tag_name }} + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + - name: Update Release + uses: actions/github-script@v7 + with: + script: | + const { data: release } = await github.rest.repos.getRelease({ + owner: context.repo.owner, + repo: context.repo.repo, + release_id: context.payload.release.id + }); + + const body = `${{ steps.generate_notes.outputs.body }} + + ## Installation + + ### Helm Chart + \`\`\`bash + helm repo add pipecd https://charts.pipecd.dev + helm repo update + helm install pipecd pipecd/pipecd --version ${{ github.event.release.tag_name }} + \`\`\` + + ### Binary Downloads + - [Linux AMD64](https://github.com/pipe-cd/pipecd/releases/download/${{ github.event.release.tag_name }}/pipecd_linux_amd64.tar.gz) + - [Linux ARM64](https://github.com/pipe-cd/pipecd/releases/download/${{ github.event.release.tag_name }}/pipecd_linux_arm64.tar.gz) + - [macOS AMD64](https://github.com/pipe-cd/pipecd/releases/download/${{ github.event.release.tag_name }}/pipecd_darwin_amd64.tar.gz) + - [macOS ARM64](https://github.com/pipe-cd/pipecd/releases/download/${{ github.event.release.tag_name }}/pipecd_darwin_arm64.tar.gz) + + ## What's Changed + ${release.body || ''} + `; + + await github.rest.repos.updateRelease({ + owner: context.repo.owner, + repo: context.repo.repo, + release_id: context.payload.release.id, + body: body + }); diff --git a/.github/workflows/security-scan.yaml b/.github/workflows/security-scan.yaml new file mode 100644 index 0000000000..2966678dc4 --- /dev/null +++ b/.github/workflows/security-scan.yaml @@ -0,0 +1,144 @@ +name: security-scan + +on: + pull_request: + branches: + - master + - 'release-v*' + push: + branches: + - master + schedule: + # Run weekly on Monday at 00:00 UTC + - cron: '0 0 * * 1' + workflow_dispatch: + +permissions: + contents: read + security-events: write + pull-requests: write + +jobs: + trivy-scan: + runs-on: ubuntu-24.04 + steps: + - name: Checkout repository + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + + - name: Run Trivy vulnerability scanner in repo mode + uses: aquasecurity/trivy-action@0.28.0 + with: + scan-type: 'fs' + scan-ref: '.' + format: 'sarif' + output: 'trivy-results.sarif' + severity: 'CRITICAL,HIGH' + + - name: Upload Trivy results to GitHub Security + uses: github/codeql-action/upload-sarif@v3 + with: + sarif_file: 'trivy-results.sarif' + + docker-scan: + runs-on: ubuntu-24.04 + strategy: + matrix: + dockerfile: + - path: 'cmd/pipecd/Dockerfile' + context: '.' + - path: 'cmd/piped/Dockerfile' + context: '.' + - path: 'tool/piped-base/Dockerfile' + context: 'tool/piped-base' + steps: + - name: Checkout repository + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + + - name: Build Docker image + run: | + docker build -f ${{ matrix.dockerfile.path }} -t test-image:latest ${{ matrix.dockerfile.context }} + + - name: Run Trivy vulnerability scanner on Docker image + uses: aquasecurity/trivy-action@0.28.0 + with: + image-ref: 'test-image:latest' + format: 'sarif' + output: 'trivy-docker-results.sarif' + severity: 'CRITICAL,HIGH' + + - name: Upload Docker scan results + uses: github/codeql-action/upload-sarif@v3 + with: + sarif_file: 'trivy-docker-results.sarif' + category: ${{ matrix.dockerfile.path }} + + gosec-scan: + runs-on: ubuntu-24.04 + steps: + - name: Checkout repository + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + + - name: Run Gosec Security Scanner + uses: securego/gosec@v2.21.4 + with: + args: '-fmt sarif -out gosec-results.sarif ./...' + + - name: Upload Gosec results + uses: github/codeql-action/upload-sarif@v3 + with: + sarif_file: 'gosec-results.sarif' + + npm-audit: + runs-on: ubuntu-24.04 + steps: + - name: Checkout repository + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: '18' + + - name: Run npm audit + working-directory: ./web + run: | + npm audit --audit-level=high --json > npm-audit.json || true + + - name: Upload npm audit results + if: always() + uses: actions/upload-artifact@v4 + with: + name: npm-audit-results + path: web/npm-audit.json + retention-days: 30 + + security-summary: + runs-on: ubuntu-24.04 + needs: [trivy-scan, gosec-scan, npm-audit] + if: always() && github.event_name == 'pull_request' + steps: + - name: Post security scan summary + uses: actions/github-script@v7 + with: + script: | + const { owner, repo } = context.repo; + const prNumber = context.payload.pull_request.number; + + const summary = `## ๐Ÿ”’ Security Scan Results + + Security scans have been completed for this PR: + - โœ… Trivy vulnerability scan (filesystem) + - โœ… Gosec security scan (Go code) + - โœ… npm audit (web dependencies) + - โœ… Docker image scanning + + Check the [Security tab](https://github.com/${owner}/${repo}/security) for detailed results. + + Critical and high severity issues are automatically flagged.`; + + await github.rest.issues.createComment({ + owner, + repo, + issue_number: prNumber, + body: summary + }); diff --git a/.github/workflows/spell-check.yaml b/.github/workflows/spell-check.yaml new file mode 100644 index 0000000000..9014b84710 --- /dev/null +++ b/.github/workflows/spell-check.yaml @@ -0,0 +1,23 @@ +name: spell-check + +on: + pull_request: + branches: + - master + - 'release-v*' + paths: + - '**.md' + - 'docs/**' + - '.github/workflows/spell-check.yaml' + +jobs: + spell-check: + runs-on: ubuntu-24.04 + steps: + - name: Checkout repository + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + + - name: Check spelling + uses: crate-ci/typos@v1.24.6 + with: + config: .typos.toml diff --git a/.github/workflows/stale-pr-reminder.yaml b/.github/workflows/stale-pr-reminder.yaml new file mode 100644 index 0000000000..6448b2c0c2 --- /dev/null +++ b/.github/workflows/stale-pr-reminder.yaml @@ -0,0 +1,132 @@ +name: stale-pr-reminder + +on: + schedule: + # Run daily at 00:00 UTC + - cron: '0 0 * * *' + workflow_dispatch: + +permissions: + pull-requests: write + issues: write + +jobs: + stale-pr-reminder: + runs-on: ubuntu-24.04 + steps: + - name: Check and comment on stale PRs + uses: actions/github-script@v7 + with: + script: | + const { owner, repo } = context.repo; + const msPerDay = 86400000; + const staleDays = 7; + const reviewRequestDays = 3; + + // Get all open PRs + const { data: prs } = await github.rest.pulls.list({ + owner, + repo, + state: 'open', + sort: 'updated', + direction: 'asc', + per_page: 100 + }); + + const now = new Date(); + + for (const pr of prs) { + const updatedAt = new Date(pr.updated_at); + const daysSinceUpdate = (now - updatedAt) / msPerDay; + + // Skip draft PRs + if (pr.draft) continue; + + // Get reviews + const { data: reviews } = await github.rest.pulls.listReviews({ + owner, + repo, + pull_number: pr.number + }); + + // Get review requests + const { data: reviewRequests } = await github.rest.pulls.listRequestedReviewers({ + owner, + repo, + pull_number: pr.number + }); + + const hasReviewRequests = reviewRequests.users.length > 0 || reviewRequests.teams.length > 0; + const hasApproval = reviews.some(r => r.state === 'APPROVED'); + const hasChangesRequested = reviews.some(r => r.state === 'CHANGES_REQUESTED'); + + // Ping reviewers if no response after 3 days + if (hasReviewRequests && daysSinceUpdate >= reviewRequestDays) { + const reviewers = [ + ...reviewRequests.users.map(u => `@${u.login}`), + ...reviewRequests.teams.map(t => `@pipe-cd/${t.slug}`) + ].join(', '); + + const comment = `## ๐Ÿ‘‹ Review Reminder + +${reviewers} - This PR has been waiting for review for ${Math.floor(daysSinceUpdate)} days. + +**PR:** #${pr.number} - ${pr.title} +**Author:** @${pr.user.login} + +Please take a moment to review when you have time. If you're no longer the right reviewer, please re-assign.`; + + await github.rest.issues.createComment({ + owner, + repo, + issue_number: pr.number, + body: comment + }); + + console.log(`Pinged reviewers for PR #${pr.number}`); + } + + // Ping author if changes were requested and no update + if (hasChangesRequested && !hasApproval && daysSinceUpdate >= staleDays) { + const comment = `## ๐Ÿ“ Friendly Reminder + +@${pr.user.login} - This PR has requested changes that haven't been addressed in ${Math.floor(daysSinceUpdate)} days. + +**Next steps:** +- Address the review comments +- Push updates to trigger new reviews +- Respond to reviewers if you need clarification + +Let us know if you need any help!`; + + await github.rest.issues.createComment({ + owner, + repo, + issue_number: pr.number, + body: comment + }); + + console.log(`Reminded author for PR #${pr.number}`); + } + + // Remind to merge if approved but not merged + if (hasApproval && !hasChangesRequested && daysSinceUpdate >= staleDays) { + const comment = `## โœ… Ready to Merge? + +This PR has been approved for ${Math.floor(daysSinceUpdate)} days. + +**Status:** Approved and ready for merge +**Author:** @${pr.user.login} + +If all CI checks pass, this can be merged! ๐Ÿš€`; + + await github.rest.issues.createComment({ + owner, + repo, + issue_number: pr.number, + body: comment + }); + + console.log(`Reminded to merge PR #${pr.number}`); + } + } diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index b91cf1612d..a8df8d4bf7 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -12,6 +12,11 @@ on: - 'release-v*' - 'feat/*' +# Cancel in-progress runs for the same workflow and ref +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + env: GO_VERSION: 1.25.0 NODE_VERSION: 18.12.0 diff --git a/.github/workflows/update-actions.yaml b/.github/workflows/update-actions.yaml new file mode 100644 index 0000000000..d7e9812364 --- /dev/null +++ b/.github/workflows/update-actions.yaml @@ -0,0 +1,52 @@ +name: update-actions + +on: + schedule: + # Run monthly on the first day at 00:00 UTC + - cron: '0 0 1 * *' + workflow_dispatch: + +permissions: + contents: write + pull-requests: write + +jobs: + update-actions: + runs-on: ubuntu-24.04 + steps: + - name: Checkout repository + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + + - name: Update GitHub Actions + id: update + run: | + # This is a placeholder for automated action updates + # In production, you would use a tool like Renovate or Dependabot + echo "Actions are managed by Dependabot" + echo "updated=false" >> $GITHUB_OUTPUT + + - name: Create Pull Request + if: steps.update.outputs.updated == 'true' + uses: peter-evans/create-pull-request@v6 + with: + token: ${{ secrets.GITHUB_TOKEN }} + commit-message: 'chore(deps): update GitHub Actions' + title: 'chore(deps): Update GitHub Actions to latest versions' + body: | + ## Description + + This PR updates GitHub Actions to their latest versions. + + ## Changes + - Updated actions to latest stable versions + - Maintained compatibility with existing workflows + + ## Testing + - [ ] All workflows pass with updated actions + - [ ] No breaking changes detected + branch: update-actions + delete-branch: true + labels: | + dependencies + github-actions + automated diff --git a/.markdown-link-check.json b/.markdown-link-check.json new file mode 100644 index 0000000000..6ab9883750 --- /dev/null +++ b/.markdown-link-check.json @@ -0,0 +1,27 @@ +{ + "ignorePatterns": [ + { + "pattern": "^http://localhost" + }, + { + "pattern": "^http://127.0.0.1" + }, + { + "pattern": "^https://pipecd.dev/docs/" + } + ], + "replacementPatterns": [], + "httpHeaders": [ + { + "urls": ["https://github.com"], + "headers": { + "Accept": "application/vnd.github.v3+json" + } + } + ], + "timeout": "20s", + "retryOn429": true, + "retryCount": 3, + "fallbackRetryDelay": "30s", + "aliveStatusCodes": [200, 206, 299, 403] +} diff --git a/.typos.toml b/.typos.toml new file mode 100644 index 0000000000..d3764633d4 --- /dev/null +++ b/.typos.toml @@ -0,0 +1,35 @@ +# Configuration for typos spell checker +# See https://github.com/crate-ci/typos + +[default] +extend-ignore-re = [ + # Ignore git SHAs + "[0-9a-f]{7,40}", + # Ignore base64 encoded strings + "[A-Za-z0-9+/]{20,}={0,2}", +] + +[files] +extend-exclude = [ + "*.sum", + "*.lock", + "package-lock.json", + "yarn.lock", + ".artifacts/", + "vendor/", + "node_modules/", + "web/build/", + "docs/public/", +] + +[default.extend-words] +# Add project-specific words that are not typos +pipecd = "pipecd" +piped = "piped" +pipectl = "pipectl" +kubectl = "kubectl" +kubernetes = "kubernetes" +kubeconfig = "kubeconfig" +gRPC = "gRPC" +GitOps = "GitOps" +CNCF = "CNCF" diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index eead6e4abd..da6a61311f 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -153,7 +153,7 @@ By contributing to PipeCD, you agree that your contributions will be licensed un ### Release Note and Breaking Changes -If your change introcudes a user-facing change, please update the following section in your PR description. +If your change introduces a user-facing change, please update the following section in your PR description. ```md **Does this PR introduce a user-facing change?**: diff --git a/cliff.toml b/cliff.toml new file mode 100644 index 0000000000..2bfaa9cffd --- /dev/null +++ b/cliff.toml @@ -0,0 +1,56 @@ +# Configuration for git-cliff +# See https://git-cliff.org/docs/configuration + +[changelog] +header = """ +# Changelog + +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +""" +body = """ +{% if version %}\ + ## [{{ version | trim_start_matches(pat="v") }}] - {{ timestamp | date(format="%Y-%m-%d") }} +{% else %}\ + ## [Unreleased] +{% endif %}\ +{% for group, commits in commits | group_by(attribute="group") %} + ### {{ group | upper_first }} + {% for commit in commits %} + - {% if commit.breaking %}[**BREAKING**] {% endif %}{{ commit.message | upper_first }} ([{{ commit.id | truncate(length=7, end="") }}]({{ commit.id }}))\ + {% endfor %} +{% endfor %}\n +""" +footer = """ + +""" +trim = true + +[git] +conventional_commits = true +filter_unconventional = true +split_commits = false +commit_preprocessors = [] +commit_parsers = [ + { message = "^feat", group = "Features" }, + { message = "^fix", group = "Bug Fixes" }, + { message = "^doc", group = "Documentation" }, + { message = "^perf", group = "Performance" }, + { message = "^refactor", group = "Refactoring" }, + { message = "^style", group = "Styling" }, + { message = "^test", group = "Testing" }, + { message = "^chore\\(release\\): prepare for", skip = true }, + { message = "^chore\\(deps\\)", group = "Dependencies" }, + { message = "^chore", group = "Miscellaneous Tasks" }, + { body = ".*security", group = "Security" }, +] +protect_breaking_commits = false +filter_commits = false +tag_pattern = "v[0-9]+\\.[0-9]+\\.[0-9]+" +skip_tags = "v0.1.0-beta.1" +ignore_tags = "" +topo_order = false +sort_commits = "oldest" diff --git a/docs/content/en/docs-dev/user-guide/managing-application/customizing-deployment/custom-sync.md b/docs/content/en/docs-dev/user-guide/managing-application/customizing-deployment/custom-sync.md index 47d7d7a534..c077b3753b 100644 --- a/docs/content/en/docs-dev/user-guide/managing-application/customizing-deployment/custom-sync.md +++ b/docs/content/en/docs-dev/user-guide/managing-application/customizing-deployment/custom-sync.md @@ -43,7 +43,7 @@ spec: Note: 1. You can use `CUSTOM_SYNC` with any current supporting application kind, but keep `alwaysUsePipeline` true to not run the application kind's default `QUICK_SYNC`. 2. Only one `CUSTOM_SYNC` stage should be used in an application pipeline. -3. The commands run with the enviroment variable `PATH` that refers `~/.piped/tools` at first. +3. The commands run with the environment variable `PATH` that refers `~/.piped/tools` at first. The public piped image available in PipeCD main repo (ref: [Dockerfile](https://github.com/pipe-cd/pipecd/blob/master/cmd/piped/Dockerfile)) is based on [alpine](https://hub.docker.com/_/alpine/) and only has a few UNIX command available (ref: [piped-base Dockerfile](https://github.com/pipe-cd/pipecd/blob/master/tool/piped-base/Dockerfile)). If you want to use your commands (`sam` in the above example), you can: diff --git a/docs/content/en/docs-v0.44.x/user-guide/managing-application/customizing-deployment/custom-sync.md b/docs/content/en/docs-v0.44.x/user-guide/managing-application/customizing-deployment/custom-sync.md index a18c9d22cd..c9201453d8 100644 --- a/docs/content/en/docs-v0.44.x/user-guide/managing-application/customizing-deployment/custom-sync.md +++ b/docs/content/en/docs-v0.44.x/user-guide/managing-application/customizing-deployment/custom-sync.md @@ -43,7 +43,7 @@ spec: Note: 1. You can use `CUSTOM_SYNC` with any current supporting application kind, but keep `alwaysUsePipeline` true to not run the application kind's default `QUICK_SYNC`. 2. Only one `CUSTOM_SYNC` stage should be used in an application pipeline. -3. The commands run with the enviroment variable `PATH` that refers `~/.piped/tools` at first. +3. The commands run with the environment variable `PATH` that refers `~/.piped/tools` at first. The public piped image available in PipeCD main repo (ref: [Dockerfile](https://github.com/pipe-cd/pipecd/blob/master/cmd/piped/Dockerfile)) is based on [alpine](https://hub.docker.com/_/alpine/) and only has a few UNIX command available (ref: [piped-base Dockerfile](https://github.com/pipe-cd/pipecd/blob/master/tool/piped-base/Dockerfile)). If you want to use your commands (`sam` in the above example), you can: diff --git a/docs/content/en/docs-v0.45.x/user-guide/managing-application/customizing-deployment/custom-sync.md b/docs/content/en/docs-v0.45.x/user-guide/managing-application/customizing-deployment/custom-sync.md index a18c9d22cd..c9201453d8 100644 --- a/docs/content/en/docs-v0.45.x/user-guide/managing-application/customizing-deployment/custom-sync.md +++ b/docs/content/en/docs-v0.45.x/user-guide/managing-application/customizing-deployment/custom-sync.md @@ -43,7 +43,7 @@ spec: Note: 1. You can use `CUSTOM_SYNC` with any current supporting application kind, but keep `alwaysUsePipeline` true to not run the application kind's default `QUICK_SYNC`. 2. Only one `CUSTOM_SYNC` stage should be used in an application pipeline. -3. The commands run with the enviroment variable `PATH` that refers `~/.piped/tools` at first. +3. The commands run with the environment variable `PATH` that refers `~/.piped/tools` at first. The public piped image available in PipeCD main repo (ref: [Dockerfile](https://github.com/pipe-cd/pipecd/blob/master/cmd/piped/Dockerfile)) is based on [alpine](https://hub.docker.com/_/alpine/) and only has a few UNIX command available (ref: [piped-base Dockerfile](https://github.com/pipe-cd/pipecd/blob/master/tool/piped-base/Dockerfile)). If you want to use your commands (`sam` in the above example), you can: diff --git a/docs/content/en/docs-v0.46.x/user-guide/managing-application/customizing-deployment/custom-sync.md b/docs/content/en/docs-v0.46.x/user-guide/managing-application/customizing-deployment/custom-sync.md index 47d7d7a534..c077b3753b 100644 --- a/docs/content/en/docs-v0.46.x/user-guide/managing-application/customizing-deployment/custom-sync.md +++ b/docs/content/en/docs-v0.46.x/user-guide/managing-application/customizing-deployment/custom-sync.md @@ -43,7 +43,7 @@ spec: Note: 1. You can use `CUSTOM_SYNC` with any current supporting application kind, but keep `alwaysUsePipeline` true to not run the application kind's default `QUICK_SYNC`. 2. Only one `CUSTOM_SYNC` stage should be used in an application pipeline. -3. The commands run with the enviroment variable `PATH` that refers `~/.piped/tools` at first. +3. The commands run with the environment variable `PATH` that refers `~/.piped/tools` at first. The public piped image available in PipeCD main repo (ref: [Dockerfile](https://github.com/pipe-cd/pipecd/blob/master/cmd/piped/Dockerfile)) is based on [alpine](https://hub.docker.com/_/alpine/) and only has a few UNIX command available (ref: [piped-base Dockerfile](https://github.com/pipe-cd/pipecd/blob/master/tool/piped-base/Dockerfile)). If you want to use your commands (`sam` in the above example), you can: diff --git a/docs/content/en/docs-v0.47.x/user-guide/managing-application/customizing-deployment/custom-sync.md b/docs/content/en/docs-v0.47.x/user-guide/managing-application/customizing-deployment/custom-sync.md index 47d7d7a534..c077b3753b 100644 --- a/docs/content/en/docs-v0.47.x/user-guide/managing-application/customizing-deployment/custom-sync.md +++ b/docs/content/en/docs-v0.47.x/user-guide/managing-application/customizing-deployment/custom-sync.md @@ -43,7 +43,7 @@ spec: Note: 1. You can use `CUSTOM_SYNC` with any current supporting application kind, but keep `alwaysUsePipeline` true to not run the application kind's default `QUICK_SYNC`. 2. Only one `CUSTOM_SYNC` stage should be used in an application pipeline. -3. The commands run with the enviroment variable `PATH` that refers `~/.piped/tools` at first. +3. The commands run with the environment variable `PATH` that refers `~/.piped/tools` at first. The public piped image available in PipeCD main repo (ref: [Dockerfile](https://github.com/pipe-cd/pipecd/blob/master/cmd/piped/Dockerfile)) is based on [alpine](https://hub.docker.com/_/alpine/) and only has a few UNIX command available (ref: [piped-base Dockerfile](https://github.com/pipe-cd/pipecd/blob/master/tool/piped-base/Dockerfile)). If you want to use your commands (`sam` in the above example), you can: diff --git a/docs/content/en/docs-v0.48.x/user-guide/managing-application/customizing-deployment/custom-sync.md b/docs/content/en/docs-v0.48.x/user-guide/managing-application/customizing-deployment/custom-sync.md index 47d7d7a534..c077b3753b 100644 --- a/docs/content/en/docs-v0.48.x/user-guide/managing-application/customizing-deployment/custom-sync.md +++ b/docs/content/en/docs-v0.48.x/user-guide/managing-application/customizing-deployment/custom-sync.md @@ -43,7 +43,7 @@ spec: Note: 1. You can use `CUSTOM_SYNC` with any current supporting application kind, but keep `alwaysUsePipeline` true to not run the application kind's default `QUICK_SYNC`. 2. Only one `CUSTOM_SYNC` stage should be used in an application pipeline. -3. The commands run with the enviroment variable `PATH` that refers `~/.piped/tools` at first. +3. The commands run with the environment variable `PATH` that refers `~/.piped/tools` at first. The public piped image available in PipeCD main repo (ref: [Dockerfile](https://github.com/pipe-cd/pipecd/blob/master/cmd/piped/Dockerfile)) is based on [alpine](https://hub.docker.com/_/alpine/) and only has a few UNIX command available (ref: [piped-base Dockerfile](https://github.com/pipe-cd/pipecd/blob/master/tool/piped-base/Dockerfile)). If you want to use your commands (`sam` in the above example), you can: diff --git a/docs/content/en/docs-v0.49.x/user-guide/managing-application/customizing-deployment/custom-sync.md b/docs/content/en/docs-v0.49.x/user-guide/managing-application/customizing-deployment/custom-sync.md index 47d7d7a534..c077b3753b 100644 --- a/docs/content/en/docs-v0.49.x/user-guide/managing-application/customizing-deployment/custom-sync.md +++ b/docs/content/en/docs-v0.49.x/user-guide/managing-application/customizing-deployment/custom-sync.md @@ -43,7 +43,7 @@ spec: Note: 1. You can use `CUSTOM_SYNC` with any current supporting application kind, but keep `alwaysUsePipeline` true to not run the application kind's default `QUICK_SYNC`. 2. Only one `CUSTOM_SYNC` stage should be used in an application pipeline. -3. The commands run with the enviroment variable `PATH` that refers `~/.piped/tools` at first. +3. The commands run with the environment variable `PATH` that refers `~/.piped/tools` at first. The public piped image available in PipeCD main repo (ref: [Dockerfile](https://github.com/pipe-cd/pipecd/blob/master/cmd/piped/Dockerfile)) is based on [alpine](https://hub.docker.com/_/alpine/) and only has a few UNIX command available (ref: [piped-base Dockerfile](https://github.com/pipe-cd/pipecd/blob/master/tool/piped-base/Dockerfile)). If you want to use your commands (`sam` in the above example), you can: diff --git a/docs/content/en/docs-v0.50.x/user-guide/managing-application/customizing-deployment/custom-sync.md b/docs/content/en/docs-v0.50.x/user-guide/managing-application/customizing-deployment/custom-sync.md index 47d7d7a534..c077b3753b 100644 --- a/docs/content/en/docs-v0.50.x/user-guide/managing-application/customizing-deployment/custom-sync.md +++ b/docs/content/en/docs-v0.50.x/user-guide/managing-application/customizing-deployment/custom-sync.md @@ -43,7 +43,7 @@ spec: Note: 1. You can use `CUSTOM_SYNC` with any current supporting application kind, but keep `alwaysUsePipeline` true to not run the application kind's default `QUICK_SYNC`. 2. Only one `CUSTOM_SYNC` stage should be used in an application pipeline. -3. The commands run with the enviroment variable `PATH` that refers `~/.piped/tools` at first. +3. The commands run with the environment variable `PATH` that refers `~/.piped/tools` at first. The public piped image available in PipeCD main repo (ref: [Dockerfile](https://github.com/pipe-cd/pipecd/blob/master/cmd/piped/Dockerfile)) is based on [alpine](https://hub.docker.com/_/alpine/) and only has a few UNIX command available (ref: [piped-base Dockerfile](https://github.com/pipe-cd/pipecd/blob/master/tool/piped-base/Dockerfile)). If you want to use your commands (`sam` in the above example), you can: diff --git a/docs/content/en/docs-v0.51.x/user-guide/managing-application/customizing-deployment/custom-sync.md b/docs/content/en/docs-v0.51.x/user-guide/managing-application/customizing-deployment/custom-sync.md index 47d7d7a534..c077b3753b 100644 --- a/docs/content/en/docs-v0.51.x/user-guide/managing-application/customizing-deployment/custom-sync.md +++ b/docs/content/en/docs-v0.51.x/user-guide/managing-application/customizing-deployment/custom-sync.md @@ -43,7 +43,7 @@ spec: Note: 1. You can use `CUSTOM_SYNC` with any current supporting application kind, but keep `alwaysUsePipeline` true to not run the application kind's default `QUICK_SYNC`. 2. Only one `CUSTOM_SYNC` stage should be used in an application pipeline. -3. The commands run with the enviroment variable `PATH` that refers `~/.piped/tools` at first. +3. The commands run with the environment variable `PATH` that refers `~/.piped/tools` at first. The public piped image available in PipeCD main repo (ref: [Dockerfile](https://github.com/pipe-cd/pipecd/blob/master/cmd/piped/Dockerfile)) is based on [alpine](https://hub.docker.com/_/alpine/) and only has a few UNIX command available (ref: [piped-base Dockerfile](https://github.com/pipe-cd/pipecd/blob/master/tool/piped-base/Dockerfile)). If you want to use your commands (`sam` in the above example), you can: diff --git a/docs/content/en/docs-v0.52.x/user-guide/managing-application/customizing-deployment/custom-sync.md b/docs/content/en/docs-v0.52.x/user-guide/managing-application/customizing-deployment/custom-sync.md index 47d7d7a534..c077b3753b 100644 --- a/docs/content/en/docs-v0.52.x/user-guide/managing-application/customizing-deployment/custom-sync.md +++ b/docs/content/en/docs-v0.52.x/user-guide/managing-application/customizing-deployment/custom-sync.md @@ -43,7 +43,7 @@ spec: Note: 1. You can use `CUSTOM_SYNC` with any current supporting application kind, but keep `alwaysUsePipeline` true to not run the application kind's default `QUICK_SYNC`. 2. Only one `CUSTOM_SYNC` stage should be used in an application pipeline. -3. The commands run with the enviroment variable `PATH` that refers `~/.piped/tools` at first. +3. The commands run with the environment variable `PATH` that refers `~/.piped/tools` at first. The public piped image available in PipeCD main repo (ref: [Dockerfile](https://github.com/pipe-cd/pipecd/blob/master/cmd/piped/Dockerfile)) is based on [alpine](https://hub.docker.com/_/alpine/) and only has a few UNIX command available (ref: [piped-base Dockerfile](https://github.com/pipe-cd/pipecd/blob/master/tool/piped-base/Dockerfile)). If you want to use your commands (`sam` in the above example), you can: diff --git a/docs/content/en/docs-v0.53.x/user-guide/managing-application/customizing-deployment/custom-sync.md b/docs/content/en/docs-v0.53.x/user-guide/managing-application/customizing-deployment/custom-sync.md index 47d7d7a534..c077b3753b 100644 --- a/docs/content/en/docs-v0.53.x/user-guide/managing-application/customizing-deployment/custom-sync.md +++ b/docs/content/en/docs-v0.53.x/user-guide/managing-application/customizing-deployment/custom-sync.md @@ -43,7 +43,7 @@ spec: Note: 1. You can use `CUSTOM_SYNC` with any current supporting application kind, but keep `alwaysUsePipeline` true to not run the application kind's default `QUICK_SYNC`. 2. Only one `CUSTOM_SYNC` stage should be used in an application pipeline. -3. The commands run with the enviroment variable `PATH` that refers `~/.piped/tools` at first. +3. The commands run with the environment variable `PATH` that refers `~/.piped/tools` at first. The public piped image available in PipeCD main repo (ref: [Dockerfile](https://github.com/pipe-cd/pipecd/blob/master/cmd/piped/Dockerfile)) is based on [alpine](https://hub.docker.com/_/alpine/) and only has a few UNIX command available (ref: [piped-base Dockerfile](https://github.com/pipe-cd/pipecd/blob/master/tool/piped-base/Dockerfile)). If you want to use your commands (`sam` in the above example), you can: diff --git a/docs/content/en/docs-v0.54.x/user-guide/managing-application/customizing-deployment/custom-sync.md b/docs/content/en/docs-v0.54.x/user-guide/managing-application/customizing-deployment/custom-sync.md index 47d7d7a534..c077b3753b 100644 --- a/docs/content/en/docs-v0.54.x/user-guide/managing-application/customizing-deployment/custom-sync.md +++ b/docs/content/en/docs-v0.54.x/user-guide/managing-application/customizing-deployment/custom-sync.md @@ -43,7 +43,7 @@ spec: Note: 1. You can use `CUSTOM_SYNC` with any current supporting application kind, but keep `alwaysUsePipeline` true to not run the application kind's default `QUICK_SYNC`. 2. Only one `CUSTOM_SYNC` stage should be used in an application pipeline. -3. The commands run with the enviroment variable `PATH` that refers `~/.piped/tools` at first. +3. The commands run with the environment variable `PATH` that refers `~/.piped/tools` at first. The public piped image available in PipeCD main repo (ref: [Dockerfile](https://github.com/pipe-cd/pipecd/blob/master/cmd/piped/Dockerfile)) is based on [alpine](https://hub.docker.com/_/alpine/) and only has a few UNIX command available (ref: [piped-base Dockerfile](https://github.com/pipe-cd/pipecd/blob/master/tool/piped-base/Dockerfile)). If you want to use your commands (`sam` in the above example), you can: diff --git a/docs/content/en/docs-v0.55.x/user-guide/managing-application/customizing-deployment/custom-sync.md b/docs/content/en/docs-v0.55.x/user-guide/managing-application/customizing-deployment/custom-sync.md index 47d7d7a534..c077b3753b 100644 --- a/docs/content/en/docs-v0.55.x/user-guide/managing-application/customizing-deployment/custom-sync.md +++ b/docs/content/en/docs-v0.55.x/user-guide/managing-application/customizing-deployment/custom-sync.md @@ -43,7 +43,7 @@ spec: Note: 1. You can use `CUSTOM_SYNC` with any current supporting application kind, but keep `alwaysUsePipeline` true to not run the application kind's default `QUICK_SYNC`. 2. Only one `CUSTOM_SYNC` stage should be used in an application pipeline. -3. The commands run with the enviroment variable `PATH` that refers `~/.piped/tools` at first. +3. The commands run with the environment variable `PATH` that refers `~/.piped/tools` at first. The public piped image available in PipeCD main repo (ref: [Dockerfile](https://github.com/pipe-cd/pipecd/blob/master/cmd/piped/Dockerfile)) is based on [alpine](https://hub.docker.com/_/alpine/) and only has a few UNIX command available (ref: [piped-base Dockerfile](https://github.com/pipe-cd/pipecd/blob/master/tool/piped-base/Dockerfile)). If you want to use your commands (`sam` in the above example), you can: