methodology-m 0.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/m.mjs +76 -0
- package/dist-m/CHANGELOG.md +45 -0
- package/dist-m/capabilities/bootstrap-root-repo/SKILL.md +138 -0
- package/dist-m/capabilities/decompose-story/SKILL.md +299 -0
- package/dist-m/capabilities/generate-acceptance-tests/SKILL.md +305 -0
- package/dist-m/capabilities/generate-pats/SKILL.md +131 -0
- package/dist-m/capabilities/scaffold-repo/SKILL.md +641 -0
- package/dist-m/capabilities/setup-workspace/SKILL.md +70 -0
- package/dist-m/capabilities/tag-release/SKILL.md +121 -0
- package/dist-m/capabilities/wire-orchestration/SKILL.md +351 -0
- package/dist-m/m.md +126 -0
- package/dist-m/providers/provider-interface.md +191 -0
- package/dist-m/providers/scm/gitlab.md +377 -0
- package/dist-m/schemas/pat.schema.json +161 -0
- package/dist-m/schemas/project.schema.json +177 -0
- package/package.json +27 -0
- package/src/commands/changelog.mjs +58 -0
- package/src/commands/clone.mjs +199 -0
- package/src/commands/diff.mjs +29 -0
- package/src/commands/init.mjs +51 -0
- package/src/commands/update.mjs +41 -0
- package/src/commands/version.mjs +43 -0
- package/src/lib/copy.mjs +20 -0
- package/src/lib/detect-agent.mjs +25 -0
- package/src/lib/diff-trees.mjs +95 -0
- package/src/lib/topology.mjs +62 -0
- package/src/lib/version-file.mjs +25 -0
- package/src/lib/workspace.mjs +40 -0
- package/src/lib/wrappers/claude.mjs +54 -0
- package/templates/claude/skills/bootstrap-root-repo/SKILL.md +13 -0
- package/templates/claude/skills/decompose-story/SKILL.md +13 -0
- package/templates/claude/skills/generate-acceptance-tests/SKILL.md +13 -0
- package/templates/claude/skills/generate-pats/SKILL.md +13 -0
- package/templates/claude/skills/scaffold-repo/SKILL.md +13 -0
- package/templates/claude/skills/setup-workspace/SKILL.md +13 -0
- package/templates/claude/skills/tag-release/SKILL.md +13 -0
- package/templates/claude/skills/wire-orchestration/SKILL.md +13 -0
- package/templates/claude/steering/m-steering.md +3 -0
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
# Provider Interface
|
|
2
|
+
|
|
3
|
+
This document defines the function namespaces that M capabilities call,
|
|
4
|
+
and the protocol for resolving those calls to concrete implementations.
|
|
5
|
+
|
|
6
|
+
## Resolution Protocol
|
|
7
|
+
|
|
8
|
+
1. Capability calls a namespaced function, e.g. `scm.create_repo(...)`
|
|
9
|
+
2. The namespace prefix (`scm`) identifies the provider category
|
|
10
|
+
3. `project.yaml` declares which provider is active per category:
|
|
11
|
+
```yaml
|
|
12
|
+
providers:
|
|
13
|
+
scm: gitlab
|
|
14
|
+
```
|
|
15
|
+
4. The agent reads `.m/providers/<category>/<provider>.md` to find the
|
|
16
|
+
function's concrete implementation (API calls, MCP tools, CLI commands)
|
|
17
|
+
5. The agent executes the concrete implementation
|
|
18
|
+
|
|
19
|
+
Config resolution for the provider choice itself follows the standard
|
|
20
|
+
M hierarchy:
|
|
21
|
+
|
|
22
|
+
```
|
|
23
|
+
Repo-level override → Project-level (project.yaml) → Org Config → M Core Config
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
## Namespaces
|
|
27
|
+
|
|
28
|
+
### `scm` — Source Code Management
|
|
29
|
+
|
|
30
|
+
Repo and project lifecycle, branch protection, webhooks, CI secrets,
|
|
31
|
+
and commit status reporting.
|
|
32
|
+
|
|
33
|
+
**Active providers:** `gitlab` (reference implementation)
|
|
34
|
+
|
|
35
|
+
#### Functions
|
|
36
|
+
|
|
37
|
+
| Function | Parameters | Returns | Used by |
|
|
38
|
+
|---|---|---|---|
|
|
39
|
+
| `scm.create_group` | `name`, `path`, `visibility`, `description`, `parent_id?` | group ID | setup-workspace |
|
|
40
|
+
| `scm.resolve_group_id` | `group_path` | group ID | setup-workspace |
|
|
41
|
+
| `scm.resolve_project_id` | `project_path` | project ID | wire-orchestration |
|
|
42
|
+
| `scm.create_repo` | `name`, `namespace_id`, `initialize_readme` | repo URL, project ID | bootstrap-root-repo, scaffold-repo |
|
|
43
|
+
| `scm.push_files` | `repo`, `branch`, `files[]`, `commit_message` | commit SHA | bootstrap-root-repo, scaffold-repo |
|
|
44
|
+
| `scm.create_or_update_file` | `repo`, `path`, `content`, `commit_message`, `branch` | commit SHA | scaffold-repo (re-run) |
|
|
45
|
+
| `scm.protect_branch` | `repo`, `branch`, `push`, `merge`, `force_push` | — | scaffold-repo, wire-orchestration |
|
|
46
|
+
| `scm.create_access_token` | `repo`, `name`, `scopes[]`, `access_level`, `expiry` | token value | scaffold-repo |
|
|
47
|
+
| `scm.create_pipeline_trigger` | `repo`, `description` | trigger token | wire-orchestration |
|
|
48
|
+
| `scm.create_webhook` | `repo`, `url`, `events{}`, `ssl_verify` | webhook ID | wire-orchestration |
|
|
49
|
+
| `scm.store_ci_secret` | `repo`, `key`, `value`, `protected`, `masked` | — | wire-orchestration |
|
|
50
|
+
| `scm.post_commit_status` | `repo`, `sha`, `state`, `name`, `description`, `target_url` | — | wire-orchestration (CI scripts) |
|
|
51
|
+
| `scm.create_branch` | `repo`, `branch`, `ref` | — | decompose-story |
|
|
52
|
+
| `scm.create_merge_request` | `repo`, `source_branch`, `target_branch`, `title`, `description?` | MR URL | decompose-story |
|
|
53
|
+
|
|
54
|
+
#### Function Contracts
|
|
55
|
+
|
|
56
|
+
**`scm.create_group(name, path, visibility, description, parent_id?)`**
|
|
57
|
+
|
|
58
|
+
Create a group/org on the SCM platform. If `parent_id` is provided,
|
|
59
|
+
creates a subgroup. Returns the group ID.
|
|
60
|
+
|
|
61
|
+
---
|
|
62
|
+
|
|
63
|
+
**`scm.resolve_group_id(group_path)`**
|
|
64
|
+
|
|
65
|
+
Resolve a human-readable group path (e.g. `methodology-m`) to the
|
|
66
|
+
platform's internal group ID. Needed when other functions require
|
|
67
|
+
numeric IDs.
|
|
68
|
+
|
|
69
|
+
---
|
|
70
|
+
|
|
71
|
+
**`scm.resolve_project_id(project_path)`**
|
|
72
|
+
|
|
73
|
+
Resolve a project path (e.g. `methodology-m/todo-m-workshop/todo-m-api-read`)
|
|
74
|
+
to the platform's internal project ID.
|
|
75
|
+
|
|
76
|
+
---
|
|
77
|
+
|
|
78
|
+
**`scm.create_repo(name, namespace_id, initialize_readme)`**
|
|
79
|
+
|
|
80
|
+
Create a new repository. `initialize_readme` MUST default to `false` —
|
|
81
|
+
M capabilities seed repos with their own initial commit. A platform
|
|
82
|
+
default README causes merge conflicts with the seed.
|
|
83
|
+
|
|
84
|
+
---
|
|
85
|
+
|
|
86
|
+
**`scm.push_files(repo, branch, files[], commit_message)`**
|
|
87
|
+
|
|
88
|
+
Push multiple files in a single atomic commit. Each file entry contains
|
|
89
|
+
`path` and `content`. Fails if any file already exists on the branch —
|
|
90
|
+
use `scm.create_or_update_file()` for idempotent writes.
|
|
91
|
+
|
|
92
|
+
---
|
|
93
|
+
|
|
94
|
+
**`scm.create_or_update_file(repo, path, content, commit_message, branch)`**
|
|
95
|
+
|
|
96
|
+
Create or overwrite a single file. Idempotent — safe for re-runs on
|
|
97
|
+
partially seeded repos.
|
|
98
|
+
|
|
99
|
+
---
|
|
100
|
+
|
|
101
|
+
**`scm.protect_branch(repo, branch, push, merge, force_push)`**
|
|
102
|
+
|
|
103
|
+
Set branch protection rules. M requires:
|
|
104
|
+
- `push: none` — no direct pushes, all changes via MR/PR
|
|
105
|
+
- `merge: maintainer` — only maintainer-level can merge
|
|
106
|
+
- `force_push: false`
|
|
107
|
+
|
|
108
|
+
The provider implementation must handle platform quirks (e.g. removing
|
|
109
|
+
existing protection before applying new rules).
|
|
110
|
+
|
|
111
|
+
---
|
|
112
|
+
|
|
113
|
+
**`scm.create_access_token(repo, name, scopes[], access_level, expiry)`**
|
|
114
|
+
|
|
115
|
+
Create a scoped token for automated operations on this repo. Used by
|
|
116
|
+
the merge transaction pipeline. Token value is returned once and must
|
|
117
|
+
be stored immediately via `scm.store_ci_secret()`.
|
|
118
|
+
|
|
119
|
+
Provider must document fallback options for platforms/tiers where
|
|
120
|
+
per-repo tokens are unavailable.
|
|
121
|
+
|
|
122
|
+
---
|
|
123
|
+
|
|
124
|
+
**`scm.create_pipeline_trigger(repo, description)`**
|
|
125
|
+
|
|
126
|
+
Create a trigger mechanism that external webhooks can use to start
|
|
127
|
+
CI pipelines on this repo. Returns a token or URL.
|
|
128
|
+
|
|
129
|
+
---
|
|
130
|
+
|
|
131
|
+
**`scm.create_webhook(repo, url, events{}, ssl_verify)`**
|
|
132
|
+
|
|
133
|
+
Install a webhook on a repo. `events` specifies which events fire
|
|
134
|
+
the webhook. For M, only MR/PR events should trigger — push events
|
|
135
|
+
MUST be explicitly disabled.
|
|
136
|
+
|
|
137
|
+
---
|
|
138
|
+
|
|
139
|
+
**`scm.store_ci_secret(repo, key, value, protected, masked)`**
|
|
140
|
+
|
|
141
|
+
Store a secret as a CI environment variable on a repo. `protected`
|
|
142
|
+
means only available on protected branches. `masked` means hidden
|
|
143
|
+
in job logs.
|
|
144
|
+
|
|
145
|
+
---
|
|
146
|
+
|
|
147
|
+
**`scm.post_commit_status(repo, sha, state, name, description, target_url)`**
|
|
148
|
+
|
|
149
|
+
Report a build/test status on a specific commit. Used by shadow
|
|
150
|
+
integration to push results back to managed repo MRs. `state` is
|
|
151
|
+
one of: `success`, `failed`, `pending`.
|
|
152
|
+
|
|
153
|
+
---
|
|
154
|
+
|
|
155
|
+
**`scm.create_branch(repo, branch, ref)`**
|
|
156
|
+
|
|
157
|
+
Create a new branch from an existing ref (branch, tag, or SHA).
|
|
158
|
+
Used by `decompose-story` to create the root repo's story branch
|
|
159
|
+
for the integration gate.
|
|
160
|
+
|
|
161
|
+
---
|
|
162
|
+
|
|
163
|
+
**`scm.create_merge_request(repo, source_branch, target_branch, title, description?)`**
|
|
164
|
+
|
|
165
|
+
Create a merge request / pull request. Returns the MR URL. Used by
|
|
166
|
+
`decompose-story` to raise the root repo MR that establishes the
|
|
167
|
+
integration gate from the moment the story is decomposed.
|
|
168
|
+
|
|
169
|
+
---
|
|
170
|
+
|
|
171
|
+
## Adding a New Namespace
|
|
172
|
+
|
|
173
|
+
When a new provider category is needed (e.g. `test.cat.*`):
|
|
174
|
+
|
|
175
|
+
1. Add the namespace to this document with its function signatures
|
|
176
|
+
2. Create a provider implementation at `.m/providers/<category>/<provider>.md`
|
|
177
|
+
3. Add the category to `project.yaml` under `providers:`
|
|
178
|
+
4. Update capabilities to use the new namespaced functions
|
|
179
|
+
|
|
180
|
+
## Adding a New Provider
|
|
181
|
+
|
|
182
|
+
To implement an existing namespace for a new platform (e.g. `scm/github`):
|
|
183
|
+
|
|
184
|
+
1. Create `.m/providers/<category>/<provider>.md`
|
|
185
|
+
2. Implement every function listed in the namespace's contract above
|
|
186
|
+
3. Document all platform-specific gotchas in the provider file
|
|
187
|
+
4. The provider is selectable via `project.yaml`:
|
|
188
|
+
```yaml
|
|
189
|
+
providers:
|
|
190
|
+
scm: github
|
|
191
|
+
```
|
|
@@ -0,0 +1,377 @@
|
|
|
1
|
+
# SCM Provider: GitLab
|
|
2
|
+
|
|
3
|
+
Implementation of the `scm.*` functions for GitLab. This is the reference
|
|
4
|
+
provider — the one used by the reference implementation (todo-m-workshop).
|
|
5
|
+
|
|
6
|
+
When executing M capabilities against GitLab, read this file to understand
|
|
7
|
+
how each `scm.*` function maps to GitLab API calls and MCP tools.
|
|
8
|
+
|
|
9
|
+
## MCP tools
|
|
10
|
+
|
|
11
|
+
This provider uses two GitLab MCP servers:
|
|
12
|
+
- `gitlab_ops` — project/group management, branch protection, webhooks, tokens
|
|
13
|
+
- `gitlab` — file operations, commits, MR management
|
|
14
|
+
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
## scm.create_group
|
|
18
|
+
|
|
19
|
+
Create a GitLab group or subgroup.
|
|
20
|
+
|
|
21
|
+
```
|
|
22
|
+
MCP: gitlab_ops
|
|
23
|
+
Tool: mcp_gitlab_ops_create_group
|
|
24
|
+
|
|
25
|
+
Parameters:
|
|
26
|
+
name: <name>
|
|
27
|
+
path: <path>
|
|
28
|
+
visibility: <visibility>
|
|
29
|
+
description: <description>
|
|
30
|
+
parent_id: <parent_id> # omit for top-level group
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
**Gotchas:**
|
|
34
|
+
- **GitLab.com SaaS:** Top-level group creation via API is disabled.
|
|
35
|
+
Create parent group manually via UI, then use `parent_id` for subgroup.
|
|
36
|
+
- **GitLab Self-Managed:** Both top-level and subgroup creation work via API.
|
|
37
|
+
|
|
38
|
+
---
|
|
39
|
+
|
|
40
|
+
## scm.resolve_group_id
|
|
41
|
+
|
|
42
|
+
Resolve a group path (e.g. `methodology-m`) to a numeric group ID.
|
|
43
|
+
|
|
44
|
+
```
|
|
45
|
+
MCP: gitlab_ops
|
|
46
|
+
Tool: mcp_gitlab_ops_get_group
|
|
47
|
+
|
|
48
|
+
Parameters:
|
|
49
|
+
group_path: <path>
|
|
50
|
+
|
|
51
|
+
Returns: group.id
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
---
|
|
55
|
+
|
|
56
|
+
## scm.resolve_project_id
|
|
57
|
+
|
|
58
|
+
Resolve a project path (e.g. `methodology-m/todo-m-workshop/todo-m-api-read`)
|
|
59
|
+
to a numeric project ID.
|
|
60
|
+
|
|
61
|
+
```
|
|
62
|
+
MCP: gitlab_ops
|
|
63
|
+
Tool: mcp_gitlab_ops_get_project
|
|
64
|
+
|
|
65
|
+
Parameters:
|
|
66
|
+
project_path: <path>
|
|
67
|
+
|
|
68
|
+
Returns: project.id
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
---
|
|
72
|
+
|
|
73
|
+
## scm.create_repo
|
|
74
|
+
|
|
75
|
+
Create a new GitLab project (repo) in a namespace.
|
|
76
|
+
|
|
77
|
+
```
|
|
78
|
+
MCP: gitlab_ops
|
|
79
|
+
Tool: mcp_gitlab_ops_create_project
|
|
80
|
+
|
|
81
|
+
Parameters:
|
|
82
|
+
name: <name>
|
|
83
|
+
namespace_id: <namespace_id>
|
|
84
|
+
initialize_with_readme: false # CRITICAL — see note
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
**Gotchas:**
|
|
88
|
+
- Do NOT set `initialize_with_readme: true`. The seed commit in the
|
|
89
|
+
capability includes a project-specific README. Initialising with
|
|
90
|
+
GitLab's default README causes a conflict when pushing seed files.
|
|
91
|
+
|
|
92
|
+
---
|
|
93
|
+
|
|
94
|
+
## scm.push_files
|
|
95
|
+
|
|
96
|
+
Push multiple files in a single commit to a repo.
|
|
97
|
+
|
|
98
|
+
```
|
|
99
|
+
MCP: gitlab
|
|
100
|
+
Tool: mcp_gitlab_push_files
|
|
101
|
+
|
|
102
|
+
Parameters:
|
|
103
|
+
project_id: <project_id>
|
|
104
|
+
branch: <branch>
|
|
105
|
+
commit_message: <message>
|
|
106
|
+
files: [
|
|
107
|
+
{ file_path: <path>, content: <content> },
|
|
108
|
+
...
|
|
109
|
+
]
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
**Gotchas:**
|
|
113
|
+
- `push_files` rejects commits that touch files already existing on
|
|
114
|
+
the branch. For re-runs on partially seeded repos, use
|
|
115
|
+
`scm.create_or_update_file()` per file instead.
|
|
116
|
+
|
|
117
|
+
---
|
|
118
|
+
|
|
119
|
+
## scm.create_or_update_file
|
|
120
|
+
|
|
121
|
+
Create or update a single file in a repo.
|
|
122
|
+
|
|
123
|
+
```
|
|
124
|
+
MCP: gitlab
|
|
125
|
+
Tool: mcp_gitlab_create_or_update_file
|
|
126
|
+
|
|
127
|
+
Parameters:
|
|
128
|
+
project_id: <project_id>
|
|
129
|
+
file_path: <path>
|
|
130
|
+
content: <content>
|
|
131
|
+
commit_message: <message>
|
|
132
|
+
branch: <branch>
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
---
|
|
136
|
+
|
|
137
|
+
## scm.protect_branch
|
|
138
|
+
|
|
139
|
+
Set branch protection to merge-only (no direct push).
|
|
140
|
+
|
|
141
|
+
GitLab auto-protects `main` on repo creation with `push_access_level: 40`
|
|
142
|
+
(maintainers can push). There is **no update API** for existing protection.
|
|
143
|
+
The sequence is: unprotect first, then re-protect with correct settings.
|
|
144
|
+
|
|
145
|
+
```
|
|
146
|
+
# Step 1: Remove existing protection
|
|
147
|
+
MCP: gitlab_ops
|
|
148
|
+
Tool: mcp_gitlab_ops_unprotect_branch
|
|
149
|
+
|
|
150
|
+
Parameters:
|
|
151
|
+
project_id: <project_id>
|
|
152
|
+
branch: "main"
|
|
153
|
+
|
|
154
|
+
# Step 2: Re-protect with M settings
|
|
155
|
+
MCP: gitlab_ops
|
|
156
|
+
Tool: mcp_gitlab_ops_protect_branch
|
|
157
|
+
|
|
158
|
+
Parameters:
|
|
159
|
+
project_id: <project_id>
|
|
160
|
+
branch: "main"
|
|
161
|
+
push_access_level: 0 # no one pushes directly
|
|
162
|
+
merge_access_level: 40 # maintainer-level merge
|
|
163
|
+
allow_force_push: false
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
**Gotchas:**
|
|
167
|
+
- `protect_branch` returns **409 Conflict** if protection already exists.
|
|
168
|
+
Always unprotect first.
|
|
169
|
+
- Seed files (push_files) must complete BEFORE protect_branch. Once
|
|
170
|
+
`push_access_level: 0` is set, even the MCP token cannot push
|
|
171
|
+
directly — only MR merges work.
|
|
172
|
+
|
|
173
|
+
---
|
|
174
|
+
|
|
175
|
+
## scm.create_access_token
|
|
176
|
+
|
|
177
|
+
Create a project access token for the merge transaction pipeline.
|
|
178
|
+
|
|
179
|
+
```
|
|
180
|
+
MCP: gitlab_ops
|
|
181
|
+
Tool: mcp_gitlab_ops_create_project_access_token
|
|
182
|
+
|
|
183
|
+
Parameters:
|
|
184
|
+
project_id: <project_id>
|
|
185
|
+
name: "m-merge-transaction"
|
|
186
|
+
scopes: ["api", "read_repository", "write_repository"]
|
|
187
|
+
access_level: 40 # maintainer
|
|
188
|
+
expires_at: <1-year-from-now>
|
|
189
|
+
|
|
190
|
+
Returns: token value (store securely — shown only once)
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
**Gotchas:**
|
|
194
|
+
- **Premium+ only.** Project access tokens are not available on GitLab
|
|
195
|
+
free tier.
|
|
196
|
+
- **Free tier fallback:** Use a personal access token (PAT) with `api`
|
|
197
|
+
scope that covers the entire group. The same PAT is stored once as a
|
|
198
|
+
CI variable on the root repo and used for all managed repos. Less
|
|
199
|
+
granular (one token for everything vs one per repo) but functionally
|
|
200
|
+
equivalent.
|
|
201
|
+
|
|
202
|
+
---
|
|
203
|
+
|
|
204
|
+
## scm.create_pipeline_trigger
|
|
205
|
+
|
|
206
|
+
Create a pipeline trigger token on a repo. Used by managed repo webhooks
|
|
207
|
+
to kick off shadow integration.
|
|
208
|
+
|
|
209
|
+
```
|
|
210
|
+
MCP: gitlab_ops
|
|
211
|
+
Tool: mcp_gitlab_ops_create_pipeline_trigger
|
|
212
|
+
|
|
213
|
+
Parameters:
|
|
214
|
+
project_id: <root-project-id>
|
|
215
|
+
description: "m-shadow-integration-trigger"
|
|
216
|
+
|
|
217
|
+
Returns: trigger token value
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
---
|
|
221
|
+
|
|
222
|
+
## scm.create_webhook
|
|
223
|
+
|
|
224
|
+
Install a webhook on a repo that fires on specific events.
|
|
225
|
+
|
|
226
|
+
```
|
|
227
|
+
MCP: gitlab_ops
|
|
228
|
+
Tool: mcp_gitlab_ops_create_webhook
|
|
229
|
+
|
|
230
|
+
Parameters:
|
|
231
|
+
project_id: <project_id>
|
|
232
|
+
url: "https://gitlab.com/api/v4/projects/<root-project-id>/trigger/pipeline?token=<trigger-token>&ref=main"
|
|
233
|
+
merge_requests_events: true
|
|
234
|
+
push_events: false # CRITICAL — see note
|
|
235
|
+
enable_ssl_verification: true
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
**Gotchas:**
|
|
239
|
+
- GitLab **defaults `push_events` to `true`** when creating a webhook,
|
|
240
|
+
even if not specified in the API call. You MUST explicitly set
|
|
241
|
+
`push_events: false`. Without this, every push to a managed repo
|
|
242
|
+
triggers a root repo pipeline — causing noise and wasted CI minutes.
|
|
243
|
+
|
|
244
|
+
---
|
|
245
|
+
|
|
246
|
+
## scm.store_ci_secret
|
|
247
|
+
|
|
248
|
+
Store a secret as a CI variable on a repo.
|
|
249
|
+
|
|
250
|
+
```
|
|
251
|
+
MCP: gitlab_ops
|
|
252
|
+
Tool: mcp_gitlab_ops_create_ci_variable
|
|
253
|
+
|
|
254
|
+
Parameters:
|
|
255
|
+
project_id: <project_id>
|
|
256
|
+
key: <key> # e.g. M_TOKEN_API_READ
|
|
257
|
+
value: <value>
|
|
258
|
+
protected: true # only on protected branches
|
|
259
|
+
masked: true # hidden in job logs
|
|
260
|
+
```
|
|
261
|
+
|
|
262
|
+
---
|
|
263
|
+
|
|
264
|
+
## scm.post_commit_status
|
|
265
|
+
|
|
266
|
+
Report a build status (pass/fail) on a specific commit. Used by shadow
|
|
267
|
+
integration to push results back to managed repo MRs.
|
|
268
|
+
|
|
269
|
+
```
|
|
270
|
+
GitLab API (direct HTTP call — no MCP tool available):
|
|
271
|
+
|
|
272
|
+
POST /projects/<project_id>/statuses/<commit_sha>
|
|
273
|
+
Headers:
|
|
274
|
+
PRIVATE-TOKEN: <M_GROUP_TOKEN>
|
|
275
|
+
Body:
|
|
276
|
+
state: success | failed
|
|
277
|
+
name: "shadow-integration"
|
|
278
|
+
description: <human-readable message>
|
|
279
|
+
target_url: <link to root pipeline>
|
|
280
|
+
```
|
|
281
|
+
|
|
282
|
+
**Gotchas:**
|
|
283
|
+
- Requires a token with `api` scope on the target repo. The
|
|
284
|
+
`M_GROUP_TOKEN` (group-level token) covers all managed repos.
|
|
285
|
+
- This is typically called from CI scripts, not from MCP tools.
|
|
286
|
+
The root repo's `.gitlab-ci.yml` shadow:report-status job uses
|
|
287
|
+
`curl` to call this API.
|
|
288
|
+
|
|
289
|
+
---
|
|
290
|
+
|
|
291
|
+
## scm.create_branch
|
|
292
|
+
|
|
293
|
+
Create a new branch from an existing ref.
|
|
294
|
+
|
|
295
|
+
```
|
|
296
|
+
MCP: gitlab
|
|
297
|
+
Tool: mcp_gitlab_create_branch
|
|
298
|
+
|
|
299
|
+
Parameters:
|
|
300
|
+
project_id: <project_id>
|
|
301
|
+
branch: <branch-name>
|
|
302
|
+
ref: <source-ref> # branch name, tag, or SHA
|
|
303
|
+
```
|
|
304
|
+
|
|
305
|
+
---
|
|
306
|
+
|
|
307
|
+
## scm.create_merge_request
|
|
308
|
+
|
|
309
|
+
Create a merge request.
|
|
310
|
+
|
|
311
|
+
```
|
|
312
|
+
MCP: gitlab
|
|
313
|
+
Tool: mcp_gitlab_create_merge_request
|
|
314
|
+
|
|
315
|
+
Parameters:
|
|
316
|
+
project_id: <project_id>
|
|
317
|
+
source_branch: <source-branch>
|
|
318
|
+
target_branch: <target-branch>
|
|
319
|
+
title: <title>
|
|
320
|
+
description: <description>
|
|
321
|
+
remove_source_branch: true
|
|
322
|
+
|
|
323
|
+
Returns: MR URL (from web_url field)
|
|
324
|
+
```
|
|
325
|
+
|
|
326
|
+
---
|
|
327
|
+
|
|
328
|
+
## CI-Specific Notes
|
|
329
|
+
|
|
330
|
+
### Pipeline configuration file
|
|
331
|
+
|
|
332
|
+
GitLab CI uses `.gitlab-ci.yml` at the repo root.
|
|
333
|
+
|
|
334
|
+
### Workflow rules (prevent duplicate pipelines)
|
|
335
|
+
|
|
336
|
+
```yaml
|
|
337
|
+
workflow:
|
|
338
|
+
rules:
|
|
339
|
+
- if: $CI_MERGE_REQUEST_IID
|
|
340
|
+
- if: $CI_COMMIT_BRANCH == "main"
|
|
341
|
+
```
|
|
342
|
+
|
|
343
|
+
Without workflow rules, GitLab creates two pipelines for the same commit
|
|
344
|
+
when an MR exists: one for the branch push, one for the MR event.
|
|
345
|
+
|
|
346
|
+
### Resource groups (merge transaction serialisation)
|
|
347
|
+
|
|
348
|
+
```yaml
|
|
349
|
+
merge-transaction:
|
|
350
|
+
resource_group: distributed_merge
|
|
351
|
+
```
|
|
352
|
+
|
|
353
|
+
Ensures only one merge transaction runs at a time across the entire project.
|
|
354
|
+
|
|
355
|
+
### Docker-in-Docker for compose
|
|
356
|
+
|
|
357
|
+
```yaml
|
|
358
|
+
image: docker:latest
|
|
359
|
+
services:
|
|
360
|
+
- docker:dind
|
|
361
|
+
variables:
|
|
362
|
+
DOCKER_TLS_CERTDIR: "/certs"
|
|
363
|
+
```
|
|
364
|
+
|
|
365
|
+
**DinD networking:** Published ports bind on the `docker` service
|
|
366
|
+
container's network interface. Health checks must use hostname `docker`,
|
|
367
|
+
not `localhost`:
|
|
368
|
+
```
|
|
369
|
+
DOCKER_GATEWAY="${DOCKER_GATEWAY:-docker}"
|
|
370
|
+
curl http://${DOCKER_GATEWAY}:3000/health
|
|
371
|
+
```
|
|
372
|
+
|
|
373
|
+
### Project settings
|
|
374
|
+
|
|
375
|
+
After scaffolding, set `only_allow_merge_if_pipeline_succeeds: true`
|
|
376
|
+
on every repo. Without this, MRs can be merged while the pipeline is
|
|
377
|
+
still running or failing.
|