qualink 0.2.0 → 0.4.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.
Files changed (48) hide show
  1. package/README.md +79 -0
  2. package/dist/cli/command-factory.d.ts +23 -23
  3. package/dist/cli/commands/biome.d.ts +23 -23
  4. package/dist/cli/commands/coverage-dotnet.d.ts +23 -23
  5. package/dist/cli/commands/coverage-js.d.ts +23 -23
  6. package/dist/cli/commands/eslint.d.ts +23 -23
  7. package/dist/cli/commands/index.d.ts +1 -0
  8. package/dist/cli/commands/index.js +1 -0
  9. package/dist/cli/commands/lighthouse.d.ts +23 -23
  10. package/dist/cli/commands/lighthouse.js +4 -1
  11. package/dist/cli/commands/meta.d.ts +23 -23
  12. package/dist/cli/commands/pipeline.d.ts +76 -0
  13. package/dist/cli/commands/pipeline.js +35 -0
  14. package/dist/cli/commands/sarif.d.ts +23 -23
  15. package/dist/cli/common-args.d.ts +2 -2
  16. package/dist/cli/common-args.js +1 -1
  17. package/dist/cli/detect-ci.d.ts +2 -0
  18. package/dist/cli/detect-ci.js +47 -0
  19. package/dist/cli/detect-project.js +31 -5
  20. package/dist/cli/detect-solution.d.ts +2 -0
  21. package/dist/cli/detect-solution.js +70 -0
  22. package/dist/cli/index.js +123 -1
  23. package/dist/cli/multi-collect/config.d.ts +23 -0
  24. package/dist/cli/multi-collect/config.js +105 -0
  25. package/dist/cli/multi-collect/discover.d.ts +11 -0
  26. package/dist/cli/multi-collect/discover.js +84 -0
  27. package/dist/cli/multi-collect/patterns.d.ts +16 -0
  28. package/dist/cli/multi-collect/patterns.js +20 -0
  29. package/dist/cli/multi-collect/resolve-metadata.d.ts +17 -0
  30. package/dist/cli/multi-collect/resolve-metadata.js +147 -0
  31. package/dist/cli/multi-collect/run-collector.d.ts +11 -0
  32. package/dist/cli/multi-collect/run-collector.js +75 -0
  33. package/dist/cli/parse-metadata.d.ts +1 -0
  34. package/dist/cli/parse-metadata.js +3 -3
  35. package/dist/collectors/eslint.d.ts +2 -0
  36. package/dist/collectors/eslint.js +32 -3
  37. package/dist/collectors/index.d.ts +1 -0
  38. package/dist/collectors/index.js +1 -0
  39. package/dist/collectors/lighthouse.d.ts +4 -1
  40. package/dist/collectors/lighthouse.js +89 -1
  41. package/dist/collectors/pipeline.d.ts +13 -0
  42. package/dist/collectors/pipeline.js +31 -0
  43. package/dist/normalize.js +1 -1
  44. package/dist/sinks/elastic.js +1 -0
  45. package/dist/types.d.ts +32 -4
  46. package/package.json +6 -6
  47. package/dist/cli/detect-package.d.ts +0 -3
  48. package/dist/cli/detect-package.js +0 -42
package/README.md CHANGED
@@ -26,6 +26,79 @@ Repo, branch, commit SHA, pipeline run ID, and provider are auto-detected from C
26
26
 
27
27
  See the [examples/](examples/) folder for copy-paste snippets for Azure DevOps and GitHub Actions.
28
28
 
29
+ ## Pipeline Tracking
30
+
31
+ Track pipeline execution metrics — which pipelines run, when, for how long, and their outcome.
32
+ Pipelines self-report by calling `qualink pipeline --status <status>` at the end of a run.
33
+
34
+ ### Azure DevOps
35
+
36
+ ```yaml
37
+ steps:
38
+ - script: echo "##vso[task.setvariable variable=PIPELINE_START]$(date +%s%3N)"
39
+ displayName: Record start time
40
+
41
+ # ... existing build/test steps ...
42
+
43
+ - script: |
44
+ END_TIME=$(date +%s%3N)
45
+ DURATION=$(( END_TIME - $(PIPELINE_START) ))
46
+ npx qualink pipeline \
47
+ --status "$(Agent.JobStatus)" \
48
+ --duration "$DURATION" \
49
+ --sink elastic
50
+ displayName: Report pipeline metrics
51
+ condition: always()
52
+ env:
53
+ ELASTIC_URL: $(ELASTIC_URL)
54
+ ELASTIC_API_KEY: $(ELASTIC_API_KEY)
55
+ ```
56
+
57
+ Auto-detected from Azure DevOps env: pipeline name (`BUILD_DEFINITIONNAME`), trigger (`BUILD_REASON`), repo, branch, commit, run ID, provider.
58
+
59
+ ### GitHub Actions
60
+
61
+ ```yaml
62
+ jobs:
63
+ build:
64
+ runs-on: ubuntu-latest
65
+ steps:
66
+ - name: Record start time
67
+ run: echo "PIPELINE_START=$(date +%s%3N)" >> "$GITHUB_ENV"
68
+
69
+ # ... existing build/test steps ...
70
+
71
+ - name: Report pipeline metrics
72
+ if: always()
73
+ run: |
74
+ END_TIME=$(date +%s%3N)
75
+ DURATION=$(( END_TIME - PIPELINE_START ))
76
+ npx qualink pipeline \
77
+ --status "${{ job.status }}" \
78
+ --duration "$DURATION" \
79
+ --sink elastic
80
+ env:
81
+ ELASTIC_URL: ${{ secrets.ELASTIC_URL }}
82
+ ELASTIC_API_KEY: ${{ secrets.ELASTIC_API_KEY }}
83
+ ```
84
+
85
+ Auto-detected from GitHub env: pipeline name (`GITHUB_WORKFLOW`), trigger (`GITHUB_EVENT_NAME`), repo, branch, commit, run ID, provider.
86
+
87
+ ### Per-stage reporting
88
+
89
+ For pipelines with distinct stages, call qualink once per stage with `--stage-name`:
90
+
91
+ ```yaml
92
+ # Azure DevOps example
93
+ - script: |
94
+ npx qualink pipeline --status "$(Agent.JobStatus)" --stage-name build --duration "$BUILD_DURATION"
95
+ condition: always()
96
+
97
+ - script: |
98
+ npx qualink pipeline --status "$(Agent.JobStatus)" --stage-name deploy --duration "$DEPLOY_DURATION"
99
+ condition: always()
100
+ ```
101
+
29
102
  ## CLI usage
30
103
 
31
104
  ```bash
@@ -38,6 +111,12 @@ Examples:
38
111
  qualink collect eslint --input eslint-report.json --sink elastic --repo frontend-mono --category frontend --tags frontend,web --branch main --commit-sha abc123 --pipeline-run-id 987
39
112
  qualink collect sarif --input analyzers.sarif --sink elastic --repo backend-api --category backend --tags backend,api --branch main --commit-sha def456 --pipeline-run-id 654
40
113
  qualink collect coverage-dotnet --input coverage.cobertura.xml --sink elastic --repo backend-api --category backend --tags backend,api --branch main --commit-sha def456 --pipeline-run-id 654
114
+
115
+ # Pipeline tracking (top-level command, not under collect)
116
+ qualink pipeline --status succeeded --sink elastic
117
+ qualink pipeline --status succeeded --duration 125000 --pipeline-name "Build and Deploy"
118
+ qualink pipeline --status succeeded --stage-name build --duration 45000
119
+ qualink pipeline --status failed --dry-run
41
120
  ```
42
121
 
43
122
  Collectors:
@@ -11,77 +11,77 @@ interface CollectorCommandConfig<TExtra extends Record<string, unknown>> {
11
11
  collect: (args: CommonArgs, metadata: CommonMetadata) => Promise<CollectorResult>;
12
12
  }
13
13
  export declare function createCollectorCommand<TExtra extends Record<string, unknown>>(config: CollectorCommandConfig<TExtra>): import("citty").CommandDef<{
14
- input: {
14
+ readonly input: {
15
15
  readonly type: "string";
16
16
  readonly required: true;
17
17
  };
18
- sink: {
18
+ readonly sink: {
19
19
  readonly type: "string";
20
20
  readonly default: "elastic";
21
21
  };
22
- repo: {
22
+ readonly repo: {
23
23
  readonly type: "string";
24
24
  };
25
- category: {
25
+ readonly category: {
26
26
  readonly type: "string";
27
27
  };
28
- tags: {
28
+ readonly tags: {
29
29
  readonly type: "string";
30
30
  };
31
- branch: {
31
+ readonly branch: {
32
32
  readonly type: "string";
33
33
  };
34
- "commit-sha": {
34
+ readonly "commit-sha": {
35
35
  readonly type: "string";
36
36
  };
37
- "pipeline-run-id": {
37
+ readonly "pipeline-run-id": {
38
38
  readonly type: "string";
39
39
  };
40
- "pipeline-provider": {
40
+ readonly "pipeline-provider": {
41
41
  readonly type: "string";
42
42
  };
43
- environment: {
43
+ readonly environment: {
44
44
  readonly type: "string";
45
45
  readonly default: "ci";
46
46
  };
47
- package: {
47
+ readonly solution: {
48
48
  readonly type: "string";
49
49
  };
50
- project: {
50
+ readonly project: {
51
51
  readonly type: "string";
52
52
  };
53
- "collector-version": {
53
+ readonly "collector-version": {
54
54
  readonly type: "string";
55
55
  };
56
- "elastic-url": {
56
+ readonly "elastic-url": {
57
57
  readonly type: "string";
58
58
  };
59
- "elastic-api-key": {
59
+ readonly "elastic-api-key": {
60
60
  readonly type: "string";
61
61
  };
62
- "loki-url": {
62
+ readonly "loki-url": {
63
63
  readonly type: "string";
64
64
  };
65
- "loki-username": {
65
+ readonly "loki-username": {
66
66
  readonly type: "string";
67
67
  };
68
- "loki-password": {
68
+ readonly "loki-password": {
69
69
  readonly type: "string";
70
70
  };
71
- "loki-tenant-id": {
71
+ readonly "loki-tenant-id": {
72
72
  readonly type: "string";
73
73
  };
74
- "retry-max": {
74
+ readonly "retry-max": {
75
75
  readonly type: "string";
76
76
  };
77
- "retry-backoff-ms": {
77
+ readonly "retry-backoff-ms": {
78
78
  readonly type: "string";
79
79
  };
80
- "allow-empty": {
80
+ readonly "allow-empty": {
81
81
  readonly type: "boolean";
82
82
  readonly default: false;
83
83
  };
84
- "dry-run": {
84
+ readonly "dry-run": {
85
85
  readonly type: "boolean";
86
86
  readonly default: false;
87
87
  };
@@ -1,75 +1,75 @@
1
1
  export declare const biomeCommand: import("citty").CommandDef<{
2
- input: {
2
+ readonly input: {
3
3
  readonly type: "string";
4
4
  readonly required: true;
5
5
  };
6
- sink: {
6
+ readonly sink: {
7
7
  readonly type: "string";
8
8
  readonly default: "elastic";
9
9
  };
10
- repo: {
10
+ readonly repo: {
11
11
  readonly type: "string";
12
12
  };
13
- category: {
13
+ readonly category: {
14
14
  readonly type: "string";
15
15
  };
16
- tags: {
16
+ readonly tags: {
17
17
  readonly type: "string";
18
18
  };
19
- branch: {
19
+ readonly branch: {
20
20
  readonly type: "string";
21
21
  };
22
- "commit-sha": {
22
+ readonly "commit-sha": {
23
23
  readonly type: "string";
24
24
  };
25
- "pipeline-run-id": {
25
+ readonly "pipeline-run-id": {
26
26
  readonly type: "string";
27
27
  };
28
- "pipeline-provider": {
28
+ readonly "pipeline-provider": {
29
29
  readonly type: "string";
30
30
  };
31
- environment: {
31
+ readonly environment: {
32
32
  readonly type: "string";
33
33
  readonly default: "ci";
34
34
  };
35
- package: {
35
+ readonly solution: {
36
36
  readonly type: "string";
37
37
  };
38
- project: {
38
+ readonly project: {
39
39
  readonly type: "string";
40
40
  };
41
- "collector-version": {
41
+ readonly "collector-version": {
42
42
  readonly type: "string";
43
43
  };
44
- "elastic-url": {
44
+ readonly "elastic-url": {
45
45
  readonly type: "string";
46
46
  };
47
- "elastic-api-key": {
47
+ readonly "elastic-api-key": {
48
48
  readonly type: "string";
49
49
  };
50
- "loki-url": {
50
+ readonly "loki-url": {
51
51
  readonly type: "string";
52
52
  };
53
- "loki-username": {
53
+ readonly "loki-username": {
54
54
  readonly type: "string";
55
55
  };
56
- "loki-password": {
56
+ readonly "loki-password": {
57
57
  readonly type: "string";
58
58
  };
59
- "loki-tenant-id": {
59
+ readonly "loki-tenant-id": {
60
60
  readonly type: "string";
61
61
  };
62
- "retry-max": {
62
+ readonly "retry-max": {
63
63
  readonly type: "string";
64
64
  };
65
- "retry-backoff-ms": {
65
+ readonly "retry-backoff-ms": {
66
66
  readonly type: "string";
67
67
  };
68
- "allow-empty": {
68
+ readonly "allow-empty": {
69
69
  readonly type: "boolean";
70
70
  readonly default: false;
71
71
  };
72
- "dry-run": {
72
+ readonly "dry-run": {
73
73
  readonly type: "boolean";
74
74
  readonly default: false;
75
75
  };
@@ -1,75 +1,75 @@
1
1
  export declare const coverageDotnetCommand: import("citty").CommandDef<{
2
- input: {
2
+ readonly input: {
3
3
  readonly type: "string";
4
4
  readonly required: true;
5
5
  };
6
- sink: {
6
+ readonly sink: {
7
7
  readonly type: "string";
8
8
  readonly default: "elastic";
9
9
  };
10
- repo: {
10
+ readonly repo: {
11
11
  readonly type: "string";
12
12
  };
13
- category: {
13
+ readonly category: {
14
14
  readonly type: "string";
15
15
  };
16
- tags: {
16
+ readonly tags: {
17
17
  readonly type: "string";
18
18
  };
19
- branch: {
19
+ readonly branch: {
20
20
  readonly type: "string";
21
21
  };
22
- "commit-sha": {
22
+ readonly "commit-sha": {
23
23
  readonly type: "string";
24
24
  };
25
- "pipeline-run-id": {
25
+ readonly "pipeline-run-id": {
26
26
  readonly type: "string";
27
27
  };
28
- "pipeline-provider": {
28
+ readonly "pipeline-provider": {
29
29
  readonly type: "string";
30
30
  };
31
- environment: {
31
+ readonly environment: {
32
32
  readonly type: "string";
33
33
  readonly default: "ci";
34
34
  };
35
- package: {
35
+ readonly solution: {
36
36
  readonly type: "string";
37
37
  };
38
- project: {
38
+ readonly project: {
39
39
  readonly type: "string";
40
40
  };
41
- "collector-version": {
41
+ readonly "collector-version": {
42
42
  readonly type: "string";
43
43
  };
44
- "elastic-url": {
44
+ readonly "elastic-url": {
45
45
  readonly type: "string";
46
46
  };
47
- "elastic-api-key": {
47
+ readonly "elastic-api-key": {
48
48
  readonly type: "string";
49
49
  };
50
- "loki-url": {
50
+ readonly "loki-url": {
51
51
  readonly type: "string";
52
52
  };
53
- "loki-username": {
53
+ readonly "loki-username": {
54
54
  readonly type: "string";
55
55
  };
56
- "loki-password": {
56
+ readonly "loki-password": {
57
57
  readonly type: "string";
58
58
  };
59
- "loki-tenant-id": {
59
+ readonly "loki-tenant-id": {
60
60
  readonly type: "string";
61
61
  };
62
- "retry-max": {
62
+ readonly "retry-max": {
63
63
  readonly type: "string";
64
64
  };
65
- "retry-backoff-ms": {
65
+ readonly "retry-backoff-ms": {
66
66
  readonly type: "string";
67
67
  };
68
- "allow-empty": {
68
+ readonly "allow-empty": {
69
69
  readonly type: "boolean";
70
70
  readonly default: false;
71
71
  };
72
- "dry-run": {
72
+ readonly "dry-run": {
73
73
  readonly type: "boolean";
74
74
  readonly default: false;
75
75
  };
@@ -1,75 +1,75 @@
1
1
  export declare const coverageJsCommand: import("citty").CommandDef<{
2
- input: {
2
+ readonly input: {
3
3
  readonly type: "string";
4
4
  readonly required: true;
5
5
  };
6
- sink: {
6
+ readonly sink: {
7
7
  readonly type: "string";
8
8
  readonly default: "elastic";
9
9
  };
10
- repo: {
10
+ readonly repo: {
11
11
  readonly type: "string";
12
12
  };
13
- category: {
13
+ readonly category: {
14
14
  readonly type: "string";
15
15
  };
16
- tags: {
16
+ readonly tags: {
17
17
  readonly type: "string";
18
18
  };
19
- branch: {
19
+ readonly branch: {
20
20
  readonly type: "string";
21
21
  };
22
- "commit-sha": {
22
+ readonly "commit-sha": {
23
23
  readonly type: "string";
24
24
  };
25
- "pipeline-run-id": {
25
+ readonly "pipeline-run-id": {
26
26
  readonly type: "string";
27
27
  };
28
- "pipeline-provider": {
28
+ readonly "pipeline-provider": {
29
29
  readonly type: "string";
30
30
  };
31
- environment: {
31
+ readonly environment: {
32
32
  readonly type: "string";
33
33
  readonly default: "ci";
34
34
  };
35
- package: {
35
+ readonly solution: {
36
36
  readonly type: "string";
37
37
  };
38
- project: {
38
+ readonly project: {
39
39
  readonly type: "string";
40
40
  };
41
- "collector-version": {
41
+ readonly "collector-version": {
42
42
  readonly type: "string";
43
43
  };
44
- "elastic-url": {
44
+ readonly "elastic-url": {
45
45
  readonly type: "string";
46
46
  };
47
- "elastic-api-key": {
47
+ readonly "elastic-api-key": {
48
48
  readonly type: "string";
49
49
  };
50
- "loki-url": {
50
+ readonly "loki-url": {
51
51
  readonly type: "string";
52
52
  };
53
- "loki-username": {
53
+ readonly "loki-username": {
54
54
  readonly type: "string";
55
55
  };
56
- "loki-password": {
56
+ readonly "loki-password": {
57
57
  readonly type: "string";
58
58
  };
59
- "loki-tenant-id": {
59
+ readonly "loki-tenant-id": {
60
60
  readonly type: "string";
61
61
  };
62
- "retry-max": {
62
+ readonly "retry-max": {
63
63
  readonly type: "string";
64
64
  };
65
- "retry-backoff-ms": {
65
+ readonly "retry-backoff-ms": {
66
66
  readonly type: "string";
67
67
  };
68
- "allow-empty": {
68
+ readonly "allow-empty": {
69
69
  readonly type: "boolean";
70
70
  readonly default: false;
71
71
  };
72
- "dry-run": {
72
+ readonly "dry-run": {
73
73
  readonly type: "boolean";
74
74
  readonly default: false;
75
75
  };
@@ -1,75 +1,75 @@
1
1
  export declare const eslintCommand: import("citty").CommandDef<{
2
- input: {
2
+ readonly input: {
3
3
  readonly type: "string";
4
4
  readonly required: true;
5
5
  };
6
- sink: {
6
+ readonly sink: {
7
7
  readonly type: "string";
8
8
  readonly default: "elastic";
9
9
  };
10
- repo: {
10
+ readonly repo: {
11
11
  readonly type: "string";
12
12
  };
13
- category: {
13
+ readonly category: {
14
14
  readonly type: "string";
15
15
  };
16
- tags: {
16
+ readonly tags: {
17
17
  readonly type: "string";
18
18
  };
19
- branch: {
19
+ readonly branch: {
20
20
  readonly type: "string";
21
21
  };
22
- "commit-sha": {
22
+ readonly "commit-sha": {
23
23
  readonly type: "string";
24
24
  };
25
- "pipeline-run-id": {
25
+ readonly "pipeline-run-id": {
26
26
  readonly type: "string";
27
27
  };
28
- "pipeline-provider": {
28
+ readonly "pipeline-provider": {
29
29
  readonly type: "string";
30
30
  };
31
- environment: {
31
+ readonly environment: {
32
32
  readonly type: "string";
33
33
  readonly default: "ci";
34
34
  };
35
- package: {
35
+ readonly solution: {
36
36
  readonly type: "string";
37
37
  };
38
- project: {
38
+ readonly project: {
39
39
  readonly type: "string";
40
40
  };
41
- "collector-version": {
41
+ readonly "collector-version": {
42
42
  readonly type: "string";
43
43
  };
44
- "elastic-url": {
44
+ readonly "elastic-url": {
45
45
  readonly type: "string";
46
46
  };
47
- "elastic-api-key": {
47
+ readonly "elastic-api-key": {
48
48
  readonly type: "string";
49
49
  };
50
- "loki-url": {
50
+ readonly "loki-url": {
51
51
  readonly type: "string";
52
52
  };
53
- "loki-username": {
53
+ readonly "loki-username": {
54
54
  readonly type: "string";
55
55
  };
56
- "loki-password": {
56
+ readonly "loki-password": {
57
57
  readonly type: "string";
58
58
  };
59
- "loki-tenant-id": {
59
+ readonly "loki-tenant-id": {
60
60
  readonly type: "string";
61
61
  };
62
- "retry-max": {
62
+ readonly "retry-max": {
63
63
  readonly type: "string";
64
64
  };
65
- "retry-backoff-ms": {
65
+ readonly "retry-backoff-ms": {
66
66
  readonly type: "string";
67
67
  };
68
- "allow-empty": {
68
+ readonly "allow-empty": {
69
69
  readonly type: "boolean";
70
70
  readonly default: false;
71
71
  };
72
- "dry-run": {
72
+ readonly "dry-run": {
73
73
  readonly type: "boolean";
74
74
  readonly default: false;
75
75
  };
@@ -4,4 +4,5 @@ export { coverageJsCommand } from "./coverage-js.js";
4
4
  export { eslintCommand } from "./eslint.js";
5
5
  export { lighthouseCommand } from "./lighthouse.js";
6
6
  export { metaCommand } from "./meta.js";
7
+ export { pipelineCommand } from "./pipeline.js";
7
8
  export { sarifCommand } from "./sarif.js";
@@ -4,4 +4,5 @@ export { coverageJsCommand } from "./coverage-js.js";
4
4
  export { eslintCommand } from "./eslint.js";
5
5
  export { lighthouseCommand } from "./lighthouse.js";
6
6
  export { metaCommand } from "./meta.js";
7
+ export { pipelineCommand } from "./pipeline.js";
7
8
  export { sarifCommand } from "./sarif.js";