From 3f24f7b5c88aa2a70a75f407e60b0f2b35cdf98e Mon Sep 17 00:00:00 2001
From: Pierre Smeyers <pierre.smeyers@gmail.com>
Date: Sun, 31 Mar 2024 11:30:20 +0200
Subject: [PATCH] feat: add go generate support

---
 README.md                      | 43 +++++++++++++++++++++++++++++++++-
 kicker.json                    | 12 ++++++++++
 templates/gitlab-ci-golang.yml | 23 ++++++++++++++++++
 3 files changed, 77 insertions(+), 1 deletion(-)

diff --git a/README.md b/README.md
index 7744acb..b644f54 100644
--- a/README.md
+++ b/README.md
@@ -49,6 +49,47 @@ The Go template uses some global configuration used throughout all jobs.
 
 ## Jobs
 
+### go generate job
+
+The Go template supports code generation with [go generate](https://go.dev/blog/generate).
+It is disable by default and can be enabled by setting the `GO_GENERATE_MODULES` variable.
+
+| Input / Variable | Description                                                                                                | Default value   |
+|------------------|------------------------------------------------------------------------------------------------------------|-----------------|
+| `generate-modules` / `GO_GENERATE_MODULES` | Space separated list of Go code generator modules (ex: `stringer mockery`) | _none_ (disabled) |
+
+#### Capture generated files as job artifacts
+
+Using [go generate](https://go.dev/blog/generate) actually generates source files, that have to be captured and promoted all the way down to the build & test jobs.
+
+In its default configuration, the template captures the following:
+
+* any folder named `mock/` wherever in the file tree (entire content),
+* any folder named `mocks/` wherever in the file tree (entire content),
+* any file matching `*mock*.go` pattern wherever in the file tree.
+
+If this default doesn't suit your needs, you'll have to override the artifact path patterns (YAML).
+An example of this is given in the next chapter.
+
+#### Example
+
+```yaml
+variables:
+  # list all required generate modules (including mockery)
+  GO_GENERATE_MODULES: >
+    github.com/vektra/mockery/v2@v2.38.0 
+    github.com/deepmap/oapi-codegen/v2/cmd/oapi-codegen@latest 
+    mockery
+
+# override the artifact path patterns
+go-generate:
+  artifacts:
+    paths:
+      # list all the matchers to capture generated code
+      - "**/*mockery.go"
+      - "myapi/client/"
+```
+
 ### build & test jobs
 
 You can specify if you want the template to build an `application` or `modules` with the `GO_BUILD_MODE` variable. It may have the following values: 
@@ -124,7 +165,7 @@ It is bound to the `build` stage, and uses the following variables:
 |-----------------------|----------------------------------------------------------------------------------------------------------|----------------------------------------|
 | `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)                        |
+| `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:
 
diff --git a/kicker.json b/kicker.json
index 9c7f912..3d1e9cc 100644
--- a/kicker.json
+++ b/kicker.json
@@ -90,6 +90,18 @@
     }
   ],
   "features": [
+    {
+      "id": "generate",
+      "name": "go generate",
+      "description": "generate code with [go generate](https://go.dev/blog/generate)",
+      "variables": [
+        {
+          "name": "GO_GENERATE_MODULES",
+          "description": "Space separated list of Go code generator modules (ex: `stringer mockery`)",
+          "mandatory": true
+        }
+      ]
+    },
     {
       "id": "golangci-lint",
       "name": "GolangCI-Lint",
diff --git a/templates/gitlab-ci-golang.yml b/templates/gitlab-ci-golang.yml
index 690e85d..dc0660b 100644
--- a/templates/gitlab-ci-golang.yml
+++ b/templates/gitlab-ci-golang.yml
@@ -28,6 +28,9 @@ spec:
     test-image:
       description: Specific Docker image used to run Go tests (as a separate job)
       default: ''
+    generate-modules:
+      description: "Space separated list of Go code generator modules (ex: `stringer mockery`)"
+      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
@@ -148,6 +151,8 @@ variables:
   # Default Docker image (can be overridden)
   GO_IMAGE: $[[ inputs.image ]]
 
+  GO_GENERATE_MODULES: $[[ inputs.generate-modules ]]
+
   # Default flags for 'build' command
   GO_BUILD_FLAGS: $[[ inputs.build-flags ]]
 
@@ -476,6 +481,24 @@ stages:
     - install_ca_certs "${CUSTOM_CA_CERTS:-$DEFAULT_CA_CERTS}"
     - cd ${GO_PROJECT_DIR}
 
+go-generate:
+  extends: .go-base
+  stage: .pre
+  script:
+    - go install $GO_GENERATE_MODULES
+    - go generate
+  rules:
+    # only if $GO_GENERATE_MODULES is set
+    - if: '$GO_GENERATE_MODULES != null && $GO_GENERATE_MODULES != ""'
+  artifacts:
+    name: "$CI_JOB_NAME artifacts from $CI_PROJECT_NAME on $CI_COMMIT_REF_SLUG"
+    expire_in: 1 day
+    # default captured paths; otherwise has to be overwritten
+    paths:
+      - "${GO_PROJECT_DIR}/**/mock/"
+      - "${GO_PROJECT_DIR}/**/mocks/"
+      - "${GO_PROJECT_DIR}/**/*mock*.go"
+
 go-build:
   extends: .go-base
   stage: build
-- 
GitLab