gitlab-labkit 5.6.1 → 5.7.0
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.
- checksums.yaml +4 -4
- data/.claude/hooks/precommit-validate.sh +1 -0
- data/.copier-answers.yml +1 -1
- data/.gitlab/CODEOWNERS +1 -1
- data/.gitlab-ci.yml +17 -3
- data/.opencode/plugins/precommit-validate.ts +181 -56
- data/.pre-commit-config.yaml +1 -1
- data/CODEOWNERS +1 -1
- data/CONTRIBUTING.md +1 -1
- data/lib/labkit/fields.rb +14 -0
- data/scripts/prepare-dev-env.sh +1 -0
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: f2d9d587afe49d99a2ada5a8757230d69024a1085009f1e65c29ac97aa005e98
|
|
4
|
+
data.tar.gz: 35e55c1e1f9aef6836736e6917cffe4813aa37655eebf5534893f9b7b232fb89
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 83a9378e749aa4c04cf05cca872fffabe8945802b169c996aba579b43b73e582d98dca6c37b31c82098fe3edda41932ddc81813010ab278e2df7569812c7926e
|
|
7
|
+
data.tar.gz: 5b00ebd19184fbfaec05c1cdf40de93b74a70c0a7aa2b167213425debada2ea6708b61874d4ad23a9de40c950724b47da599d37daf0116d323ed8b4db76a6d23
|
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
# touched. On failure it prints the output to stderr and exits 2, which feeds the
|
|
6
6
|
# result back to Claude so it can fix the issue. A clean run exits 0 silently.
|
|
7
7
|
set -euo pipefail
|
|
8
|
+
IFS=$'\n\t'
|
|
8
9
|
|
|
9
10
|
# no-commit-to-branch guards the branch, not file content, and would fire
|
|
10
11
|
# spuriously (e.g. on jj's detached HEAD). It is irrelevant to file validation.
|
data/.copier-answers.yml
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
# See the project for instructions on how to update the project
|
|
4
4
|
#
|
|
5
5
|
# Changes here will be overwritten by Copier; NEVER EDIT MANUALLY
|
|
6
|
-
_commit: v1.
|
|
6
|
+
_commit: v1.87.1
|
|
7
7
|
_src_path: https://gitlab.com/gitlab-com/gl-infra/common-template-copier.git
|
|
8
8
|
ee_licensed: false
|
|
9
9
|
gitlab_namespace: gitlab-org/ruby/gems
|
data/.gitlab/CODEOWNERS
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
* @
|
|
1
|
+
* @mkaeppler @ayufan @hmerscher @sankalp_gl @hardikgala @nindurkar @ashs2
|
data/.gitlab-ci.yml
CHANGED
|
@@ -19,13 +19,27 @@ include:
|
|
|
19
19
|
# It includes standard checks, gitlab-scanners, validations and release processes
|
|
20
20
|
# common to all projects using this template library.
|
|
21
21
|
# see https://gitlab.com/gitlab-com/gl-infra/common-ci-tasks/-/blob/main/templates/standard.md
|
|
22
|
-
- component: $CI_SERVER_FQDN/gitlab-com/gl-infra/common-ci-tasks/standard-build@v5.
|
|
22
|
+
- component: $CI_SERVER_FQDN/gitlab-com/gl-infra/common-ci-tasks/standard-build@v5.46
|
|
23
23
|
|
|
24
24
|
# Runs rspec tests and rubocop on the project
|
|
25
25
|
# see https://gitlab.com/gitlab-com/gl-infra/common-ci-tasks/-/blob/main/templates/ruby.md
|
|
26
|
-
- component: $CI_SERVER_FQDN/gitlab-com/gl-infra/common-ci-tasks/ruby-build@v5.
|
|
26
|
+
- component: $CI_SERVER_FQDN/gitlab-com/gl-infra/common-ci-tasks/ruby-build@v5.46
|
|
27
27
|
|
|
28
|
-
- component: $CI_SERVER_FQDN/gitlab-com/gl-infra/common-ci-tasks/danger@v5.
|
|
28
|
+
- component: $CI_SERVER_FQDN/gitlab-com/gl-infra/common-ci-tasks/danger@v5.46
|
|
29
|
+
|
|
30
|
+
# danger-review reads its token from Vault, which the community fork has no
|
|
31
|
+
# access to, so it fails on merge requests from the fork. Let it fail for those;
|
|
32
|
+
# the second rule is the component's own. See
|
|
33
|
+
# https://gitlab.com/gitlab-org/labkit/-/work_items/171
|
|
34
|
+
danger-review:
|
|
35
|
+
rules:
|
|
36
|
+
- if: $CI_PIPELINE_SOURCE == "merge_request_event" && $CI_MERGE_REQUEST_SOURCE_PROJECT_PATH == "gitlab-community/gitlab-org/ruby/gems/labkit-ruby"
|
|
37
|
+
exists:
|
|
38
|
+
- Dangerfile
|
|
39
|
+
allow_failure: true
|
|
40
|
+
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
|
|
41
|
+
exists:
|
|
42
|
+
- Dangerfile
|
|
29
43
|
|
|
30
44
|
# Attach a redis service to the rspec job from common-ci-tasks/ruby-build.
|
|
31
45
|
# GitLab merges keys when a local job has the same name as an included one,
|
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { Hooks, PluginModule } from "@opencode-ai/plugin";
|
|
2
|
+
import type { Plugin } from "@opencode/plugin";
|
|
3
|
+
import { execFile, spawn } from "node:child_process";
|
|
2
4
|
import { existsSync } from "node:fs";
|
|
3
5
|
import { isAbsolute, join, resolve } from "node:path";
|
|
4
6
|
|
|
@@ -22,80 +24,203 @@ import { isAbsolute, join, resolve } from "node:path";
|
|
|
22
24
|
*
|
|
23
25
|
* The script is reused verbatim: it reads Claude Code's PostToolUse payload on
|
|
24
26
|
* stdin (`{ "tool_input": { "file_path": "..." } }`), so we synthesize that same
|
|
25
|
-
* shape here from OpenCode's tool
|
|
27
|
+
* shape here from OpenCode's tool input.
|
|
28
|
+
*
|
|
29
|
+
* Supports both plugin APIs from one default export, as described in
|
|
30
|
+
* https://opencode.ai/v2/docs/build/plugins/migrate-v1:
|
|
31
|
+
* - OpenCode 2 reads `id` and `setup()` (the `@opencode/plugin` API).
|
|
32
|
+
* - OpenCode 1 (>= 1.18.29) calls `server()` (the `@opencode-ai/plugin` API).
|
|
33
|
+
* Both imports are type-only, so neither OpenCode version needs the other's
|
|
34
|
+
* plugin package installed at runtime. Remove `server()` once V1 is gone.
|
|
26
35
|
*
|
|
27
36
|
* Auto-loaded from `.opencode/plugins/`.
|
|
28
37
|
*/
|
|
29
38
|
|
|
30
|
-
|
|
31
|
-
// matcher. Current OpenCode may use `apply_patch` for file edits.
|
|
32
|
-
const FILE_TOOLS = new Set(["apply_patch", "edit", "write"]);
|
|
39
|
+
const ID = "precommit-validate";
|
|
33
40
|
|
|
34
41
|
const HOOK_SCRIPT = ".claude/hooks/precommit-validate.sh";
|
|
35
42
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
43
|
+
// OpenCode file-mutating tools, analogous to Claude Code's `Edit|Write|MultiEdit`
|
|
44
|
+
// matcher. V1 and V2 both have `edit` and `write`; patches go through
|
|
45
|
+
// `apply_patch` in V1 and `patch` in V2.
|
|
46
|
+
const FILE_TOOLS = new Set(["apply_patch", "edit", "patch", "write"]);
|
|
39
47
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
48
|
+
interface HookResult {
|
|
49
|
+
/** Exit code 2: pre-commit findings to feed back to the model. */
|
|
50
|
+
readonly reports: string[];
|
|
51
|
+
/** Any other failure: environment problems to log for the user. */
|
|
52
|
+
readonly warnings: string[];
|
|
53
|
+
}
|
|
45
54
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
if (filePath) filePaths.add(filePath);
|
|
55
|
+
const asRecord = (value: unknown): Record<string, unknown> =>
|
|
56
|
+
value && typeof value === "object" && !Array.isArray(value) ? (value as Record<string, unknown>) : {};
|
|
49
57
|
|
|
50
|
-
|
|
51
|
-
if (typeof file.filePath === "string") filePaths.add(file.filePath);
|
|
52
|
-
}
|
|
58
|
+
const asString = (value: unknown): string | undefined => (typeof value === "string" && value ? value : undefined);
|
|
53
59
|
|
|
60
|
+
/**
|
|
61
|
+
* Collect the files a tool call touched from its input and result metadata.
|
|
62
|
+
*
|
|
63
|
+
* Input: V2 `edit`/`write` take `path`; V1 takes `filePath`.
|
|
64
|
+
* Metadata: `files` entries carry `file` in V2 and `filePath` in V1. This is
|
|
65
|
+
* the only source for patch tools, whose input is a single `patchText` blob.
|
|
66
|
+
*/
|
|
67
|
+
function touchedFiles(input: unknown, metadata: unknown): Set<string> {
|
|
68
|
+
const args = asRecord(input);
|
|
69
|
+
const files = new Set<string>();
|
|
70
|
+
|
|
71
|
+
const direct = asString(args.path) ?? asString(args.filePath);
|
|
72
|
+
if (direct) files.add(direct);
|
|
73
|
+
|
|
74
|
+
const entries = asRecord(metadata).files;
|
|
75
|
+
for (const entry of Array.isArray(entries) ? entries : []) {
|
|
76
|
+
const file = asRecord(entry);
|
|
77
|
+
// A deleted file has nothing left to validate.
|
|
78
|
+
if (file.status === "deleted" || file.type === "delete") continue;
|
|
79
|
+
const path = asString(file.file) ?? asString(file.filePath);
|
|
80
|
+
if (path) files.add(path);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
return files;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/** Run the shared hook script for one file, feeding the payload on stdin. */
|
|
87
|
+
function runHookScript(
|
|
88
|
+
script: string,
|
|
89
|
+
root: string,
|
|
90
|
+
payload: string,
|
|
91
|
+
signal?: AbortSignal,
|
|
92
|
+
): Promise<{ code: number | null; stdout: string; stderr: string }> {
|
|
93
|
+
return new Promise((done, fail) => {
|
|
94
|
+
const child = spawn(script, [], { cwd: root, signal, stdio: ["pipe", "pipe", "pipe"] });
|
|
95
|
+
let stdout = "";
|
|
96
|
+
let stderr = "";
|
|
97
|
+
child.stdout.setEncoding("utf8").on("data", (chunk: string) => (stdout += chunk));
|
|
98
|
+
child.stderr.setEncoding("utf8").on("data", (chunk: string) => (stderr += chunk));
|
|
99
|
+
// The script exits early (e.g. mise missing) without reading stdin.
|
|
100
|
+
child.stdin.on("error", () => {});
|
|
101
|
+
child.on("error", fail);
|
|
102
|
+
child.on("close", (code) => done({ code, stdout, stderr }));
|
|
103
|
+
child.stdin.end(payload);
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/** Validate every touched file and sort the outcomes into reports and warnings. */
|
|
108
|
+
async function validate(root: string, filePaths: Iterable<string>, signal?: AbortSignal): Promise<HookResult> {
|
|
109
|
+
const result: HookResult = { reports: [], warnings: [] };
|
|
110
|
+
const script = join(root, HOOK_SCRIPT);
|
|
111
|
+
// Inert when the shared script is absent (e.g. loaded in another repo).
|
|
112
|
+
if (!existsSync(script)) return result;
|
|
113
|
+
|
|
114
|
+
for (const filePath of filePaths) {
|
|
115
|
+
if (signal?.aborted) break;
|
|
116
|
+
const absolute = isAbsolute(filePath) ? filePath : resolve(root, filePath);
|
|
117
|
+
|
|
118
|
+
// Same JSON shape Claude Code's PostToolUse hook delivers on stdin. The
|
|
119
|
+
// script itself decides whether the file lives inside the repo.
|
|
120
|
+
const payload = JSON.stringify({ tool_input: { file_path: absolute } });
|
|
121
|
+
|
|
122
|
+
let run: Awaited<ReturnType<typeof runHookScript>>;
|
|
123
|
+
try {
|
|
124
|
+
run = await runHookScript(script, root, payload, signal);
|
|
125
|
+
} catch (error) {
|
|
126
|
+
if (signal?.aborted) break; // plugin unloaded mid-run
|
|
127
|
+
result.warnings.push(`pre-commit validation hook failed to start: ${String(error)}`);
|
|
128
|
+
continue;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
if (run.code === 0) continue; // clean / no-op
|
|
132
|
+
|
|
133
|
+
const report = run.stderr.trim() || run.stdout.trim();
|
|
134
|
+
|
|
135
|
+
if (run.code === 2) {
|
|
136
|
+
// Blocking: pre-commit reported issues. Surface them to the model, the
|
|
137
|
+
// OpenCode equivalent of feeding the hook's stderr back to Claude Code.
|
|
138
|
+
if (report) result.reports.push(report);
|
|
139
|
+
continue;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
// Non-blocking error (e.g. exit 1 = mise not on PATH). Not something the
|
|
143
|
+
// model can act on, so log it for the user instead of polluting the turn.
|
|
144
|
+
result.warnings.push(report || `pre-commit validation hook exited ${run.code}`);
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
return result;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
const formatReports = (reports: string[]): string =>
|
|
151
|
+
`<pre-commit-validation>\n${reports.join("\n\n")}\n</pre-commit-validation>`;
|
|
152
|
+
|
|
153
|
+
/** The repository root, so the hook script is found from any subdirectory. */
|
|
154
|
+
function gitToplevel(directory: string): Promise<string> {
|
|
155
|
+
return new Promise((done) => {
|
|
156
|
+
execFile("git", ["rev-parse", "--show-toplevel"], { cwd: directory }, (error, stdout) => {
|
|
157
|
+
done(error ? directory : stdout.trim() || directory);
|
|
158
|
+
});
|
|
159
|
+
});
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
/** OpenCode 2 implementation (`@opencode/plugin`). */
|
|
163
|
+
const v2: Plugin.Plugin = {
|
|
164
|
+
id: ID,
|
|
165
|
+
async setup(ctx) {
|
|
166
|
+
const root = await gitToplevel(ctx.location.directory);
|
|
167
|
+
// Hook events carry no abort signal; stop in-flight runs on unload instead.
|
|
168
|
+
const controller = new AbortController();
|
|
169
|
+
|
|
170
|
+
await ctx.tool.hook("execute.after", async (event) => {
|
|
171
|
+
if (event.status !== "completed") return;
|
|
172
|
+
if (!FILE_TOOLS.has(event.tool)) return;
|
|
173
|
+
|
|
174
|
+
const filePaths = touchedFiles(event.input, event.result.metadata);
|
|
54
175
|
if (filePaths.size === 0) return;
|
|
55
176
|
|
|
56
|
-
const reports
|
|
177
|
+
const { reports, warnings } = await validate(root, filePaths, controller.signal);
|
|
178
|
+
|
|
179
|
+
for (const warning of warnings) console.warn(`[${ID}] ${warning}`);
|
|
57
180
|
|
|
58
|
-
|
|
59
|
-
const absolute = isAbsolute(filePath) ? filePath : resolve(root, filePath);
|
|
181
|
+
if (reports.length === 0) return;
|
|
60
182
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
183
|
+
// Results are read-only: replace the result, appending to its content.
|
|
184
|
+
const text = formatReports(reports);
|
|
185
|
+
const content = event.result.content;
|
|
186
|
+
event.result = {
|
|
187
|
+
...event.result,
|
|
188
|
+
content:
|
|
189
|
+
typeof content === "string" || content === undefined
|
|
190
|
+
? content ? `${content}\n\n${text}` : text
|
|
191
|
+
: [...content, { type: "text", text }],
|
|
192
|
+
};
|
|
193
|
+
});
|
|
194
|
+
|
|
195
|
+
return () => controller.abort();
|
|
196
|
+
},
|
|
197
|
+
};
|
|
64
198
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
199
|
+
/** OpenCode 1 implementation (`@opencode-ai/plugin`, >= 1.18.29). */
|
|
200
|
+
const v1: PluginModule = {
|
|
201
|
+
id: ID,
|
|
202
|
+
async server({ client, directory, worktree }) {
|
|
203
|
+
const root = worktree || directory;
|
|
69
204
|
|
|
70
|
-
|
|
205
|
+
const hooks: Hooks = {
|
|
206
|
+
"tool.execute.after": async (input, output) => {
|
|
207
|
+
if (!FILE_TOOLS.has(input.tool)) return;
|
|
71
208
|
|
|
72
|
-
const
|
|
73
|
-
|
|
209
|
+
const filePaths = touchedFiles(input.args, output.metadata);
|
|
210
|
+
if (filePaths.size === 0) return;
|
|
74
211
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
if (report) reports.push(report);
|
|
80
|
-
continue;
|
|
212
|
+
const { reports, warnings } = await validate(root, filePaths);
|
|
213
|
+
|
|
214
|
+
for (const warning of warnings) {
|
|
215
|
+
await client.app.log({ body: { service: ID, level: "warn", message: warning } });
|
|
81
216
|
}
|
|
82
217
|
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
message: report || `pre-commit validation hook exited ${result.exitCode}`,
|
|
90
|
-
},
|
|
91
|
-
});
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
if (reports.length > 0) {
|
|
95
|
-
output.output += `\n\n<pre-commit-validation>\n${reports.join("\n\n")}\n</pre-commit-validation>`;
|
|
96
|
-
}
|
|
97
|
-
},
|
|
98
|
-
};
|
|
99
|
-
|
|
100
|
-
return hooks;
|
|
218
|
+
if (reports.length > 0) output.output += `\n\n${formatReports(reports)}`;
|
|
219
|
+
},
|
|
220
|
+
};
|
|
221
|
+
|
|
222
|
+
return hooks;
|
|
223
|
+
},
|
|
101
224
|
};
|
|
225
|
+
|
|
226
|
+
export default { ...v2, server: v1.server };
|
data/.pre-commit-config.yaml
CHANGED
|
@@ -25,7 +25,7 @@ repos:
|
|
|
25
25
|
# Documentation available at
|
|
26
26
|
# https://gitlab.com/gitlab-com/gl-infra/common-ci-tasks/-/blob/main/docs/pre-commit.md
|
|
27
27
|
- repo: https://gitlab.com/gitlab-com/gl-infra/common-ci-tasks
|
|
28
|
-
rev: v5.
|
|
28
|
+
rev: v5.46 # renovate:managed
|
|
29
29
|
|
|
30
30
|
hooks:
|
|
31
31
|
- id: shellcheck # Run shellcheck for changed Shell files
|
data/CODEOWNERS
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
# CODEOWNERS is used to lookup assignees for
|
|
2
2
|
# Renovate Bot dependency change Merge Requests.
|
|
3
3
|
# https://docs.renovatebot.com/configuration-options/#assigneesfromcodeowners
|
|
4
|
-
* @
|
|
4
|
+
* @ayufan @hmerscher @e_forbes @M_Alvarez @mwoolf @sankalp_gl @hardikgala @nindurkar @ashs2
|
data/CONTRIBUTING.md
CHANGED
|
@@ -6,7 +6,7 @@ Except for the license granted herein to GitLab Inc. and recipients of software
|
|
|
6
6
|
distributed by GitLab Inc., you reserve all right, title, and interest in and to
|
|
7
7
|
your Contributions.
|
|
8
8
|
|
|
9
|
-
All contributions are subject to the Developer Certificate of Origin and license set out at [docs.gitlab.com/
|
|
9
|
+
All contributions are subject to the Developer Certificate of Origin and license set out at [docs.gitlab.com/legal/developer_certificate_of_origin](https://docs.gitlab.com/legal/developer_certificate_of_origin/).
|
|
10
10
|
|
|
11
11
|
_This notice should stay as the first item in the CONTRIBUTING.md file._
|
|
12
12
|
|
data/lib/labkit/fields.rb
CHANGED
|
@@ -16,6 +16,12 @@ module Labkit
|
|
|
16
16
|
# GitLab username.
|
|
17
17
|
GL_USER_NAME = "gl_user_name"
|
|
18
18
|
|
|
19
|
+
# Type of key used for authentication (e.g. "deploy_key", "key").
|
|
20
|
+
GL_KEY_TYPE = "gl_key_type"
|
|
21
|
+
|
|
22
|
+
# Numeric ID of the key used for authentication.
|
|
23
|
+
GL_KEY_ID = "gl_key_id"
|
|
24
|
+
|
|
19
25
|
# Duo Workflow definition identifier (e.g. "analytics_agent/v1"). Identifies
|
|
20
26
|
# which Duo Workflow agent originated a request, enabling per-agent
|
|
21
27
|
# filtering in Kibana and Grafana.
|
|
@@ -149,12 +155,19 @@ module Labkit
|
|
|
149
155
|
# connection field.
|
|
150
156
|
GRAPHQL_CONNECTION_NODES = "graphql_connection_nodes"
|
|
151
157
|
|
|
158
|
+
# Protocol or subsystem that produced an access log line (e.g. "http",
|
|
159
|
+
# "grpc"). Emitted by the LabKit access-logging middleware so a single
|
|
160
|
+
# service's HTTP and gRPC access logs can be told apart.
|
|
161
|
+
SYSTEM = "system"
|
|
162
|
+
|
|
152
163
|
# Maps each field constant to its logging field variant version.
|
|
153
164
|
# A version of 0 means the field is not yet assigned to any variant.
|
|
154
165
|
VARIANT_VERSION = {
|
|
155
166
|
CORRELATION_ID => 1,
|
|
156
167
|
GL_USER_ID => 1,
|
|
157
168
|
GL_USER_NAME => 1,
|
|
169
|
+
GL_KEY_TYPE => 0,
|
|
170
|
+
GL_KEY_ID => 0,
|
|
158
171
|
DUO_WORKFLOW_DEFINITION => 0,
|
|
159
172
|
DUO_WORKFLOW_ID => 0,
|
|
160
173
|
ERROR_TYPE => 0,
|
|
@@ -192,6 +205,7 @@ module Labkit
|
|
|
192
205
|
ADDITIONAL_DETAILS => 0,
|
|
193
206
|
GRAPHQL_COMPLEXITY_RAW => 0,
|
|
194
207
|
GRAPHQL_CONNECTION_NODES => 0,
|
|
208
|
+
SYSTEM => 0,
|
|
195
209
|
}.freeze
|
|
196
210
|
|
|
197
211
|
# Get the constant name for a field value
|
data/scripts/prepare-dev-env.sh
CHANGED