From 9055ab51647d59e7621edf97952d2ab5ad0476a7 Mon Sep 17 00:00:00 2001 From: Pierre Smeyers <pierre.smeyers@gmail.com> Date: Sun, 14 Jan 2024 17:54:47 +0100 Subject: [PATCH] feat: migrate to CI/CD component MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ⚠ requires GitLab 16.6 or later --- .gitlab-ci.yml | 2 +- README.md | 83 +++++++++++++------- bumpversion.sh | 4 +- kicker.json | 4 +- logo.png | Bin 15907 -> 10742 bytes templates/gitlab-ci-golang.yml | 139 ++++++++++++++++++++++++++------- 6 files changed, 170 insertions(+), 62 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index d37fb77..bf4db2c 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -10,7 +10,7 @@ include: file: '/templates/validation.yml' - project: 'to-be-continuous/bash' ref: '3.3' - file: 'templates/gitlab-ci-bash.yml' + file: '/templates/gitlab-ci-bash.yml' - project: 'to-be-continuous/semantic-release' ref: '3.7' file: '/templates/gitlab-ci-semrel.yml' diff --git a/README.md b/README.md index bbe96c8..f3acfc5 100644 --- a/README.md +++ b/README.md @@ -4,25 +4,48 @@ This project implements a GitLab CI/CD template to build, test and analyse your ## Usage -In order to include this template in your project, add the following to your `gitlab-ci.yml`: +This template can be used both as a [CI/CD component](https://docs.gitlab.com/ee/ci/components/#use-a-component-in-a-cicd-configuration) +or using the legacy [`include:project`](https://docs.gitlab.com/ee/ci/yaml/index.html#includeproject) syntax. + +### Use as a CI/CD component + +Add the following to your `gitlab-ci.yml`: + +```yaml +include: + # 1: include the component + - component: gitlab.com/to-be-continuous/golang/gitlab-ci-golang@4.7.0 + # 2: set/override component inputs + inputs: + image: "registry.hub.docker.com/library/golang:buster" # ⚠ this is only an example +``` + +### Use as a CI/CD template (legacy) + +Add the following to your `gitlab-ci.yml`: ```yaml include: + # 1: include the template - project: 'to-be-continuous/golang' ref: '4.7.0' file: '/templates/gitlab-ci-golang.yml' + +variables: + # 2: set/override template variables + GO_IMAGE: "registry.hub.docker.com/library/golang:buster" # ⚠ this is only an example ``` ## Global configuration The Go template uses some global configuration used throughout all jobs. -| Name | Description | Default value | +| Input / Variable | Description | Default value | |------------------|------------------------------------------------------------------------------------------------------------|-----------------| -| `GO_IMAGE` | The Docker image used to run Go for `go-build` <br/>:warning: **set the version required by your project** | `registry.hub.docker.com/library/golang:buster` | -| `GO_TEST_IMAGE` | The Docker image used to run Go for `go-test` <br/>:warning: **set the version required by your project** | _none_ | -| `GO_PROJECT_DIR` | Go project root directory | `.` | -| `GOPROXY` | URL of Go module proxy | _none_ | +| `image` / `GO_IMAGE` | The Docker image used to run Go for `go-build` <br/>:warning: **set the version required by your project** | `registry.hub.docker.com/library/golang:bookworm` | +| `test-image` / `GO_TEST_IMAGE` | The Docker image used to run Go for `go-test` <br/>:warning: **set the version required by your project** | _none_ | +| `project-dir` / `GO_PROJECT_DIR` | Go project root directory | `.` | +| `goproxy` / `GOPROXY` | URL of Go module proxy | _none_ | ## Jobs @@ -68,18 +91,18 @@ go-build: These jobs use the following variable: -| Name | Description | Default value | +| Input / Variable | Description | Default value | |-------------------------|-------------------------------------------------------------------------------------------------------------------------|-----------------------------------------------| -| `GO_BUILD_MODE` | The template build mode (accepted values are `application`, `modules` and `auto`) | `auto` | -| `GO_BUILD_FLAGS` | Flags used by the [go build command](https://pkg.go.dev/cmd/go#hdr-Compile_packages_and_dependencies) | `-mod=readonly` | -| `GO_BUILD_LINKER_FLAGS` | Linker flags used by the [go build command](https://pkg.go.dev/cmd/go#hdr-Compile_packages_and_dependencies) `-ldflags` | `-s -w` | -| `GO_BUILD_PACKAGES` | Packages to build with the [go build command](https://pkg.go.dev/cmd/go#hdr-Compile_packages_and_dependencies) | `./...` | -| `GO_TEST_FLAGS` | Flags used by the [go test command](https://pkg.go.dev/cmd/go#hdr-Test_packages) | `-mod=readonly -v -race` | -| `GO_TEST_PACKAGES` | Packages to test with the [go test command](https://pkg.go.dev/cmd/go#hdr-Test_packages) | `./...` | -| `GO_LIST_ARGS` | Arguments used by the list command | `list -u -m -mod=readonly -json all` | -| `GO_TARGET_OS` | The `GOOS` target [see available values](https://gist.github.com/asukakenji/f15ba7e588ac42795f421b48b8aede63) | _none_ (fallback to go docker image `GOOS`) | -| `GO_TARGET_ARCH` | The `GOARCH` target [see available values](https://gist.github.com/asukakenji/f15ba7e588ac42795f421b48b8aede63) | _none_ (fallback to go docker image `GOARCH`) | -| `GO_COBERTURA_FLAGS` | The `GOFLAGS` to use with `gocover-cobertura` if needed | _none_ | +| `build-mode` / `GO_BUILD_MODE` | The template build mode (accepted values are `application`, `modules` and `auto`) | `auto` | +| `build-flags` / `GO_BUILD_FLAGS` | Flags used by the [go build command](https://pkg.go.dev/cmd/go#hdr-Compile_packages_and_dependencies) | `-mod=readonly` | +| `build-linker-flags` / `GO_BUILD_LINKER_FLAGS` | Linker flags used by the [go build command](https://pkg.go.dev/cmd/go#hdr-Compile_packages_and_dependencies) `-ldflags` | `-s -w` | +| `build-packages` / `GO_BUILD_PACKAGES` | Packages to build with the [go build command](https://pkg.go.dev/cmd/go#hdr-Compile_packages_and_dependencies) | `./...` | +| `test-flags` / `GO_TEST_FLAGS` | Flags used by the [go test command](https://pkg.go.dev/cmd/go#hdr-Test_packages) | `-mod=readonly -v -race` | +| `test-packages` / `GO_TEST_PACKAGES` | Packages to test with the [go test command](https://pkg.go.dev/cmd/go#hdr-Test_packages) | `./...` | +| `list-args` / `GO_LIST_ARGS` | Arguments used by the list command | `list -u -m -mod=readonly -json all` | +| `target-os` / `GO_TARGET_OS` | The `GOOS` target [see available values](https://gist.github.com/asukakenji/f15ba7e588ac42795f421b48b8aede63) | _none_ (fallback to go docker image `GOOS`) | +| `target-arch` / `GO_TARGET_ARCH` | The `GOARCH` target [see available values](https://gist.github.com/asukakenji/f15ba7e588ac42795f421b48b8aede63) | _none_ (fallback to go docker image `GOARCH`) | +| `cobertura-flags` / `GO_COBERTURA_FLAGS` | The `GOFLAGS` to use with `gocover-cobertura` if needed | _none_ | In addition to a textual report in the console, the test jobs produce the following reports, kept for one day: @@ -97,11 +120,11 @@ This job enables a manual [GolangCI-Lint](https://github.com/golangci/golangci-l It is bound to the `build` stage, and uses the following variables: -| Name | Description | Default value | +| Input / Variable | Description | Default value | |-----------------------|----------------------------------------------------------------------------------------------------------|----------------------------------------| -| `GO_CI_LINT_IMAGE` | The Docker image used to run `golangci-lint` | `registry.hub.docker.com/golangci/golangci-lint:latest-alpine` | -| `GO_CI_LINT_ARGS` | `golangci-lint` [command line arguments](https://github.com/golangci/golangci-lint#command-line-options) | `-E gosec,goimports ./...` | -| `GO_CI_LINT_DISABLED` | Set to `true` to disable this job | _none_(enabled) | +| `ci-lint-image` / `GO_CI_LINT_IMAGE` | The Docker image used to run `golangci-lint` | `registry.hub.docker.com/golangci/golangci-lint:latest-alpine` | +| `ci-lint-args` / `GO_CI_LINT_ARGS` | `golangci-lint` [command line arguments](https://github.com/golangci/golangci-lint#command-line-options) | `-E gosec,goimports ./...` | +| `ci-lint-disabled` / `GO_CI_LINT_DISABLED` | Set to `true` to disable this job | _none_(enabled) | In addition to a textual report in the console, this job produces the following reports, kept for one day: @@ -116,9 +139,9 @@ This job enables a manual [Go-mod-outdated](https://github.com/psampaz/go-mod-ou It is bound to the `test` stage, and uses the following variables: -| Name | Description | Default value | +| Input / Variable | Description | Default value | |------------------------|-----------------------------------------------------------------------------------------------|-------------------| -| `GO_MOD_OUTDATED_ARGS` | `god-mod-outdated` [command line arguments](https://github.com/psampaz/go-mod-outdated#usage) | `-update -direct` | +| `mod-outdated-args` / `GO_MOD_OUTDATED_ARGS` | `god-mod-outdated` [command line arguments](https://github.com/psampaz/go-mod-outdated#usage) | `-update -direct` | Checking outdated modules can be a long operation and therefore the job is configured to be ran **manually** by default (overridable). @@ -161,11 +184,11 @@ This job generates a [SBOM](https://cyclonedx.org/) file listing installed packa It is bound to the `test` stage, and uses the following variables: -| Name | Description | Default value | +| Input / Variable | Description | Default value | | --------------------- | -------------------------------------- | ----------------- | -| `GO_SBOM_DISABLED` | Set to `true` to disable this job | _none_ | -| `GO_SBOM_IMAGE` | Image of cyclonedx-gomod used for SBOM analysis | `registry.hub.docker.com/cyclonedx/cyclonedx-gomod:latest` | -| `GO_SBOM_OPTS` | [@cyclonedx/cyclonedx-gomod options](https://github.com/CycloneDX/cyclonedx-gomod#usage) used for SBOM analysis | `-main .` | +| `sbom-disabled` / `GO_SBOM_DISABLED` | Set to `true` to disable this job | _none_ | +| `sbom-image` / `GO_SBOM_IMAGE` | Image of cyclonedx-gomod used for SBOM analysis | `registry.hub.docker.com/cyclonedx/cyclonedx-gomod:latest` | +| `sbom-opts` / `GO_SBOM_OPTS` | [@cyclonedx/cyclonedx-gomod options](https://github.com/CycloneDX/cyclonedx-gomod#usage) used for SBOM analysis | `-main .` | :warning: if you don't have your main class located at the root of your `GO_PROJECT_DIR`, then you will need to override the `-main` option in `GO_SBOM_OPTS` and define your real main class location. @@ -182,7 +205,7 @@ This job enables Vulnerability Management with [Govulncheck](https://go.dev/blog It is bound to the `test` stage, and uses the following variables: -| Name | Description | Default value | +| Input / Variable | Description | Default value | | --------------------- | -------------------------------------- | ----------------- | -| `GO_VULNCHECK_DISABLED` | Set to `true` to disable this job | _none_ -| `GO_VULNCHECK_ARGS` | `govulncheck` [command line arguments](https://pkg.go.dev/golang.org/x/vuln/cmd/govulncheck#hdr-Flags) | `./...` | \ No newline at end of file +| `vulncheck-disabled` / `GO_VULNCHECK_DISABLED` | Set to `true` to disable this job | _none_ +| `vulncheck-args` / `GO_VULNCHECK_ARGS` | `govulncheck` [command line arguments](https://pkg.go.dev/golang.org/x/vuln/cmd/govulncheck#hdr-Flags) | `./...` | \ No newline at end of file diff --git a/bumpversion.sh b/bumpversion.sh index f06829a..ed44d7b 100755 --- a/bumpversion.sh +++ b/bumpversion.sh @@ -27,13 +27,13 @@ if [[ "$curVer" ]]; then log_info "Bump version from \\e[33;1m${curVer}\\e[0m to \\e[33;1m${nextVer}\\e[0m (release type: $relType)..." # replace in README - sed -e "s/ref: '$curVer'/ref: '$nextVer'/" README.md > README.md.next + sed -e "s/ref: *'$curVer'/ref: '$nextVer'/" -e "s/ref: *\"$curVer\”/ref: \”$nextVer\”/" -e "s/component: *\(.*\)@$curVer/component: \1@$nextVer/" README.md > README.md.next mv -f README.md.next README.md # replace in template and variants for tmpl in templates/*.yml do - sed -e "s/\"$curVer\"/\"$nextVer\"/" "$tmpl" > "$tmpl.next" + sed -e "s/command: *\[\"--service\", \"\(.*\)\", \"$curVer\"\]/command: [\"--service\", \"\1\", \"$nextVer\"]/" "$tmpl" > "$tmpl.next" mv -f "$tmpl.next" "$tmpl" done else diff --git a/kicker.json b/kicker.json index b5faad7..9c7f912 100644 --- a/kicker.json +++ b/kicker.json @@ -3,11 +3,13 @@ "description": "Build, test and analyse your [Go](https://golang.org/) projects", "template_path": "templates/gitlab-ci-golang.yml", "kind": "build", + "prefix": "go", + "is_component": true, "variables": [ { "name": "GO_IMAGE", "description": "The Docker image used to run Go (build+test or build only) - **set the version required by your project**", - "default": "registry.hub.docker.com/library/golang:buster" + "default": "registry.hub.docker.com/library/golang:bookworm" }, { "name": "GO_PROJECT_DIR", diff --git a/logo.png b/logo.png index 17ae6fffd14eebeb1eaaa89a4047fac7bb06be46..795421951799ca4ce1c200aefe6bce2e80080195 100644 GIT binary patch literal 10742 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 literal 15907 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 diff --git a/templates/gitlab-ci-golang.yml b/templates/gitlab-ci-golang.yml index 2abcda5..f7a0c9a 100644 --- a/templates/gitlab-ci-golang.yml +++ b/templates/gitlab-ci-golang.yml @@ -14,6 +14,90 @@ # Floor, Boston, MA 02110-1301, USA. # ========================================================================================= # default workflow rules: Merge Request pipelines +spec: + inputs: + image: + description: The Docker image used to run Go (build+test or build only) - **set the version required by your project** + default: registry.hub.docker.com/library/golang:bookworm + project-dir: + description: Go project root directory + default: . + goproxy: + description: URL of Go module proxy (see [Go env](https://golang.org/cmd/go/#hdr-Environment_variables)) + default: '' + test-image: + description: Specific Docker image used to run Go tests (as a separate job) + default: '' + build-flags: + description: Flags used by the [go build command](https://pkg.go.dev/cmd/go#hdr-Compile_packages_and_dependencies) + default: -mod=readonly + build-mode: + description: The template build mode (accepted values are `application`, `modules` and `auto`) + options: + - auto + - application + - modules + default: auto + build-linker-flags: + description: Linker flags used by the [go build command](https://pkg.go.dev/cmd/go#hdr-Compile_packages_and_dependencies) `-ldflags` + default: -s -w + build-packages: + description: Packages to build with the [go build command](https://pkg.go.dev/cmd/go#hdr-Compile_packages_and_dependencies) + default: ./... + target-os: + description: |- + The `$GOOS` target [see available values](https://gist.github.com/asukakenji/f15ba7e588ac42795f421b48b8aede63) + + Fallbacks to default `$GOOS` from the Go Docker image + default: '' + target-arch: + description: |- + The `$GOARCH` target [see available values](https://gist.github.com/asukakenji/f15ba7e588ac42795f421b48b8aede63) + + Fallbacks to default `$GOARCH` from the Go Docker image + default: '' + test-flags: + description: Flags used by the [go test command](https://pkg.go.dev/cmd/go#hdr-Test_packages) + default: -mod=readonly -v -race + test-packages: + description: Packages to test with the [go test command](https://pkg.go.dev/cmd/go#hdr-Test_packages) + default: ./... + list-args: + description: Arguments used by the list command + default: list -u -m -mod=readonly -json all + cobertura-flags: + description: Build flags to add to use gocover-cobertura, leave blank if not needed + default: '' + ci-lint-disabled: + description: Disable GolangCI-Lint + type: boolean + default: false + ci-lint-image: + description: The Docker image used to run `golangci-lint` + default: registry.hub.docker.com/golangci/golangci-lint:latest-alpine + ci-lint-args: + description: '`golangci-lint` [command line arguments](https://github.com/golangci/golangci-lint#command-line-options)' + default: -E gosec,goimports ./... + mod-outdated-args: + description: '`god-mod-outdated` [command line arguments](https://github.com/psampaz/go-mod-outdated#usage' + default: -update -direct + sbom-disabled: + description: Disable Software Bill of Materials + type: boolean + default: false + sbom-image: + default: registry.hub.docker.com/cyclonedx/cyclonedx-gomod:latest + sbom-opts: + description: '[@cyclonedx/cyclonedx-gomod options](https://github.com/CycloneDX/cyclonedx-gomod#usage) used for SBOM analysis' + default: -main . + vulncheck-disabled: + description: Disable Govulncheck + type: boolean + default: false + vulncheck-args: + description: '`govulncheck` [command line arguments](https://pkg.go.dev/golang.org/x/vuln/cmd/govulncheck#hdr-Flags)' + default: ./... +--- workflow: rules: # prevent branch pipeline when an MR is open (prefer MR pipeline) @@ -56,67 +140,66 @@ workflow: variables: # variabilized tracking image - TBC_TRACKING_IMAGE: "registry.gitlab.com/to-be-continuous/tools/tracking:master" + TBC_TRACKING_IMAGE: registry.gitlab.com/to-be-continuous/tools/tracking:master # Default Go project root directory - GO_PROJECT_DIR: . + GO_PROJECT_DIR: $[[ inputs.project-dir ]] # Default Docker image (can be overridden) - GO_IMAGE: "registry.hub.docker.com/library/golang:bookworm" + GO_IMAGE: $[[ inputs.image ]] # Default flags for 'build' command - GO_BUILD_FLAGS: >- - -mod=readonly + GO_BUILD_FLAGS: $[[ inputs.build-flags ]] # Default flags for go build linker - GO_BUILD_LINKER_FLAGS: "-s -w" + GO_BUILD_LINKER_FLAGS: $[[ inputs.build-linker-flags ]] # Default packages for 'build' command - GO_BUILD_PACKAGES: >- + GO_BUILD_PACKAGES: $[[ inputs.build-packages ]] ./... # Default build mode (application/modules/auto) - GO_BUILD_MODE: auto + GO_BUILD_MODE: $[[ inputs.build-mode ]] # Default flags for 'test' command - GO_TEST_FLAGS: >- - -mod=readonly - -v - -race + GO_TEST_FLAGS: $[[ inputs.test-flags ]] # Default packages for 'test' command - GO_TEST_PACKAGES: >- - ./... + GO_TEST_PACKAGES: $[[ inputs.test-packages ]] # Default arguments for 'list' command - GO_LIST_ARGS : >- - list - -u - -m - -mod=readonly - -json all + GO_LIST_ARGS: $[[ inputs.list-args ]] # Default arguments for go-mod-outdated command - GO_MOD_OUTDATED_ARGS: '-update -direct' + GO_MOD_OUTDATED_ARGS: $[[ inputs.mod-outdated-args ]] - GO_VULNCHECK_ARGS: >- + GO_VULNCHECK_ARGS: $[[ inputs.vulncheck-args ]] ./... # Default golangci-lint Docker image (can be overridden) - GO_CI_LINT_IMAGE: "registry.hub.docker.com/golangci/golangci-lint:latest-alpine" + GO_CI_LINT_IMAGE: $[[ inputs.ci-lint-image ]] # Default arguments for golangci-lint command - GO_CI_LINT_ARGS: '-E gosec,goimports ./...' + GO_CI_LINT_ARGS: $[[ inputs.ci-lint-args ]] + + GOPROXY: $[[ inputs.goproxy ]] + GO_TEST_IMAGE: $[[ inputs.test-image ]] + GO_TARGET_OS: $[[ inputs.target-os ]] + GO_TARGET_ARCH: $[[ inputs.target-arch ]] + GO_COBERTURA_FLAGS: $[[ inputs.cobertura-flags ]] + GO_CI_LINT_DISABLED: $[[ inputs.ci-lint-disabled ]] + GO_SBOM_DISABLED: $[[ inputs.sbom-disabled ]] + GO_VULNCHECK_DISABLED: $[[ inputs.vulncheck-disabled ]] # Image of cyclonedx-gomod used for SBOM analysis - GO_SBOM_IMAGE: "registry.hub.docker.com/cyclonedx/cyclonedx-gomod:latest" + GO_SBOM_IMAGE: $[[ inputs.sbom-image ]] # Options for cyclonedx-gomod used for SBOM analysis - GO_SBOM_OPTS: "-main ." + GO_SBOM_OPTS: $[[ inputs.sbom-opts ]] # default production ref name (pattern) - PROD_REF: '/^(master|main)$/' + PROD_REF: /^(master|main)$/ # default integration ref name (pattern) - INTEG_REF: '/^develop$/' + INTEG_REF: /^develop$/ stages: - build -- GitLab