diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md new file mode 100644 index 00000000..a7b73b8b --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -0,0 +1,40 @@ +--- +name: Bug Report +about: Help us diagnose and fix bugs in Crossplane +labels: bug +--- + + +### What happened? + + + +### How can we reproduce it? + + +### What environment did it happen in? +Crossplane version: + + diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md new file mode 100644 index 00000000..c385d797 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -0,0 +1,24 @@ +--- +name: Feature Request +about: Help us make Crossplane more useful +labels: enhancement +--- + + +### What problem are you facing? + + +### How could Crossplane help solve your problem? + diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 00000000..7627d1a9 --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,35 @@ + + +### Description of your changes + + +Fixes # + +I have: + +- [ ] Read and followed Crossplane's [contribution process]. +- [ ] Run `make reviewable test` to ensure this PR is ready for review. + +### How has this code been tested + + + +[contribution process]: https://git.io/fj2m9 diff --git a/.github/stale.yml b/.github/stale.yml new file mode 100644 index 00000000..f6c6e0ac --- /dev/null +++ b/.github/stale.yml @@ -0,0 +1,38 @@ +# Configuration for probot-stale - https://github.com/probot/stale + +# Number of days of inactivity before an Issue or Pull Request becomes stale +daysUntilStale: 90 + +# Number of days of inactivity before a stale Issue or Pull Request is closed. +# Set to false to disable. If disabled, issues still need to be closed manually, but will remain marked as stale. +daysUntilClose: 7 + +# Issues or Pull Requests with these labels will never be considered stale. Set to `[]` to disable +exemptLabels: + - security + +# Set to true to ignore issues in a project (defaults to false) +exemptProjects: false + +# Set to true to ignore issues in a milestone (defaults to false) +exemptMilestones: false + +# Label to use when marking as stale +staleLabel: wontfix + +# Comment to post when marking as stale. Set to `false` to disable +markComment: > + This issue has been automatically marked as stale because it has not had + recent activity. It will be closed if no further activity occurs. Thank you + for your contributions. + +# Comment to post when closing a stale Issue or Pull Request. +closeComment: > + This issue has been automatically closed due to inactivity. Please re-open + if this still requires investigation. + +# Limit the number of actions per hour, from 1-30. Default is 30 +limitPerRun: 30 + +# Limit to only `issues` or `pulls` +only: issues diff --git a/.github/workflows/backport.yml b/.github/workflows/backport.yml new file mode 100644 index 00000000..00502c6b --- /dev/null +++ b/.github/workflows/backport.yml @@ -0,0 +1,34 @@ +name: Backport + +on: + # NOTE(negz): This is a risky target, but we run this action only when and if + # a PR is closed, then filter down to specifically merged PRs. We also don't + # invoke any scripts, etc from within the repo. I believe the fact that we'll + # be able to review PRs before this runs makes this fairly safe. + # https://securitylab.github.com/research/github-actions-preventing-pwn-requests/ + pull_request_target: + types: [closed] + # See also commands.yml for the /backport triggered variant of this workflow. + +jobs: + # NOTE(negz): I tested many backport GitHub actions before landing on this + # one. Many do not support merge commits, or do not support pull requests with + # more than one commit. This one does. It also handily links backport PRs with + # new PRs, and provides commentary and instructions when it can't backport. + # The main gotchas with this action are that it _only_ supports merge commits, + # and that PRs _must_ be labelled before they're merged to trigger a backport. + open-pr: + runs-on: ubuntu-18.04 + if: github.event.pull_request.merged + steps: + - name: Checkout + uses: actions/checkout@v2 + with: + fetch-depth: 0 + + - name: Open Backport PR + uses: zeebe-io/backport-action@v0.0.4 + with: + github_token: ${{ secrets.GITHUB_TOKEN }} + github_workspace: ${{ github.workspace }} + version: v0.0.4 diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 00000000..86199696 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,317 @@ +name: CI + +on: + push: + branches: + - main + - release-* + pull_request: {} + workflow_dispatch: {} + +env: + # Common versions + GO_VERSION: '1.16' + GOLANGCI_VERSION: 'v1.31' + DOCKER_BUILDX_VERSION: 'v0.4.2' + + # Common users. We can't run a step 'if secrets.AWS_USR != ""' but we can run + # a step 'if env.AWS_USR' != ""', so we copy these to succinctly test whether + # credentials have been provided before trying to run steps that need them. + DOCKER_USR: ${{ secrets.DOCKER_USR }} + AWS_USR: ${{ secrets.AWS_USR }} + +jobs: + detect-noop: + runs-on: ubuntu-18.04 + outputs: + noop: ${{ steps.noop.outputs.should_skip }} + steps: + - name: Detect No-op Changes + id: noop + uses: fkirc/skip-duplicate-actions@v2.0.0 + with: + github_token: ${{ secrets.GITHUB_TOKEN }} + paths_ignore: '["**.md", "**.png", "**.jpg"]' + do_not_skip: '["workflow_dispatch", "schedule", "push"]' + + + lint: + runs-on: ubuntu-18.04 + needs: detect-noop + if: needs.detect-noop.outputs.noop != 'true' + + steps: + - name: Checkout + uses: actions/checkout@v2 + with: + submodules: true + + - name: Find the Go Build Cache + id: go + run: echo "::set-output name=cache::$(go env GOCACHE)" + + - name: Cache the Go Build Cache + uses: actions/cache@v2 + with: + path: ${{ steps.go.outputs.cache }} + key: ${{ runner.os }}-build-lint-${{ hashFiles('**/go.sum') }} + restore-keys: ${{ runner.os }}-build-lint- + + - name: Cache Go Dependencies + uses: actions/cache@v2 + with: + path: .work/pkg + key: ${{ runner.os }}-pkg-${{ hashFiles('**/go.sum') }} + restore-keys: ${{ runner.os }}-pkg- + + - name: Vendor Dependencies + run: make vendor vendor.check + + # This action uses its own setup-go, which always seems to use the latest + # stable version of Go. We could run 'make lint' to ensure our desired Go + # version, but we prefer this action because it leaves 'annotations' (i.e. + # it comments on PRs to point out linter violations). + - name: Lint + uses: golangci/golangci-lint-action@v2 + with: + version: ${{ env.GOLANGCI_VERSION }} + + check-diff: + runs-on: ubuntu-18.04 + needs: detect-noop + if: needs.detect-noop.outputs.noop != 'true' + + steps: + - name: Checkout + uses: actions/checkout@v2 + with: + submodules: true + + - name: Setup Go + uses: actions/setup-go@v2 + with: + go-version: ${{ env.GO_VERSION }} + + - name: Find the Go Build Cache + id: go + run: echo "::set-output name=cache::$(go env GOCACHE)" + + - name: Cache the Go Build Cache + uses: actions/cache@v2 + with: + path: ${{ steps.go.outputs.cache }} + key: ${{ runner.os }}-build-check-diff-${{ hashFiles('**/go.sum') }} + restore-keys: ${{ runner.os }}-build-check-diff- + + - name: Cache Go Dependencies + uses: actions/cache@v2 + with: + path: .work/pkg + key: ${{ runner.os }}-pkg-${{ hashFiles('**/go.sum') }} + restore-keys: ${{ runner.os }}-pkg- + + - name: Vendor Dependencies + run: make vendor vendor.check + + - name: Check Diff + run: make check-diff + + unit-tests: + runs-on: ubuntu-18.04 + needs: detect-noop + if: needs.detect-noop.outputs.noop != 'true' + + steps: + - name: Checkout + uses: actions/checkout@v2 + with: + submodules: true + + - name: Fetch History + run: git fetch --prune --unshallow + + - name: Setup Go + uses: actions/setup-go@v2 + with: + go-version: ${{ env.GO_VERSION }} + + - name: Find the Go Build Cache + id: go + run: echo "::set-output name=cache::$(go env GOCACHE)" + + - name: Cache the Go Build Cache + uses: actions/cache@v2 + with: + path: ${{ steps.go.outputs.cache }} + key: ${{ runner.os }}-build-unit-tests-${{ hashFiles('**/go.sum') }} + restore-keys: ${{ runner.os }}-build-unit-tests- + + - name: Cache Go Dependencies + uses: actions/cache@v2 + with: + path: .work/pkg + key: ${{ runner.os }}-pkg-${{ hashFiles('**/go.sum') }} + restore-keys: ${{ runner.os }}-pkg- + + - name: Vendor Dependencies + run: make vendor vendor.check + + - name: Run Unit Tests + run: make -j2 test + + - name: Publish Unit Test Coverage + uses: codecov/codecov-action@v1 + with: + flags: unittests + file: _output/tests/linux_amd64/coverage.txt + + e2e-tests: + runs-on: ubuntu-18.04 + needs: detect-noop + if: needs.detect-noop.outputs.noop != 'true' + + steps: + - name: Setup QEMU + uses: docker/setup-qemu-action@v1 + with: + platforms: all + + - name: Setup Docker Buildx + uses: docker/setup-buildx-action@v1 + with: + version: ${{ env.DOCKER_BUILDX_VERSION }} + install: true + + - name: Checkout + uses: actions/checkout@v2 + with: + submodules: true + + - name: Fetch History + run: git fetch --prune --unshallow + + - name: Setup Go + uses: actions/setup-go@v2 + with: + go-version: ${{ env.GO_VERSION }} + + - name: Find the Go Build Cache + id: go + run: echo "::set-output name=cache::$(go env GOCACHE)" + + - name: Cache the Go Build Cache + uses: actions/cache@v2 + with: + path: ${{ steps.go.outputs.cache }} + key: ${{ runner.os }}-build-e2e-tests-${{ hashFiles('**/go.sum') }} + restore-keys: ${{ runner.os }}-build-e2e-tests- + + - name: Cache Go Dependencies + uses: actions/cache@v2 + with: + path: .work/pkg + key: ${{ runner.os }}-pkg-${{ hashFiles('**/go.sum') }} + restore-keys: | + ${{ runner.os }}-pkg- + + - name: Vendor Dependencies + run: make vendor vendor.check + + - name: Build Helm Chart + run: make -j2 build + env: + # We're using docker buildx, which doesn't actually load the images it + # builds by default. Specifying --load does so. + BUILD_ARGS: "--load" + + #- name: Run E2E Tests + # run: make e2e USE_HELM3=true + + publish-artifacts: + runs-on: ubuntu-18.04 + needs: detect-noop + if: needs.detect-noop.outputs.noop != 'true' + + steps: + - name: Setup QEMU + uses: docker/setup-qemu-action@v1 + with: + platforms: all + + - name: Setup Docker Buildx + uses: docker/setup-buildx-action@v1 + with: + version: ${{ env.DOCKER_BUILDX_VERSION }} + install: true + + - name: Checkout + uses: actions/checkout@v2 + with: + submodules: true + + - name: Fetch History + run: git fetch --prune --unshallow + + - name: Setup Go + uses: actions/setup-go@v2 + with: + go-version: ${{ env.GO_VERSION }} + + - name: Find the Go Build Cache + id: go + run: echo "::set-output name=cache::$(go env GOCACHE)" + + - name: Cache the Go Build Cache + uses: actions/cache@v2 + with: + path: ${{ steps.go.outputs.cache }} + key: ${{ runner.os }}-build-publish-artifacts-${{ hashFiles('**/go.sum') }} + restore-keys: ${{ runner.os }}-build-publish-artifacts- + + - name: Cache Go Dependencies + uses: actions/cache@v2 + with: + path: .work/pkg + key: ${{ runner.os }}-pkg-${{ hashFiles('**/go.sum') }} + restore-keys: ${{ runner.os }}-pkg- + + - name: Vendor Dependencies + run: make vendor vendor.check + + - name: Build Artifacts + run: make -j2 build.all + env: + # We're using docker buildx, which doesn't actually load the images it + # builds by default. Specifying --load does so. + BUILD_ARGS: "--load" + + - name: Publish Artifacts to GitHub + uses: actions/upload-artifact@v2 + with: + name: output + path: _output/** + + - name: Login to Docker + uses: docker/login-action@v1 + if: env.DOCKER_USR != '' + with: + username: ${{ secrets.DOCKER_USR }} + password: ${{ secrets.DOCKER_PSW }} + + - name: Publish Artifacts to S3 and Docker Hub + run: make -j2 publish BRANCH_NAME=${GITHUB_REF##*/} + if: env.AWS_USR != '' && env.DOCKER_USR != '' + env: + AWS_ACCESS_KEY_ID: ${{ secrets.AWS_USR }} + AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_PSW }} + GIT_API_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + - name: Promote Artifacts in S3 and Docker Hub + if: github.ref == 'refs/heads/main' && env.AWS_USR != '' && env.DOCKER_USR != '' + run: make -j2 promote + env: + BRANCH_NAME: main + CHANNEL: main + AWS_ACCESS_KEY_ID: ${{ secrets.AWS_USR }} + AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_PSW }} + \ No newline at end of file diff --git a/.github/workflows/commands.yml b/.github/workflows/commands.yml new file mode 100644 index 00000000..b9c504c4 --- /dev/null +++ b/.github/workflows/commands.yml @@ -0,0 +1,92 @@ +name: Comment Commands + +on: issue_comment + +jobs: + points: + runs-on: ubuntu-18.04 + if: startsWith(github.event.comment.body, '/points') + + steps: + - name: Extract Command + id: command + uses: xt0rted/slash-command-action@v1 + with: + repo-token: ${{ secrets.GITHUB_TOKEN }} + command: points + reaction: "true" + reaction-type: "eyes" + allow-edits: "false" + permission-level: write + - name: Handle Command + uses: actions/github-script@v4 + env: + POINTS: ${{ steps.command.outputs.command-arguments }} + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + script: | + const points = process.env.POINTS + + if (isNaN(parseInt(points))) { + console.log("Malformed command - expected '/points '") + github.reactions.createForIssueComment({ + owner: context.repo.owner, + repo: context.repo.repo, + comment_id: context.payload.comment.id, + content: "confused" + }) + return + } + const label = "points/" + points + + // Delete our needs-points-label label. + try { + await github.issues.deleteLabel({ + issue_number: context.issue.number, + owner: context.repo.owner, + repo: context.repo.repo, + name: ['needs-points-label'] + }) + console.log("Deleted 'needs-points-label' label.") + } + catch(e) { + console.log("Label 'needs-points-label' probably didn't exist.") + } + + // Add our points label. + github.issues.addLabels({ + issue_number: context.issue.number, + owner: context.repo.owner, + repo: context.repo.repo, + labels: [label] + }) + console.log("Added '" + label + "' label.") + + # NOTE(negz): See also backport.yml, which is the variant that triggers on PR + # merge rather than on comment. + backport: + runs-on: ubuntu-18.04 + if: github.event.issue.pull_request && startsWith(github.event.comment.body, '/backport') + steps: + - name: Extract Command + id: command + uses: xt0rted/slash-command-action@v1 + with: + repo-token: ${{ secrets.GITHUB_TOKEN }} + command: backport + reaction: "true" + reaction-type: "eyes" + allow-edits: "false" + permission-level: write + + - name: Checkout + uses: actions/checkout@v2 + with: + fetch-depth: 0 + + - name: Open Backport PR + uses: zeebe-io/backport-action@v0.0.4 + with: + github_token: ${{ secrets.GITHUB_TOKEN }} + github_workspace: ${{ github.workspace }} + version: v0.0.4 diff --git a/.github/workflows/promote.yml b/.github/workflows/promote.yml new file mode 100644 index 00000000..8e84d5a8 --- /dev/null +++ b/.github/workflows/promote.yml @@ -0,0 +1,49 @@ +name: Promote + +on: + workflow_dispatch: + inputs: + version: + description: 'Release version (e.g. v0.1.0)' + required: true + channel: + description: 'Release channel' + required: true + default: 'alpha' + +env: + # Common users. We can't run a step 'if secrets.AWS_USR != ""' but we can run + # a step 'if env.AWS_USR' != ""', so we copy these to succinctly test whether + # credentials have been provided before trying to run steps that need them. + DOCKER_USR: ${{ secrets.DOCKER_USR }} + AWS_USR: ${{ secrets.AWS_USR }} + +jobs: + promote-artifacts: + runs-on: ubuntu-18.04 + + steps: + - name: Checkout + uses: actions/checkout@v2 + with: + submodules: true + + - name: Fetch History + run: git fetch --prune --unshallow + + - name: Login to Docker + uses: docker/login-action@v1 + if: env.DOCKER_USR != '' + with: + username: ${{ secrets.DOCKER_USR }} + password: ${{ secrets.DOCKER_PSW }} + + - name: Promote Artifacts in S3 and Docker Hub + if: env.AWS_USR != '' && env.DOCKER_USR != '' + run: make -j2 promote BRANCH_NAME=${GITHUB_REF##*/} + env: + VERSION: ${{ github.event.inputs.version }} + CHANNEL: ${{ github.event.inputs.channel }} + AWS_ACCESS_KEY_ID: ${{ secrets.AWS_USR }} + AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_PSW }} + \ No newline at end of file diff --git a/.github/workflows/tag.yml b/.github/workflows/tag.yml new file mode 100644 index 00000000..0d0a89ef --- /dev/null +++ b/.github/workflows/tag.yml @@ -0,0 +1,26 @@ +name: Tag + +on: + workflow_dispatch: + inputs: + version: + description: 'Release version (e.g. v0.1.0)' + required: true + message: + description: 'Tag message' + required: true + +jobs: + create-tag: + runs-on: ubuntu-18.04 + + steps: + - name: Checkout + uses: actions/checkout@v2 + + - name: Create Tag + uses: negz/create-tag@v1 + with: + version: ${{ github.event.inputs.version }} + message: ${{ github.event.inputs.message }} + token: ${{ secrets.GITHUB_TOKEN }} \ No newline at end of file