bktide 1.0.1755559112 → 1.0.1755639164

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.
Files changed (32) hide show
  1. package/README.md +42 -0
  2. package/dist/commands/ShowBuild.js +31 -5
  3. package/dist/commands/ShowBuild.js.map +1 -1
  4. package/dist/formatters/build-detail/PlainTextFormatter.js +533 -180
  5. package/dist/formatters/build-detail/PlainTextFormatter.js.map +1 -1
  6. package/dist/formatters/builds/PlainTextFormatter.js +4 -2
  7. package/dist/formatters/builds/PlainTextFormatter.js.map +1 -1
  8. package/dist/formatters/pipelines/PlainTextFormatter.js +3 -6
  9. package/dist/formatters/pipelines/PlainTextFormatter.js.map +1 -1
  10. package/dist/graphql/fragments/index.js +3 -0
  11. package/dist/graphql/fragments/index.js.map +1 -0
  12. package/dist/graphql/fragments/jobs.js +112 -0
  13. package/dist/graphql/fragments/jobs.js.map +1 -0
  14. package/dist/graphql/queries.js +35 -53
  15. package/dist/graphql/queries.js.map +1 -1
  16. package/dist/index.js +1 -0
  17. package/dist/index.js.map +1 -1
  18. package/dist/scripts/extract-data-patterns.js +118 -0
  19. package/dist/scripts/extract-data-patterns.js.map +1 -0
  20. package/dist/services/BuildkiteClient.js +109 -32
  21. package/dist/services/BuildkiteClient.js.map +1 -1
  22. package/dist/services/BuildkiteRestClient.js +8 -7
  23. package/dist/services/BuildkiteRestClient.js.map +1 -1
  24. package/dist/test-helpers/DataProfiler.js +307 -0
  25. package/dist/test-helpers/DataProfiler.js.map +1 -0
  26. package/dist/test-helpers/PatternMockGenerator.js +590 -0
  27. package/dist/test-helpers/PatternMockGenerator.js.map +1 -0
  28. package/dist/ui/theme.js +193 -8
  29. package/dist/ui/theme.js.map +1 -1
  30. package/dist/utils/terminal-links.js +165 -0
  31. package/dist/utils/terminal-links.js.map +1 -0
  32. package/package.json +19 -3
@@ -0,0 +1,590 @@
1
+ /**
2
+ * PatternMockGenerator uses extracted data patterns to generate realistic mock data
3
+ */
4
+ import { faker } from '@faker-js/faker';
5
+ import { MockList } from '@graphql-tools/mock';
6
+ import { promises as fs } from 'fs';
7
+ export class PatternMockGenerator {
8
+ patterns = null;
9
+ patternsPath;
10
+ useDefaultPatterns = false;
11
+ constructor(patternsPath = './test/fixtures/data-patterns.json') {
12
+ this.patternsPath = patternsPath;
13
+ }
14
+ async loadPatterns() {
15
+ try {
16
+ const data = await fs.readFile(this.patternsPath, 'utf-8');
17
+ this.patterns = JSON.parse(data);
18
+ console.log(`✓ Loaded data patterns from ${this.patternsPath}`);
19
+ }
20
+ catch (error) {
21
+ console.warn(`⚠️ Could not load patterns from ${this.patternsPath}, using defaults`);
22
+ this.useDefaultPatterns = true;
23
+ }
24
+ }
25
+ generateMocks() {
26
+ if (!this.patterns && !this.useDefaultPatterns) {
27
+ throw new Error('Patterns not loaded. Call loadPatterns() first.');
28
+ }
29
+ return {
30
+ // Core types
31
+ Build: () => ({
32
+ id: faker.string.uuid(),
33
+ number: this.generateBuildNumber(),
34
+ state: this.generateBuildState(),
35
+ branch: this.generateBranch(),
36
+ message: this.generateCommitMessage(),
37
+ commit: faker.git.commitSha(),
38
+ createdAt: faker.date.recent({ days: 30 }).toISOString(),
39
+ scheduledAt: faker.date.recent({ days: 30 }).toISOString(),
40
+ startedAt: faker.date.recent({ days: 30 }).toISOString(),
41
+ finishedAt: this.generateFinishedAt(),
42
+ canceledAt: null,
43
+ url: `https://buildkite.com/${faker.word.noun()}/${faker.word.noun()}/builds/${faker.number.int({ min: 1, max: 9999 })}`,
44
+ webUrl: `https://buildkite.com/${faker.word.noun()}/${faker.word.noun()}/builds/${faker.number.int({ min: 1, max: 9999 })}`,
45
+ pullRequest: this.generatePullRequest(),
46
+ rebuiltFrom: null,
47
+ jobs: this.generateJobs(),
48
+ annotations: this.generateAnnotations(),
49
+ createdBy: this.generateCreator(),
50
+ pipeline: this.generatePipelineRef(),
51
+ organization: this.generateOrganizationRef()
52
+ }),
53
+ Pipeline: () => ({
54
+ id: faker.string.uuid(),
55
+ graphqlId: faker.string.uuid(),
56
+ slug: this.generatePipelineSlug(),
57
+ name: this.generatePipelineName(),
58
+ description: faker.datatype.boolean({ probability: 0.7 })
59
+ ? faker.lorem.sentence()
60
+ : null,
61
+ url: `https://buildkite.com/${faker.word.noun()}/${faker.word.noun()}`,
62
+ webUrl: `https://buildkite.com/${faker.word.noun()}/${faker.word.noun()}`,
63
+ repository: this.generateRepository(),
64
+ defaultBranch: this.generateDefaultBranch(),
65
+ visibility: this.generateVisibility(),
66
+ archived: faker.datatype.boolean({ probability: 0.05 }),
67
+ createdAt: faker.date.past({ years: 2 }).toISOString(),
68
+ createdBy: this.generateCreator(),
69
+ builds: () => new MockList([0, 10]),
70
+ organization: this.generateOrganizationRef()
71
+ }),
72
+ Job: () => this.generateJob(),
73
+ JobTypeCommand: () => ({
74
+ ...this.generateJobBase(),
75
+ __typename: 'JobTypeCommand',
76
+ command: faker.helpers.arrayElement([
77
+ 'npm test',
78
+ 'yarn build',
79
+ 'make test',
80
+ './scripts/test.sh',
81
+ 'docker build .',
82
+ 'pytest',
83
+ 'cargo test'
84
+ ]),
85
+ exitStatus: this.generateExitStatus(),
86
+ passed: faker.datatype.boolean({ probability: 0.85 }),
87
+ softFailed: faker.datatype.boolean({ probability: 0.02 }),
88
+ parallelGroupIndex: this.generateParallelGroupIndex(),
89
+ parallelGroupTotal: this.generateParallelGroupTotal(),
90
+ retriedAutomatically: faker.datatype.boolean({
91
+ probability: this.patterns?.jobs.retryRates.automatic || 0.05
92
+ }),
93
+ retriedManually: faker.datatype.boolean({
94
+ probability: this.patterns?.jobs.retryRates.manual || 0.02
95
+ }),
96
+ retryType: null,
97
+ agent: this.generateAgent(),
98
+ agentQueryRules: [],
99
+ artifacts: () => new MockList([0, 5])
100
+ }),
101
+ JobTypeWait: () => ({
102
+ ...this.generateJobBase(),
103
+ __typename: 'JobTypeWait',
104
+ continueOnFailure: faker.datatype.boolean({ probability: 0.1 })
105
+ }),
106
+ JobTypeTrigger: () => ({
107
+ ...this.generateJobBase(),
108
+ __typename: 'JobTypeTrigger',
109
+ triggered: faker.datatype.boolean({ probability: 0.9 }),
110
+ triggeredBuild: faker.datatype.boolean({ probability: 0.9 })
111
+ ? { id: faker.string.uuid() }
112
+ : null
113
+ }),
114
+ Organization: () => ({
115
+ id: faker.string.uuid(),
116
+ graphqlId: faker.string.uuid(),
117
+ slug: this.generateOrganizationSlug(),
118
+ name: this.generateOrganizationName(),
119
+ url: `https://buildkite.com/${faker.word.noun()}`,
120
+ webUrl: `https://buildkite.com/${faker.word.noun()}`,
121
+ pipelines: () => new MockList(this.selectByDistribution(this.patterns?.organizations.pipelineCount || {
122
+ values: [{ value: 10, frequency: 0.5, count: 1 }]
123
+ })),
124
+ members: () => new MockList(this.selectByDistribution(this.patterns?.organizations.memberCount || {
125
+ values: [{ value: 5, frequency: 0.5, count: 1 }]
126
+ })),
127
+ teams: () => new MockList([1, 5]),
128
+ createdAt: faker.date.past({ years: 3 }).toISOString()
129
+ }),
130
+ Annotation: () => ({
131
+ id: faker.string.uuid(),
132
+ context: this.generateAnnotationContext(),
133
+ style: this.generateAnnotationStyle(),
134
+ bodyHtml: this.generateAnnotationBody(),
135
+ createdAt: faker.date.recent({ days: 1 }).toISOString(),
136
+ updatedAt: faker.date.recent({ days: 1 }).toISOString()
137
+ }),
138
+ User: () => ({
139
+ id: faker.string.uuid(),
140
+ uuid: faker.string.uuid(),
141
+ name: this.generateUserName(),
142
+ email: this.generateUserEmail(),
143
+ avatar: {
144
+ url: faker.image.avatar()
145
+ },
146
+ bot: faker.datatype.boolean({
147
+ probability: this.patterns?.builds.creatorPatterns.botUsers || 0.1
148
+ })
149
+ }),
150
+ Agent: () => this.generateAgent(),
151
+ Viewer: () => ({
152
+ id: faker.string.uuid(),
153
+ user: {
154
+ id: faker.string.uuid(),
155
+ uuid: faker.string.uuid(),
156
+ name: faker.person.fullName(),
157
+ email: faker.internet.email()
158
+ },
159
+ organizations: () => new MockList([1, 5])
160
+ }),
161
+ // Scalar types
162
+ DateTime: () => faker.date.recent().toISOString(),
163
+ ISO8601Date: () => faker.date.recent().toISOString().split('T')[0],
164
+ JSON: () => JSON.stringify({ key: faker.word.noun(), value: faker.word.verb() }),
165
+ YAML: () => `key: ${faker.word.noun()}\nvalue: ${faker.word.verb()}`,
166
+ Int: () => faker.number.int({ min: 0, max: 1000 }),
167
+ Float: () => faker.number.float({ min: 0, max: 1000, multipleOf: 0.01 }),
168
+ Boolean: () => faker.datatype.boolean(),
169
+ String: () => faker.lorem.word()
170
+ };
171
+ }
172
+ selectByDistribution(distribution) {
173
+ if (!distribution.values || distribution.values.length === 0) {
174
+ // Return a default value based on type
175
+ return 0;
176
+ }
177
+ const random = Math.random();
178
+ let cumulative = 0;
179
+ for (const item of distribution.values) {
180
+ cumulative += item.frequency;
181
+ if (random <= cumulative) {
182
+ return item.value;
183
+ }
184
+ }
185
+ return distribution.values[0].value;
186
+ }
187
+ generateBuildNumber() {
188
+ if (this.patterns?.builds.numberRange) {
189
+ const { min, max } = this.patterns.builds.numberRange;
190
+ return faker.number.int({ min, max });
191
+ }
192
+ return faker.number.int({ min: 1, max: 9999 });
193
+ }
194
+ generateBuildState() {
195
+ if (this.patterns?.builds.states) {
196
+ return this.selectByDistribution(this.patterns.builds.states);
197
+ }
198
+ return faker.helpers.arrayElement([
199
+ 'PASSED', 'FAILED', 'RUNNING', 'SCHEDULED',
200
+ 'CANCELED', 'CANCELING', 'BLOCKED', 'NOT_RUN'
201
+ ]);
202
+ }
203
+ generateBranch() {
204
+ if (!this.patterns?.builds.branches) {
205
+ return faker.git.branch();
206
+ }
207
+ const formats = this.patterns.builds.branches.formats;
208
+ const random = Math.random();
209
+ if (random < formats.feature) {
210
+ return `feature/${faker.word.verb()}-${faker.word.noun()}`;
211
+ }
212
+ else if (random < formats.feature + formats.bugfix) {
213
+ return `bugfix/${faker.word.verb()}-${faker.word.noun()}`;
214
+ }
215
+ else if (random < formats.feature + formats.bugfix + formats.release) {
216
+ return `release/${faker.system.semver()}`;
217
+ }
218
+ else if (random < formats.feature + formats.bugfix + formats.release + formats.main) {
219
+ return faker.helpers.arrayElement(['main', 'master', 'develop']);
220
+ }
221
+ else {
222
+ return faker.git.branch();
223
+ }
224
+ }
225
+ generateCommitMessage() {
226
+ if (!this.patterns?.builds.messagePatterns) {
227
+ return faker.git.commitMessage();
228
+ }
229
+ const patterns = this.patterns.builds.messagePatterns;
230
+ const useConventional = Math.random() < patterns.conventionalCommits;
231
+ const useEmoji = Math.random() < patterns.hasEmoji;
232
+ const useGithubRef = Math.random() < patterns.githubRefs;
233
+ const useJiraRef = Math.random() < patterns.jiraRefs;
234
+ const useMultiline = Math.random() < patterns.multiline;
235
+ let message = '';
236
+ if (useConventional) {
237
+ const type = faker.helpers.arrayElement([
238
+ 'feat', 'fix', 'docs', 'style', 'refactor',
239
+ 'test', 'chore', 'perf', 'ci', 'build'
240
+ ]);
241
+ const scope = Math.random() < 0.3 ? `(${faker.word.noun()})` : '';
242
+ message = `${type}${scope}: `;
243
+ }
244
+ if (useEmoji) {
245
+ message += faker.helpers.arrayElement(['🎉', '🚀', '✨', '🔧', '📦', '👷', '🐛', '⚡️', '✅', '💚']) + ' ';
246
+ }
247
+ message += faker.git.commitMessage();
248
+ if (useGithubRef) {
249
+ message += ` (#${faker.number.int({ min: 1, max: 9999 })})`;
250
+ }
251
+ if (useJiraRef) {
252
+ const project = faker.helpers.arrayElement(['PROJ', 'TEAM', 'BUG', 'FEAT']);
253
+ message += ` ${project}-${faker.number.int({ min: 1, max: 9999 })}`;
254
+ }
255
+ if (useMultiline) {
256
+ message += '\n\n' + faker.lorem.paragraph();
257
+ }
258
+ return message;
259
+ }
260
+ generateFinishedAt() {
261
+ const shouldBeFinished = Math.random() < 0.9;
262
+ if (shouldBeFinished) {
263
+ return faker.date.recent({ days: 30 }).toISOString();
264
+ }
265
+ return null;
266
+ }
267
+ generatePullRequest() {
268
+ const hasPR = Math.random() < 0.3;
269
+ if (!hasPR)
270
+ return null;
271
+ return {
272
+ id: faker.number.int({ min: 1, max: 9999 }).toString(),
273
+ base: faker.git.branch(),
274
+ repository: `https://github.com/${faker.word.noun()}/${faker.word.noun()}`
275
+ };
276
+ }
277
+ generateJobs() {
278
+ const count = this.patterns?.builds.jobCounts
279
+ ? this.selectByDistribution(this.patterns.builds.jobCounts)
280
+ : faker.number.int({ min: 1, max: 10 });
281
+ return () => new MockList(count);
282
+ }
283
+ generateAnnotations() {
284
+ const count = this.patterns?.builds.annotationCounts
285
+ ? this.selectByDistribution(this.patterns.builds.annotationCounts)
286
+ : faker.number.int({ min: 0, max: 3 });
287
+ return () => new MockList(count);
288
+ }
289
+ generateCreator() {
290
+ return {
291
+ id: faker.string.uuid(),
292
+ name: this.generateUserName(),
293
+ email: this.generateUserEmail(),
294
+ avatar: {
295
+ url: faker.image.avatar()
296
+ }
297
+ };
298
+ }
299
+ generateUserName() {
300
+ if (this.patterns?.builds.creatorPatterns.nameFormats) {
301
+ const format = this.selectByDistribution(this.patterns.builds.creatorPatterns.nameFormats);
302
+ switch (format) {
303
+ case 'full-name':
304
+ return faker.person.fullName();
305
+ case 'dotted':
306
+ return `${faker.person.firstName()}.${faker.person.lastName()}`.toLowerCase();
307
+ case 'hyphenated':
308
+ return `${faker.person.firstName()}-${faker.person.lastName()}`.toLowerCase();
309
+ case 'underscored':
310
+ return `${faker.person.firstName()}_${faker.person.lastName()}`.toLowerCase();
311
+ case 'lowercase':
312
+ return faker.internet.username().toLowerCase();
313
+ default:
314
+ return faker.person.fullName();
315
+ }
316
+ }
317
+ return faker.person.fullName();
318
+ }
319
+ generateUserEmail() {
320
+ if (this.patterns?.builds.creatorPatterns.domains) {
321
+ const domain = this.selectByDistribution(this.patterns.builds.creatorPatterns.domains);
322
+ return `${faker.internet.username()}@${domain}`.toLowerCase();
323
+ }
324
+ return faker.internet.email();
325
+ }
326
+ generatePipelineSlug() {
327
+ const format = this.patterns?.pipelines.slugFormats
328
+ ? this.selectByDistribution(this.patterns.pipelines.slugFormats)
329
+ : 'kebab-case';
330
+ const words = [faker.word.noun(), faker.word.verb()];
331
+ switch (format) {
332
+ case 'kebab-case':
333
+ return words.join('-').toLowerCase();
334
+ case 'snake_case':
335
+ return words.join('_').toLowerCase();
336
+ case 'camelCase':
337
+ return words[0].toLowerCase() + words.slice(1).map(w => w.charAt(0).toUpperCase() + w.slice(1).toLowerCase()).join('');
338
+ default:
339
+ return words.join('').toLowerCase();
340
+ }
341
+ }
342
+ generatePipelineName() {
343
+ const length = this.patterns?.pipelines.nameLength?.average || 20;
344
+ const variance = 10;
345
+ const targetLength = Math.max(5, Math.floor(length + (Math.random() - 0.5) * variance));
346
+ let name = faker.company.name();
347
+ while (name.length < targetLength) {
348
+ name += ' ' + faker.word.noun();
349
+ }
350
+ return name.substring(0, targetLength);
351
+ }
352
+ generateRepository() {
353
+ const provider = this.patterns?.pipelines.repositoryProviders
354
+ ? this.selectByDistribution(this.patterns.pipelines.repositoryProviders)
355
+ : 'github';
356
+ const org = faker.word.noun();
357
+ const repo = faker.word.noun();
358
+ switch (provider) {
359
+ case 'github':
360
+ return {
361
+ url: `https://github.com/${org}/${repo}`,
362
+ provider: { name: 'GitHub' }
363
+ };
364
+ case 'gitlab':
365
+ return {
366
+ url: `https://gitlab.com/${org}/${repo}`,
367
+ provider: { name: 'GitLab' }
368
+ };
369
+ case 'bitbucket':
370
+ return {
371
+ url: `https://bitbucket.org/${org}/${repo}`,
372
+ provider: { name: 'Bitbucket' }
373
+ };
374
+ default:
375
+ return {
376
+ url: `git@git.example.com:${org}/${repo}.git`,
377
+ provider: { name: 'Git' }
378
+ };
379
+ }
380
+ }
381
+ generateDefaultBranch() {
382
+ if (this.patterns?.pipelines.defaultBranches) {
383
+ return this.selectByDistribution(this.patterns.pipelines.defaultBranches);
384
+ }
385
+ return faker.helpers.arrayElement(['main', 'master', 'develop']);
386
+ }
387
+ generateVisibility() {
388
+ if (this.patterns?.pipelines.visibility) {
389
+ return this.selectByDistribution(this.patterns.pipelines.visibility);
390
+ }
391
+ return faker.helpers.arrayElement(['PRIVATE', 'PUBLIC']);
392
+ }
393
+ generateJobBase() {
394
+ return {
395
+ id: faker.string.uuid(),
396
+ uuid: faker.string.uuid(),
397
+ label: this.generateJobLabel(),
398
+ state: this.generateJobState(),
399
+ runAt: faker.date.recent({ days: 1 }).toISOString(),
400
+ scheduledAt: faker.date.recent({ days: 1 }).toISOString(),
401
+ startedAt: faker.date.recent({ days: 1 }).toISOString(),
402
+ finishedAt: faker.date.recent({ days: 1 }).toISOString(),
403
+ canceledAt: null,
404
+ unblockable: faker.datatype.boolean({ probability: 0.1 }),
405
+ unblockUrl: null,
406
+ url: `https://buildkite.com/${faker.word.noun()}/${faker.word.noun()}/builds/${faker.number.int()}/jobs/${faker.string.uuid()}`,
407
+ webUrl: `https://buildkite.com/${faker.word.noun()}/${faker.word.noun()}/builds/${faker.number.int()}#${faker.string.uuid()}`,
408
+ build: { id: faker.string.uuid() }
409
+ };
410
+ }
411
+ generateJob() {
412
+ const type = faker.helpers.arrayElement(['command', 'wait', 'trigger']);
413
+ switch (type) {
414
+ case 'wait':
415
+ return { __typename: 'JobTypeWait' };
416
+ case 'trigger':
417
+ return { __typename: 'JobTypeTrigger' };
418
+ default:
419
+ return { __typename: 'JobTypeCommand' };
420
+ }
421
+ }
422
+ generateJobLabel() {
423
+ if (this.patterns?.jobs.labelPatterns) {
424
+ const pattern = this.selectByDistribution(this.patterns.jobs.labelPatterns);
425
+ return pattern
426
+ .replace(':version', faker.system.semver())
427
+ .replace(':os', faker.helpers.arrayElement(['linux', 'ubuntu', 'macos', 'windows']))
428
+ .replace(':test', faker.helpers.arrayElement(['unit', 'integration', 'e2e', 'smoke']))
429
+ .replace(':sha', faker.git.commitSha().substring(0, 7));
430
+ }
431
+ return faker.helpers.arrayElement([
432
+ `Test on ${faker.helpers.arrayElement(['Node', 'Python', 'Ruby'])} ${faker.system.semver()}`,
433
+ 'Build Docker Image',
434
+ 'Deploy to Staging',
435
+ 'Run Integration Tests',
436
+ 'Lint and Format',
437
+ 'Security Scan',
438
+ 'Performance Tests'
439
+ ]);
440
+ }
441
+ generateJobState() {
442
+ return faker.helpers.arrayElement([
443
+ 'PENDING', 'WAITING', 'BLOCKED', 'UNBLOCKED', 'LIMITING',
444
+ 'LIMITED', 'SCHEDULED', 'ASSIGNED', 'ACCEPTED', 'RUNNING',
445
+ 'FINISHED', 'CANCELING', 'CANCELED', 'TIMING_OUT',
446
+ 'TIMED_OUT', 'SKIPPED', 'BROKEN'
447
+ ]);
448
+ }
449
+ generateExitStatus() {
450
+ if (this.patterns?.jobs.exitStatusDistribution) {
451
+ return this.selectByDistribution(this.patterns.jobs.exitStatusDistribution);
452
+ }
453
+ const hasExitStatus = Math.random() < 0.95;
454
+ if (!hasExitStatus)
455
+ return null;
456
+ // Most jobs succeed (0), some fail (1), rare other codes
457
+ const random = Math.random();
458
+ if (random < 0.85)
459
+ return 0;
460
+ if (random < 0.95)
461
+ return 1;
462
+ return faker.helpers.arrayElement([2, 127, 128, 130, 137]);
463
+ }
464
+ generateParallelGroupIndex() {
465
+ const hasParallel = Math.random() < 0.2;
466
+ if (!hasParallel)
467
+ return null;
468
+ return faker.number.int({ min: 0, max: 9 });
469
+ }
470
+ generateParallelGroupTotal() {
471
+ const hasParallel = Math.random() < 0.2;
472
+ if (!hasParallel)
473
+ return null;
474
+ return faker.number.int({ min: 2, max: 10 });
475
+ }
476
+ generateAgent() {
477
+ return {
478
+ id: faker.string.uuid(),
479
+ uuid: faker.string.uuid(),
480
+ name: faker.helpers.arrayElement([
481
+ `agent-${faker.word.noun()}-${faker.number.int({ min: 1, max: 99 })}`,
482
+ `buildkite-agent-${faker.string.alphanumeric(8)}`,
483
+ `${faker.helpers.arrayElement(['linux', 'macos', 'windows'])}-${faker.number.int({ min: 1, max: 20 })}`
484
+ ]),
485
+ hostname: faker.internet.domainName(),
486
+ version: faker.system.semver(),
487
+ isRunningJob: faker.datatype.boolean({ probability: 0.3 })
488
+ };
489
+ }
490
+ generateOrganizationSlug() {
491
+ const format = this.patterns?.organizations.slugFormats
492
+ ? this.selectByDistribution(this.patterns.organizations.slugFormats)
493
+ : 'kebab-case';
494
+ const name = faker.company.name().toLowerCase();
495
+ switch (format) {
496
+ case 'kebab-case':
497
+ return name.replace(/\s+/g, '-').replace(/[^a-z0-9-]/g, '');
498
+ case 'snake_case':
499
+ return name.replace(/\s+/g, '_').replace(/[^a-z0-9_]/g, '');
500
+ default:
501
+ return name.replace(/[^a-z0-9]/g, '');
502
+ }
503
+ }
504
+ generateOrganizationName() {
505
+ const length = this.patterns?.organizations.nameLength?.average || 15;
506
+ const variance = 10;
507
+ const targetLength = Math.max(3, Math.floor(length + (Math.random() - 0.5) * variance));
508
+ let name = faker.company.name();
509
+ while (name.length < targetLength) {
510
+ name += ' ' + faker.company.buzzNoun();
511
+ }
512
+ return name.substring(0, targetLength);
513
+ }
514
+ generatePipelineRef() {
515
+ return {
516
+ id: faker.string.uuid(),
517
+ slug: this.generatePipelineSlug(),
518
+ name: this.generatePipelineName()
519
+ };
520
+ }
521
+ generateOrganizationRef() {
522
+ return {
523
+ id: faker.string.uuid(),
524
+ slug: this.generateOrganizationSlug(),
525
+ name: this.generateOrganizationName()
526
+ };
527
+ }
528
+ generateAnnotationContext() {
529
+ return faker.helpers.arrayElement([
530
+ 'test-results',
531
+ 'coverage',
532
+ 'lint',
533
+ 'security',
534
+ 'performance',
535
+ 'deployment',
536
+ 'release-notes'
537
+ ]);
538
+ }
539
+ generateAnnotationStyle() {
540
+ return faker.helpers.arrayElement(['info', 'warning', 'error', 'success']);
541
+ }
542
+ generateAnnotationBody() {
543
+ const useMarkdown = Math.random() < 0.6;
544
+ if (useMarkdown) {
545
+ const style = faker.helpers.arrayElement(['summary', 'detailed', 'table']);
546
+ switch (style) {
547
+ case 'summary':
548
+ return `<h3>${faker.lorem.sentence()}</h3>
549
+ <p>${faker.lorem.paragraph()}</p>
550
+ <ul>
551
+ <li>✅ ${faker.lorem.sentence()}</li>
552
+ <li>⚠️ ${faker.lorem.sentence()}</li>
553
+ <li>❌ ${faker.lorem.sentence()}</li>
554
+ </ul>`;
555
+ case 'detailed':
556
+ return `<details>
557
+ <summary>${faker.lorem.sentence()}</summary>
558
+ <p>${faker.lorem.paragraph()}</p>
559
+ <pre><code>${faker.hacker.phrase()}</code></pre>
560
+ </details>`;
561
+ case 'table':
562
+ return `<table>
563
+ <thead>
564
+ <tr>
565
+ <th>Test</th>
566
+ <th>Status</th>
567
+ <th>Duration</th>
568
+ </tr>
569
+ </thead>
570
+ <tbody>
571
+ <tr>
572
+ <td>${faker.hacker.noun()}</td>
573
+ <td>✅ Passed</td>
574
+ <td>${faker.number.float({ min: 0.1, max: 10, multipleOf: 0.1 })}s</td>
575
+ </tr>
576
+ <tr>
577
+ <td>${faker.hacker.noun()}</td>
578
+ <td>❌ Failed</td>
579
+ <td>${faker.number.float({ min: 0.1, max: 10, multipleOf: 0.1 })}s</td>
580
+ </tr>
581
+ </tbody>
582
+ </table>`;
583
+ default:
584
+ return `<p>${faker.lorem.paragraph()}</p>`;
585
+ }
586
+ }
587
+ return `<p>${faker.lorem.paragraph()}</p>`;
588
+ }
589
+ }
590
+ //# sourceMappingURL=PatternMockGenerator.js.map