Skip to content
Back to skills

Gen Gitlab Ci

ASecurity

Generate GitLab CI/CD pipeline configuration for Go projects with testing, coverage, and automated releases

  • 16 stars
  • 0 votes
  • 0 copies
  • 0 views
  • Added September 25, 2026
developmentgobashdockerkubernetestestinggitci/cddocumentation

Works with

  • claude code
  • cli

Security analysis

A100/100

Scanned September 25, 2026

npx -y skills add sgaunet/claude-plugins --skill gen-gitlab-ci --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Gen Gitlab Ci?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Gen Gitlab Ci
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/sgaunet-gen-gitlab-ci/badge)](https://www.skillsdirectory.com/skills/sgaunet-gen-gitlab-ci)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: gen-gitlab-ci
description: Generate GitLab CI/CD pipeline configuration for Go projects with testing, coverage, and automated releases
argument-hint: "[--force] [--dry-run]"
user-invocable: true
disable-model-invocation: true
allowed-tools: Read, Write, Bash(git:*), Bash(test:*), AskUserQuestion
---

# Generate GitLab CI Configuration

Instantly create a `.gitlab-ci.yml` file for Go projects with a production-ready, **mise-based** GitLab CI/CD pipeline including unit tests, linting, optional coverage reporting, snapshot builds, and automated releases.

## Why This Skill Exists

**Problem**: Setting up GitLab CI/CD for Go projects requires manually creating pipeline configuration, understanding GitLab CI syntax, and keeping tool versions in sync between local development and CI - a 30-45 minute process.

**Solution**: One-command generation that:
- Creates a complete `.gitlab-ci.yml` configuration (mise-based)
- Runs every job in the `jdx/mise:latest` image, installs tools via `mise install`, then runs `task …` — so CI uses the exact versions pinned in `mise.toml`
- Ensures a `mise.toml` exists at the repo root (creates one with detected versions if missing) — the single source of truth shared with local dev
- Includes a pipeline: unit tests, linter, snapshot builds, releases (+ optional coverage)
- Keeps Docker-in-Docker image publishing as a clearly-marked optional block
- Preserves all customization comments for user control

## Content Generation Rules

**CRITICAL**: When generating any content (pipeline files, commit messages, or any other output):
- **NEVER** add Claude Code attribution or co-authorship
- **NEVER** include phrases like "Generated by Claude", "Created with Claude Code", or similar
- **NEVER** add "Co-Authored-By: Claude" in commit messages or documentation
- All generated content should appear as if written by a human developer
- Focus on technical accuracy and providing working templates

## Process (6 Phases)

### Phase 1: Prerequisites Validation

**Critical checks before proceeding:**

1. **Validate Git repository:**
   ```bash
   git rev-parse --git-dir
   ```
   - If fails: Exit with error "Not a git repository. Run 'git init' first."

2. **Validate Go project:**
   ```bash
   test -f go.mod
   ```
   - If fails: Exit with error "go.mod not found. This skill is for Go projects only."

3. **Check existing .gitlab-ci.yml:**
   ```bash
   test -f .gitlab-ci.yml
   ```
   - If exists: Store `existingGitlabCi = true`
   - If not exists: Store `existingGitlabCi = false`

4. **Verify skill assets directory:**
   - Use Read tool to verify `${CLAUDE_PLUGIN_ROOT}/assets/gitlab-ci/.gitlab-ci.yml` exists
   - Use Read tool to verify `${CLAUDE_PLUGIN_ROOT}/assets/mise/mise.toml` exists
   - If either fails: Exit with error "Skill assets directory not found at ${CLAUDE_PLUGIN_ROOT}/assets/. Plugin may be corrupted. Reinstall the go-specialist plugin."

5. **Check for .goreleaser.yml (non-blocking):**
   ```bash
   test -f .goreleaser.yml
   ```
   - If missing: Store `goreleaserMissing = true` (warn in Phase 6, don't block creation)
   - If exists: Store `goreleaserMissing = false`

6. **Check existing mise.toml:**
   ```bash
   test -f mise.toml
   ```
   - Store `existingMise = true|false`. The pipeline depends on `mise.toml`; if it
     is missing this skill creates one (Phase 3.5). An existing one is preserved.

### Phase 2: Argument Parsing

Parse skill arguments from `$argument` string:

**Supported flags:**
- `--force`: Skip confirmation for existing .gitlab-ci.yml
- `--dry-run`: Show preview without writing file

**Parsing logic:**
```
arguments = split($argument by space)
for each arg in arguments:
  if arg == "--force": set forceMode = true
  if arg == "--dry-run": set dryRunMode = true
```

**No minimal mode:** The template is already compact with comprehensive coverage.

### Phase 3: Template Reading

**Read template file** from skill assets directory:

**Files to read:**

1. **.gitlab-ci.yml**
   - Path: `${CLAUDE_PLUGIN_ROOT}/assets/gitlab-ci/.gitlab-ci.yml`
   - Target: `.gitlab-ci.yml` (project root)

2. **mise.toml** [Only if `existingMise == false`]
   - Path: `${CLAUDE_PLUGIN_ROOT}/assets/mise/mise.toml`
   - Target: `mise.toml` (repo root)

**Template handling:**
- Store content in memory for Phase 3.5 substitution
- The `.gitlab-ci.yml` template is **static** apart from the runner `tags:` —
  tool versioning lives in `mise.toml`.
- Preserve all `# CUSTOMIZE:` comments

**Error handling:**
- If Read fails: Exit with error "Failed to read template file. Plugin may be corrupted."

### Phase 3.5: Auto-Detection & Substitution

**Detection Function Library:** Use the shared detection functions from `${CLAUDE_PLUGIN_ROOT}/assets/detection-functions.md`. Read that file to get the bash detection functions (`detect_go_version`, `detect_golangci_lint_version`, `detect_goreleaser_version`, `strip_leading_v`, `substitute_version_placeholders`).

**Detection Workflow:**

1. **The `.gitlab-ci.yml` template needs no version substitution.** Every job runs
   in the `jdx/mise:latest` image and installs tools via `mise install`, so tool
   versions come from `mise.toml`, not the pipeline YAML. The only thing to review
   is the runner `tags:` (see customizations).

2. **Ensure `mise.toml` exists (create if missing):**
   ```bash
   if [[ "$existingMise" != "true" ]]; then
       GO_VERSION=$(detect_go_version)
       GOLANGCI_LINT_VERSION=$(detect_golangci_lint_version)
       GORELEASER_VERSION=$(detect_goreleaser_version)
       GOLANGCI_LINT_VERSION_BARE=$(strip_leading_v "${GOLANGCI_LINT_VERSION:-v2.2.2}")

       mise_template=$(substitute_version_placeholders "$mise_template" \
           "GO_VERSION=${GO_VERSION:-1.25}" \
           "GOLANGCI_LINT_VERSION_BARE=${GOLANGCI_LINT_VERSION_BARE:-2.2.2}" \
           "GORELEASER_VERSION=${GORELEASER_VERSION:-v2.12.0}")
       # Written in Phase 5.
   fi
   ```
   - If `existingMise == true`: do NOT modify the existing `mise.toml`; note it in the report.

### Phase 4: User Confirmation

**Build preview summary:**

```
File to be created:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
✅ .gitlab-ci.yml

Pipeline Structure (mise-based):
- 2 Stages: test, release
- Jobs (each runs in jdx/mise:latest, `mise install`, then `task ...`):
  • unit-tests: `task test` on every push
  • linter: `task lint` on every push
  • build-snapshot: `task snapshot` (test release, no publish)
  • build-release: `task release` on Git tags
  • coverage: Optional (currently commented out)

[If existingMise == false:]
✅ mise.toml (created — pins go/task/golangci-lint/goreleaser for dev + CI)
[If existingMise == true:]
ℹ️  mise.toml already exists — preserved (pipeline will use it as-is)

[If existingGitlabCi == true:]
⚠️  WARNING: .gitlab-ci.yml already exists and will be overwritten

[If goreleaserMissing == true:]
⚠️  NOTE: .goreleaser.yml not found
    The snapshot/release jobs require this file to function.
    Generate with: /gen-goreleaser
```

**Dry run mode:**
If `dryRunMode == true`:
- Show preview summary above
- Display first 30 lines of .gitlab-ci.yml
- Show customization requirements
- Display next steps guide
- Exit without creating file

**Confirmation logic:**

1. **If `--force` flag provided:** Skip confirmation, proceed to Phase 5

2. **If existing .gitlab-ci.yml without `--force`:**
   ```
   Use AskUserQuestion:
   Question: ".gitlab-ci.yml already exists. Overwrite existing pipeline configuration?"
   Options:
   1. "Yes, overwrite file" [Recommended if upgrading pipeline]
   2. "Show full preview first"
   3. "Cancel"

   If option 2: Display full content preview, then re-ask confirmation
   If option 3: Exit gracefully
   ```

3. **If no .gitlab-ci.yml exists:**
   ```
   Use AskUserQuestion:
   Question: "Create .gitlab-ci.yml at project root?"
   Options:
   1. "Yes, create file"
   2. "Show preview first"
   3. "Cancel"
   ```

### Phase 5: File Creation

**File writing:**

1. `mise.toml` [Only if `existingMise == false`]
   - Use Write tool with file path: `mise.toml`
   - Write the version-substituted template from Phase 3.5
   - If `existingMise == true`: skip (preserve the project's existing tool pins)

2. `.gitlab-ci.yml`
   - Use Write tool with file path: `.gitlab-ci.yml`
   - Write content from Phase 3 (static apart from runner tags)
   - Track success/failure status

**Error handling:**
- If a write fails: Report the error (continue if at least `.gitlab-ci.yml` succeeds)
- If successful: Proceed to Phase 6 validation

### Phase 6: Validation & Success Report

**Post-creation validation:** confirm `.gitlab-ci.yml` exists and is non-zero; on failure
report the error and exit.

**Report to the user** — cover these facts; no fixed layout required:

- **Files written:** `.gitlab-ci.yml`, and `mise.toml` marked as created vs. preserved.
- **Pipeline structure:** 2 stages (test, release). Every job runs `jdx/mise:latest` →
  `mise install` → `task ...`: `unit-tests` (`task test`) and `linter` (`task lint`) on every
  push, `build-snapshot` (`task snapshot`, no publish), `build-release` (`task release`) on
  git tags, and `coverage` (commented out by default).
- **Detected values:** if `mise.toml` was created, the pinned Go version (from go.mod),
  golangci-lint version and goreleaser version.
- **Required customization — PRIORITY 1, the pipeline will not run without it:** replace
  `tags: [gitlab-org-docker]` on every job with the project's own runner tags, found under
  GitLab Settings → CI/CD → Runners (commonly `docker`, `linux`, `kubernetes`).
- **Other customizations:** tool versions live in `mise.toml`, not the pipeline YAML —
  editing it changes both local (`mise install`) and CI versions. The `coverage:` job can be
  uncommented (with coverage exclusions configured if needed). To publish Docker images,
  uncomment the docker tools (buildx, docker-cli) in `mise.toml` and the `.docker-dind` block
  in `.gitlab-ci.yml`, then `extends:` it from the release jobs — it authenticates with
  `CI_REGISTRY` / `CI_JOB_TOKEN`.
- **GoReleaser status:** if `.goreleaser.yml` exists, say the release jobs are ready. If it
  is missing, warn that `build-snapshot` and `build-release` will both fail, and point at
  `/gen-goreleaser` or https://goreleaser.com/quick-start/.
- **Troubleshooting:** "No such runner tags: gitlab-org-docker" → update the runner tags
  (check Settings → CI/CD → Runners). "goreleaser: config file not found" → generate
  `.goreleaser.yml` with `/gen-goreleaser`. "task/mise: command not found" → jobs run in
  `jdx/mise:latest` and call `mise install` in `before_script`, so `mise.toml` must exist at
  the repo root (this skill creates it). "Docker login failed" (only with the optional
  docker block) → enable the Container Registry under Settings → General → Visibility and
  confirm `.docker-dind` is uncommented and extended by the release jobs.
- **Next steps:** review `.gitlab-ci.yml` (runner tags) and `mise.toml` (versions), ensure
  `.goreleaser.yml` exists, then `git add .gitlab-ci.yml mise.toml` and
  `git commit -m "ci: add mise-based GitLab CI/CD pipeline"`, `git push origin main`, and
  confirm the pipeline runs under CI/CD → Pipelines.
- **Docs:** inline comments in `.gitlab-ci.yml` · `/gen-goreleaser` for `.goreleaser.yml` ·
  runner configuration under GitLab Settings → CI/CD → Runners.

**On failure:** report which files were written, which failed and why, and that `--force`
retries. Partial success is a warning, total failure an error — for a total failure also
name the likely causes (permissions, disk space, filesystem restrictions).

## Arguments

Arguments are parsed from the `argument` string parameter:

- **`--force`**: Skip confirmation prompt and overwrite existing file
  - Use when: Upgrading existing pipeline to latest template
  - Behavior: Overwrites .gitlab-ci.yml directly without confirmation

- **`--dry-run`**: Preview file without writing to disk
  - Shows: File preview, pipeline structure, customization requirements
  - Writes: Nothing
  - Use when: Reviewing what will be created before committing

**Parsing example:**
```
argument = "--force"
Split by space, check for each flag:
- forceMode = true
- dryRunMode = false
```

## Error Handling

### Critical Errors (Exit Immediately)

**Not a Git repository:**
```
❌ Error: Not a git repository

This skill requires a Git repository. Initialize one:
  git init
  git add .
  git commit -m "Initial commit"
```

**Not a Go project:**
```
❌ Error: go.mod not found

This skill is for Go projects only. Initialize a Go module:
  go mod init gitlab.com/username/project
```

**Skill assets missing:**
```
❌ Error: Skill assets directory not found

The go-specialist plugin may be corrupted. Try:
1. Reinstalling the plugin
2. Updating Claude Code to latest version
3. Reporting issue at: https://github.com/sgaunet/claude-plugins/issues
```

### Warning Errors (Continue with Warnings)

**Existing .gitlab-ci.yml:**
- Without `--force`: Request user confirmation
- With `--force`: Overwrite silently

**Missing .goreleaser.yml:**
- Don't block creation
- Warn in success report
- Suggest using the `/gen-goreleaser` skill

### Recovery Actions

**If file write fails:**
```
❌ Error: Failed to write .gitlab-ci.yml

Check:
1. Current directory is writable
2. Sufficient disk space
3. No file system restrictions

Current permissions: [show with ls -ld .]
```

## File Mapping

| Source Path | Target (Relative to CWD) | Mode |
|-------------|--------------------------|------|
| `${CLAUDE_PLUGIN_ROOT}/assets/gitlab-ci/.gitlab-ci.yml` | `.gitlab-ci.yml` | Always |
| `${CLAUDE_PLUGIN_ROOT}/assets/mise/mise.toml` | `mise.toml` | Create-if-missing |

## Integration with Other Skills

**Works with:**
- `/commit`: Commit generated .gitlab-ci.yml
- `/gen-goreleaser`: Generate .goreleaser.yml config (required for release/snapshot jobs)
- `/create-issue`: Create issue to track customization tasks

**Typical Workflow:**
```bash
# 1. Generate dev tooling first (Taskfile.yml + mise.toml)
/gen-taskfiles

# 2. Generate GitLab CI configuration (reuses mise.toml; creates it if missing)
/gen-gitlab-ci

# 3. Generate GoReleaser config (required)
/gen-goreleaser

# 4. Customize files
# Edit .gitlab-ci.yml: Update runner tags
# Edit mise.toml: Adjust tool versions if needed

# 5. Commit everything
git add .gitlab-ci.yml mise.toml Taskfile*.yml .goreleaser.yml
git commit -m "ci: add mise-based GitLab CI/CD pipeline"

# 5. Push and verify
git push origin main
# Check: GitLab → CI/CD → Pipelines
```

## Prerequisites for Pipeline

**Required for pipeline to function:**

1. **mise.toml** (auto-created by this skill if missing):
   - Pins the tool versions installed via `mise install` in every job
   - Managed canonically by `/gen-taskfiles`

2. **Taskfile.yml** with `test`, `lint`, `snapshot`, `release` tasks:
   - Generate with `/gen-taskfiles` (also emits mise.toml)

3. **.goreleaser.yml** configuration:
   - Generate with `/gen-goreleaser` (required for build-snapshot and build-release)

4. **GitLab Runner** that can run container images:
   - Update runner tags in .gitlab-ci.yml (one per job)
   - Check available runners: Settings → CI/CD → Runners
   - Docker-in-Docker is only needed if you enable the optional image-publishing block

**Optional enhancements:**

1. **Coverage reporting:**
   - Uncomment the `coverage:` job in .gitlab-ci.yml
   - Configure coverage badge in README.md

2. **Docker image publishing:**
   - Uncomment the docker tools in mise.toml (buildx, docker-cli)
   - Uncomment the `.docker-dind` block and `extends:` it from the release jobs

3. **Custom tag patterns:**
   - Edit build-release job in .gitlab-ci.yml
   - Adjust `rules: - if: $CI_COMMIT_TAG` to filter specific tag patterns

## Template Customization Points

All template files include `# CUSTOMIZE:` comments marking required changes:

**mise.toml:**
- Tool versions (`go`, `golangci-lint`, `goreleaser`) → adjust as needed (used by dev + CI)
- Docker tools (`buildx`, `docker-cli`) → uncomment if publishing images

**.gitlab-ci.yml:**
- `tags: [gitlab-org-docker]` (one per job) → Replace with your runner tags
- `coverage:` job → Uncomment to enable (configure exclusions if needed)
- `.docker-dind` block → Uncomment + `extends:` from release jobs to publish images
- Tag filtering → Adjust the `rules:` in the build-release job

## Best Practices

**Before running this skill:**
1. Ensure git repository initialized
2. Have go.mod configured
3. Review pipeline configuration inline comments in template
4. Check available GitLab Runners and their tags

**After generation:**
1. Review all `# CUSTOMIZE:` comments in .gitlab-ci.yml
2. Generate .goreleaser.yml with the `/gen-goreleaser` skill
3. Update runner tags (most critical customization)
4. Update Go version to match your project
5. Commit with meaningful message
6. Monitor first pipeline run for errors

**Ongoing maintenance:**
1. Keep GoReleaser version updated
2. Review pipeline efficiency and optimize as needed
3. Adjust coverage thresholds as codebase matures
4. Add custom pipeline jobs as project needs evolve

## Limitations

**This skill does NOT:**
- Generate .goreleaser.yml (use `/gen-goreleaser` skill)
- Generate Taskfile.yml (use `/gen-taskfiles`, which also manages mise.toml)
- Modify an existing mise.toml (it is preserved; only created when missing)
- Modify existing .gitlab-ci.yml intelligently (use `--force` to overwrite)
- Validate that pipeline will work (requires proper runner setup)
- Configure GitLab repository settings (must be done via UI)
- Create GitLab Runners (requires infrastructure setup)

**Scope boundaries:**
- Handles `.gitlab-ci.yml` (and creates mise.toml when missing)
- Template is opinionated (aligned with Go best practices)
- Assumes standard Go project structure
- Requires manual customization post-generation (runner tags)
- Docker-in-Docker only required if you enable the optional image-publishing block

## Examples

```bash
# Standard generation
/gen-gitlab-ci

# Preview before creating
/gen-gitlab-ci --dry-run

# Overwrite existing pipeline
/gen-gitlab-ci --force

# Force with dry run (preview what would be overwritten)
/gen-gitlab-ci --force --dry-run
```

## Output Summary

**Standard mode (default):**
- .gitlab-ci.yml + mise.toml (if missing)
- Comprehensive, mise-based CI/CD pipeline (test + release stages)

**Dry run mode (`--dry-run`):**
- 0 files created
- Preview shown
- Safe exploration

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.