@itssky/nx-sonar 1.0.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.
- package/README.md +156 -0
- package/executors.json +9 -0
- package/generators.json +14 -0
- package/package.json +40 -0
- package/src/executors/scan/executor.d.ts +5 -0
- package/src/executors/scan/executor.js +48 -0
- package/src/executors/scan/executor.js.map +1 -0
- package/src/executors/scan/schema.d.ts +1 -0
- package/src/executors/scan/schema.json +41 -0
- package/src/generators/configuration/generator.d.ts +4 -0
- package/src/generators/configuration/generator.js +44 -0
- package/src/generators/configuration/generator.js.map +1 -0
- package/src/generators/configuration/schema.d.ts +5 -0
- package/src/generators/configuration/schema.json +27 -0
- package/src/generators/init/generator.d.ts +4 -0
- package/src/generators/init/generator.js +64 -0
- package/src/generators/init/generator.js.map +1 -0
- package/src/generators/init/schema.d.ts +5 -0
- package/src/generators/init/schema.json +14 -0
- package/src/index.d.ts +0 -0
- package/src/index.js +1 -0
- package/src/index.js.map +1 -0
- package/src/utils/build-scanner-properties.d.ts +9 -0
- package/src/utils/build-scanner-properties.js +42 -0
- package/src/utils/build-scanner-properties.js.map +1 -0
- package/src/utils/detect-ci-context.d.ts +4 -0
- package/src/utils/detect-ci-context.js +87 -0
- package/src/utils/detect-ci-context.js.map +1 -0
- package/src/utils/detect-test-runner.d.ts +3 -0
- package/src/utils/detect-test-runner.js +15 -0
- package/src/utils/detect-test-runner.js.map +1 -0
- package/src/utils/errors.d.ts +14 -0
- package/src/utils/errors.js +43 -0
- package/src/utils/errors.js.map +1 -0
- package/src/utils/resolve-options.d.ts +7 -0
- package/src/utils/resolve-options.js +52 -0
- package/src/utils/resolve-options.js.map +1 -0
- package/src/utils/resolve-project-paths.d.ts +13 -0
- package/src/utils/resolve-project-paths.js +26 -0
- package/src/utils/resolve-project-paths.js.map +1 -0
- package/src/utils/run-scanner.d.ts +5 -0
- package/src/utils/run-scanner.js +36 -0
- package/src/utils/run-scanner.js.map +1 -0
- package/src/utils/types.d.ts +52 -0
- package/src/utils/types.js +13 -0
- package/src/utils/types.js.map +1 -0
package/README.md
ADDED
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
# @itssky/nx-sonar
|
|
2
|
+
|
|
3
|
+
> Turnkey nx plugin for SonarQube and SonarCloud scans.
|
|
4
|
+
|
|
5
|
+
[](https://www.npmjs.com/package/@itssky/nx-sonar)
|
|
6
|
+
[](https://github.com/xItsSky/nx-sonar/actions/workflows/ci.yml)
|
|
7
|
+
[](https://codecov.io/gh/xItsSky/nx-sonar)
|
|
8
|
+
[](../../LICENSE)
|
|
9
|
+
|
|
10
|
+
## What it does
|
|
11
|
+
|
|
12
|
+
`@itssky/nx-sonar` adds a `sonar` target to any nx project. The target runs
|
|
13
|
+
your tests with coverage (via `dependsOn: ["test"]`), then invokes the official
|
|
14
|
+
Sonar scanner — the binary is downloaded on first use, no separate install.
|
|
15
|
+
|
|
16
|
+
Works with **SonarQube** and **SonarCloud**, and with any test runner that
|
|
17
|
+
emits LCOV (jest, vitest, …).
|
|
18
|
+
|
|
19
|
+
## Install
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
npm install --save-dev @itssky/nx-sonar
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## Quickstart
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
# 1. Configure the workspace
|
|
29
|
+
npx nx g @itssky/nx-sonar:init --hostUrl=https://sonarcloud.io --organization=my-org
|
|
30
|
+
|
|
31
|
+
# 2. Add a sonar target to a project
|
|
32
|
+
npx nx g @itssky/nx-sonar:configuration --project=my-app --projectKey=org_my-app
|
|
33
|
+
|
|
34
|
+
# 3. Run a scan (tests run first via dependsOn)
|
|
35
|
+
export SONAR_TOKEN=<your-token>
|
|
36
|
+
npx nx run my-app:sonar
|
|
37
|
+
|
|
38
|
+
# Or scan everything that's affected by your last change:
|
|
39
|
+
npx nx affected -t sonar
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
## Configuration
|
|
43
|
+
|
|
44
|
+
Options can live in three places (each later layer overrides the previous):
|
|
45
|
+
|
|
46
|
+
```
|
|
47
|
+
project.json target options > nx.json -> nxSonar > environment variables > built-in default
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
The `token` is **always** read from `SONAR_TOKEN` — never from `nx.json` or
|
|
51
|
+
`project.json`. The plugin refuses to start if a token is found in a
|
|
52
|
+
committed file.
|
|
53
|
+
|
|
54
|
+
### Executor options
|
|
55
|
+
|
|
56
|
+
| Option | Type | Default | Description |
|
|
57
|
+
|---|---|---|---|
|
|
58
|
+
| `projectKey` | string | required | Sonar project key |
|
|
59
|
+
| `projectName` | string | nx project name | Display name in Sonar |
|
|
60
|
+
| `projectVersion` | string | from `package.json` | |
|
|
61
|
+
| `hostUrl` | string | `https://sonarcloud.io` | Sonar server URL |
|
|
62
|
+
| `organization` | string | — | SonarCloud organization |
|
|
63
|
+
| `sources` | string \| string[] | project root | |
|
|
64
|
+
| `tests` | string \| string[] | unset | Optional `sonar.tests` value |
|
|
65
|
+
| `exclusions` | string[] | sensible defaults | Merged with workspace defaults |
|
|
66
|
+
| `coverageLcovPath` | string | `coverage/<projectRoot>/lcov.info` | LCOV report path |
|
|
67
|
+
| `testExecutionReportPath` | string | unset | JUnit XML test report (existence checked) |
|
|
68
|
+
| `qualityGateWait` | boolean | `true` | Fail the build if the Quality Gate fails |
|
|
69
|
+
| `branchDetection` | boolean | `true` | Auto-detect branch/PR from CI env vars |
|
|
70
|
+
| `extraProperties` | `Record<string,string>` | `{}` | Raw `sonar.*` properties (overrides built-ins) |
|
|
71
|
+
| `verbose` | boolean | `false` | Pass `-X` to the scanner |
|
|
72
|
+
|
|
73
|
+
### Environment variables
|
|
74
|
+
|
|
75
|
+
| Env var | Purpose |
|
|
76
|
+
|---|---|
|
|
77
|
+
| `SONAR_TOKEN` | **Required.** Authentication token. |
|
|
78
|
+
| `SONAR_HOST_URL` | Default `hostUrl` if not set in config. |
|
|
79
|
+
| `SONAR_ORGANIZATION` | Default `organization` if not set in config. |
|
|
80
|
+
| `SONAR_PROJECT_KEY` | Default `projectKey` if not set in config. |
|
|
81
|
+
|
|
82
|
+
### Workspace defaults
|
|
83
|
+
|
|
84
|
+
The `init` generator writes defaults under `nx.json` → `nxSonar`:
|
|
85
|
+
|
|
86
|
+
```json
|
|
87
|
+
{
|
|
88
|
+
"nxSonar": {
|
|
89
|
+
"hostUrl": "https://sonarcloud.io",
|
|
90
|
+
"organization": "my-org",
|
|
91
|
+
"exclusions": ["**/legacy/**"]
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
## CI recipes
|
|
97
|
+
|
|
98
|
+
### GitHub Actions
|
|
99
|
+
|
|
100
|
+
```yaml
|
|
101
|
+
- uses: actions/checkout@v4
|
|
102
|
+
with:
|
|
103
|
+
fetch-depth: 0 # required for Sonar branch analysis
|
|
104
|
+
- uses: actions/setup-node@v4
|
|
105
|
+
with:
|
|
106
|
+
node-version: 20
|
|
107
|
+
- run: npm ci
|
|
108
|
+
- run: npx nx affected -t sonar
|
|
109
|
+
env:
|
|
110
|
+
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
### GitLab CI
|
|
114
|
+
|
|
115
|
+
```yaml
|
|
116
|
+
sonar:
|
|
117
|
+
image: node:20
|
|
118
|
+
script:
|
|
119
|
+
- npm ci
|
|
120
|
+
- npx nx affected -t sonar
|
|
121
|
+
variables:
|
|
122
|
+
SONAR_TOKEN: $SONAR_TOKEN
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
Branch and merge-request context are auto-detected on GitHub Actions, GitLab
|
|
126
|
+
CI, CircleCI, and Bitbucket Pipelines.
|
|
127
|
+
|
|
128
|
+
## Troubleshooting
|
|
129
|
+
|
|
130
|
+
**`SONAR_TOKEN is not set`** — generate a token in your Sonar server and export
|
|
131
|
+
it before running. In CI, configure it as a secret.
|
|
132
|
+
|
|
133
|
+
**`Coverage report not found at coverage/<...>/lcov.info`** — enable LCOV in
|
|
134
|
+
your test runner:
|
|
135
|
+
- jest: `"coverageReporters": ["lcov"]` in `jest.config.ts`
|
|
136
|
+
- vitest: `"test.coverage.reporter": ["lcov"]` in `vite.config.ts`
|
|
137
|
+
|
|
138
|
+
**`A "token" was found in nx.json`** — remove it. Tokens belong in
|
|
139
|
+
`SONAR_TOKEN` only.
|
|
140
|
+
|
|
141
|
+
**Quality Gate failed but I don't want to block the build** — set
|
|
142
|
+
`qualityGateWait: false` in the target options.
|
|
143
|
+
|
|
144
|
+
## Migrating from `@koliveira15/nx-sonarqube`
|
|
145
|
+
|
|
146
|
+
| Old | New |
|
|
147
|
+
|---|---|
|
|
148
|
+
| executor name `@koliveira15/nx-sonarqube:scan` | `@itssky/nx-sonar:scan` |
|
|
149
|
+
| `hostUrl` (option) | same, also reads from `SONAR_HOST_URL` |
|
|
150
|
+
| `qualityGate` (option) | renamed to `qualityGateWait` |
|
|
151
|
+
| Token in options | refused — use `SONAR_TOKEN` env |
|
|
152
|
+
| Manual coverage merge step | not needed (per-project LCOV) |
|
|
153
|
+
|
|
154
|
+
## License
|
|
155
|
+
|
|
156
|
+
[MIT](../../LICENSE) © Quentin (xItsSky)
|
package/executors.json
ADDED
package/generators.json
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
{
|
|
2
|
+
"generators": {
|
|
3
|
+
"init": {
|
|
4
|
+
"factory": "./src/generators/init/generator",
|
|
5
|
+
"schema": "./src/generators/init/schema.json",
|
|
6
|
+
"description": "Configure @itssky/nx-sonar in the workspace."
|
|
7
|
+
},
|
|
8
|
+
"configuration": {
|
|
9
|
+
"factory": "./src/generators/configuration/generator",
|
|
10
|
+
"schema": "./src/generators/configuration/schema.json",
|
|
11
|
+
"description": "Add a sonar target to a project."
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@itssky/nx-sonar",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Turnkey nx plugin that runs SonarQube/SonarCloud scans on nx projects.",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"nx",
|
|
7
|
+
"nx-plugin",
|
|
8
|
+
"sonar",
|
|
9
|
+
"sonarqube",
|
|
10
|
+
"sonarcloud",
|
|
11
|
+
"code-quality"
|
|
12
|
+
],
|
|
13
|
+
"homepage": "https://github.com/xItsSky/nx-sonar#readme",
|
|
14
|
+
"bugs": "https://github.com/xItsSky/nx-sonar/issues",
|
|
15
|
+
"repository": {
|
|
16
|
+
"type": "git",
|
|
17
|
+
"url": "https://github.com/xItsSky/nx-sonar.git",
|
|
18
|
+
"directory": "nx-sonar"
|
|
19
|
+
},
|
|
20
|
+
"license": "MIT",
|
|
21
|
+
"author": "Quentin (xItsSky)",
|
|
22
|
+
"publishConfig": {
|
|
23
|
+
"access": "public"
|
|
24
|
+
},
|
|
25
|
+
"type": "commonjs",
|
|
26
|
+
"main": "./src/index.js",
|
|
27
|
+
"types": "./src/index.d.ts",
|
|
28
|
+
"engines": {
|
|
29
|
+
"node": ">=20.0.0"
|
|
30
|
+
},
|
|
31
|
+
"peerDependencies": {
|
|
32
|
+
"@nx/devkit": ">=22.0.0"
|
|
33
|
+
},
|
|
34
|
+
"dependencies": {
|
|
35
|
+
"sonarqube-scanner": "^4.3.6",
|
|
36
|
+
"tslib": "^2.3.0"
|
|
37
|
+
},
|
|
38
|
+
"executors": "./executors.json",
|
|
39
|
+
"generators": "./generators.json"
|
|
40
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.default = scanExecutor;
|
|
4
|
+
const tslib_1 = require("tslib");
|
|
5
|
+
const build_scanner_properties_1 = require("../../utils/build-scanner-properties");
|
|
6
|
+
const detect_ci_context_1 = require("../../utils/detect-ci-context");
|
|
7
|
+
const errors_1 = require("../../utils/errors");
|
|
8
|
+
const resolve_options_1 = require("../../utils/resolve-options");
|
|
9
|
+
const resolve_project_paths_1 = require("../../utils/resolve-project-paths");
|
|
10
|
+
const run_scanner_1 = require("../../utils/run-scanner");
|
|
11
|
+
function scanExecutor(options, context) {
|
|
12
|
+
return tslib_1.__awaiter(this, void 0, void 0, function* () {
|
|
13
|
+
var _a, _b, _c, _d, _e;
|
|
14
|
+
try {
|
|
15
|
+
const projectConfig = (_b = (_a = context.projectsConfigurations) === null || _a === void 0 ? void 0 : _a.projects) === null || _b === void 0 ? void 0 : _b[(_c = context.projectName) !== null && _c !== void 0 ? _c : ''];
|
|
16
|
+
if (!projectConfig) {
|
|
17
|
+
throw new errors_1.NxSonarError(`Cannot resolve project config for "${context.projectName}".`);
|
|
18
|
+
}
|
|
19
|
+
const nxJsonConfig = ((_e = (_d = context.nxJsonConfiguration) === null || _d === void 0 ? void 0 : _d.nxSonar) !== null && _e !== void 0 ? _e : {});
|
|
20
|
+
const resolved = (0, resolve_options_1.resolveOptions)({
|
|
21
|
+
projectOptions: options,
|
|
22
|
+
nxJsonConfig,
|
|
23
|
+
env: process.env,
|
|
24
|
+
});
|
|
25
|
+
const paths = (0, resolve_project_paths_1.resolveProjectPaths)({
|
|
26
|
+
workspaceRoot: context.root,
|
|
27
|
+
projectRoot: projectConfig.root,
|
|
28
|
+
options,
|
|
29
|
+
});
|
|
30
|
+
const ciContext = (0, detect_ci_context_1.detectCiContext)(process.env);
|
|
31
|
+
const properties = (0, build_scanner_properties_1.buildScannerProperties)({
|
|
32
|
+
options: resolved,
|
|
33
|
+
paths,
|
|
34
|
+
ciContext,
|
|
35
|
+
});
|
|
36
|
+
const result = yield (0, run_scanner_1.runScanner)(properties);
|
|
37
|
+
return { success: result.success };
|
|
38
|
+
}
|
|
39
|
+
catch (err) {
|
|
40
|
+
if (err instanceof errors_1.NxSonarError) {
|
|
41
|
+
console.error(`[@itssky/nx-sonar] ${err.message}`);
|
|
42
|
+
return { success: false };
|
|
43
|
+
}
|
|
44
|
+
throw err;
|
|
45
|
+
}
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
//# sourceMappingURL=executor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"executor.js","sourceRoot":"","sources":["../../../../../nx-sonar/src/executors/scan/executor.ts"],"names":[],"mappings":";;AAYA,+BA8CC;;AAzDD,mFAA8E;AAC9E,qEAAgE;AAChE,+CAAkD;AAClD,iEAA6D;AAC7D,6EAAwE;AACxE,yDAAqD;AAMrD,SAA8B,YAAY,CACxC,OAA4B,EAC5B,OAAwB;;;QAExB,IAAI,CAAC;YACH,MAAM,aAAa,GACjB,MAAA,MAAA,OAAO,CAAC,sBAAsB,0CAAE,QAAQ,0CAAG,MAAA,OAAO,CAAC,WAAW,mCAAI,EAAE,CAAC,CAAC;YACxE,IAAI,CAAC,aAAa,EAAE,CAAC;gBACnB,MAAM,IAAI,qBAAY,CACpB,sCAAsC,OAAO,CAAC,WAAW,IAAI,CAC9D,CAAC;YACJ,CAAC;YAED,MAAM,YAAY,GAChB,CAAC,MAAA,MAAC,OAAO,CAAC,mBAAuD,0CAC7D,OAAO,mCAAI,EAAE,CAAsB,CAAC;YAE1C,MAAM,QAAQ,GAAG,IAAA,gCAAc,EAAC;gBAC9B,cAAc,EAAE,OAAO;gBACvB,YAAY;gBACZ,GAAG,EAAE,OAAO,CAAC,GAAG;aACjB,CAAC,CAAC;YAEH,MAAM,KAAK,GAAG,IAAA,2CAAmB,EAAC;gBAChC,aAAa,EAAE,OAAO,CAAC,IAAI;gBAC3B,WAAW,EAAE,aAAa,CAAC,IAAI;gBAC/B,OAAO;aACR,CAAC,CAAC;YAEH,MAAM,SAAS,GAAG,IAAA,mCAAe,EAAC,OAAO,CAAC,GAAG,CAAC,CAAC;YAE/C,MAAM,UAAU,GAAG,IAAA,iDAAsB,EAAC;gBACxC,OAAO,EAAE,QAAQ;gBACjB,KAAK;gBACL,SAAS;aACV,CAAC,CAAC;YAEH,MAAM,MAAM,GAAG,MAAM,IAAA,wBAAU,EAAC,UAAU,CAAC,CAAC;YAC5C,OAAO,EAAE,OAAO,EAAE,MAAM,CAAC,OAAO,EAAE,CAAC;QACrC,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,IAAI,GAAG,YAAY,qBAAY,EAAE,CAAC;gBAChC,OAAO,CAAC,KAAK,CAAC,sBAAsB,GAAG,CAAC,OAAO,EAAE,CAAC,CAAC;gBACnD,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC;YAC5B,CAAC;YACD,MAAM,GAAG,CAAC;QACZ,CAAC;IACH,CAAC;CAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export type { ScanExecutorOptions as Schema } from '../../utils/types';
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/schema",
|
|
3
|
+
"$id": "NxSonarScanExecutor",
|
|
4
|
+
"title": "@itssky/nx-sonar:scan",
|
|
5
|
+
"description": "Run a SonarQube/SonarCloud scan against the project.",
|
|
6
|
+
"type": "object",
|
|
7
|
+
"properties": {
|
|
8
|
+
"projectKey": { "type": "string", "description": "Sonar project key." },
|
|
9
|
+
"projectName": { "type": "string", "description": "Display name in Sonar." },
|
|
10
|
+
"projectVersion": { "type": "string" },
|
|
11
|
+
"hostUrl": { "type": "string", "format": "uri" },
|
|
12
|
+
"organization": { "type": "string", "description": "SonarCloud organization." },
|
|
13
|
+
"sources": {
|
|
14
|
+
"oneOf": [
|
|
15
|
+
{ "type": "string" },
|
|
16
|
+
{ "type": "array", "items": { "type": "string" } }
|
|
17
|
+
]
|
|
18
|
+
},
|
|
19
|
+
"tests": {
|
|
20
|
+
"oneOf": [
|
|
21
|
+
{ "type": "string" },
|
|
22
|
+
{ "type": "array", "items": { "type": "string" } }
|
|
23
|
+
]
|
|
24
|
+
},
|
|
25
|
+
"exclusions": {
|
|
26
|
+
"type": "array",
|
|
27
|
+
"items": { "type": "string" }
|
|
28
|
+
},
|
|
29
|
+
"coverageLcovPath": { "type": "string" },
|
|
30
|
+
"testExecutionReportPath": { "type": "string" },
|
|
31
|
+
"qualityGateWait": { "type": "boolean", "default": true },
|
|
32
|
+
"branchDetection": { "type": "boolean", "default": true },
|
|
33
|
+
"extraProperties": {
|
|
34
|
+
"type": "object",
|
|
35
|
+
"additionalProperties": { "type": "string" }
|
|
36
|
+
},
|
|
37
|
+
"verbose": { "type": "boolean", "default": false }
|
|
38
|
+
},
|
|
39
|
+
"required": [],
|
|
40
|
+
"additionalProperties": false
|
|
41
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.configurationGenerator = configurationGenerator;
|
|
4
|
+
const tslib_1 = require("tslib");
|
|
5
|
+
const devkit_1 = require("@nx/devkit");
|
|
6
|
+
const detect_test_runner_1 = require("../../utils/detect-test-runner");
|
|
7
|
+
const EXECUTOR = '@itssky/nx-sonar:scan';
|
|
8
|
+
function configurationGenerator(tree, options) {
|
|
9
|
+
return tslib_1.__awaiter(this, void 0, void 0, function* () {
|
|
10
|
+
var _a, _b;
|
|
11
|
+
const project = (0, devkit_1.readProjectConfiguration)(tree, options.project);
|
|
12
|
+
if (((_a = project.targets) === null || _a === void 0 ? void 0 : _a.sonar) && !options.force) {
|
|
13
|
+
throw new Error(`Project "${options.project}" already exists with a sonar target. Re-run with --force to overwrite.`);
|
|
14
|
+
}
|
|
15
|
+
const runner = (0, detect_test_runner_1.detectTestRunner)(project);
|
|
16
|
+
if (runner === 'none') {
|
|
17
|
+
console.warn(`[@itssky/nx-sonar] Project "${options.project}" has no \`test\` target. The sonar target will still be added with dependsOn:["test"], but it will fail until you configure tests with coverage.`);
|
|
18
|
+
}
|
|
19
|
+
else {
|
|
20
|
+
warnIfCoverageNotConfigured(runner, project);
|
|
21
|
+
}
|
|
22
|
+
const sonarTarget = {
|
|
23
|
+
executor: EXECUTOR,
|
|
24
|
+
dependsOn: ['test'],
|
|
25
|
+
options: Object.assign(Object.assign({}, (options.projectKey ? { projectKey: options.projectKey } : {})), { projectName: options.project }),
|
|
26
|
+
};
|
|
27
|
+
project.targets = Object.assign(Object.assign({}, ((_b = project.targets) !== null && _b !== void 0 ? _b : {})), { sonar: sonarTarget });
|
|
28
|
+
(0, devkit_1.updateProjectConfiguration)(tree, options.project, project);
|
|
29
|
+
yield (0, devkit_1.formatFiles)(tree);
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
function warnIfCoverageNotConfigured(runner, project) {
|
|
33
|
+
var _a, _b, _c;
|
|
34
|
+
const opts = (_c = (_b = (_a = project.targets) === null || _a === void 0 ? void 0 : _a.test) === null || _b === void 0 ? void 0 : _b.options) !== null && _c !== void 0 ? _c : {};
|
|
35
|
+
const hasCoverage = 'coverage' in opts ||
|
|
36
|
+
'codeCoverage' in opts ||
|
|
37
|
+
'collectCoverage' in opts;
|
|
38
|
+
if (!hasCoverage) {
|
|
39
|
+
console.warn(`[@itssky/nx-sonar] The "test" target does not appear to enable coverage. ` +
|
|
40
|
+
`For ${runner}, enable coverage so an lcov.info file is produced at coverage/<projectRoot>/lcov.info.`);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
exports.default = configurationGenerator;
|
|
44
|
+
//# sourceMappingURL=generator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"generator.js","sourceRoot":"","sources":["../../../../../nx-sonar/src/generators/configuration/generator.ts"],"names":[],"mappings":";;AAWA,wDAoCC;;AA/CD,uCAKoB;AACpB,uEAAkE;AAGlE,MAAM,QAAQ,GAAG,uBAAuB,CAAC;AAEzC,SAAsB,sBAAsB,CAC1C,IAAU,EACV,OAAqC;;;QAErC,MAAM,OAAO,GAAG,IAAA,iCAAwB,EAAC,IAAI,EAAE,OAAO,CAAC,OAAO,CAAC,CAAC;QAEhE,IAAI,CAAA,MAAA,OAAO,CAAC,OAAO,0CAAE,KAAK,KAAI,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC;YAC7C,MAAM,IAAI,KAAK,CACb,YAAY,OAAO,CAAC,OAAO,yEAAyE,CACrG,CAAC;QACJ,CAAC;QAED,MAAM,MAAM,GAAG,IAAA,qCAAgB,EAAC,OAAO,CAAC,CAAC;QACzC,IAAI,MAAM,KAAK,MAAM,EAAE,CAAC;YACtB,OAAO,CAAC,IAAI,CACV,+BAA+B,OAAO,CAAC,OAAO,mJAAmJ,CAClM,CAAC;QACJ,CAAC;aAAM,CAAC;YACN,2BAA2B,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;QAC/C,CAAC;QAED,MAAM,WAAW,GAAG;YAClB,QAAQ,EAAE,QAAQ;YAClB,SAAS,EAAE,CAAC,MAAM,CAAC;YACnB,OAAO,kCACF,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,UAAU,EAAE,OAAO,CAAC,UAAU,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,KACjE,WAAW,EAAE,OAAO,CAAC,OAAO,GAC7B;SACF,CAAC;QAEF,OAAO,CAAC,OAAO,mCACV,CAAC,MAAA,OAAO,CAAC,OAAO,mCAAI,EAAE,CAAC,KAC1B,KAAK,EAAE,WAAW,GACnB,CAAC;QACF,IAAA,mCAA0B,EAAC,IAAI,EAAE,OAAO,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;QAC3D,MAAM,IAAA,oBAAW,EAAC,IAAI,CAAC,CAAC;IAC1B,CAAC;CAAA;AAED,SAAS,2BAA2B,CAClC,MAAmC,EACnC,OAA4E;;IAE5E,MAAM,IAAI,GAAG,MAAA,MAAA,MAAA,OAAO,CAAC,OAAO,0CAAE,IAAI,0CAAE,OAAO,mCAAI,EAAE,CAAC;IAClD,MAAM,WAAW,GACf,UAAU,IAAI,IAAI;QAClB,cAAc,IAAI,IAAI;QACtB,iBAAiB,IAAI,IAAI,CAAC;IAC5B,IAAI,CAAC,WAAW,EAAE,CAAC;QACjB,OAAO,CAAC,IAAI,CACV,2EAA2E;YACzE,OAAO,MAAM,yFAAyF,CACzG,CAAC;IACJ,CAAC;AACH,CAAC;AAED,kBAAe,sBAAsB,CAAC"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/schema",
|
|
3
|
+
"$id": "NxSonarConfigurationGenerator",
|
|
4
|
+
"title": "@itssky/nx-sonar:configuration",
|
|
5
|
+
"description": "Add a sonar target to a project.",
|
|
6
|
+
"type": "object",
|
|
7
|
+
"properties": {
|
|
8
|
+
"project": {
|
|
9
|
+
"type": "string",
|
|
10
|
+
"description": "Project to configure.",
|
|
11
|
+
"$default": { "$source": "projectName" },
|
|
12
|
+
"x-prompt": "Which project should be configured for Sonar?"
|
|
13
|
+
},
|
|
14
|
+
"projectKey": {
|
|
15
|
+
"type": "string",
|
|
16
|
+
"description": "Sonar project key.",
|
|
17
|
+
"x-prompt": "Sonar projectKey (leave blank to set later in project.json):"
|
|
18
|
+
},
|
|
19
|
+
"force": {
|
|
20
|
+
"type": "boolean",
|
|
21
|
+
"default": false,
|
|
22
|
+
"description": "Overwrite an existing sonar target."
|
|
23
|
+
}
|
|
24
|
+
},
|
|
25
|
+
"required": ["project"],
|
|
26
|
+
"additionalProperties": false
|
|
27
|
+
}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.initGenerator = initGenerator;
|
|
4
|
+
const tslib_1 = require("tslib");
|
|
5
|
+
const devkit_1 = require("@nx/devkit");
|
|
6
|
+
const PLUGIN_NAME = '@itssky/nx-sonar';
|
|
7
|
+
const ENV_LINES = [
|
|
8
|
+
'# @itssky/nx-sonar — required for `nx run <project>:sonar`',
|
|
9
|
+
'SONAR_TOKEN=',
|
|
10
|
+
'SONAR_HOST_URL=',
|
|
11
|
+
'SONAR_ORGANIZATION=',
|
|
12
|
+
];
|
|
13
|
+
function initGenerator(tree, options) {
|
|
14
|
+
return tslib_1.__awaiter(this, void 0, void 0, function* () {
|
|
15
|
+
registerPluginInNxJson(tree, options);
|
|
16
|
+
ensureGitignoreCoverage(tree);
|
|
17
|
+
appendEnvExampleIfPresent(tree);
|
|
18
|
+
yield (0, devkit_1.formatFiles)(tree);
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
function registerPluginInNxJson(tree, options) {
|
|
22
|
+
var _a, _b, _c;
|
|
23
|
+
const nxJson = ((_a = (0, devkit_1.readNxJson)(tree)) !== null && _a !== void 0 ? _a : {});
|
|
24
|
+
const plugins = (_b = nxJson.plugins) !== null && _b !== void 0 ? _b : [];
|
|
25
|
+
const alreadyHasPlugin = plugins.some((p) => typeof p === 'string' ? p === PLUGIN_NAME : (p === null || p === void 0 ? void 0 : p.plugin) === PLUGIN_NAME);
|
|
26
|
+
if (!alreadyHasPlugin) {
|
|
27
|
+
plugins.push({ plugin: PLUGIN_NAME });
|
|
28
|
+
}
|
|
29
|
+
nxJson.plugins = plugins;
|
|
30
|
+
const sonarDefaults = Object.assign({}, ((_c = nxJson.nxSonar) !== null && _c !== void 0 ? _c : {}));
|
|
31
|
+
if (options.hostUrl)
|
|
32
|
+
sonarDefaults.hostUrl = options.hostUrl;
|
|
33
|
+
if (options.organization)
|
|
34
|
+
sonarDefaults.organization = options.organization;
|
|
35
|
+
if (Object.keys(sonarDefaults).length > 0) {
|
|
36
|
+
nxJson.nxSonar = sonarDefaults;
|
|
37
|
+
}
|
|
38
|
+
(0, devkit_1.updateNxJson)(tree, nxJson);
|
|
39
|
+
}
|
|
40
|
+
function ensureGitignoreCoverage(tree) {
|
|
41
|
+
var _a;
|
|
42
|
+
const path = '.gitignore';
|
|
43
|
+
const existing = tree.exists(path) ? (_a = tree.read(path, 'utf-8')) !== null && _a !== void 0 ? _a : '' : '';
|
|
44
|
+
const lines = existing.split('\n');
|
|
45
|
+
if (!lines.some((l) => l.trim() === 'coverage/')) {
|
|
46
|
+
const updated = existing.length === 0 || existing.endsWith('\n')
|
|
47
|
+
? `${existing}coverage/\n`
|
|
48
|
+
: `${existing}\ncoverage/\n`;
|
|
49
|
+
tree.write(path, updated);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
function appendEnvExampleIfPresent(tree) {
|
|
53
|
+
var _a;
|
|
54
|
+
const path = '.env.example';
|
|
55
|
+
if (!tree.exists(path))
|
|
56
|
+
return;
|
|
57
|
+
const existing = (_a = tree.read(path, 'utf-8')) !== null && _a !== void 0 ? _a : '';
|
|
58
|
+
if (existing.includes('SONAR_TOKEN='))
|
|
59
|
+
return;
|
|
60
|
+
const sep = existing.endsWith('\n') ? '' : '\n';
|
|
61
|
+
tree.write(path, `${existing}${sep}${ENV_LINES.join('\n')}\n`);
|
|
62
|
+
}
|
|
63
|
+
exports.default = initGenerator;
|
|
64
|
+
//# sourceMappingURL=generator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"generator.js","sourceRoot":"","sources":["../../../../../nx-sonar/src/generators/init/generator.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/schema",
|
|
3
|
+
"$id": "NxSonarInitGenerator",
|
|
4
|
+
"title": "@itssky/nx-sonar:init",
|
|
5
|
+
"description": "Configure @itssky/nx-sonar in the workspace.",
|
|
6
|
+
"type": "object",
|
|
7
|
+
"properties": {
|
|
8
|
+
"hostUrl": { "type": "string", "format": "uri" },
|
|
9
|
+
"organization": { "type": "string" },
|
|
10
|
+
"skipPrompts": { "type": "boolean", "default": false }
|
|
11
|
+
},
|
|
12
|
+
"required": [],
|
|
13
|
+
"additionalProperties": false
|
|
14
|
+
}
|
package/src/index.d.ts
ADDED
|
File without changes
|
package/src/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
//# sourceMappingURL=index.js.map
|
package/src/index.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../nx-sonar/src/index.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { CiContext, ResolvedOptions } from './types';
|
|
2
|
+
import { ResolvedPaths } from './resolve-project-paths';
|
|
3
|
+
export interface BuildPropsInput {
|
|
4
|
+
options: ResolvedOptions;
|
|
5
|
+
paths: ResolvedPaths;
|
|
6
|
+
ciContext: CiContext;
|
|
7
|
+
}
|
|
8
|
+
export type ScannerProperties = Record<string, string>;
|
|
9
|
+
export declare function buildScannerProperties({ options, paths, ciContext, }: BuildPropsInput): ScannerProperties;
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.buildScannerProperties = buildScannerProperties;
|
|
4
|
+
function buildScannerProperties({ options, paths, ciContext, }) {
|
|
5
|
+
const props = {};
|
|
6
|
+
props['sonar.projectKey'] = options.projectKey;
|
|
7
|
+
if (options.projectName)
|
|
8
|
+
props['sonar.projectName'] = options.projectName;
|
|
9
|
+
if (options.projectVersion)
|
|
10
|
+
props['sonar.projectVersion'] = options.projectVersion;
|
|
11
|
+
props['sonar.host.url'] = options.hostUrl;
|
|
12
|
+
if (options.organization)
|
|
13
|
+
props['sonar.organization'] = options.organization;
|
|
14
|
+
props['sonar.token'] = options.token;
|
|
15
|
+
props['sonar.sources'] = joinList(paths.sources);
|
|
16
|
+
if (paths.tests)
|
|
17
|
+
props['sonar.tests'] = joinList(paths.tests);
|
|
18
|
+
props['sonar.javascript.lcov.reportPaths'] = paths.coveragePath;
|
|
19
|
+
props['sonar.typescript.lcov.reportPaths'] = paths.coveragePath;
|
|
20
|
+
if (paths.testExecutionReportPath)
|
|
21
|
+
props['sonar.testExecutionReportPaths'] = paths.testExecutionReportPath;
|
|
22
|
+
props['sonar.exclusions'] = options.exclusions.join(',');
|
|
23
|
+
props['sonar.qualitygate.wait'] = String(options.qualityGateWait);
|
|
24
|
+
if (options.verbose)
|
|
25
|
+
props['sonar.verbose'] = 'true';
|
|
26
|
+
if (options.branchDetection && ciContext) {
|
|
27
|
+
if (ciContext.kind === 'branch') {
|
|
28
|
+
props['sonar.branch.name'] = ciContext.name;
|
|
29
|
+
}
|
|
30
|
+
else {
|
|
31
|
+
props['sonar.pullrequest.key'] = ciContext.key;
|
|
32
|
+
props['sonar.pullrequest.branch'] = ciContext.branch;
|
|
33
|
+
props['sonar.pullrequest.base'] = ciContext.base;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
// extraProperties last so users can override anything above.
|
|
37
|
+
return Object.assign(Object.assign({}, props), options.extraProperties);
|
|
38
|
+
}
|
|
39
|
+
function joinList(value) {
|
|
40
|
+
return Array.isArray(value) ? value.join(',') : value;
|
|
41
|
+
}
|
|
42
|
+
//# sourceMappingURL=build-scanner-properties.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"build-scanner-properties.js","sourceRoot":"","sources":["../../../../nx-sonar/src/utils/build-scanner-properties.ts"],"names":[],"mappings":";;AAWA,wDAwCC;AAxCD,SAAgB,sBAAsB,CAAC,EACrC,OAAO,EACP,KAAK,EACL,SAAS,GACO;IAChB,MAAM,KAAK,GAAsB,EAAE,CAAC;IAEpC,KAAK,CAAC,kBAAkB,CAAC,GAAG,OAAO,CAAC,UAAU,CAAC;IAC/C,IAAI,OAAO,CAAC,WAAW;QAAE,KAAK,CAAC,mBAAmB,CAAC,GAAG,OAAO,CAAC,WAAW,CAAC;IAC1E,IAAI,OAAO,CAAC,cAAc;QACxB,KAAK,CAAC,sBAAsB,CAAC,GAAG,OAAO,CAAC,cAAc,CAAC;IAEzD,KAAK,CAAC,gBAAgB,CAAC,GAAG,OAAO,CAAC,OAAO,CAAC;IAC1C,IAAI,OAAO,CAAC,YAAY;QAAE,KAAK,CAAC,oBAAoB,CAAC,GAAG,OAAO,CAAC,YAAY,CAAC;IAC7E,KAAK,CAAC,aAAa,CAAC,GAAG,OAAO,CAAC,KAAK,CAAC;IAErC,KAAK,CAAC,eAAe,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;IACjD,IAAI,KAAK,CAAC,KAAK;QAAE,KAAK,CAAC,aAAa,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;IAE9D,KAAK,CAAC,mCAAmC,CAAC,GAAG,KAAK,CAAC,YAAY,CAAC;IAChE,KAAK,CAAC,mCAAmC,CAAC,GAAG,KAAK,CAAC,YAAY,CAAC;IAChE,IAAI,KAAK,CAAC,uBAAuB;QAC/B,KAAK,CAAC,gCAAgC,CAAC,GAAG,KAAK,CAAC,uBAAuB,CAAC;IAE1E,KAAK,CAAC,kBAAkB,CAAC,GAAG,OAAO,CAAC,UAAU,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IACzD,KAAK,CAAC,wBAAwB,CAAC,GAAG,MAAM,CAAC,OAAO,CAAC,eAAe,CAAC,CAAC;IAClE,IAAI,OAAO,CAAC,OAAO;QAAE,KAAK,CAAC,eAAe,CAAC,GAAG,MAAM,CAAC;IAErD,IAAI,OAAO,CAAC,eAAe,IAAI,SAAS,EAAE,CAAC;QACzC,IAAI,SAAS,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;YAChC,KAAK,CAAC,mBAAmB,CAAC,GAAG,SAAS,CAAC,IAAI,CAAC;QAC9C,CAAC;aAAM,CAAC;YACN,KAAK,CAAC,uBAAuB,CAAC,GAAG,SAAS,CAAC,GAAG,CAAC;YAC/C,KAAK,CAAC,0BAA0B,CAAC,GAAG,SAAS,CAAC,MAAM,CAAC;YACrD,KAAK,CAAC,wBAAwB,CAAC,GAAG,SAAS,CAAC,IAAI,CAAC;QACnD,CAAC;IACH,CAAC;IAED,6DAA6D;IAC7D,uCAAY,KAAK,GAAK,OAAO,CAAC,eAAe,EAAG;AAClD,CAAC;AAED,SAAS,QAAQ,CAAC,KAAwB;IACxC,OAAO,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC;AACxD,CAAC"}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.detectCiContext = detectCiContext;
|
|
4
|
+
function detectCiContext(env) {
|
|
5
|
+
var _a, _b, _c, _d;
|
|
6
|
+
return ((_d = (_c = (_b = (_a = detectGitHubActions(env)) !== null && _a !== void 0 ? _a : detectGitLab(env)) !== null && _b !== void 0 ? _b : detectCircleCi(env)) !== null && _c !== void 0 ? _c : detectBitbucket(env)) !== null && _d !== void 0 ? _d : null);
|
|
7
|
+
}
|
|
8
|
+
function detectGitHubActions(env) {
|
|
9
|
+
var _a, _b, _c;
|
|
10
|
+
if (env.GITHUB_ACTIONS !== 'true')
|
|
11
|
+
return null;
|
|
12
|
+
if (env.GITHUB_EVENT_NAME === 'pull_request' ||
|
|
13
|
+
env.GITHUB_EVENT_NAME === 'pull_request_target') {
|
|
14
|
+
const key = parsePrFromRef(env.GITHUB_REF);
|
|
15
|
+
return key
|
|
16
|
+
? {
|
|
17
|
+
kind: 'pullRequest',
|
|
18
|
+
key,
|
|
19
|
+
branch: (_a = env.GITHUB_HEAD_REF) !== null && _a !== void 0 ? _a : '',
|
|
20
|
+
base: (_b = env.GITHUB_BASE_REF) !== null && _b !== void 0 ? _b : 'main',
|
|
21
|
+
}
|
|
22
|
+
: null;
|
|
23
|
+
}
|
|
24
|
+
if ((_c = env.GITHUB_REF) === null || _c === void 0 ? void 0 : _c.startsWith('refs/heads/')) {
|
|
25
|
+
return { kind: 'branch', name: env.GITHUB_REF.slice('refs/heads/'.length) };
|
|
26
|
+
}
|
|
27
|
+
return null;
|
|
28
|
+
}
|
|
29
|
+
function detectGitLab(env) {
|
|
30
|
+
var _a, _b;
|
|
31
|
+
if (env.GITLAB_CI !== 'true')
|
|
32
|
+
return null;
|
|
33
|
+
if (env.CI_MERGE_REQUEST_IID) {
|
|
34
|
+
return {
|
|
35
|
+
kind: 'pullRequest',
|
|
36
|
+
key: env.CI_MERGE_REQUEST_IID,
|
|
37
|
+
branch: (_a = env.CI_MERGE_REQUEST_SOURCE_BRANCH_NAME) !== null && _a !== void 0 ? _a : '',
|
|
38
|
+
base: (_b = env.CI_MERGE_REQUEST_TARGET_BRANCH_NAME) !== null && _b !== void 0 ? _b : 'main',
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
if (env.CI_COMMIT_BRANCH) {
|
|
42
|
+
return { kind: 'branch', name: env.CI_COMMIT_BRANCH };
|
|
43
|
+
}
|
|
44
|
+
return null;
|
|
45
|
+
}
|
|
46
|
+
function detectCircleCi(env) {
|
|
47
|
+
var _a;
|
|
48
|
+
if (env.CIRCLECI !== 'true')
|
|
49
|
+
return null;
|
|
50
|
+
if (env.CIRCLE_PULL_REQUEST) {
|
|
51
|
+
const key = env.CIRCLE_PULL_REQUEST.split('/').pop();
|
|
52
|
+
if (key) {
|
|
53
|
+
return {
|
|
54
|
+
kind: 'pullRequest',
|
|
55
|
+
key,
|
|
56
|
+
branch: (_a = env.CIRCLE_BRANCH) !== null && _a !== void 0 ? _a : '',
|
|
57
|
+
base: 'main',
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
if (env.CIRCLE_BRANCH) {
|
|
62
|
+
return { kind: 'branch', name: env.CIRCLE_BRANCH };
|
|
63
|
+
}
|
|
64
|
+
return null;
|
|
65
|
+
}
|
|
66
|
+
function detectBitbucket(env) {
|
|
67
|
+
var _a, _b;
|
|
68
|
+
if (!env.BITBUCKET_BUILD_NUMBER)
|
|
69
|
+
return null;
|
|
70
|
+
if (env.BITBUCKET_PR_ID) {
|
|
71
|
+
return {
|
|
72
|
+
kind: 'pullRequest',
|
|
73
|
+
key: env.BITBUCKET_PR_ID,
|
|
74
|
+
branch: (_a = env.BITBUCKET_BRANCH) !== null && _a !== void 0 ? _a : '',
|
|
75
|
+
base: (_b = env.BITBUCKET_PR_DESTINATION_BRANCH) !== null && _b !== void 0 ? _b : 'main',
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
if (env.BITBUCKET_BRANCH) {
|
|
79
|
+
return { kind: 'branch', name: env.BITBUCKET_BRANCH };
|
|
80
|
+
}
|
|
81
|
+
return null;
|
|
82
|
+
}
|
|
83
|
+
function parsePrFromRef(ref) {
|
|
84
|
+
const m = ref === null || ref === void 0 ? void 0 : ref.match(/^refs\/pull\/(\d+)\//);
|
|
85
|
+
return m ? m[1] : null;
|
|
86
|
+
}
|
|
87
|
+
//# sourceMappingURL=detect-ci-context.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"detect-ci-context.js","sourceRoot":"","sources":["../../../../nx-sonar/src/utils/detect-ci-context.ts"],"names":[],"mappings":";;AAIA,0CAQC;AARD,SAAgB,eAAe,CAAC,GAAQ;;IACtC,OAAO,CACL,MAAA,MAAA,MAAA,MAAA,mBAAmB,CAAC,GAAG,CAAC,mCACxB,YAAY,CAAC,GAAG,CAAC,mCACjB,cAAc,CAAC,GAAG,CAAC,mCACnB,eAAe,CAAC,GAAG,CAAC,mCACpB,IAAI,CACL,CAAC;AACJ,CAAC;AAED,SAAS,mBAAmB,CAAC,GAAQ;;IACnC,IAAI,GAAG,CAAC,cAAc,KAAK,MAAM;QAAE,OAAO,IAAI,CAAC;IAC/C,IACE,GAAG,CAAC,iBAAiB,KAAK,cAAc;QACxC,GAAG,CAAC,iBAAiB,KAAK,qBAAqB,EAC/C,CAAC;QACD,MAAM,GAAG,GAAG,cAAc,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;QAC3C,OAAO,GAAG;YACR,CAAC,CAAC;gBACE,IAAI,EAAE,aAAa;gBACnB,GAAG;gBACH,MAAM,EAAE,MAAA,GAAG,CAAC,eAAe,mCAAI,EAAE;gBACjC,IAAI,EAAE,MAAA,GAAG,CAAC,eAAe,mCAAI,MAAM;aACpC;YACH,CAAC,CAAC,IAAI,CAAC;IACX,CAAC;IACD,IAAI,MAAA,GAAG,CAAC,UAAU,0CAAE,UAAU,CAAC,aAAa,CAAC,EAAE,CAAC;QAC9C,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,GAAG,CAAC,UAAU,CAAC,KAAK,CAAC,aAAa,CAAC,MAAM,CAAC,EAAE,CAAC;IAC9E,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED,SAAS,YAAY,CAAC,GAAQ;;IAC5B,IAAI,GAAG,CAAC,SAAS,KAAK,MAAM;QAAE,OAAO,IAAI,CAAC;IAC1C,IAAI,GAAG,CAAC,oBAAoB,EAAE,CAAC;QAC7B,OAAO;YACL,IAAI,EAAE,aAAa;YACnB,GAAG,EAAE,GAAG,CAAC,oBAAoB;YAC7B,MAAM,EAAE,MAAA,GAAG,CAAC,mCAAmC,mCAAI,EAAE;YACrD,IAAI,EAAE,MAAA,GAAG,CAAC,mCAAmC,mCAAI,MAAM;SACxD,CAAC;IACJ,CAAC;IACD,IAAI,GAAG,CAAC,gBAAgB,EAAE,CAAC;QACzB,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,GAAG,CAAC,gBAAgB,EAAE,CAAC;IACxD,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED,SAAS,cAAc,CAAC,GAAQ;;IAC9B,IAAI,GAAG,CAAC,QAAQ,KAAK,MAAM;QAAE,OAAO,IAAI,CAAC;IACzC,IAAI,GAAG,CAAC,mBAAmB,EAAE,CAAC;QAC5B,MAAM,GAAG,GAAG,GAAG,CAAC,mBAAmB,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,CAAC;QACrD,IAAI,GAAG,EAAE,CAAC;YACR,OAAO;gBACL,IAAI,EAAE,aAAa;gBACnB,GAAG;gBACH,MAAM,EAAE,MAAA,GAAG,CAAC,aAAa,mCAAI,EAAE;gBAC/B,IAAI,EAAE,MAAM;aACb,CAAC;QACJ,CAAC;IACH,CAAC;IACD,IAAI,GAAG,CAAC,aAAa,EAAE,CAAC;QACtB,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,GAAG,CAAC,aAAa,EAAE,CAAC;IACrD,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED,SAAS,eAAe,CAAC,GAAQ;;IAC/B,IAAI,CAAC,GAAG,CAAC,sBAAsB;QAAE,OAAO,IAAI,CAAC;IAC7C,IAAI,GAAG,CAAC,eAAe,EAAE,CAAC;QACxB,OAAO;YACL,IAAI,EAAE,aAAa;YACnB,GAAG,EAAE,GAAG,CAAC,eAAe;YACxB,MAAM,EAAE,MAAA,GAAG,CAAC,gBAAgB,mCAAI,EAAE;YAClC,IAAI,EAAE,MAAA,GAAG,CAAC,+BAA+B,mCAAI,MAAM;SACpD,CAAC;IACJ,CAAC;IACD,IAAI,GAAG,CAAC,gBAAgB,EAAE,CAAC;QACzB,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,GAAG,CAAC,gBAAgB,EAAE,CAAC;IACxD,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED,SAAS,cAAc,CAAC,GAAuB;IAC7C,MAAM,CAAC,GAAG,GAAG,aAAH,GAAG,uBAAH,GAAG,CAAE,KAAK,CAAC,sBAAsB,CAAC,CAAC;IAC7C,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;AACzB,CAAC"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.detectTestRunner = detectTestRunner;
|
|
4
|
+
function detectTestRunner(project) {
|
|
5
|
+
var _a, _b;
|
|
6
|
+
const executor = (_b = (_a = project.targets) === null || _a === void 0 ? void 0 : _a.test) === null || _b === void 0 ? void 0 : _b.executor;
|
|
7
|
+
if (!executor)
|
|
8
|
+
return 'none';
|
|
9
|
+
if (executor.includes('jest'))
|
|
10
|
+
return 'jest';
|
|
11
|
+
if (executor.includes('vite'))
|
|
12
|
+
return 'vitest';
|
|
13
|
+
return 'other';
|
|
14
|
+
}
|
|
15
|
+
//# sourceMappingURL=detect-test-runner.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"detect-test-runner.js","sourceRoot":"","sources":["../../../../nx-sonar/src/utils/detect-test-runner.ts"],"names":[],"mappings":";;AAIA,4CAMC;AAND,SAAgB,gBAAgB,CAAC,OAA6B;;IAC5D,MAAM,QAAQ,GAAG,MAAA,MAAA,OAAO,CAAC,OAAO,0CAAE,IAAI,0CAAE,QAAQ,CAAC;IACjD,IAAI,CAAC,QAAQ;QAAE,OAAO,MAAM,CAAC;IAC7B,IAAI,QAAQ,CAAC,QAAQ,CAAC,MAAM,CAAC;QAAE,OAAO,MAAM,CAAC;IAC7C,IAAI,QAAQ,CAAC,QAAQ,CAAC,MAAM,CAAC;QAAE,OAAO,QAAQ,CAAC;IAC/C,OAAO,OAAO,CAAC;AACjB,CAAC"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export declare class NxSonarError extends Error {
|
|
2
|
+
constructor(message: string);
|
|
3
|
+
}
|
|
4
|
+
export declare class MissingTokenError extends NxSonarError {
|
|
5
|
+
constructor();
|
|
6
|
+
}
|
|
7
|
+
export declare class MissingCoverageError extends NxSonarError {
|
|
8
|
+
constructor(path: string);
|
|
9
|
+
}
|
|
10
|
+
export declare class TokenInDiskConfigError extends NxSonarError {
|
|
11
|
+
constructor(source: string);
|
|
12
|
+
}
|
|
13
|
+
export declare class InvalidConfigError extends NxSonarError {
|
|
14
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.InvalidConfigError = exports.TokenInDiskConfigError = exports.MissingCoverageError = exports.MissingTokenError = exports.NxSonarError = void 0;
|
|
4
|
+
class NxSonarError extends Error {
|
|
5
|
+
constructor(message) {
|
|
6
|
+
super(message);
|
|
7
|
+
this.name = new.target.name;
|
|
8
|
+
Object.setPrototypeOf(this, new.target.prototype);
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
exports.NxSonarError = NxSonarError;
|
|
12
|
+
class MissingTokenError extends NxSonarError {
|
|
13
|
+
constructor() {
|
|
14
|
+
super('SONAR_TOKEN environment variable is not set. ' +
|
|
15
|
+
'Generate a token in your Sonar server and export it before running the scan, e.g. ' +
|
|
16
|
+
'`export SONAR_TOKEN=...` locally or as a secret in CI.');
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
exports.MissingTokenError = MissingTokenError;
|
|
20
|
+
class MissingCoverageError extends NxSonarError {
|
|
21
|
+
constructor(path) {
|
|
22
|
+
super(`Coverage report not found at "${path}".\n` +
|
|
23
|
+
'Make sure the test target emits LCOV:\n' +
|
|
24
|
+
' - jest: add "coverageReporters": ["lcov"] in jest.config.ts\n' +
|
|
25
|
+
' - vitest: add "test.coverage.reporter": ["lcov"] in vite.config.ts\n' +
|
|
26
|
+
'Or pass `coverageLcovPath` in the sonar target options if your file lives elsewhere.');
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
exports.MissingCoverageError = MissingCoverageError;
|
|
30
|
+
class TokenInDiskConfigError extends NxSonarError {
|
|
31
|
+
constructor(source) {
|
|
32
|
+
super(`A "token" was found in ${source}. ` +
|
|
33
|
+
'Tokens are secrets and must not be committed. ' +
|
|
34
|
+
'Remove it from ' +
|
|
35
|
+
source +
|
|
36
|
+
' and provide it via the SONAR_TOKEN environment variable instead.');
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
exports.TokenInDiskConfigError = TokenInDiskConfigError;
|
|
40
|
+
class InvalidConfigError extends NxSonarError {
|
|
41
|
+
}
|
|
42
|
+
exports.InvalidConfigError = InvalidConfigError;
|
|
43
|
+
//# sourceMappingURL=errors.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.js","sourceRoot":"","sources":["../../../../nx-sonar/src/utils/errors.ts"],"names":[],"mappings":";;;AAAA,MAAa,YAAa,SAAQ,KAAK;IACrC,YAAY,OAAe;QACzB,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC;QAC5B,MAAM,CAAC,cAAc,CAAC,IAAI,EAAE,GAAG,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;IACpD,CAAC;CACF;AAND,oCAMC;AAED,MAAa,iBAAkB,SAAQ,YAAY;IACjD;QACE,KAAK,CACH,+CAA+C;YAC7C,oFAAoF;YACpF,wDAAwD,CAC3D,CAAC;IACJ,CAAC;CACF;AARD,8CAQC;AAED,MAAa,oBAAqB,SAAQ,YAAY;IACpD,YAAY,IAAY;QACtB,KAAK,CACH,iCAAiC,IAAI,MAAM;YACzC,yCAAyC;YACzC,iEAAiE;YACjE,wEAAwE;YACxE,sFAAsF,CACzF,CAAC;IACJ,CAAC;CACF;AAVD,oDAUC;AAED,MAAa,sBAAuB,SAAQ,YAAY;IACtD,YAAY,MAAc;QACxB,KAAK,CACH,0BAA0B,MAAM,IAAI;YAClC,gDAAgD;YAChD,iBAAiB;YACjB,MAAM;YACN,mEAAmE,CACtE,CAAC;IACJ,CAAC;CACF;AAVD,wDAUC;AAED,MAAa,kBAAmB,SAAQ,YAAY;CAAG;AAAvD,gDAAuD"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { NxJsonSonarConfig, ResolvedOptions, ScanExecutorOptions } from './types';
|
|
2
|
+
export interface ResolveInput {
|
|
3
|
+
projectOptions: ScanExecutorOptions;
|
|
4
|
+
nxJsonConfig: NxJsonSonarConfig;
|
|
5
|
+
env: NodeJS.ProcessEnv | Record<string, string | undefined>;
|
|
6
|
+
}
|
|
7
|
+
export declare function resolveOptions({ projectOptions, nxJsonConfig, env, }: ResolveInput): ResolvedOptions;
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.resolveOptions = resolveOptions;
|
|
4
|
+
const errors_1 = require("./errors");
|
|
5
|
+
const types_1 = require("./types");
|
|
6
|
+
function resolveOptions({ projectOptions, nxJsonConfig, env, }) {
|
|
7
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r;
|
|
8
|
+
refuseTokenInDiskConfig(projectOptions, 'project.json');
|
|
9
|
+
refuseTokenInDiskConfig(nxJsonConfig, 'nx.json');
|
|
10
|
+
const token = env.SONAR_TOKEN;
|
|
11
|
+
if (!token || token.trim() === '') {
|
|
12
|
+
throw new errors_1.MissingTokenError();
|
|
13
|
+
}
|
|
14
|
+
const projectKey = (_b = (_a = projectOptions.projectKey) !== null && _a !== void 0 ? _a : nxJsonConfig.projectKey) !== null && _b !== void 0 ? _b : env.SONAR_PROJECT_KEY;
|
|
15
|
+
if (!projectKey) {
|
|
16
|
+
throw new errors_1.InvalidConfigError('projectKey is required. Set it in the sonar target options, in nx.json under nxSonar, or via the SONAR_PROJECT_KEY env var.');
|
|
17
|
+
}
|
|
18
|
+
const hostUrl = (_e = (_d = (_c = projectOptions.hostUrl) !== null && _c !== void 0 ? _c : nxJsonConfig.hostUrl) !== null && _d !== void 0 ? _d : env.SONAR_HOST_URL) !== null && _e !== void 0 ? _e : types_1.DEFAULT_HOST_URL;
|
|
19
|
+
const organization = (_g = (_f = projectOptions.organization) !== null && _f !== void 0 ? _f : nxJsonConfig.organization) !== null && _g !== void 0 ? _g : env.SONAR_ORGANIZATION;
|
|
20
|
+
const exclusions = uniq([
|
|
21
|
+
...types_1.DEFAULT_EXCLUSIONS,
|
|
22
|
+
...((_h = nxJsonConfig.exclusions) !== null && _h !== void 0 ? _h : []),
|
|
23
|
+
...((_j = projectOptions.exclusions) !== null && _j !== void 0 ? _j : []),
|
|
24
|
+
]);
|
|
25
|
+
const extraProperties = Object.assign(Object.assign({}, ((_k = nxJsonConfig.extraProperties) !== null && _k !== void 0 ? _k : {})), ((_l = projectOptions.extraProperties) !== null && _l !== void 0 ? _l : {}));
|
|
26
|
+
return {
|
|
27
|
+
projectKey,
|
|
28
|
+
projectName: projectOptions.projectName,
|
|
29
|
+
projectVersion: projectOptions.projectVersion,
|
|
30
|
+
hostUrl,
|
|
31
|
+
organization,
|
|
32
|
+
sources: projectOptions.sources,
|
|
33
|
+
tests: projectOptions.tests,
|
|
34
|
+
exclusions,
|
|
35
|
+
coverageLcovPath: projectOptions.coverageLcovPath,
|
|
36
|
+
testExecutionReportPath: projectOptions.testExecutionReportPath,
|
|
37
|
+
qualityGateWait: (_o = (_m = projectOptions.qualityGateWait) !== null && _m !== void 0 ? _m : nxJsonConfig.qualityGateWait) !== null && _o !== void 0 ? _o : true,
|
|
38
|
+
branchDetection: (_q = (_p = projectOptions.branchDetection) !== null && _p !== void 0 ? _p : nxJsonConfig.branchDetection) !== null && _q !== void 0 ? _q : true,
|
|
39
|
+
extraProperties,
|
|
40
|
+
verbose: (_r = projectOptions.verbose) !== null && _r !== void 0 ? _r : false,
|
|
41
|
+
token,
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
function refuseTokenInDiskConfig(config, source) {
|
|
45
|
+
if (config && typeof config === 'object' && 'token' in config) {
|
|
46
|
+
throw new errors_1.TokenInDiskConfigError(source);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
function uniq(values) {
|
|
50
|
+
return Array.from(new Set(values));
|
|
51
|
+
}
|
|
52
|
+
//# sourceMappingURL=resolve-options.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resolve-options.js","sourceRoot":"","sources":["../../../../nx-sonar/src/utils/resolve-options.ts"],"names":[],"mappings":";;AAmBA,wCAgEC;AAnFD,qCAIkB;AAClB,mCAMiB;AAQjB,SAAgB,cAAc,CAAC,EAC7B,cAAc,EACd,YAAY,EACZ,GAAG,GACU;;IACb,uBAAuB,CAAC,cAAc,EAAE,cAAc,CAAC,CAAC;IACxD,uBAAuB,CAAC,YAAY,EAAE,SAAS,CAAC,CAAC;IAEjD,MAAM,KAAK,GAAG,GAAG,CAAC,WAAW,CAAC;IAC9B,IAAI,CAAC,KAAK,IAAI,KAAK,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC;QAClC,MAAM,IAAI,0BAAiB,EAAE,CAAC;IAChC,CAAC;IAED,MAAM,UAAU,GACd,MAAA,MAAA,cAAc,CAAC,UAAU,mCACxB,YAAoC,CAAC,UAAU,mCAChD,GAAG,CAAC,iBAAiB,CAAC;IACxB,IAAI,CAAC,UAAU,EAAE,CAAC;QAChB,MAAM,IAAI,2BAAkB,CAC1B,6HAA6H,CAC9H,CAAC;IACJ,CAAC;IAED,MAAM,OAAO,GACX,MAAA,MAAA,MAAA,cAAc,CAAC,OAAO,mCACtB,YAAY,CAAC,OAAO,mCACpB,GAAG,CAAC,cAAc,mCAClB,wBAAgB,CAAC;IAEnB,MAAM,YAAY,GAChB,MAAA,MAAA,cAAc,CAAC,YAAY,mCAC3B,YAAY,CAAC,YAAY,mCACzB,GAAG,CAAC,kBAAkB,CAAC;IAEzB,MAAM,UAAU,GAAG,IAAI,CAAC;QACtB,GAAG,0BAAkB;QACrB,GAAG,CAAC,MAAA,YAAY,CAAC,UAAU,mCAAI,EAAE,CAAC;QAClC,GAAG,CAAC,MAAA,cAAc,CAAC,UAAU,mCAAI,EAAE,CAAC;KACrC,CAAC,CAAC;IAEH,MAAM,eAAe,mCAChB,CAAC,MAAA,YAAY,CAAC,eAAe,mCAAI,EAAE,CAAC,GACpC,CAAC,MAAA,cAAc,CAAC,eAAe,mCAAI,EAAE,CAAC,CAC1C,CAAC;IAEF,OAAO;QACL,UAAU;QACV,WAAW,EAAE,cAAc,CAAC,WAAW;QACvC,cAAc,EAAE,cAAc,CAAC,cAAc;QAC7C,OAAO;QACP,YAAY;QACZ,OAAO,EAAE,cAAc,CAAC,OAAO;QAC/B,KAAK,EAAE,cAAc,CAAC,KAAK;QAC3B,UAAU;QACV,gBAAgB,EAAE,cAAc,CAAC,gBAAgB;QACjD,uBAAuB,EAAE,cAAc,CAAC,uBAAuB;QAC/D,eAAe,EACb,MAAA,MAAA,cAAc,CAAC,eAAe,mCAAI,YAAY,CAAC,eAAe,mCAAI,IAAI;QACxE,eAAe,EACb,MAAA,MAAA,cAAc,CAAC,eAAe,mCAAI,YAAY,CAAC,eAAe,mCAAI,IAAI;QACxE,eAAe;QACf,OAAO,EAAE,MAAA,cAAc,CAAC,OAAO,mCAAI,KAAK;QACxC,KAAK;KACN,CAAC;AACJ,CAAC;AAED,SAAS,uBAAuB,CAC9B,MAAc,EACd,MAAc;IAEd,IAAI,MAAM,IAAI,OAAO,MAAM,KAAK,QAAQ,IAAI,OAAO,IAAI,MAAM,EAAE,CAAC;QAC9D,MAAM,IAAI,+BAAsB,CAAC,MAAM,CAAC,CAAC;IAC3C,CAAC;AACH,CAAC;AAED,SAAS,IAAI,CAAI,MAAoB;IACnC,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC;AACrC,CAAC"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { ScanExecutorOptions } from './types';
|
|
2
|
+
export interface ResolvedPaths {
|
|
3
|
+
sources: string | string[];
|
|
4
|
+
tests?: string | string[];
|
|
5
|
+
coveragePath: string;
|
|
6
|
+
testExecutionReportPath?: string;
|
|
7
|
+
}
|
|
8
|
+
export interface ResolvePathsInput {
|
|
9
|
+
workspaceRoot: string;
|
|
10
|
+
projectRoot: string;
|
|
11
|
+
options: ScanExecutorOptions;
|
|
12
|
+
}
|
|
13
|
+
export declare function resolveProjectPaths({ workspaceRoot, projectRoot, options, }: ResolvePathsInput): ResolvedPaths;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.resolveProjectPaths = resolveProjectPaths;
|
|
4
|
+
const fs_1 = require("fs");
|
|
5
|
+
const path_1 = require("path");
|
|
6
|
+
const errors_1 = require("./errors");
|
|
7
|
+
function resolveProjectPaths({ workspaceRoot, projectRoot, options, }) {
|
|
8
|
+
var _a, _b;
|
|
9
|
+
const sources = (_a = options.sources) !== null && _a !== void 0 ? _a : projectRoot;
|
|
10
|
+
const tests = options.tests;
|
|
11
|
+
const coveragePath = (_b = options.coverageLcovPath) !== null && _b !== void 0 ? _b : `coverage/${projectRoot}/lcov.info`;
|
|
12
|
+
if (!(0, fs_1.existsSync)((0, path_1.join)(workspaceRoot, coveragePath))) {
|
|
13
|
+
throw new errors_1.MissingCoverageError(coveragePath);
|
|
14
|
+
}
|
|
15
|
+
let testExecutionReportPath;
|
|
16
|
+
if (options.testExecutionReportPath) {
|
|
17
|
+
if ((0, fs_1.existsSync)((0, path_1.join)(workspaceRoot, options.testExecutionReportPath))) {
|
|
18
|
+
testExecutionReportPath = options.testExecutionReportPath;
|
|
19
|
+
}
|
|
20
|
+
else {
|
|
21
|
+
console.warn(`[@itssky/nx-sonar] testExecutionReportPath "${options.testExecutionReportPath}" not found — omitting from scanner properties.`);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
return { sources, tests, coveragePath, testExecutionReportPath };
|
|
25
|
+
}
|
|
26
|
+
//# sourceMappingURL=resolve-project-paths.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resolve-project-paths.js","sourceRoot":"","sources":["../../../../nx-sonar/src/utils/resolve-project-paths.ts"],"names":[],"mappings":";;AAkBA,kDA2BC;AA7CD,2BAAgC;AAChC,+BAA4B;AAC5B,qCAAgD;AAgBhD,SAAgB,mBAAmB,CAAC,EAClC,aAAa,EACb,WAAW,EACX,OAAO,GACW;;IAClB,MAAM,OAAO,GAAG,MAAA,OAAO,CAAC,OAAO,mCAAI,WAAW,CAAC;IAC/C,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC;IAE5B,MAAM,YAAY,GAChB,MAAA,OAAO,CAAC,gBAAgB,mCAAI,YAAY,WAAW,YAAY,CAAC;IAElE,IAAI,CAAC,IAAA,eAAU,EAAC,IAAA,WAAI,EAAC,aAAa,EAAE,YAAY,CAAC,CAAC,EAAE,CAAC;QACnD,MAAM,IAAI,6BAAoB,CAAC,YAAY,CAAC,CAAC;IAC/C,CAAC;IAED,IAAI,uBAA2C,CAAC;IAChD,IAAI,OAAO,CAAC,uBAAuB,EAAE,CAAC;QACpC,IAAI,IAAA,eAAU,EAAC,IAAA,WAAI,EAAC,aAAa,EAAE,OAAO,CAAC,uBAAuB,CAAC,CAAC,EAAE,CAAC;YACrE,uBAAuB,GAAG,OAAO,CAAC,uBAAuB,CAAC;QAC5D,CAAC;aAAM,CAAC;YACN,OAAO,CAAC,IAAI,CACV,+CAA+C,OAAO,CAAC,uBAAuB,iDAAiD,CAChI,CAAC;QACJ,CAAC;IACH,CAAC;IAED,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,YAAY,EAAE,uBAAuB,EAAE,CAAC;AACnE,CAAC"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.runScanner = runScanner;
|
|
4
|
+
const tslib_1 = require("tslib");
|
|
5
|
+
const fs_1 = require("fs");
|
|
6
|
+
const path_1 = require("path");
|
|
7
|
+
const sonarqube_scanner_1 = require("sonarqube-scanner");
|
|
8
|
+
function runScanner(properties) {
|
|
9
|
+
return tslib_1.__awaiter(this, void 0, void 0, function* () {
|
|
10
|
+
if (process.env.NX_SONAR_DRY_RUN === '1') {
|
|
11
|
+
const out = process.env.NX_SONAR_DRY_RUN_OUT;
|
|
12
|
+
if (!out) {
|
|
13
|
+
throw new Error('NX_SONAR_DRY_RUN=1 requires NX_SONAR_DRY_RUN_OUT to be set to a file path.');
|
|
14
|
+
}
|
|
15
|
+
(0, fs_1.mkdirSync)((0, path_1.dirname)(out), { recursive: true });
|
|
16
|
+
(0, fs_1.writeFileSync)(out, JSON.stringify(properties, null, 2));
|
|
17
|
+
return { success: true };
|
|
18
|
+
}
|
|
19
|
+
const serverUrl = properties['sonar.host.url'];
|
|
20
|
+
return yield new Promise((resolve) => {
|
|
21
|
+
(0, sonarqube_scanner_1.default)({
|
|
22
|
+
serverUrl,
|
|
23
|
+
options: properties,
|
|
24
|
+
}, (error) => {
|
|
25
|
+
if (error) {
|
|
26
|
+
console.error('[@itssky/nx-sonar] scanner failed:', error);
|
|
27
|
+
resolve({ success: false });
|
|
28
|
+
}
|
|
29
|
+
else {
|
|
30
|
+
resolve({ success: true });
|
|
31
|
+
}
|
|
32
|
+
});
|
|
33
|
+
});
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
//# sourceMappingURL=run-scanner.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"run-scanner.js","sourceRoot":"","sources":["../../../../nx-sonar/src/utils/run-scanner.ts"],"names":[],"mappings":";;AASA,gCAgCC;;AAzCD,2BAA8C;AAC9C,+BAA+B;AAC/B,yDAAwC;AAOxC,SAAsB,UAAU,CAC9B,UAA6B;;QAE7B,IAAI,OAAO,CAAC,GAAG,CAAC,gBAAgB,KAAK,GAAG,EAAE,CAAC;YACzC,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC,oBAAoB,CAAC;YAC7C,IAAI,CAAC,GAAG,EAAE,CAAC;gBACT,MAAM,IAAI,KAAK,CACb,4EAA4E,CAC7E,CAAC;YACJ,CAAC;YACD,IAAA,cAAS,EAAC,IAAA,cAAO,EAAC,GAAG,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;YAC7C,IAAA,kBAAa,EAAC,GAAG,EAAE,IAAI,CAAC,SAAS,CAAC,UAAU,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;YACxD,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;QAC3B,CAAC;QAED,MAAM,SAAS,GAAG,UAAU,CAAC,gBAAgB,CAAC,CAAC;QAC/C,OAAO,MAAM,IAAI,OAAO,CAAa,CAAC,OAAO,EAAE,EAAE;YAC/C,IAAA,2BAAO,EACL;gBACE,SAAS;gBACT,OAAO,EAAE,UAAU;aACpB,EACD,CAAC,KAAe,EAAE,EAAE;gBAClB,IAAI,KAAK,EAAE,CAAC;oBACV,OAAO,CAAC,KAAK,CAAC,oCAAoC,EAAE,KAAK,CAAC,CAAC;oBAC3D,OAAO,CAAC,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC,CAAC;gBAC9B,CAAC;qBAAM,CAAC;oBACN,OAAO,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC;gBAC7B,CAAC;YACH,CAAC,CACF,CAAC;QACJ,CAAC,CAAC,CAAC;IACL,CAAC;CAAA"}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
export interface ScanExecutorOptions {
|
|
2
|
+
projectKey?: string;
|
|
3
|
+
projectName?: string;
|
|
4
|
+
projectVersion?: string;
|
|
5
|
+
hostUrl?: string;
|
|
6
|
+
organization?: string;
|
|
7
|
+
sources?: string | string[];
|
|
8
|
+
tests?: string | string[];
|
|
9
|
+
exclusions?: string[];
|
|
10
|
+
coverageLcovPath?: string;
|
|
11
|
+
testExecutionReportPath?: string;
|
|
12
|
+
qualityGateWait?: boolean;
|
|
13
|
+
branchDetection?: boolean;
|
|
14
|
+
extraProperties?: Record<string, string>;
|
|
15
|
+
verbose?: boolean;
|
|
16
|
+
}
|
|
17
|
+
export interface NxJsonSonarConfig {
|
|
18
|
+
hostUrl?: string;
|
|
19
|
+
organization?: string;
|
|
20
|
+
exclusions?: string[];
|
|
21
|
+
qualityGateWait?: boolean;
|
|
22
|
+
branchDetection?: boolean;
|
|
23
|
+
extraProperties?: Record<string, string>;
|
|
24
|
+
}
|
|
25
|
+
export interface ResolvedOptions {
|
|
26
|
+
projectKey: string;
|
|
27
|
+
projectName?: string;
|
|
28
|
+
projectVersion?: string;
|
|
29
|
+
hostUrl: string;
|
|
30
|
+
organization?: string;
|
|
31
|
+
sources?: string | string[];
|
|
32
|
+
tests?: string | string[];
|
|
33
|
+
exclusions: string[];
|
|
34
|
+
coverageLcovPath?: string;
|
|
35
|
+
testExecutionReportPath?: string;
|
|
36
|
+
qualityGateWait: boolean;
|
|
37
|
+
branchDetection: boolean;
|
|
38
|
+
extraProperties: Record<string, string>;
|
|
39
|
+
verbose: boolean;
|
|
40
|
+
token: string;
|
|
41
|
+
}
|
|
42
|
+
export declare const DEFAULT_EXCLUSIONS: readonly ["**/node_modules/**", "**/dist/**", "**/*.spec.ts", "**/*.test.ts", "**/*.spec.tsx", "**/*.test.tsx"];
|
|
43
|
+
export declare const DEFAULT_HOST_URL = "https://sonarcloud.io";
|
|
44
|
+
export type CiContext = {
|
|
45
|
+
kind: 'branch';
|
|
46
|
+
name: string;
|
|
47
|
+
} | {
|
|
48
|
+
kind: 'pullRequest';
|
|
49
|
+
key: string;
|
|
50
|
+
branch: string;
|
|
51
|
+
base: string;
|
|
52
|
+
} | null;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.DEFAULT_HOST_URL = exports.DEFAULT_EXCLUSIONS = void 0;
|
|
4
|
+
exports.DEFAULT_EXCLUSIONS = [
|
|
5
|
+
'**/node_modules/**',
|
|
6
|
+
'**/dist/**',
|
|
7
|
+
'**/*.spec.ts',
|
|
8
|
+
'**/*.test.ts',
|
|
9
|
+
'**/*.spec.tsx',
|
|
10
|
+
'**/*.test.tsx',
|
|
11
|
+
];
|
|
12
|
+
exports.DEFAULT_HOST_URL = 'https://sonarcloud.io';
|
|
13
|
+
//# sourceMappingURL=types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../../../nx-sonar/src/utils/types.ts"],"names":[],"mappings":";;;AA4Ca,QAAA,kBAAkB,GAAG;IAChC,oBAAoB;IACpB,YAAY;IACZ,cAAc;IACd,cAAc;IACd,eAAe;IACf,eAAe;CACP,CAAC;AAEE,QAAA,gBAAgB,GAAG,uBAAuB,CAAC"}
|