diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 000000000..0f046820f --- /dev/null +++ b/.dockerignore @@ -0,0 +1,4 @@ +# More info: https://docs.docker.com/engine/reference/builder/#dockerignore-file +# Ignore build and test binaries. +bin/ +testbin/ diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 000000000..4ab3e2985 --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,33 @@ + +### Description of your changes + + + +Fixes # + +I have: + +- [ ] Read and followed fleet's [Code of conduct](https://github.com/Azure/fleet/blob/main/CODE_OF_CONDUCT.md). +- [ ] Run `make reviewable` to ensure this PR is ready for review. + +### How has this code been tested + + + + +### Special notes for your reviewer + + diff --git a/.github/pr-title-config.json b/.github/pr-title-config.json new file mode 100644 index 000000000..58d0421da --- /dev/null +++ b/.github/pr-title-config.json @@ -0,0 +1,9 @@ +{ + "LABEL": { + "name": "title-needs-formatting", + "color": "EEEEEE" + }, + "CHECKS": { + "prefixes": [ "[WIP] ", "Feat: ", "Test: ", "Fix: ", "Docs: ", "Style: ", "Interface: ", "Util: ", "Chore: ", "CI: ", "Perf: ", "Refactor: ", "Revert: " ] + } + } diff --git a/.github/workflows/build-images.yml b/.github/workflows/build-images.yml new file mode 100644 index 000000000..dd8545c6d --- /dev/null +++ b/.github/workflows/build-images.yml @@ -0,0 +1,61 @@ +name: build_images + +on: + push: + branches: [ main ] + # Publish semver tags as releases. + tags: [ 'v*.*.*' ] + +env: + REGISTRY: ghcr.io + # github.repository as / + IMAGE_NAME: ${{ github.repository }} + +jobs: + build: + + runs-on: ubuntu-latest + permissions: + contents: read + packages: write + # This is used to complete the identity challenge + # with sigstore/fulcio when running outside of PRs. + id-token: write + + steps: + - name: Checkout repository + uses: actions/checkout@v2 + + # Workaround: https://github.com/docker/build-push-action/issues/461 + - name: Setup Docker buildx + uses: docker/setup-buildx-action@79abd3f86f79a9d68a23c75a09a9a85889262adf + + # Login against the container registry except on PR + # https://github.com/docker/login-action + - name: Log into registry ${{ env.REGISTRY }} + if: github.event_name != 'pull_request' + uses: docker/login-action@28218f9b04b4f3f62068d7b6ce6ca5b26e35336c + with: + registry: ${{ env.REGISTRY }} + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + # Extract metadata (tags, labels) for Docker + # https://github.com/docker/metadata-action + - name: Extract image metadata + id: meta + uses: docker/metadata-action@98669ae865ea3cffbcbaa878cf57c20bbf1c6c38 + with: + images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} + + + # Build and push container image with Buildx (don't push on PR) + # https://github.com/docker/build-push-action + - name: Build and push image + id: build-and-push + uses: docker/build-push-action@ad44023a93711e3deb337508980b4b5e9bcdc5dc + with: + context: . + push: ${{ github.event_name != 'pull_request' }} + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 000000000..34f631ba0 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,58 @@ +name: fleet-ci + +on: + push: + branches: + - main + - release-* + workflow_dispatch: {} + pull_request: + branches: + - main + - release-* + paths-ignore: [docs/**, "**.md", "**.mdx", "**.png", "**.jpg"] + +jobs: + + detect-noop: + runs-on: ubuntu-latest + outputs: + noop: ${{ steps.noop.outputs.should_skip }} + steps: + - name: Detect No-op Changes + id: noop + uses: fkirc/skip-duplicate-actions@v3.3.0 + with: + github_token: ${{ secrets.GITHUB_TOKEN }} + do_not_skip: '["workflow_dispatch", "schedule", "push"]' + concurrent_skipping: false + + codecov: + runs-on: ubuntu-latest + needs: detect-noop + if: needs.detect-noop.outputs.noop != 'true' + + steps: + - name: Set up Go + uses: actions/setup-go@v2 + with: + go-version: ${{ env.GO_VERSION }} + + - name: Check out code into the Go module directory + uses: actions/checkout@v2 + + - name: Get dependencies + run: go get -v -t -d ./... + + - name: Run tests & Generate coverage + run: make test + + - name: Upload report + uses: codecov/codecov-action@v2.1.0 + with: + ## Repository upload token - get it from codecov.io. Required only for private repositories + token: ${{ secrets.CODECOV_TOKEN }} + ## Comma-separated list of files to upload + files: ./cover.out + flags: ci-tests + name: codecov-umbrella diff --git a/.github/workflows/commit-lint.yml b/.github/workflows/commit-lint.yml new file mode 100644 index 000000000..f6f394220 --- /dev/null +++ b/.github/workflows/commit-lint.yml @@ -0,0 +1,19 @@ +name: PR Title Checker +on: + pull_request: + types: + - opened + - edited + - synchronize + - labeled + - unlabeled + +jobs: + check: + runs-on: ubuntu-latest + steps: + - uses: thehanimo/pr-title-checker@v1.3.1 + with: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + pass_on_octokit_error: true + configuration_path: ".github/pr-title-config.json" diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml new file mode 100644 index 000000000..7c133c483 --- /dev/null +++ b/.github/workflows/go.yml @@ -0,0 +1,80 @@ +name: Go + +on: + push: + branches: + - main + - release-* + workflow_dispatch: {} + pull_request: + branches: + - main + - release-* + paths-ignore: [docs/**, "**.md", "**.mdx", "**.png", "**.jpg"] + +env: + # Common versions + GO_VERSION: '1.17' + +jobs: + + detect-noop: + runs-on: ubuntu-latest + outputs: + noop: ${{ steps.noop.outputs.should_skip }} + steps: + - name: Detect No-op Changes + id: noop + uses: fkirc/skip-duplicate-actions@v3.3.0 + with: + github_token: ${{ secrets.GITHUB_TOKEN }} + do_not_skip: '["workflow_dispatch", "schedule", "push"]' + concurrent_skipping: false + + staticcheck: + runs-on: ubuntu-latest + needs: detect-noop + if: needs.detect-noop.outputs.noop != 'true' + + steps: + - name: Setup Go + uses: actions/setup-go@v2 + with: + go-version: ${{ env.GO_VERSION }} + + - name: Checkout + uses: actions/checkout@v2 + with: + submodules: true + + - 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: Install StaticCheck + run: GO111MODULE=off go get honnef.co/go/tools/cmd/staticcheck + + - name: Static Check + run: staticcheck ./... + + lint: + name: "Lint" + runs-on: ubuntu-latest + timeout-minutes: 10 + permissions: + contents: read + + steps: + - name: Set up Go ${{ env.GO_VERSION }} + uses: actions/setup-go@v2 + with: + go-version: ${{ env.GO_VERSION }} + + - name: Check out code into the Go module directory + uses: actions/checkout@v2 + + - name: golangci-lint + run: make lint diff --git a/.github/workflows/markdown-lint.yml b/.github/workflows/markdown-lint.yml new file mode 100644 index 000000000..890238e79 --- /dev/null +++ b/.github/workflows/markdown-lint.yml @@ -0,0 +1,20 @@ +name: Check Markdown + +on: + pull_request: + paths: + - '**.md' + - "docs/**" + +jobs: + markdown-link-check: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - uses: gaurav-nelson/github-action-markdown-link-check@v1 + with: + # this will only show errors in the output + use-quiet-mode: 'yes' + # this will show detailed HTTP status for checked links + use-verbose-mode: 'yes' + config-file: '.github/workflows/markdown.links.config.json' diff --git a/.github/workflows/markdown.links.config.json b/.github/workflows/markdown.links.config.json new file mode 100644 index 000000000..04d1e1de1 --- /dev/null +++ b/.github/workflows/markdown.links.config.json @@ -0,0 +1,6 @@ +{ + "aliveStatusCodes": [ + 200, + 203 + ] +} diff --git a/.gitignore b/.gitignore index 66fd13c90..77f381f28 100644 --- a/.gitignore +++ b/.gitignore @@ -13,3 +13,7 @@ # Dependency directories (remove the comment below to include it) # vendor/ + +# binary output +bin/ +hack/tools/bin/ diff --git a/.golangci.yml b/.golangci.yml new file mode 100644 index 000000000..111804033 --- /dev/null +++ b/.golangci.yml @@ -0,0 +1,31 @@ +run: + deadline: 10m + +linters: + disable-all: true + enable: + - deadcode + - errcheck + - errorlint + - goconst + - gocyclo + - gofmt + - goimports + - gosec + - gosimple + - govet + - ineffassign + - misspell + - nakedret + - nilerr + - prealloc + - revive + - staticcheck + - structcheck + - typecheck + - unconvert + - unused + - varcheck + - whitespace + # Run with --fast=false for more extensive checks + fast: true diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 000000000..36efa5104 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,26 @@ +# Build the manager binary +FROM golang:1.17 as builder + +WORKDIR /workspace +# Copy the Go Modules manifests +COPY go.mod go.mod +COPY go.sum go.sum +# cache deps before building and copying source so that we don't need to re-download as much +# and so that source changes don't invalidate our downloaded layer +RUN go mod download + +# Copy the go source +COPY cmd/main.go main.go +# TODO COPY pgk/apis +# Build +ARG TARGETARCH +RUN CGO_ENABLED=0 GOOS=linux GOARCH=${TARGETARCH} GO111MODULE=on go build -o manager main.go + +# Use distroless as minimal base image to package the manager binary +# Refer to https://github.com/GoogleContainerTools/distroless for more details +FROM gcr.io/distroless/static:nonroot +WORKDIR / +COPY --from=builder /workspace/manager . +USER 65532:65532 + +ENTRYPOINT ["/manager"] diff --git a/Makefile b/Makefile new file mode 100644 index 000000000..f7fe2fb59 --- /dev/null +++ b/Makefile @@ -0,0 +1,39 @@ +include makefiles/dependency.mk + +# Get the currently used golang install path (in GOPATH/bin, unless GOBIN is set) +ifeq (,$(shell go env GOBIN)) +GOBIN=$(shell go env GOPATH)/bin +else +GOBIN=$(shell go env GOBIN) +endif + +## -------------------------------------- +## Linting +## -------------------------------------- + +.PHONY: lint +lint: $(GOLANGCI_LINT) + $(GOLANGCI_LINT) run -v + +.PHONY: lint-full +lint-full: $(GOLANGCI_LINT) ## Run slower linters to detect possible issues + $(GOLANGCI_LINT) run -v --fast=false + +## -------------------------------------- +## Development +## -------------------------------------- + +.PHONY: fmt +fmt: goimports ## Run go fmt against code. + go fmt ./... + $(GOIMPORTS) -local go.goms.io/fleet -w $$(go list -f {{.Dir}} ./...) + +.PHONY: vet +vet: ## Run go vet against code. + go vet ./... + +.PHONY: test +test: envtest## Run tests. + go test ./... -coverprofile cover.out + +## TODO: make run/install/manifest diff --git a/cmd/main.go b/cmd/main.go new file mode 100644 index 000000000..de12cbc1d --- /dev/null +++ b/cmd/main.go @@ -0,0 +1,7 @@ +package main + +import "k8s.io/klog" + +func main() { + klog.Info("starting fleet") +} diff --git a/go.mod b/go.mod new file mode 100644 index 000000000..5fb465e25 --- /dev/null +++ b/go.mod @@ -0,0 +1,5 @@ +module go.goms.io/fleet + +go 1.17 + +require k8s.io/klog v1.0.0 diff --git a/go.sum b/go.sum new file mode 100644 index 000000000..3356d3fcb --- /dev/null +++ b/go.sum @@ -0,0 +1,3 @@ +github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas= +k8s.io/klog v1.0.0 h1:Pt+yjF5aB1xDSVbau4VsWe+dQNzA0qv1LlXdC2dF6Q8= +k8s.io/klog v1.0.0/go.mod h1:4Bi6QPql/J/LkTDqv7R/cd3hPo4k2DG6Ptcz060Ez5I= diff --git a/hack/go-install.sh b/hack/go-install.sh new file mode 100755 index 000000000..8f0356201 --- /dev/null +++ b/hack/go-install.sh @@ -0,0 +1,44 @@ +#!/usr/bin/env bash +# https://github.com/kubernetes-sigs/cluster-api-provider-azure/blob/master/scripts/go_install.sh + +set -o errexit +set -o nounset +set -o pipefail + +if [[ -z "${1}" ]]; then + echo "must provide module as first parameter" + exit 1 +fi + +if [[ -z "${2}" ]]; then + echo "must provide binary name as second parameter" + exit 1 +fi + +if [[ -z "${3}" ]]; then + echo "must provide version as third parameter" + exit 1 +fi + +if [[ -z "${GOBIN}" ]]; then + echo "GOBIN is not set. Must set GOBIN to install the bin in a specified directory." + exit 1 +fi + +tmp_dir=$(mktemp -d -t goinstall_XXXXXXXXXX) +function clean { + rm -rf "${tmp_dir}" +} +trap clean EXIT + +rm "${GOBIN}/${2}"* || true + +cd "${tmp_dir}" + +# create a new module in the tmp directory +go mod init fake/mod + +# install the golang module specified as the first argument +go install "${1}@${3}" +mv "${GOBIN}/${2}" "${GOBIN}/${2}-${3}" +ln -sf "${GOBIN}/${2}-${3}" "${GOBIN}/${2}" diff --git a/makefiles/dependency.mk b/makefiles/dependency.mk new file mode 100644 index 000000000..3a81d9bbb --- /dev/null +++ b/makefiles/dependency.mk @@ -0,0 +1,52 @@ +# Directories +ROOT_DIR := $(shell dirname $(realpath $(firstword $(MAKEFILE_LIST)))) +BIN_DIR := $(abspath $(ROOT_DIR)/bin) +TOOLS_DIR := hack/tools +TOOLS_BIN_DIR := $(abspath $(TOOLS_DIR)/bin) + +# Binaries +GOLANGCI_LINT_VER := v1.41.1 +GOLANGCI_LINT_BIN := golangci-lint +GOLANGCI_LINT := $(TOOLS_BIN_DIR)/$(GOLANGCI_LINT_BIN)-$(GOLANGCI_LINT_VER) + +# Scripts +GO_INSTALL := ./hack/go-install.sh + +## -------------------------------------- +## Tooling Binaries +## -------------------------------------- + +$(GOLANGCI_LINT): + GOBIN=$(TOOLS_BIN_DIR) $(GO_INSTALL) github.com/golangci/golangci-lint/cmd/golangci-lint $(GOLANGCI_LINT_BIN) $(GOLANGCI_LINT_VER) + +## -------------------------------------- +## GOIMPORTS +## -------------------------------------- + +.PHONY: goimports +goimports: +ifeq (, $(shell which goimports)) + @{ \ + set -e ;\ + go install golang.org/x/tools/cmd/goimports@latest ;\ + } +GOIMPORTS=$(GOBIN)/goimports +else +GOIMPORTS=$(shell which goimports) +endif + +## -------------------------------------- +## ENVTEST +## -------------------------------------- + +.PHONY: envtest +envtest: +ifeq (, $(shell which setup-envtest)) + @{ \ + set -e ;\ + go install sigs.k8s.io/controller-runtime/tools/setup-envtest@latest ;\ + } +ENVTEST=$(GOBIN)/setup-envtest +else +ENVTEST=$(shell which setup-envtest) +endif