@freshworks/shiftleft-tools 1.1.18 → 1.1.19
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 +18 -4
- package/package.json +1 -1
- package/templates/postman/scripts/lib/__pycache__/publish_health.cpython-310.pyc +0 -0
- package/templates/postman/scripts/lib/__pycache__/report_combined.cpython-310.pyc +0 -0
- package/templates/postman/scripts/lib/__pycache__/report_generator.cpython-310.pyc +0 -0
- package/templates/postman/scripts/lib/publish_health.py +178 -0
- package/templates/postman/scripts/lib/report_combined.py +62 -0
- package/templates/postman/scripts/lib/report_generator.py +10 -0
- package/templates/postman/scripts/run-all.sh +10 -1
- package/templates/postman-node/requirements.txt +1 -0
- package/templates/postman-node/scripts/run-all.sh +10 -1
package/README.md
CHANGED
|
@@ -70,6 +70,18 @@ shiftleft --version
|
|
|
70
70
|
|
|
71
71
|
## Usage
|
|
72
72
|
|
|
73
|
+
| Command | Purpose | Key flags |
|
|
74
|
+
|---|---|---|
|
|
75
|
+
| `init-rules` | Symlink Cursor rules/skills into a repo | `--force`, `--skip-skills`, `--copy`, `--stack` |
|
|
76
|
+
| `init-postman` | Scaffold Postman/Newman infra | `--name`, `--stack`, `--with-staging`, `--force` |
|
|
77
|
+
| `link` | (Re)create Cursor symlinks | `--copy`, `--stack` |
|
|
78
|
+
| `test` | Stage latest scripts + run orchestrator | *(flags pass through to run-all.sh)* |
|
|
79
|
+
| `stage-scripts` | Stage library scripts only (no run) | `--stack` |
|
|
80
|
+
| `protect` | Mark a staged script repo-owned | `--list`, `--remove` |
|
|
81
|
+
| `update` | Refresh rules/skills/postman | `--rules`, `--skills`, `--postman`, `--force` |
|
|
82
|
+
| `doctor` | Report drift vs latest | `--check`, `--json` |
|
|
83
|
+
| `setup-pipeline` | Audit + scaffold pipeline | `-y/--yes`, `--force` |
|
|
84
|
+
|
|
73
85
|
### Claude Code skills: install the plugin (once per machine)
|
|
74
86
|
|
|
75
87
|
Claude Code skills are delivered as a **plugin**, not copied into each repo — so
|
|
@@ -166,6 +178,10 @@ postman/scripts/
|
|
|
166
178
|
└── database/ # Node
|
|
167
179
|
```
|
|
168
180
|
|
|
181
|
+
Java LocalStack/WireMock orchestration auto-detects the container runtime — **docker preferred, podman fallback** (`infra/container-runtime.sh`) — so S3/attachment tests run on podman-only machines.
|
|
182
|
+
|
|
183
|
+
Java `runners/run-tests-local.sh` / `run-tests-staging.sh` ship **generic**. `/setup-api-tests` fills the repo-specific block (port, profile, Maven module, coverage package, JWT) and then runs `shiftleft protect` so staging won't overwrite your customizations.
|
|
184
|
+
|
|
169
185
|
The library scripts are *not vendored*: `shiftleft test` (and the `run-all.sh`
|
|
170
186
|
shim) re-stages them from the installed package before every run, so
|
|
171
187
|
`npm i -g @freshworks/shiftleft-tools@latest` changes test behavior in every repo
|
|
@@ -186,9 +202,7 @@ shiftleft stage-scripts # stage only (before calling staged scrip
|
|
|
186
202
|
|
|
187
203
|
### Protect a customized library script
|
|
188
204
|
|
|
189
|
-
Staging overwrites library scripts from the package on every run.
|
|
190
|
-
has customized one (e.g. a service-specific `runners/run-tests-local.sh`), mark
|
|
191
|
-
it **protected** so staging leaves it alone:
|
|
205
|
+
Staging overwrites library scripts from the package on every run. For Java repos, **`shiftleft protect` is the required final step of `/setup-api-tests`** — without it, every `shiftleft test` run silently discards your runner customizations. If you've manually customized a script, mark it **protected** so staging leaves it alone:
|
|
192
206
|
|
|
193
207
|
```bash
|
|
194
208
|
shiftleft protect runners/run-tests-local.sh runners/run-tests-staging.sh
|
|
@@ -343,7 +357,7 @@ npm pack
|
|
|
343
357
|
## Requirements
|
|
344
358
|
|
|
345
359
|
- Node.js 18+ and npm 8.4+ (for the CLI and Postman/Newman runner)
|
|
346
|
-
- **Java projects:** Java
|
|
360
|
+
- **Java projects:** Java (version per your service; the local runner honors `JAVA_VERSION`), Maven, Docker or Podman
|
|
347
361
|
- **Node projects:** Yarn (recommended), Mocha, nyc, Stryker
|
|
348
362
|
- AWS CLI (for staging Postman tests with JWT from Secrets Manager)
|
|
349
363
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@freshworks/shiftleft-tools",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.19",
|
|
4
4
|
"description": "CLI for managing Cursor rules/skills and Postman test infrastructure across Java Spring Boot and Node.js/Express projects",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "src/index.js",
|
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Publish a normalized test-health row to DynamoDB after each ShiftLeft run.
|
|
3
|
+
|
|
4
|
+
Gated: only writes when SHIFTLEFT_PUBLISH_METRICS=true and SHIFTLEFT_HEALTH_TABLE is set.
|
|
5
|
+
A publish failure logs a warning and never fails the build.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
import os
|
|
9
|
+
import re
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def _normalize_repo(url):
|
|
13
|
+
"""git@github.com:owner/repo.git or https://github.com/owner/repo.git → owner/repo"""
|
|
14
|
+
url = (url or '').strip()
|
|
15
|
+
# SSH
|
|
16
|
+
m = re.match(r'git@[^:]+:(.+?)(?:\.git)?$', url)
|
|
17
|
+
if m:
|
|
18
|
+
return m.group(1)
|
|
19
|
+
# HTTPS
|
|
20
|
+
m = re.match(r'https?://[^/]+/(.+?)(?:\.git)?$', url)
|
|
21
|
+
if m:
|
|
22
|
+
return m.group(1)
|
|
23
|
+
return url
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def build_row(metrics, meta):
|
|
27
|
+
"""
|
|
28
|
+
Build a normalized DynamoDB item from computed metrics and run context.
|
|
29
|
+
|
|
30
|
+
metrics keys (all optional):
|
|
31
|
+
mutation – dict with keys killed/survived/no_coverage(or noCoverage)/timeout/total
|
|
32
|
+
api_coverage – api-coverage-matrix JSON dict
|
|
33
|
+
postman – dict: assertions_total/passed/failed, collections_passed/failed
|
|
34
|
+
postman_collections – list of per-collection dicts (name, assertions_total/passed/failed, status)
|
|
35
|
+
|
|
36
|
+
meta keys:
|
|
37
|
+
git_repo, git_commit, git_branch, pr_number
|
|
38
|
+
datetime – ISO-8601 string (UTC)
|
|
39
|
+
display_name – human-readable service name
|
|
40
|
+
stack – 'Java' | 'NodeJS' etc.
|
|
41
|
+
environment – 'local' | 'staging'
|
|
42
|
+
mutation_tool – 'pit' | 'stryker'
|
|
43
|
+
products – optional list of product slugs (multi-product repos)
|
|
44
|
+
"""
|
|
45
|
+
postman = metrics.get('postman') or {}
|
|
46
|
+
api_coverage = metrics.get('api_coverage')
|
|
47
|
+
mutation = metrics.get('mutation')
|
|
48
|
+
postman_collections = metrics.get('postman_collections') or []
|
|
49
|
+
|
|
50
|
+
# --- passRate ---
|
|
51
|
+
assertions_total = int(postman.get('assertions_total', 0))
|
|
52
|
+
assertions_passed = int(postman.get('assertions_passed', 0))
|
|
53
|
+
assertions_failed = int(postman.get('assertions_failed', 0))
|
|
54
|
+
col_passed = int(postman.get('collections_passed', 0))
|
|
55
|
+
col_failed = int(postman.get('collections_failed', 0))
|
|
56
|
+
if assertions_total > 0:
|
|
57
|
+
pass_status = 'pass' if assertions_failed == 0 else 'fail'
|
|
58
|
+
else:
|
|
59
|
+
pass_status = 'unknown'
|
|
60
|
+
|
|
61
|
+
pass_rate = {
|
|
62
|
+
'collectionsTotal': col_passed + col_failed,
|
|
63
|
+
'collectionsPassed': col_passed,
|
|
64
|
+
'assertionsTotal': assertions_total,
|
|
65
|
+
'assertionsPassed': assertions_passed,
|
|
66
|
+
'assertionsFailed': assertions_failed,
|
|
67
|
+
'status': pass_status,
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
# --- coverage (API coverage) ---
|
|
71
|
+
if api_coverage:
|
|
72
|
+
cov_pct = float(api_coverage.get('coverage_percent', 0))
|
|
73
|
+
well_pct = float(api_coverage.get('well_tested_percent', 0))
|
|
74
|
+
qp_pct = float(api_coverage.get('query_params_percent', 0))
|
|
75
|
+
skipped = int(api_coverage.get('skipped_tests', 0))
|
|
76
|
+
gaps = (api_coverage.get('gaps') or [])[:25]
|
|
77
|
+
by_method = api_coverage.get('by_method') or {}
|
|
78
|
+
else:
|
|
79
|
+
cov_pct = well_pct = qp_pct = 0.0
|
|
80
|
+
skipped = 0
|
|
81
|
+
gaps = []
|
|
82
|
+
by_method = {}
|
|
83
|
+
|
|
84
|
+
coverage = {
|
|
85
|
+
'coveragePercent': cov_pct,
|
|
86
|
+
'wellTestedPercent': well_pct,
|
|
87
|
+
'queryParamsPercent': qp_pct,
|
|
88
|
+
'skippedTests': skipped,
|
|
89
|
+
'gaps': gaps,
|
|
90
|
+
'byMethod': by_method,
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
# --- mutation ---
|
|
94
|
+
mut_row = None
|
|
95
|
+
if mutation:
|
|
96
|
+
killed = int(mutation.get('killed', 0))
|
|
97
|
+
survived = int(mutation.get('survived', 0))
|
|
98
|
+
# PIT uses no_coverage; normalize to noCoverage
|
|
99
|
+
no_cov = int(mutation.get('noCoverage', mutation.get('no_coverage', 0)))
|
|
100
|
+
timeout = int(mutation.get('timeout', 0))
|
|
101
|
+
total = int(mutation.get('total', 0))
|
|
102
|
+
denominator = killed + survived + no_cov
|
|
103
|
+
score = round((killed / denominator * 100), 2) if denominator > 0 else 0.0
|
|
104
|
+
mut_row = {
|
|
105
|
+
'tool': meta.get('mutation_tool', 'pit'),
|
|
106
|
+
'killed': killed,
|
|
107
|
+
'survived': survived,
|
|
108
|
+
'noCoverage': no_cov,
|
|
109
|
+
'timeout': timeout,
|
|
110
|
+
'total': total,
|
|
111
|
+
'score': score,
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
# --- failures (top 25 failing collections) ---
|
|
115
|
+
failures = [
|
|
116
|
+
{
|
|
117
|
+
'suite': col.get('name', ''),
|
|
118
|
+
'test': '',
|
|
119
|
+
'reason': f"{col.get('assertions_failed', 0)} assertion(s) failed",
|
|
120
|
+
}
|
|
121
|
+
for col in postman_collections
|
|
122
|
+
if int(col.get('assertions_failed', 0)) > 0
|
|
123
|
+
][:25]
|
|
124
|
+
|
|
125
|
+
# --- suites (per-collection breakdown) ---
|
|
126
|
+
suites = [
|
|
127
|
+
{
|
|
128
|
+
'name': col.get('name', ''),
|
|
129
|
+
'assertionsTotal': int(col.get('assertions_total', 0)),
|
|
130
|
+
'assertionsPassed': int(col.get('assertions_passed', 0)),
|
|
131
|
+
'coveragePercent': 0,
|
|
132
|
+
}
|
|
133
|
+
for col in postman_collections
|
|
134
|
+
]
|
|
135
|
+
|
|
136
|
+
repo = _normalize_repo(meta.get('git_repo', ''))
|
|
137
|
+
|
|
138
|
+
row = {
|
|
139
|
+
'Repo': repo,
|
|
140
|
+
'DateTime': meta.get('datetime', ''),
|
|
141
|
+
'displayName': meta.get('display_name', ''),
|
|
142
|
+
'stack': meta.get('stack', ''),
|
|
143
|
+
'environment': meta.get('environment', ''),
|
|
144
|
+
'prNumber': meta.get('pr_number', ''),
|
|
145
|
+
'commitSha': meta.get('git_commit', ''),
|
|
146
|
+
'passRate': pass_rate,
|
|
147
|
+
'coverage': coverage,
|
|
148
|
+
'failures': failures,
|
|
149
|
+
'suites': suites,
|
|
150
|
+
}
|
|
151
|
+
if mut_row:
|
|
152
|
+
row['mutation'] = mut_row
|
|
153
|
+
products = meta.get('products') or []
|
|
154
|
+
if products:
|
|
155
|
+
row['products'] = products
|
|
156
|
+
|
|
157
|
+
return row
|
|
158
|
+
|
|
159
|
+
|
|
160
|
+
def publish(row):
|
|
161
|
+
"""Write row to DynamoDB. Gated by SHIFTLEFT_PUBLISH_METRICS=true. Never fails the build."""
|
|
162
|
+
flag = os.environ.get('SHIFTLEFT_PUBLISH_METRICS', '').strip().lower()
|
|
163
|
+
if flag not in ('true', '1', 'yes'):
|
|
164
|
+
return
|
|
165
|
+
table_name = os.environ.get('SHIFTLEFT_HEALTH_TABLE', 'mp-shiftleft-health')
|
|
166
|
+
if not table_name:
|
|
167
|
+
return
|
|
168
|
+
if not row.get('Repo') or not row.get('DateTime'):
|
|
169
|
+
print('[publish_health] Warning: Repo or DateTime missing — skipping publish.')
|
|
170
|
+
return
|
|
171
|
+
try:
|
|
172
|
+
import boto3
|
|
173
|
+
dynamodb = boto3.resource('dynamodb')
|
|
174
|
+
table = dynamodb.Table(table_name)
|
|
175
|
+
table.put_item(Item=row)
|
|
176
|
+
print(f'[publish_health] Published health row: {row["Repo"]} @ {row["DateTime"]}')
|
|
177
|
+
except Exception as exc:
|
|
178
|
+
print(f'[publish_health] Warning: publish failed (non-fatal): {exc}')
|
|
@@ -13,6 +13,30 @@ from report_utils import (
|
|
|
13
13
|
from report_unit import parse_surefire_reports, parse_jacoco_report, parse_mutation_data
|
|
14
14
|
|
|
15
15
|
|
|
16
|
+
def _parse_stryker_json(path):
|
|
17
|
+
"""Parse Stryker mutation-report.json into the same shape as parse_mutation_data."""
|
|
18
|
+
killed = survived = no_coverage = timeout = 0
|
|
19
|
+
try:
|
|
20
|
+
with open(path, 'r') as f:
|
|
21
|
+
data = json.load(f)
|
|
22
|
+
for fdata in data.get('files', {}).values():
|
|
23
|
+
for m in fdata.get('mutants', []):
|
|
24
|
+
st = m.get('status', '')
|
|
25
|
+
if st == 'Killed':
|
|
26
|
+
killed += 1
|
|
27
|
+
elif st == 'Survived':
|
|
28
|
+
survived += 1
|
|
29
|
+
elif st == 'NoCoverage':
|
|
30
|
+
no_coverage += 1
|
|
31
|
+
elif st == 'Timeout':
|
|
32
|
+
timeout += 1
|
|
33
|
+
except Exception as e:
|
|
34
|
+
print(f'Warning: Could not parse stryker JSON {path}: {e}')
|
|
35
|
+
total = killed + survived + no_coverage + timeout
|
|
36
|
+
return {'killed': killed, 'survived': survived, 'no_coverage': no_coverage, 'timeout': timeout, 'total': total,
|
|
37
|
+
'mutator_stats': {}, 'survived_mutations': []}
|
|
38
|
+
|
|
39
|
+
|
|
16
40
|
def generate_combined_report(args):
|
|
17
41
|
output_html = args.output_file
|
|
18
42
|
|
|
@@ -20,6 +44,11 @@ def generate_combined_report(args):
|
|
|
20
44
|
jacoco = parse_jacoco_report(args.jacoco_xml) if args.jacoco_xml and os.path.isfile(args.jacoco_xml) else None
|
|
21
45
|
mutation = parse_mutation_data(args.mutations_xml) if args.mutations_xml and os.path.isfile(args.mutations_xml) else None
|
|
22
46
|
|
|
47
|
+
# Node stack: Stryker mutation report (--stryker-json)
|
|
48
|
+
stryker_json_path = getattr(args, 'stryker_json', None)
|
|
49
|
+
if mutation is None and stryker_json_path and os.path.isfile(stryker_json_path):
|
|
50
|
+
mutation = _parse_stryker_json(stryker_json_path)
|
|
51
|
+
|
|
23
52
|
api_coverage = None
|
|
24
53
|
if args.api_coverage_file and os.path.isfile(args.api_coverage_file):
|
|
25
54
|
with open(args.api_coverage_file, 'r') as f:
|
|
@@ -178,6 +207,39 @@ def generate_combined_report(args):
|
|
|
178
207
|
])
|
|
179
208
|
|
|
180
209
|
postman_collections = _load_postman_collections(args)
|
|
210
|
+
|
|
211
|
+
# Publish normalized health row to DynamoDB (gated by SHIFTLEFT_PUBLISH_METRICS env var)
|
|
212
|
+
try:
|
|
213
|
+
import datetime as _dt
|
|
214
|
+
from publish_health import build_row, publish
|
|
215
|
+
_mut_tool = 'stryker' if getattr(args, 'stryker_json', None) else 'pit'
|
|
216
|
+
_metrics = {
|
|
217
|
+
'mutation': mutation,
|
|
218
|
+
'api_coverage': api_coverage,
|
|
219
|
+
'postman': {
|
|
220
|
+
'assertions_total': postman_total,
|
|
221
|
+
'assertions_passed': postman_passed,
|
|
222
|
+
'assertions_failed': postman_failed,
|
|
223
|
+
'collections_passed': postman_col_passed,
|
|
224
|
+
'collections_failed': postman_col_failed,
|
|
225
|
+
},
|
|
226
|
+
'postman_collections': postman_collections,
|
|
227
|
+
}
|
|
228
|
+
_meta = {
|
|
229
|
+
'git_repo': getattr(args, 'git_repo', '') or '',
|
|
230
|
+
'git_commit': getattr(args, 'git_commit', '') or '',
|
|
231
|
+
'git_branch': getattr(args, 'git_branch', '') or '',
|
|
232
|
+
'pr_number': getattr(args, 'pr_number', '') or '',
|
|
233
|
+
'datetime': _dt.datetime.utcnow().isoformat() + 'Z',
|
|
234
|
+
'display_name': getattr(args, 'logo', ''),
|
|
235
|
+
'stack': getattr(args, 'stack', '') or '',
|
|
236
|
+
'environment': getattr(args, 'env', '') or '',
|
|
237
|
+
'mutation_tool': _mut_tool,
|
|
238
|
+
}
|
|
239
|
+
publish(build_row(_metrics, _meta))
|
|
240
|
+
except Exception as _e:
|
|
241
|
+
print(f'[health] Warning: publish health failed (non-fatal): {_e}')
|
|
242
|
+
|
|
181
243
|
products_present = sorted(set(c['product'] for c in postman_collections))
|
|
182
244
|
real_products = [p for p in products_present if p and p != 'default']
|
|
183
245
|
is_multi_product = len(real_products) > 1
|
|
@@ -98,6 +98,16 @@ def main():
|
|
|
98
98
|
comb.add_argument('--postman-consolidated-html')
|
|
99
99
|
comb.add_argument('--env', default=None)
|
|
100
100
|
comb.add_argument('--timestamp', default=None)
|
|
101
|
+
# Node-stack unit/mutation inputs
|
|
102
|
+
comb.add_argument('--stryker-json')
|
|
103
|
+
comb.add_argument('--mocha-xml')
|
|
104
|
+
comb.add_argument('--lcov')
|
|
105
|
+
# Run context for health publishing
|
|
106
|
+
comb.add_argument('--git-repo', default='')
|
|
107
|
+
comb.add_argument('--git-commit', default='')
|
|
108
|
+
comb.add_argument('--git-branch', default='')
|
|
109
|
+
comb.add_argument('--pr-number', default='')
|
|
110
|
+
comb.add_argument('--stack', default='')
|
|
101
111
|
|
|
102
112
|
args = parser.parse_args()
|
|
103
113
|
|
|
@@ -51,6 +51,13 @@ REPORTS_DIR="$POSTMAN_DIR/reports"
|
|
|
51
51
|
APP_PORT="${APP_PORT:-9090}"
|
|
52
52
|
TIMESTAMP=$(date +"%Y%m%d-%H%M%S")
|
|
53
53
|
|
|
54
|
+
# Git / CI run context for health publishing
|
|
55
|
+
GIT_COMMIT=$(git -C "$PROJECT_ROOT" rev-parse HEAD 2>/dev/null || echo "unknown")
|
|
56
|
+
GIT_BRANCH=$(git -C "$PROJECT_ROOT" rev-parse --abbrev-ref HEAD 2>/dev/null || echo "unknown")
|
|
57
|
+
GIT_REPO=$(git -C "$PROJECT_ROOT" config --get remote.origin.url 2>/dev/null || echo "unknown")
|
|
58
|
+
PR_NUMBER="${CHANGE_ID:-${GITHUB_PR_NUMBER:-}}"
|
|
59
|
+
export GIT_COMMIT GIT_BRANCH GIT_REPO PR_NUMBER
|
|
60
|
+
|
|
54
61
|
# Environment selection (local or staging)
|
|
55
62
|
POSTMAN_ENV="${POSTMAN_ENV:-local}"
|
|
56
63
|
|
|
@@ -369,7 +376,9 @@ if [ "$SKIP_REPORT" = false ]; then
|
|
|
369
376
|
echo -e "${YELLOW}Generating combined report...${NC}"
|
|
370
377
|
|
|
371
378
|
# Build report arguments as an array to handle spaces properly
|
|
372
|
-
REPORT_ARGS=(combined "$COMBINED_OUTPUT" --logo "$REPORT_LOGO" --env "$POSTMAN_ENV" --timestamp "$TIMESTAMP")
|
|
379
|
+
REPORT_ARGS=(combined "$COMBINED_OUTPUT" --logo "$REPORT_LOGO" --env "$POSTMAN_ENV" --timestamp "$TIMESTAMP" --stack "Java")
|
|
380
|
+
REPORT_ARGS+=(--git-repo "$GIT_REPO" --git-commit "$GIT_COMMIT" --git-branch "$GIT_BRANCH")
|
|
381
|
+
[ -n "${PR_NUMBER:-}" ] && REPORT_ARGS+=(--pr-number "$PR_NUMBER")
|
|
373
382
|
|
|
374
383
|
# Unit test data (use preserved unit test JaCoCo, not the postman one)
|
|
375
384
|
[ -d "$SUREFIRE_DIR" ] && REPORT_ARGS+=(--surefire-dir "$SUREFIRE_DIR")
|
|
@@ -33,6 +33,13 @@ source "$SCRIPT_DIR/lib/cleanup-stryker.sh"
|
|
|
33
33
|
REPORTS_DIR="$POSTMAN_DIR/reports"
|
|
34
34
|
TIMESTAMP=$(date +"%Y%m%d-%H%M%S")
|
|
35
35
|
|
|
36
|
+
# Git / CI run context for health publishing
|
|
37
|
+
GIT_COMMIT=$(git -C "$PROJECT_ROOT" rev-parse HEAD 2>/dev/null || echo "unknown")
|
|
38
|
+
GIT_BRANCH=$(git -C "$PROJECT_ROOT" rev-parse --abbrev-ref HEAD 2>/dev/null || echo "unknown")
|
|
39
|
+
GIT_REPO=$(git -C "$PROJECT_ROOT" config --get remote.origin.url 2>/dev/null || echo "unknown")
|
|
40
|
+
PR_NUMBER="${CHANGE_ID:-${GITHUB_PR_NUMBER:-}}"
|
|
41
|
+
export GIT_COMMIT GIT_BRANCH GIT_REPO PR_NUMBER
|
|
42
|
+
|
|
36
43
|
POSTMAN_ENV="${POSTMAN_ENV:-local}"
|
|
37
44
|
SKIP_UNIT=false
|
|
38
45
|
SKIP_MUTATION=false
|
|
@@ -246,7 +253,9 @@ if [ "$SKIP_REPORT" = false ]; then
|
|
|
246
253
|
|
|
247
254
|
"$SCRIPT_DIR/report-generators/stage-report-artifacts.sh" "$PROJECT_ROOT" "$REPORTS_DIR"
|
|
248
255
|
|
|
249
|
-
REPORT_ARGS=(combined "$COMBINED_OUTPUT" --logo "API Service")
|
|
256
|
+
REPORT_ARGS=(combined "$COMBINED_OUTPUT" --logo "API Service" --stack "NodeJS")
|
|
257
|
+
REPORT_ARGS+=(--git-repo "$GIT_REPO" --git-commit "$GIT_COMMIT" --git-branch "$GIT_BRANCH")
|
|
258
|
+
[ -n "${PR_NUMBER:-}" ] && REPORT_ARGS+=(--pr-number "$PR_NUMBER")
|
|
250
259
|
|
|
251
260
|
[ -f "$MOCHA_XML" ] && REPORT_ARGS+=(--mocha-xml "$MOCHA_XML")
|
|
252
261
|
[ -f "$LCOV" ] && REPORT_ARGS+=(--lcov "$LCOV")
|