gitlab-labkit 5.6.0 → 5.6.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.
- checksums.yaml +4 -4
- data/.claude/hooks/precommit-validate.sh +47 -0
- data/.claude/settings.json +15 -0
- data/.copier-answers.yml +2 -1
- data/.gitignore +0 -1
- data/.gitlab/duo/agent-config.yml +7 -7
- data/.mise.toml +3 -0
- data/.opencode/plugins/precommit-validate.ts +101 -0
- data/.pre-commit-config.yaml +2 -1
- data/.rubocop_todo.yml +2 -17
- data/AGENTS.md +37 -0
- data/CLAUDE.md +1 -0
- data/Gemfile +5 -0
- data/README.md +6 -19
- data/lib/labkit/json_schema/README.md +1 -1
- data/lib/labkit/rspec/matchers/user_experience_matchers.rb +2 -2
- data/performance.yml +70 -0
- data/scripts/prepare-dev-env.sh +23 -1
- metadata +6 -2
- data/.env.example.sh +0 -7
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: a1ef319c707c40ea0cca46358bbacdf18d1068b8f2b778ebc1a1486c33cea1ef
|
|
4
|
+
data.tar.gz: 5cbead469ab098d29afb9dcf2dd97576976a703db93eda7ea337a54bc94fcde9
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 1488c581703cab14db63d485aa2ef3159d8a0cd8449cc34b4aeeb522d97ad2207edb57096f388240cff213ef44aaa925a8219a2464b3ab4054a81b0e8569129a
|
|
7
|
+
data.tar.gz: 4c65d98b9b29084a3c5bdc7e0d9dc166a4708f203840a08180421172f21c0356005641557e46dc14f48fb277570f4bdae041d61072c454dbdfa252e4e8baf5fd
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# PostToolUse hook: validate a just-edited file against this repo's pre-commit rules.
|
|
3
|
+
#
|
|
4
|
+
# Runs `pre-commit run --files <file>` on the file that Edit/Write/MultiEdit
|
|
5
|
+
# touched. On failure it prints the output to stderr and exits 2, which feeds the
|
|
6
|
+
# result back to Claude so it can fix the issue. A clean run exits 0 silently.
|
|
7
|
+
set -euo pipefail
|
|
8
|
+
|
|
9
|
+
# no-commit-to-branch guards the branch, not file content, and would fire
|
|
10
|
+
# spuriously (e.g. on jj's detached HEAD). It is irrelevant to file validation.
|
|
11
|
+
export SKIP="no-commit-to-branch"
|
|
12
|
+
|
|
13
|
+
# Run through `mise exec` so mise-managed tools that the hooks rely on
|
|
14
|
+
# (pre-commit, jsonnet-tool, shfmt, ...) are on PATH, matching a normal
|
|
15
|
+
# interactive shell.
|
|
16
|
+
if ! command -v mise >/dev/null 2>&1; then
|
|
17
|
+
echo "pre-commit validation hook requires mise to run." >&2
|
|
18
|
+
exit 1
|
|
19
|
+
fi
|
|
20
|
+
|
|
21
|
+
run() { mise exec -- "$@"; }
|
|
22
|
+
|
|
23
|
+
repo_root="$(git rev-parse --show-toplevel 2>/dev/null)" || exit 0
|
|
24
|
+
|
|
25
|
+
input="$(cat)"
|
|
26
|
+
file="$(printf '%s' "$input" | mise exec jq@1.8 -- jq -r '.tool_input.file_path // empty')"
|
|
27
|
+
[[ -z $file ]] && exit 0
|
|
28
|
+
|
|
29
|
+
# Only validate files that live inside this repository.
|
|
30
|
+
case "$file" in
|
|
31
|
+
"$repo_root"/*) ;;
|
|
32
|
+
*) exit 0 ;;
|
|
33
|
+
esac
|
|
34
|
+
|
|
35
|
+
if ! output="$(cd "$repo_root" && run pre-commit run --files "$file" 2>&1)"; then
|
|
36
|
+
{
|
|
37
|
+
echo "pre-commit reported issues on ${file#"$repo_root"/}:"
|
|
38
|
+
echo
|
|
39
|
+
echo "$output"
|
|
40
|
+
echo
|
|
41
|
+
echo "Re-read the file (hooks such as trailing-whitespace, shfmt, and"
|
|
42
|
+
echo "generate may have rewritten it) and fix any remaining problems."
|
|
43
|
+
} >&2
|
|
44
|
+
exit 2
|
|
45
|
+
fi
|
|
46
|
+
|
|
47
|
+
exit 0
|
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.85.0
|
|
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
|
|
@@ -17,5 +17,6 @@ release_platform: false
|
|
|
17
17
|
ruby: true
|
|
18
18
|
rubygem: true
|
|
19
19
|
rust: false
|
|
20
|
+
scaffold_target: repo
|
|
20
21
|
terraform: false
|
|
21
22
|
truncated_tags: true
|
data/.gitignore
CHANGED
|
@@ -7,22 +7,22 @@
|
|
|
7
7
|
image: registry.gitlab.com/gitlab-com/gl-infra/common-ci-tasks-images/duo-workflow-sandbox:latest
|
|
8
8
|
|
|
9
9
|
setup_script:
|
|
10
|
-
#
|
|
11
|
-
#
|
|
12
|
-
-
|
|
13
|
-
- export MISE_CACHE_DIR="${CI_PROJECT_DIR}/.cache/mise/cache"
|
|
14
|
-
- mise trust --yes
|
|
15
|
-
- mise install --yes
|
|
10
|
+
# duo-workflow-setup (baked into the image) exports some variables as
|
|
11
|
+
# `export KEY=VALUE` lines on stdout, which we `eval` into the flow's shell.
|
|
12
|
+
- eval "$(/usr/local/bin/duo-workflow-setup)"
|
|
16
13
|
|
|
17
14
|
cache:
|
|
18
|
-
# Re-use installed tools as long as the version
|
|
15
|
+
# Re-use installed tools and primed pre-commit hooks as long as the version
|
|
16
|
+
# pins / hook config are unchanged.
|
|
19
17
|
key:
|
|
20
18
|
files:
|
|
21
19
|
- .tool-versions
|
|
22
20
|
- .mise.toml
|
|
21
|
+
- .pre-commit-config.yaml
|
|
23
22
|
paths:
|
|
24
23
|
- .cache/mise/data
|
|
25
24
|
- .cache/mise/cache
|
|
25
|
+
- .cache/pre-commit
|
|
26
26
|
|
|
27
27
|
network_policy:
|
|
28
28
|
# Allow the Sandbox Runtime's recommended allowlist (GitLab, package
|
data/.mise.toml
CHANGED
|
@@ -7,6 +7,9 @@ legacy_version_file = false
|
|
|
7
7
|
# OpenSSL and sidesteps it. This becomes mise's default in 2026.8.0.
|
|
8
8
|
ruby.compile = false
|
|
9
9
|
|
|
10
|
+
# Disable sending anonymous download statistics to mise-versions.jdx.dev.
|
|
11
|
+
use_versions_host_track = false
|
|
12
|
+
|
|
10
13
|
[tools]
|
|
11
14
|
# Please continue to use `.tool-versions` to specify tool versions, rather than adding them directly here.
|
|
12
15
|
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import type { Plugin, Hooks } from "@opencode-ai/plugin";
|
|
2
|
+
import { existsSync } from "node:fs";
|
|
3
|
+
import { isAbsolute, join, resolve } from "node:path";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* precommit-validate plugin
|
|
7
|
+
*
|
|
8
|
+
* OpenCode equivalent of the Claude Code PostToolUse hook defined in
|
|
9
|
+
* `.claude/hooks/precommit-validate.sh` (wired up by `.claude/settings.json`).
|
|
10
|
+
*
|
|
11
|
+
* After the agent edits or writes a file, this runs that *same* shell script to
|
|
12
|
+
* validate the file against the repo's pre-commit rules. When pre-commit reports
|
|
13
|
+
* problems, the findings are appended to the tool result so the agent sees them
|
|
14
|
+
* on its next turn and can fix the file. A clean run is silent.
|
|
15
|
+
*
|
|
16
|
+
* The script's exit codes mirror Claude Code's hook contract, so we honour the
|
|
17
|
+
* same distinction here:
|
|
18
|
+
* - 0 = clean or no-op (silent)
|
|
19
|
+
* - 2 = pre-commit reported issues; feed the report back to the model
|
|
20
|
+
* - any other non-zero = non-blocking error (e.g. mise missing); log it for
|
|
21
|
+
* the user but do not nag the model, since it can't fix its environment.
|
|
22
|
+
*
|
|
23
|
+
* The script is reused verbatim: it reads Claude Code's PostToolUse payload on
|
|
24
|
+
* stdin (`{ "tool_input": { "file_path": "..." } }`), so we synthesize that same
|
|
25
|
+
* shape here from OpenCode's tool arguments.
|
|
26
|
+
*
|
|
27
|
+
* Auto-loaded from `.opencode/plugins/`.
|
|
28
|
+
*/
|
|
29
|
+
|
|
30
|
+
// OpenCode file-mutating tools, analogous to Claude Code's `Edit|Write|MultiEdit`
|
|
31
|
+
// matcher. Current OpenCode may use `apply_patch` for file edits.
|
|
32
|
+
const FILE_TOOLS = new Set(["apply_patch", "edit", "write"]);
|
|
33
|
+
|
|
34
|
+
const HOOK_SCRIPT = ".claude/hooks/precommit-validate.sh";
|
|
35
|
+
|
|
36
|
+
export const PrecommitValidatePlugin: Plugin = async ({ $, client, directory, worktree }) => {
|
|
37
|
+
const root = worktree || directory;
|
|
38
|
+
const script = join(root, HOOK_SCRIPT);
|
|
39
|
+
|
|
40
|
+
const hooks: Hooks = {
|
|
41
|
+
"tool.execute.after": async (input, output) => {
|
|
42
|
+
if (!FILE_TOOLS.has(input.tool)) return;
|
|
43
|
+
// Inert when the shared script is absent (e.g. loaded in another repo).
|
|
44
|
+
if (!existsSync(script)) return;
|
|
45
|
+
|
|
46
|
+
const filePaths = new Set<string>();
|
|
47
|
+
const filePath: string | undefined = input.args?.filePath;
|
|
48
|
+
if (filePath) filePaths.add(filePath);
|
|
49
|
+
|
|
50
|
+
for (const file of output.metadata?.files ?? []) {
|
|
51
|
+
if (typeof file.filePath === "string") filePaths.add(file.filePath);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
if (filePaths.size === 0) return;
|
|
55
|
+
|
|
56
|
+
const reports: string[] = [];
|
|
57
|
+
|
|
58
|
+
for (const filePath of filePaths) {
|
|
59
|
+
const absolute = isAbsolute(filePath) ? filePath : resolve(root, filePath);
|
|
60
|
+
|
|
61
|
+
// Same JSON shape Claude Code's PostToolUse hook delivers on stdin. The
|
|
62
|
+
// script itself decides whether the file lives inside the repo.
|
|
63
|
+
const payload = JSON.stringify({ tool_input: { file_path: absolute } });
|
|
64
|
+
|
|
65
|
+
const result = await $`printf '%s' ${payload} | ${script}`
|
|
66
|
+
.cwd(root)
|
|
67
|
+
.nothrow()
|
|
68
|
+
.quiet();
|
|
69
|
+
|
|
70
|
+
if (result.exitCode === 0) continue; // clean / no-op
|
|
71
|
+
|
|
72
|
+
const report =
|
|
73
|
+
result.stderr.toString().trim() || result.stdout.toString().trim();
|
|
74
|
+
|
|
75
|
+
if (result.exitCode === 2) {
|
|
76
|
+
// Blocking: pre-commit reported issues. Surface them to the model by
|
|
77
|
+
// appending to the tool output, the OpenCode equivalent of feeding the
|
|
78
|
+
// hook's stderr back to Claude Code on exit 2.
|
|
79
|
+
if (report) reports.push(report);
|
|
80
|
+
continue;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// Non-blocking error (e.g. exit 1 = mise not on PATH). Not something the
|
|
84
|
+
// model can act on, so log it for the user instead of polluting the turn.
|
|
85
|
+
await client.app.log({
|
|
86
|
+
body: {
|
|
87
|
+
service: "precommit-validate",
|
|
88
|
+
level: "warn",
|
|
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;
|
|
101
|
+
};
|
data/.pre-commit-config.yaml
CHANGED
|
@@ -15,7 +15,7 @@ repos:
|
|
|
15
15
|
- id: check-json
|
|
16
16
|
- id: detect-private-key
|
|
17
17
|
- id: mixed-line-ending
|
|
18
|
-
args: [
|
|
18
|
+
args: [--fix=lf]
|
|
19
19
|
- id: no-commit-to-branch
|
|
20
20
|
args: [--branch, main]
|
|
21
21
|
- id: pretty-format-json
|
|
@@ -36,3 +36,4 @@ repos:
|
|
|
36
36
|
- id: gitleaks # Detect hardcoded secrets using Gitleaks
|
|
37
37
|
- id: editorconfig # Validate text files against .editorconfig
|
|
38
38
|
- id: yamllint # Validate YAML files using yamllint
|
|
39
|
+
- id: ensure-claude-md
|
data/.rubocop_todo.yml
CHANGED
|
@@ -151,12 +151,6 @@ Lint/SymbolConversion:
|
|
|
151
151
|
- 'spec/labkit/logging/json_logger_spec.rb'
|
|
152
152
|
- 'spec/support/tracing/shared_examples.rb'
|
|
153
153
|
|
|
154
|
-
# Offense count: 1
|
|
155
|
-
# Configuration parameters: Methods.
|
|
156
|
-
Lint/UnexpectedBlockArity:
|
|
157
|
-
Exclude:
|
|
158
|
-
- 'tools/update-changelog.rb'
|
|
159
|
-
|
|
160
154
|
# Offense count: 41
|
|
161
155
|
# This cop supports safe autocorrection (--autocorrect).
|
|
162
156
|
# Configuration parameters: AutoCorrect, AllowUnusedKeywordArguments, IgnoreEmptyMethods, IgnoreNotImplementedMethods, NotImplementedExceptions.
|
|
@@ -196,13 +190,6 @@ Naming/RescuedExceptionsVariableName:
|
|
|
196
190
|
Exclude:
|
|
197
191
|
- 'lib/labkit/logging/grpc/server_interceptor.rb'
|
|
198
192
|
|
|
199
|
-
# Offense count: 1
|
|
200
|
-
# This cop supports safe autocorrection (--autocorrect).
|
|
201
|
-
# Configuration parameters: EnabledForFlattenWithoutParams.
|
|
202
|
-
Performance/FlatMap:
|
|
203
|
-
Exclude:
|
|
204
|
-
- 'tools/update-changelog.rb'
|
|
205
|
-
|
|
206
193
|
# Offense count: 1
|
|
207
194
|
Performance/MethodObjectAsBlock:
|
|
208
195
|
Exclude:
|
|
@@ -402,7 +389,7 @@ Style/FileNull:
|
|
|
402
389
|
- 'spec/labkit/middleware/sidekiq/user_experience_sli/server_spec.rb'
|
|
403
390
|
- 'spec/spec_helper.rb'
|
|
404
391
|
|
|
405
|
-
# Offense count:
|
|
392
|
+
# Offense count: 7
|
|
406
393
|
# This cop supports unsafe autocorrection (--autocorrect-all).
|
|
407
394
|
# Configuration parameters: EnforcedStyle.
|
|
408
395
|
# SupportedStyles: always, always_true, never
|
|
@@ -415,7 +402,6 @@ Style/FrozenStringLiteralComment:
|
|
|
415
402
|
- 'spec/labkit/tracing/rails/active_support/cache_read_instrumenter_spec.rb'
|
|
416
403
|
- 'spec/labkit/tracing/rails/active_support/cache_write_instrumenter_spec.rb'
|
|
417
404
|
- 'spec/support/grpc_service/test_services_pb.rb'
|
|
418
|
-
- 'tools/update-changelog.rb'
|
|
419
405
|
|
|
420
406
|
# Offense count: 2
|
|
421
407
|
# This cop supports unsafe autocorrection (--autocorrect-all).
|
|
@@ -539,7 +525,7 @@ Style/StringConcatenation:
|
|
|
539
525
|
- 'lib/labkit/tracing/jaeger_factory.rb'
|
|
540
526
|
- 'lib/labkit/tracing/redis/redis_interceptor_helper.rb'
|
|
541
527
|
|
|
542
|
-
# Offense count:
|
|
528
|
+
# Offense count: 4
|
|
543
529
|
# This cop supports safe autocorrection (--autocorrect).
|
|
544
530
|
# Configuration parameters: EnforcedStyle.
|
|
545
531
|
# SupportedStyles: single_quotes, double_quotes
|
|
@@ -549,7 +535,6 @@ Style/StringLiteralsInInterpolation:
|
|
|
549
535
|
- 'lib/labkit/tracing/grpc/server_interceptor.rb'
|
|
550
536
|
- 'lib/labkit/tracing/jaeger_factory.rb'
|
|
551
537
|
- 'spec/labkit/logging/json_logger_spec.rb'
|
|
552
|
-
- 'tools/update-changelog.rb'
|
|
553
538
|
|
|
554
539
|
# Offense count: 10
|
|
555
540
|
# This cop supports safe autocorrection (--autocorrect).
|
data/AGENTS.md
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
<<<<<<< before updating
|
|
1
2
|
# AGENTS.md
|
|
2
3
|
|
|
3
4
|
Instructions for AI agents and automated tooling working in this repository.
|
|
@@ -134,3 +135,39 @@ When a change does not fit one layer clearly, say so in the MR instead of pickin
|
|
|
134
135
|
Mention the sync agent on the review thread to have it draft the scenario MR; if it cannot, open a labkit-spec issue and link it from the thread.
|
|
135
136
|
- Never edit Lua scripts, key construction, header names, metric names, or log field names to fix a Ruby-only bug.
|
|
136
137
|
If a fix seems to need that, it is a contract change.
|
|
138
|
+
=======
|
|
139
|
+
# Agent guidelines
|
|
140
|
+
|
|
141
|
+
This project uses [Conventional Commits](https://www.conventionalcommits.org/).
|
|
142
|
+
Commit messages drive automated [semantic releases](https://semantic-release.gitbook.io/)
|
|
143
|
+
(see `.releaserc.json`), so use `feat:`, `fix:`, etc. prefixes to ensure the
|
|
144
|
+
correct version bump and changelog entry.
|
|
145
|
+
|
|
146
|
+
## AI-authored GitLab comments
|
|
147
|
+
|
|
148
|
+
Wrap the full body of any comment, note, or reply you post to GitLab (issues,
|
|
149
|
+
merge requests, epics — via `glab`/`glab api`) in `<:robot:>` / `</:robot:>`
|
|
150
|
+
tags (GitLab emoji shortcode, renders as 🤖), so readers can tell at a glance
|
|
151
|
+
that it's AI-generated:
|
|
152
|
+
|
|
153
|
+
```
|
|
154
|
+
<:robot:>
|
|
155
|
+
|
|
156
|
+
...full comment body...
|
|
157
|
+
|
|
158
|
+
</:robot:>
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
This applies to newly posted comments. It does not apply to code, commit
|
|
162
|
+
messages, or MR/issue descriptions unless asked.
|
|
163
|
+
|
|
164
|
+
<!--
|
|
165
|
+
####################################################################
|
|
166
|
+
# 🌊✨ PLEASE ADD PROJECT SPECIFIC RULES BELOW THIS LINE ✨🌊 #
|
|
167
|
+
# The section above is managed by the common-template-copier #
|
|
168
|
+
# template and is updated automatically on `copier update`. #
|
|
169
|
+
# Add your project-specific instructions below this line so #
|
|
170
|
+
# they are preserved when the template is updated. #
|
|
171
|
+
####################################################################
|
|
172
|
+
-->
|
|
173
|
+
>>>>>>> after updating
|
data/CLAUDE.md
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
@AGENTS.md
|
data/Gemfile
CHANGED
|
@@ -3,3 +3,8 @@
|
|
|
3
3
|
source "https://rubygems.org"
|
|
4
4
|
|
|
5
5
|
gemspec
|
|
6
|
+
|
|
7
|
+
# Exports RSpec results to the DX Observer when GLCI_OBSERVER_AUTH_TOKEN is set.
|
|
8
|
+
# Exporter source: https://gitlab.com/gitlab-org/quality/analytics/test-metrics-exporters
|
|
9
|
+
# Owned by: @gitlab-org/quality/analytics (group::development analytics)
|
|
10
|
+
gem 'gitlab-rspec-metrics-exporter', '~> 0.2', groups: [:development, :test]
|
data/README.md
CHANGED
|
@@ -80,27 +80,14 @@ pass.
|
|
|
80
80
|
|
|
81
81
|
Please also review the [development section of the LabKit (go) README](https://gitlab.com/gitlab-org/labkit#developing-labkit) for details of the LabKit architectural philosophy.
|
|
82
82
|
|
|
83
|
-
To work on some of the scripts we use for releasing a new version,
|
|
84
|
-
make sure to add a new `.env.sh`.
|
|
85
|
-
|
|
86
|
-
```console
|
|
87
|
-
cp .env.example.sh .env.sh`
|
|
88
|
-
```
|
|
89
|
-
|
|
90
|
-
Inside `.env.sh`, add a personal acccess token for the `CHANGELOG_GITLAB_TOKEN`
|
|
91
|
-
environment variable. Next source the file:
|
|
92
|
-
|
|
93
|
-
```console
|
|
94
|
-
. .env.sh
|
|
95
|
-
```
|
|
96
|
-
|
|
97
83
|
### Releasing a new version
|
|
98
84
|
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
85
|
+
Releases are cut automatically by
|
|
86
|
+
[semantic-release](https://github.com/semantic-release/semantic-release)
|
|
87
|
+
when changes are merged to `master` or to an `N-N-stable` branch. The
|
|
88
|
+
[Conventional Commits](https://www.conventionalcommits.org/) type of each
|
|
89
|
+
commit decides the version bump (see [AGENTS.md](AGENTS.md)), and the
|
|
90
|
+
release notes are generated from those commit messages.
|
|
104
91
|
|
|
105
92
|
The new version will automatically be published to `gitlab-labkit` on
|
|
106
93
|
[rubygems](https://rubygems.org/gems/gitlab-labkit) when the pipeline
|
|
@@ -66,7 +66,7 @@ Labkit::JsonSchema::RefResolver.cache.clear
|
|
|
66
66
|
|
|
67
67
|
## Use Case Example
|
|
68
68
|
|
|
69
|
-
The `RefResolver` is used in the User Experience SLI Registry [lib/labkit/user_experience_sli/registry.rb](
|
|
69
|
+
The `RefResolver` is used in the User Experience SLI Registry [lib/labkit/user_experience_sli/registry.rb](../user_experience_sli/registry.rb) to validate user experience definitions against a JSON schema.
|
|
70
70
|
|
|
71
71
|
## Implementation Details
|
|
72
72
|
|
|
@@ -173,7 +173,7 @@ RSpec::Matchers.define :complete_user_experience do |user_experience_id, error:
|
|
|
173
173
|
"Failed to complete user experience '#{user_experience_id}':\n" \
|
|
174
174
|
"expected checkpoint='end' counter to increase by 1, but increased by #{@checkpoint_change}\n" \
|
|
175
175
|
"expected total='error: #{error}' counter to increase by 1, but increased by #{@total_change}\n" \
|
|
176
|
-
"expected apdex='success: #{success}' counter to increase by 1, but increased by #{@apdex_change}"
|
|
176
|
+
"expected apdex='success: #{success}' counter to increase by #{error ? 0 : 1}, but increased by #{@apdex_change}"
|
|
177
177
|
end
|
|
178
178
|
|
|
179
179
|
match_when_negated do |actual|
|
|
@@ -192,7 +192,7 @@ RSpec::Matchers.define :complete_user_experience do |user_experience_id, error:
|
|
|
192
192
|
@total_change = total_after - total_before
|
|
193
193
|
@apdex_change = apdex_after - apdex_before
|
|
194
194
|
|
|
195
|
-
@checkpoint_change.zero? && @total_change.zero? && @apdex_change
|
|
195
|
+
@checkpoint_change.zero? && @total_change.zero? && @apdex_change.zero?
|
|
196
196
|
end
|
|
197
197
|
|
|
198
198
|
failure_message_when_negated do
|
data/performance.yml
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
# Performance contract for labkit-ruby
|
|
2
|
+
# https://handbook.gitlab.com/handbook/engineering/testing/performance-contracts/
|
|
3
|
+
#
|
|
4
|
+
# This file is the single entry point for performance contract tooling.
|
|
5
|
+
# Customize the sections relevant to your service and remove the rest.
|
|
6
|
+
# Schema reference: https://handbook.gitlab.com/handbook/engineering/testing/performance-contracts/#schema-definition
|
|
7
|
+
|
|
8
|
+
version: "1.0"
|
|
9
|
+
service:
|
|
10
|
+
name: "labkit-ruby"
|
|
11
|
+
description: "Performance contract for labkit-ruby"
|
|
12
|
+
|
|
13
|
+
# ---------------------------------------------------------------------------
|
|
14
|
+
# Frontend / UI contracts (SiteSpeed)
|
|
15
|
+
# Uncomment and configure if this service has a frontend component.
|
|
16
|
+
# Budget files live in the sitespeed-measurement-setup submodule.
|
|
17
|
+
# ---------------------------------------------------------------------------
|
|
18
|
+
# frontend:
|
|
19
|
+
# enabled: true
|
|
20
|
+
# budgets:
|
|
21
|
+
# production: testrunner/sitespeed-measurement-setup/performance/budgets/environments/production.json
|
|
22
|
+
# staging: testrunner/sitespeed-measurement-setup/performance/budgets/environments/staging.json
|
|
23
|
+
# mr: testrunner/sitespeed-measurement-setup/performance/budgets/environments/mr.json
|
|
24
|
+
# teams:
|
|
25
|
+
# labkit-ruby:
|
|
26
|
+
# url_dir: testrunner/sitespeed-measurement-setup/gitlab/desktop/urls
|
|
27
|
+
# budget: testrunner/sitespeed-measurement-setup/performance/budgets/teams/labkit-ruby.json
|
|
28
|
+
# default_budget: mr
|
|
29
|
+
|
|
30
|
+
# ---------------------------------------------------------------------------
|
|
31
|
+
# Backend / Service contracts (k6 / CPT)
|
|
32
|
+
# Define endpoint categories with latency and error-rate targets.
|
|
33
|
+
# Choose a tier as a starting point, then tune from baseline data.
|
|
34
|
+
#
|
|
35
|
+
# Tier 1 (fast reads): p95=100ms, p99=250ms, error_rate=0.001
|
|
36
|
+
# Tier 2 (std reads): p95=500ms, p99=1000ms, error_rate=0.005
|
|
37
|
+
# Tier 3 (writes): p95=1500ms, p99=3000ms, error_rate=0.01
|
|
38
|
+
# Tier 4 (git ops): p95=5000ms, p99=10000ms,error_rate=0.001
|
|
39
|
+
# ---------------------------------------------------------------------------
|
|
40
|
+
# endpoints:
|
|
41
|
+
# fast_reads:
|
|
42
|
+
# description: >
|
|
43
|
+
# Single item lookup by ID. Simulates one indexed DB read.
|
|
44
|
+
# routes:
|
|
45
|
+
# - "GET /api/v1/items/{id}"
|
|
46
|
+
# metrics:
|
|
47
|
+
# latency_p95_ms: 100
|
|
48
|
+
# latency_p99_ms: 250
|
|
49
|
+
# error_rate_threshold: 0.001
|
|
50
|
+
|
|
51
|
+
# ---------------------------------------------------------------------------
|
|
52
|
+
# Resource budgets (informational; enforcement planned for a future iteration)
|
|
53
|
+
# ---------------------------------------------------------------------------
|
|
54
|
+
# resources:
|
|
55
|
+
# memory_limit_mb: 256
|
|
56
|
+
# cpu_limit_cores: 0.5
|
|
57
|
+
# connection_pool_max: 10
|
|
58
|
+
|
|
59
|
+
# ---------------------------------------------------------------------------
|
|
60
|
+
# SLI mapping -- links contract endpoints to Prometheus metrics emitted by
|
|
61
|
+
# LabKit v2. Fill in once your service is instrumented.
|
|
62
|
+
# ---------------------------------------------------------------------------
|
|
63
|
+
# sli_mapping:
|
|
64
|
+
# metrics_namespace: gitlab
|
|
65
|
+
# component: labkit-ruby
|
|
66
|
+
# fast_reads:
|
|
67
|
+
# requests_total_metric: gitlab_http_requests_total
|
|
68
|
+
# duration_metric: gitlab_http_request_duration_seconds
|
|
69
|
+
# endpoint_id_label: "GET /api/v1/items/{id}"
|
|
70
|
+
# feature_category_label: labkit_ruby
|
data/scripts/prepare-dev-env.sh
CHANGED
|
@@ -21,6 +21,28 @@ warn() {
|
|
|
21
21
|
echo >&2 -e "Recommended reading: https://gitlab.com/gitlab-com/gl-infra/common-ci-tasks/-/blob/main/docs/developer-setup.md"
|
|
22
22
|
}
|
|
23
23
|
|
|
24
|
+
# `mise plugins update` contacts GitHub for every registered plugin: slow, and
|
|
25
|
+
# it adds up when many vendored copies of this script run across many projects
|
|
26
|
+
# on the same machine. Throttle it to once a day using a stamp file in the
|
|
27
|
+
# user's cache directory, deliberately outside the project so that the throttle
|
|
28
|
+
# is shared by every project that vendors this script.
|
|
29
|
+
mise_plugins_update() {
|
|
30
|
+
local stamp_dir="${XDG_CACHE_HOME:-${HOME:-}/.cache}/common-template-copier"
|
|
31
|
+
local stamp_file="${stamp_dir}/mise-plugins-update"
|
|
32
|
+
|
|
33
|
+
# `find -mtime -1` rather than `stat`, which is spelled differently on
|
|
34
|
+
# GNU/BSD. It prints nothing when the stamp is missing or over a day old.
|
|
35
|
+
if [[ -z ${FORCE_MISE_PLUGINS_UPDATE-} ]] && [[ -n $(find "$stamp_file" -mtime -1 2>/dev/null) ]]; then
|
|
36
|
+
echo >&2 "skipping 'mise plugins update' (ran in the last 24h; set FORCE_MISE_PLUGINS_UPDATE=1 to force)"
|
|
37
|
+
return 0
|
|
38
|
+
fi
|
|
39
|
+
|
|
40
|
+
mise plugins update -q
|
|
41
|
+
|
|
42
|
+
# Best effort: a machine without a writable cache dir just updates every time.
|
|
43
|
+
mkdir -p "$stamp_dir" && touch "$stamp_file" || true
|
|
44
|
+
}
|
|
45
|
+
|
|
24
46
|
if command -v mise >/dev/null; then
|
|
25
47
|
echo >&2 -e "mise installed..."
|
|
26
48
|
elif command -v rtx >/dev/null; then
|
|
@@ -53,8 +75,8 @@ fi
|
|
|
53
75
|
|
|
54
76
|
# install mise/asdf dependencies
|
|
55
77
|
echo "installing required plugins with mise install.."
|
|
56
|
-
mise plugins update -q
|
|
57
78
|
mise trust --yes
|
|
79
|
+
mise_plugins_update
|
|
58
80
|
mise install
|
|
59
81
|
|
|
60
82
|
# set PROMPT_COMMAND to empty value for mise if unset
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: gitlab-labkit
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 5.6.
|
|
4
|
+
version: 5.6.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Andrew Newdigate
|
|
@@ -562,9 +562,10 @@ executables:
|
|
|
562
562
|
extensions: []
|
|
563
563
|
extra_rdoc_files: []
|
|
564
564
|
files:
|
|
565
|
+
- ".claude/hooks/precommit-validate.sh"
|
|
566
|
+
- ".claude/settings.json"
|
|
565
567
|
- ".copier-answers.yml"
|
|
566
568
|
- ".editorconfig"
|
|
567
|
-
- ".env.example.sh"
|
|
568
569
|
- ".gitignore"
|
|
569
570
|
- ".gitlab-ci-asdf-versions.yml"
|
|
570
571
|
- ".gitlab-ci-other-versions.yml"
|
|
@@ -574,6 +575,7 @@ files:
|
|
|
574
575
|
- ".gitlab/merge_request_templates/default.md"
|
|
575
576
|
- ".gitleaks.toml"
|
|
576
577
|
- ".mise.toml"
|
|
578
|
+
- ".opencode/plugins/precommit-validate.ts"
|
|
577
579
|
- ".pre-commit-config.yaml"
|
|
578
580
|
- ".releaserc.json"
|
|
579
581
|
- ".rspec"
|
|
@@ -583,6 +585,7 @@ files:
|
|
|
583
585
|
- ".tool-versions"
|
|
584
586
|
- ".yamllint.yaml"
|
|
585
587
|
- AGENTS.md
|
|
588
|
+
- CLAUDE.md
|
|
586
589
|
- CODEOWNERS
|
|
587
590
|
- CONTRIBUTING.md
|
|
588
591
|
- Dangerfile
|
|
@@ -712,6 +715,7 @@ files:
|
|
|
712
715
|
- lib/labkit/user_experience_sli/experience.rb
|
|
713
716
|
- lib/labkit/user_experience_sli/null.rb
|
|
714
717
|
- lib/labkit/user_experience_sli/registry.rb
|
|
718
|
+
- performance.yml
|
|
715
719
|
- renovate.json
|
|
716
720
|
- scripts/prepare-dev-env.sh
|
|
717
721
|
- scripts/update-asdf-version-variables.sh
|
data/.env.example.sh
DELETED
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
export CI_PROJECT_ID=10947578
|
|
2
|
-
export CI_API_V4_URL="https://gitlab.com/api/v4"
|
|
3
|
-
export CI_PROJECT_URL="https://gitlab.com/gitlab-org/ruby/gems/labkit-ruby"
|
|
4
|
-
# Don't keep secrets in plaintext files. Use a keyring or 1password to load
|
|
5
|
-
# it instead and export it as an env var.
|
|
6
|
-
token=$(load-your-token)
|
|
7
|
-
export GITLAB_TOKEN=$token
|