swipium 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/LICENSE +21 -0
- package/README.md +295 -0
- package/dist/appMap/automationLink.js +74 -0
- package/dist/appMap/automationLink.js.map +1 -0
- package/dist/appMap/build.js +193 -0
- package/dist/appMap/build.js.map +1 -0
- package/dist/appMap/codeIndex.js +73 -0
- package/dist/appMap/codeIndex.js.map +1 -0
- package/dist/appMap/featureModel.js +83 -0
- package/dist/appMap/featureModel.js.map +1 -0
- package/dist/appMap/firstRunApply.js +131 -0
- package/dist/appMap/firstRunApply.js.map +1 -0
- package/dist/appMap/fsWalk.js +75 -0
- package/dist/appMap/fsWalk.js.map +1 -0
- package/dist/appMap/issues.js +227 -0
- package/dist/appMap/issues.js.map +1 -0
- package/dist/appMap/migrations.js +87 -0
- package/dist/appMap/migrations.js.map +1 -0
- package/dist/appMap/prelaunch.js +66 -0
- package/dist/appMap/prelaunch.js.map +1 -0
- package/dist/appMap/projectRegistry.js +70 -0
- package/dist/appMap/projectRegistry.js.map +1 -0
- package/dist/appMap/provenance.js +52 -0
- package/dist/appMap/provenance.js.map +1 -0
- package/dist/appMap/query.js +118 -0
- package/dist/appMap/query.js.map +1 -0
- package/dist/appMap/runtimeMerge.js +207 -0
- package/dist/appMap/runtimeMerge.js.map +1 -0
- package/dist/appMap/schema.js +65 -0
- package/dist/appMap/schema.js.map +1 -0
- package/dist/appMap/screenMatch.js +75 -0
- package/dist/appMap/screenMatch.js.map +1 -0
- package/dist/appMap/staticScan.js +614 -0
- package/dist/appMap/staticScan.js.map +1 -0
- package/dist/appMap/store.js +173 -0
- package/dist/appMap/store.js.map +1 -0
- package/dist/appMap/tsAstScan.js +184 -0
- package/dist/appMap/tsAstScan.js.map +1 -0
- package/dist/artifacts/bundletool.js +199 -0
- package/dist/artifacts/bundletool.js.map +1 -0
- package/dist/artifacts/resolve.js +388 -0
- package/dist/artifacts/resolve.js.map +1 -0
- package/dist/automationGen/appiumModel.js +129 -0
- package/dist/automationGen/appiumModel.js.map +1 -0
- package/dist/automationGen/ciEmitter.js +80 -0
- package/dist/automationGen/ciEmitter.js.map +1 -0
- package/dist/automationGen/jsEmitter.js +440 -0
- package/dist/automationGen/jsEmitter.js.map +1 -0
- package/dist/automationGen/packagePatch.js +56 -0
- package/dist/automationGen/packagePatch.js.map +1 -0
- package/dist/automationGen/projectProfile.js +317 -0
- package/dist/automationGen/projectProfile.js.map +1 -0
- package/dist/automationGen/pythonEmitter.js +386 -0
- package/dist/automationGen/pythonEmitter.js.map +1 -0
- package/dist/automationGen/readmeEmitter.js +66 -0
- package/dist/automationGen/readmeEmitter.js.map +1 -0
- package/dist/automationGen/suitePlan.js +94 -0
- package/dist/automationGen/suitePlan.js.map +1 -0
- package/dist/automationGen/validation.js +150 -0
- package/dist/automationGen/validation.js.map +1 -0
- package/dist/build/parseBuildLog.js +119 -0
- package/dist/build/parseBuildLog.js.map +1 -0
- package/dist/build/plan.js +150 -0
- package/dist/build/plan.js.map +1 -0
- package/dist/ci/preflight.js +85 -0
- package/dist/ci/preflight.js.map +1 -0
- package/dist/cli/init.js +105 -0
- package/dist/cli/init.js.map +1 -0
- package/dist/cli/scan.js +85 -0
- package/dist/cli/scan.js.map +1 -0
- package/dist/cli/suite.js +85 -0
- package/dist/cli/suite.js.map +1 -0
- package/dist/cli/verify.js +62 -0
- package/dist/cli/verify.js.map +1 -0
- package/dist/consent/consent.js +43 -0
- package/dist/consent/consent.js.map +1 -0
- package/dist/context/detect.js +156 -0
- package/dist/context/detect.js.map +1 -0
- package/dist/context/findApps.js +198 -0
- package/dist/context/findApps.js.map +1 -0
- package/dist/context/projectRoot.js +41 -0
- package/dist/context/projectRoot.js.map +1 -0
- package/dist/context/scan.js +167 -0
- package/dist/context/scan.js.map +1 -0
- package/dist/core/target.js +115 -0
- package/dist/core/target.js.map +1 -0
- package/dist/core/targetPlan.js +140 -0
- package/dist/core/targetPlan.js.map +1 -0
- package/dist/drivers/DirectDriver.js +228 -0
- package/dist/drivers/DirectDriver.js.map +1 -0
- package/dist/drivers/Driver.js +4 -0
- package/dist/drivers/Driver.js.map +1 -0
- package/dist/drivers/SimctlDriver.js +127 -0
- package/dist/drivers/SimctlDriver.js.map +1 -0
- package/dist/drivers/WdaDriver.js +250 -0
- package/dist/drivers/WdaDriver.js.map +1 -0
- package/dist/explore/candidates.js +93 -0
- package/dist/explore/candidates.js.map +1 -0
- package/dist/explore/graph.js +116 -0
- package/dist/explore/graph.js.map +1 -0
- package/dist/explore/memory.js +35 -0
- package/dist/explore/memory.js.map +1 -0
- package/dist/explore/planner.js +105 -0
- package/dist/explore/planner.js.map +1 -0
- package/dist/explore/policy.js +85 -0
- package/dist/explore/policy.js.map +1 -0
- package/dist/explore/runner.js +475 -0
- package/dist/explore/runner.js.map +1 -0
- package/dist/explore/signatures.js +35 -0
- package/dist/explore/signatures.js.map +1 -0
- package/dist/explore/suite.js +55 -0
- package/dist/explore/suite.js.map +1 -0
- package/dist/featureTesting/executionBootstrap.js +140 -0
- package/dist/featureTesting/executionBootstrap.js.map +1 -0
- package/dist/firstRun/authStateMachine.js +83 -0
- package/dist/firstRun/authStateMachine.js.map +1 -0
- package/dist/firstRun/classifyScreen.js +201 -0
- package/dist/firstRun/classifyScreen.js.map +1 -0
- package/dist/firstRun/firstRunPlanner.js +207 -0
- package/dist/firstRun/firstRunPlanner.js.map +1 -0
- package/dist/firstRun/firstRunRunner.js +331 -0
- package/dist/firstRun/firstRunRunner.js.map +1 -0
- package/dist/firstRun/generatedDataPolicy.js +215 -0
- package/dist/firstRun/generatedDataPolicy.js.map +1 -0
- package/dist/firstRun/inputPlanner.js +67 -0
- package/dist/firstRun/inputPlanner.js.map +1 -0
- package/dist/firstRun/onboardingStateMachine.js +46 -0
- package/dist/firstRun/onboardingStateMachine.js.map +1 -0
- package/dist/firstRun/paywallPolicy.js +54 -0
- package/dist/firstRun/paywallPolicy.js.map +1 -0
- package/dist/firstRun/types.js +7 -0
- package/dist/firstRun/types.js.map +1 -0
- package/dist/fixtures/catalog.js +131 -0
- package/dist/fixtures/catalog.js.map +1 -0
- package/dist/flows/discover.js +18 -0
- package/dist/flows/discover.js.map +1 -0
- package/dist/flows/generate.js +211 -0
- package/dist/flows/generate.js.map +1 -0
- package/dist/flows/lint.js +97 -0
- package/dist/flows/lint.js.map +1 -0
- package/dist/flows/pack.js +68 -0
- package/dist/flows/pack.js.map +1 -0
- package/dist/flows/run.js +738 -0
- package/dist/flows/run.js.map +1 -0
- package/dist/flows/schema.js +240 -0
- package/dist/flows/schema.js.map +1 -0
- package/dist/flows/seedExec.js +108 -0
- package/dist/flows/seedExec.js.map +1 -0
- package/dist/flows/templates.js +155 -0
- package/dist/flows/templates.js.map +1 -0
- package/dist/flows/waitGuards.js +12 -0
- package/dist/flows/waitGuards.js.map +1 -0
- package/dist/index.js +33 -0
- package/dist/index.js.map +1 -0
- package/dist/ios/signing.js +182 -0
- package/dist/ios/signing.js.map +1 -0
- package/dist/issues/classify.js +186 -0
- package/dist/issues/classify.js.map +1 -0
- package/dist/issues/fingerprint.js +130 -0
- package/dist/issues/fingerprint.js.map +1 -0
- package/dist/issues/index.js +240 -0
- package/dist/issues/index.js.map +1 -0
- package/dist/issues/metrics.js +155 -0
- package/dist/issues/metrics.js.map +1 -0
- package/dist/issues/recurrence.js +193 -0
- package/dist/issues/recurrence.js.map +1 -0
- package/dist/issues/report.js +110 -0
- package/dist/issues/report.js.map +1 -0
- package/dist/issues/reportBridge.js +119 -0
- package/dist/issues/reportBridge.js.map +1 -0
- package/dist/issues/schema.js +90 -0
- package/dist/issues/schema.js.map +1 -0
- package/dist/issues/sourceRevision.js +108 -0
- package/dist/issues/sourceRevision.js.map +1 -0
- package/dist/issues/store.js +155 -0
- package/dist/issues/store.js.map +1 -0
- package/dist/lib/android.js +278 -0
- package/dist/lib/android.js.map +1 -0
- package/dist/lib/commandTemplate.js +55 -0
- package/dist/lib/commandTemplate.js.map +1 -0
- package/dist/lib/coordSpace.js +23 -0
- package/dist/lib/coordSpace.js.map +1 -0
- package/dist/lib/device.js +87 -0
- package/dist/lib/device.js.map +1 -0
- package/dist/lib/gitignore.js +22 -0
- package/dist/lib/gitignore.js.map +1 -0
- package/dist/lib/image.js +97 -0
- package/dist/lib/image.js.map +1 -0
- package/dist/lib/logger.js +8 -0
- package/dist/lib/logger.js.map +1 -0
- package/dist/lib/metroState.js +45 -0
- package/dist/lib/metroState.js.map +1 -0
- package/dist/lib/needsInput.js +201 -0
- package/dist/lib/needsInput.js.map +1 -0
- package/dist/lib/png.js +103 -0
- package/dist/lib/png.js.map +1 -0
- package/dist/lib/redact.js +21 -0
- package/dist/lib/redact.js.map +1 -0
- package/dist/lib/result.js +87 -0
- package/dist/lib/result.js.map +1 -0
- package/dist/lib/schemaHash.js +65 -0
- package/dist/lib/schemaHash.js.map +1 -0
- package/dist/lib/sensitive.js +13 -0
- package/dist/lib/sensitive.js.map +1 -0
- package/dist/lib/simctl.js +149 -0
- package/dist/lib/simctl.js.map +1 -0
- package/dist/lib/spawn.js +144 -0
- package/dist/lib/spawn.js.map +1 -0
- package/dist/lib/wda.js +347 -0
- package/dist/lib/wda.js.map +1 -0
- package/dist/lib/wdaConfig.js +69 -0
- package/dist/lib/wdaConfig.js.map +1 -0
- package/dist/lib/wdaTune.js +58 -0
- package/dist/lib/wdaTune.js.map +1 -0
- package/dist/oracle/auth.js +22 -0
- package/dist/oracle/auth.js.map +1 -0
- package/dist/oracle/failures.js +193 -0
- package/dist/oracle/failures.js.map +1 -0
- package/dist/oracle/health.js +123 -0
- package/dist/oracle/health.js.map +1 -0
- package/dist/oracle/record.js +36 -0
- package/dist/oracle/record.js.map +1 -0
- package/dist/orchestration/envelope.js +52 -0
- package/dist/orchestration/envelope.js.map +1 -0
- package/dist/orchestration/goal.js +98 -0
- package/dist/orchestration/goal.js.map +1 -0
- package/dist/plan/plan.js +124 -0
- package/dist/plan/plan.js.map +1 -0
- package/dist/prompts/index.js +63 -0
- package/dist/prompts/index.js.map +1 -0
- package/dist/report/artifactManifest.js +44 -0
- package/dist/report/artifactManifest.js.map +1 -0
- package/dist/report/coverage.js +60 -0
- package/dist/report/coverage.js.map +1 -0
- package/dist/report/evidence.js +84 -0
- package/dist/report/evidence.js.map +1 -0
- package/dist/report/export.js +447 -0
- package/dist/report/export.js.map +1 -0
- package/dist/report/flake.js +61 -0
- package/dist/report/flake.js.map +1 -0
- package/dist/report/history.js +564 -0
- package/dist/report/history.js.map +1 -0
- package/dist/report/policy.js +98 -0
- package/dist/report/policy.js.map +1 -0
- package/dist/report/qaLevel.js +96 -0
- package/dist/report/qaLevel.js.map +1 -0
- package/dist/report/readiness.js +213 -0
- package/dist/report/readiness.js.map +1 -0
- package/dist/report/summary.js +42 -0
- package/dist/report/summary.js.map +1 -0
- package/dist/report/testCatalog.js +93 -0
- package/dist/report/testCatalog.js.map +1 -0
- package/dist/report/timing.js +37 -0
- package/dist/report/timing.js.map +1 -0
- package/dist/server.js +180 -0
- package/dist/server.js.map +1 -0
- package/dist/services/automationGenerate.js +60 -0
- package/dist/services/automationGenerate.js.map +1 -0
- package/dist/services/build.js +66 -0
- package/dist/services/build.js.map +1 -0
- package/dist/services/preflight.js +51 -0
- package/dist/services/preflight.js.map +1 -0
- package/dist/services/prepareAndroid.js +183 -0
- package/dist/services/prepareAndroid.js.map +1 -0
- package/dist/services/prepareIos.js +162 -0
- package/dist/services/prepareIos.js.map +1 -0
- package/dist/services/report.js +537 -0
- package/dist/services/report.js.map +1 -0
- package/dist/services/smoke.js +120 -0
- package/dist/services/smoke.js.map +1 -0
- package/dist/services/suiteGenerate.js +123 -0
- package/dist/services/suiteGenerate.js.map +1 -0
- package/dist/services/testSuiteKnowledge.js +150 -0
- package/dist/services/testSuiteKnowledge.js.map +1 -0
- package/dist/session/attach.js +47 -0
- package/dist/session/attach.js.map +1 -0
- package/dist/session/progress.js +56 -0
- package/dist/session/progress.js.map +1 -0
- package/dist/session/store.js +329 -0
- package/dist/session/store.js.map +1 -0
- package/dist/snapshot/overlays.js +132 -0
- package/dist/snapshot/overlays.js.map +1 -0
- package/dist/snapshot/parse.js +204 -0
- package/dist/snapshot/parse.js.map +1 -0
- package/dist/snapshot/present.js +12 -0
- package/dist/snapshot/present.js.map +1 -0
- package/dist/snapshot/settle.js +36 -0
- package/dist/snapshot/settle.js.map +1 -0
- package/dist/state/profile.js +318 -0
- package/dist/state/profile.js.map +1 -0
- package/dist/suite/compile.js +176 -0
- package/dist/suite/compile.js.map +1 -0
- package/dist/suite/lint.js +45 -0
- package/dist/suite/lint.js.map +1 -0
- package/dist/suite/pom.js +285 -0
- package/dist/suite/pom.js.map +1 -0
- package/dist/suite/testcase.js +87 -0
- package/dist/suite/testcase.js.map +1 -0
- package/dist/testSuite/generator.js +222 -0
- package/dist/testSuite/generator.js.map +1 -0
- package/dist/testSuite/history.js +44 -0
- package/dist/testSuite/history.js.map +1 -0
- package/dist/testSuite/issueLinks.js +96 -0
- package/dist/testSuite/issueLinks.js.map +1 -0
- package/dist/testSuite/merge.js +190 -0
- package/dist/testSuite/merge.js.map +1 -0
- package/dist/testSuite/schema.js +86 -0
- package/dist/testSuite/schema.js.map +1 -0
- package/dist/testSuite/store.js +116 -0
- package/dist/testSuite/store.js.map +1 -0
- package/dist/testSuite/traceability.js +55 -0
- package/dist/testSuite/traceability.js.map +1 -0
- package/dist/tools/act.js +457 -0
- package/dist/tools/act.js.map +1 -0
- package/dist/tools/agent.js +225 -0
- package/dist/tools/agent.js.map +1 -0
- package/dist/tools/appMap.js +317 -0
- package/dist/tools/appMap.js.map +1 -0
- package/dist/tools/assertVisual.js +74 -0
- package/dist/tools/assertVisual.js.map +1 -0
- package/dist/tools/automationGenerate.js +394 -0
- package/dist/tools/automationGenerate.js.map +1 -0
- package/dist/tools/capabilities.js +114 -0
- package/dist/tools/capabilities.js.map +1 -0
- package/dist/tools/clearOverlay.js +150 -0
- package/dist/tools/clearOverlay.js.map +1 -0
- package/dist/tools/detectContext.js +41 -0
- package/dist/tools/detectContext.js.map +1 -0
- package/dist/tools/doctor.js +116 -0
- package/dist/tools/doctor.js.map +1 -0
- package/dist/tools/explore.js +289 -0
- package/dist/tools/explore.js.map +1 -0
- package/dist/tools/firstRun.js +136 -0
- package/dist/tools/firstRun.js.map +1 -0
- package/dist/tools/flow.js +331 -0
- package/dist/tools/flow.js.map +1 -0
- package/dist/tools/flowGenerate.js +55 -0
- package/dist/tools/flowGenerate.js.map +1 -0
- package/dist/tools/getArtifact.js +39 -0
- package/dist/tools/getArtifact.js.map +1 -0
- package/dist/tools/health.js +41 -0
- package/dist/tools/health.js.map +1 -0
- package/dist/tools/ios.js +492 -0
- package/dist/tools/ios.js.map +1 -0
- package/dist/tools/jobs.js +20 -0
- package/dist/tools/jobs.js.map +1 -0
- package/dist/tools/network.js +50 -0
- package/dist/tools/network.js.map +1 -0
- package/dist/tools/note.js +69 -0
- package/dist/tools/note.js.map +1 -0
- package/dist/tools/plan.js +49 -0
- package/dist/tools/plan.js.map +1 -0
- package/dist/tools/prepareIosTarget.js +99 -0
- package/dist/tools/prepareIosTarget.js.map +1 -0
- package/dist/tools/prepareTarget.js +257 -0
- package/dist/tools/prepareTarget.js.map +1 -0
- package/dist/tools/report.js +42 -0
- package/dist/tools/report.js.map +1 -0
- package/dist/tools/screenRecord.js +24 -0
- package/dist/tools/screenRecord.js.map +1 -0
- package/dist/tools/screenshot.js +63 -0
- package/dist/tools/screenshot.js.map +1 -0
- package/dist/tools/smoke.js +39 -0
- package/dist/tools/smoke.js.map +1 -0
- package/dist/tools/snapshot.js +129 -0
- package/dist/tools/snapshot.js.map +1 -0
- package/dist/tools/startSession.js +169 -0
- package/dist/tools/startSession.js.map +1 -0
- package/dist/tools/state.js +87 -0
- package/dist/tools/state.js.map +1 -0
- package/dist/tools/suite.js +412 -0
- package/dist/tools/suite.js.map +1 -0
- package/dist/tools/testThis.js +774 -0
- package/dist/tools/testThis.js.map +1 -0
- package/dist/tools/wda.js +477 -0
- package/dist/tools/wda.js.map +1 -0
- package/dist/version.js +62 -0
- package/dist/version.js.map +1 -0
- package/dist/visual/ocr.js +72 -0
- package/dist/visual/ocr.js.map +1 -0
- package/dist/visual/provider.js +75 -0
- package/dist/visual/provider.js.map +1 -0
- package/docs/README.md +19 -0
- package/docs/assets/swipium-lockup-ink-on-light.png +0 -0
- package/docs/mcp-server.md +135 -0
- package/docs/tools.md +130 -0
- package/package.json +70 -0
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
// SWIPIUM-REQ-04 — generated-code validation. Pure: validates emitted files WITHOUT a device.
|
|
2
|
+
// Checks (REQ-04 §qa_automation_validate + acceptance criteria):
|
|
3
|
+
// - no inlined secrets (env-only),
|
|
4
|
+
// - locator durability threshold (fails on brittle-only above threshold unless candidate-only),
|
|
5
|
+
// - capability config presence,
|
|
6
|
+
// - lightweight syntax sanity (brace balance for JS/TS),
|
|
7
|
+
// - no empty essential files.
|
|
8
|
+
// password = "literal" / token: 'literal' etc. — but NOT process.env / os.environ references.
|
|
9
|
+
const SECRET_ASSIGN_RE = /(password|passwd|secret|token|api[_-]?key|apikey|bearer|credential|pwd)\s*[:=]\s*(["'])(?!\s*\2)([^"']{3,})\2/i;
|
|
10
|
+
const ENV_REF_RE = /(process\.env|os\.environ|getenv|\$\{?env)/i;
|
|
11
|
+
function scanSecrets(files, secrets) {
|
|
12
|
+
const findings = [];
|
|
13
|
+
for (const f of files) {
|
|
14
|
+
const lines = f.content.split('\n');
|
|
15
|
+
lines.forEach((line, i) => {
|
|
16
|
+
// Skip comment lines and lines that read from the environment.
|
|
17
|
+
const trimmed = line.trim();
|
|
18
|
+
if (trimmed.startsWith('//') || trimmed.startsWith('#') || trimmed.startsWith('*'))
|
|
19
|
+
return;
|
|
20
|
+
if (ENV_REF_RE.test(line))
|
|
21
|
+
return;
|
|
22
|
+
const m = SECRET_ASSIGN_RE.exec(line);
|
|
23
|
+
if (m) {
|
|
24
|
+
findings.push({ code: 'INLINED_SECRET', severity: 'error', file: f.path, message: `possible inlined secret at line ${i + 1}: ${m[1]} assigned a literal — read from the environment instead` });
|
|
25
|
+
}
|
|
26
|
+
// Explicit: a known secret env-var name assigned a literal value.
|
|
27
|
+
for (const s of secrets) {
|
|
28
|
+
const re = new RegExp(`${s}\\s*[:=]\\s*["'][^"']+["']`);
|
|
29
|
+
if (re.test(line) && !ENV_REF_RE.test(line)) {
|
|
30
|
+
findings.push({ code: 'INLINED_SECRET', severity: 'error', file: f.path, message: `secret var ${s} assigned a literal at line ${i + 1}` });
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
return findings;
|
|
36
|
+
}
|
|
37
|
+
function braceBalance(files) {
|
|
38
|
+
const findings = [];
|
|
39
|
+
for (const f of files) {
|
|
40
|
+
if (!/\.(ts|js)$/.test(f.path))
|
|
41
|
+
continue;
|
|
42
|
+
const pairs = [['{', '}', 'braces'], ['(', ')', 'parens'], ['[', ']', 'brackets']];
|
|
43
|
+
// Strip strings/comments crudely to avoid counting literals.
|
|
44
|
+
const stripped = stripJs(f.content);
|
|
45
|
+
for (const [open, close, name] of pairs) {
|
|
46
|
+
const o = countChar(stripped, open);
|
|
47
|
+
const c = countChar(stripped, close);
|
|
48
|
+
if (o !== c)
|
|
49
|
+
findings.push({ code: 'UNBALANCED_SYNTAX', severity: 'error', file: f.path, message: `unbalanced ${name} (${o} ${open} vs ${c} ${close})` });
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
return findings;
|
|
53
|
+
}
|
|
54
|
+
function stripJs(src) {
|
|
55
|
+
let out = '';
|
|
56
|
+
let i = 0;
|
|
57
|
+
while (i < src.length) {
|
|
58
|
+
const ch = src[i];
|
|
59
|
+
const next = src[i + 1];
|
|
60
|
+
if (ch === '/' && next === '/') {
|
|
61
|
+
while (i < src.length && src[i] !== '\n')
|
|
62
|
+
i++;
|
|
63
|
+
continue;
|
|
64
|
+
}
|
|
65
|
+
if (ch === '/' && next === '*') {
|
|
66
|
+
i += 2;
|
|
67
|
+
while (i < src.length && !(src[i] === '*' && src[i + 1] === '/'))
|
|
68
|
+
i++;
|
|
69
|
+
i += 2;
|
|
70
|
+
continue;
|
|
71
|
+
}
|
|
72
|
+
if (ch === '"' || ch === "'" || ch === '`') {
|
|
73
|
+
const quote = ch;
|
|
74
|
+
i++;
|
|
75
|
+
while (i < src.length && src[i] !== quote) {
|
|
76
|
+
if (src[i] === '\\')
|
|
77
|
+
i++;
|
|
78
|
+
i++;
|
|
79
|
+
}
|
|
80
|
+
i++;
|
|
81
|
+
continue;
|
|
82
|
+
}
|
|
83
|
+
out += ch;
|
|
84
|
+
i++;
|
|
85
|
+
}
|
|
86
|
+
return out;
|
|
87
|
+
}
|
|
88
|
+
function countChar(s, ch) {
|
|
89
|
+
let n = 0;
|
|
90
|
+
for (const c of s)
|
|
91
|
+
if (c === ch)
|
|
92
|
+
n++;
|
|
93
|
+
return n;
|
|
94
|
+
}
|
|
95
|
+
function capabilityPresence(files) {
|
|
96
|
+
const capFile = files.find((f) => /config\/capabilities\.(ts|js)$/.test(f.path) || /conftest\.py$/.test(f.path));
|
|
97
|
+
if (!capFile) {
|
|
98
|
+
return [{ code: 'NO_CAPABILITIES', severity: 'warning', message: 'no capabilities/conftest file found in the generated suite' }];
|
|
99
|
+
}
|
|
100
|
+
const ok = /platformName/i.test(capFile.content) && /(UiAutomator2|XCUITest)/.test(capFile.content);
|
|
101
|
+
return ok ? [] : [{ code: 'INVALID_CAPABILITIES', severity: 'error', file: capFile.path, message: 'capability config missing platformName/automationName' }];
|
|
102
|
+
}
|
|
103
|
+
function emptyEssentials(files) {
|
|
104
|
+
const findings = [];
|
|
105
|
+
for (const f of files) {
|
|
106
|
+
if (/__init__\.py$/.test(f.path))
|
|
107
|
+
continue; // intentionally empty
|
|
108
|
+
if (f.content.trim() === '')
|
|
109
|
+
findings.push({ code: 'EMPTY_FILE', severity: 'warning', file: f.path, message: 'generated file is empty' });
|
|
110
|
+
}
|
|
111
|
+
return findings;
|
|
112
|
+
}
|
|
113
|
+
export function validateGeneratedSuite(files, opts = {}) {
|
|
114
|
+
const brittlePct = opts.brittlePct ?? 0;
|
|
115
|
+
const brittleThreshold = opts.brittleThreshold ?? 40;
|
|
116
|
+
const candidateOnly = opts.candidateOnly ?? false;
|
|
117
|
+
const findings = [];
|
|
118
|
+
const secretFindings = scanSecrets(files, opts.secrets ?? []);
|
|
119
|
+
findings.push(...secretFindings);
|
|
120
|
+
findings.push(...braceBalance(files));
|
|
121
|
+
findings.push(...capabilityPresence(files));
|
|
122
|
+
findings.push(...emptyEssentials(files));
|
|
123
|
+
// Locator durability threshold: a brittle-heavy suite is not release-grade unless explicitly
|
|
124
|
+
// labeled candidate-only.
|
|
125
|
+
if (brittlePct > brittleThreshold && !candidateOnly) {
|
|
126
|
+
findings.push({
|
|
127
|
+
code: 'BRITTLE_OVER_THRESHOLD',
|
|
128
|
+
severity: 'error',
|
|
129
|
+
message: `brittle locators ${brittlePct}% exceed the ${brittleThreshold}% threshold — add durable locators or label the suite candidate-only`,
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
else if (brittlePct > brittleThreshold && candidateOnly) {
|
|
133
|
+
findings.push({
|
|
134
|
+
code: 'BRITTLE_OVER_THRESHOLD',
|
|
135
|
+
severity: 'warning',
|
|
136
|
+
message: `brittle locators ${brittlePct}% exceed the ${brittleThreshold}% threshold — suite is labeled candidate-only`,
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
const ok = !findings.some((f) => f.severity === 'error');
|
|
140
|
+
return {
|
|
141
|
+
ok,
|
|
142
|
+
findings,
|
|
143
|
+
secretsClean: secretFindings.length === 0,
|
|
144
|
+
brittlePct,
|
|
145
|
+
brittleThreshold,
|
|
146
|
+
candidateOnly,
|
|
147
|
+
filesChecked: files.length,
|
|
148
|
+
};
|
|
149
|
+
}
|
|
150
|
+
//# sourceMappingURL=validation.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"validation.js","sourceRoot":"","sources":["../../src/automationGen/validation.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
// Build-failure log parsing (Dev2 plan §4 "framework-specific build log parsing"). A build
|
|
2
|
+
// that exits non-zero is an ENVIRONMENT/BUILD failure, never an app QA failure — but "build
|
|
3
|
+
// failed" is useless to a developer. This module turns the captured build log into a typed
|
|
4
|
+
// blocker with the LIKELY OWNER (app dev vs environment vs user) and a CONCRETE fix, plus the
|
|
5
|
+
// relevant log tail (the lines that actually mention the error, not the whole transcript).
|
|
6
|
+
//
|
|
7
|
+
// PURE + testable: it only reads a log string + the step that produced it (no I/O), so the
|
|
8
|
+
// signatures below are unit-testable against fixture logs without any real toolchain.
|
|
9
|
+
/** Classify a build step into the tool whose log signatures we should match. */
|
|
10
|
+
export function buildLogTool(step) {
|
|
11
|
+
if (!step)
|
|
12
|
+
return 'unknown';
|
|
13
|
+
const exe = step.argv[0] ?? '';
|
|
14
|
+
const cmd = step.command.toLowerCase();
|
|
15
|
+
const label = step.label.toLowerCase();
|
|
16
|
+
if (exe === 'xcodebuild')
|
|
17
|
+
return 'xcodebuild';
|
|
18
|
+
if (exe === 'flutter' && !label.includes('pub get'))
|
|
19
|
+
return 'flutter';
|
|
20
|
+
if (exe === 'pod' || label.includes('cocoapods'))
|
|
21
|
+
return 'cocoapods';
|
|
22
|
+
if (exe === './gradlew' || cmd.includes('gradlew'))
|
|
23
|
+
return 'gradle';
|
|
24
|
+
if (cmd.includes('expo run') || cmd.includes('expo prebuild'))
|
|
25
|
+
return 'expo';
|
|
26
|
+
if (exe === 'npm' || exe === 'yarn' || exe === 'pnpm' || label.includes('dependencies') || label.includes('pub get'))
|
|
27
|
+
return 'node-install';
|
|
28
|
+
return 'unknown';
|
|
29
|
+
}
|
|
30
|
+
// Ordered most-specific-first. Expo/Flutter android builds delegate to Gradle, so Gradle
|
|
31
|
+
// signatures are also consulted for those tools (see SIGNATURES_BY_TOOL wiring below).
|
|
32
|
+
const GRADLE_SIGNATURES = [
|
|
33
|
+
{ name: 'sdk-location', test: /SDK location not found|ANDROID_HOME .* not|local\.properties/i, failureCode: 'GRADLE_FAILED', owner: 'environment', reason: 'Android SDK location not configured.', fix: 'Set ANDROID_HOME / sdk.dir (local.properties) to a valid Android SDK, then rebuild.' },
|
|
34
|
+
{ name: 'sdk-platform-missing', test: /Failed to find target with hash string|Failed to find Build Tools|Could not (?:find|determine) .*(?:platforms|build-tools)|install the (?:missing )?platform/i, failureCode: 'GRADLE_FAILED', owner: 'environment', reason: 'Required Android SDK platform/build-tools are missing.', fix: 'Install the required SDK platform + build-tools via Android Studio SDK Manager or `sdkmanager`, then rebuild.' },
|
|
35
|
+
{ name: 'sdk-license', test: /have not accepted the license|licenses? (?:have )?not.*accepted|to accept the SDK license/i, failureCode: 'GRADLE_FAILED', owner: 'environment', reason: 'Android SDK licenses are not accepted.', fix: 'Run `sdkmanager --licenses` (or accept licenses in Android Studio), then rebuild.' },
|
|
36
|
+
{ name: 'ndk-missing', test: /NDK (?:is )?not configured|No version of NDK matched|Failed to install the following Android SDK packages.*ndk/i, failureCode: 'GRADLE_FAILED', owner: 'environment', reason: 'Required Android NDK is missing.', fix: 'Install the NDK version the project requests (SDK Manager / ndkVersion), then rebuild.' },
|
|
37
|
+
{ name: 'signing', test: /Keystore file .* not found|Failed to read key .* from store|Could not (?:read|find) keystore|SigningConfig .* (?:is )?invalid|Failed to load signing config|keystore password was incorrect/i, failureCode: 'ANDROID_SIGNING_FAILED', owner: 'environment', reason: 'Gradle signing config (keystore) is missing or invalid.', fix: 'Provide a valid keystore + credentials, or build a debug variant (auto-signed with the debug keystore) for emulator QA.' },
|
|
38
|
+
{ name: 'dependency-resolve', test: /Could not resolve|Could not find [^\n]*\.(?:jar|aar|pom)|Could not download|Failed to resolve:|Could not GET/i, failureCode: 'GRADLE_FAILED', owner: 'app', reason: 'A Gradle dependency could not be resolved/downloaded.', fix: 'Check the missing coordinate/repository and network access; fix the dependency declaration, then rebuild.' },
|
|
39
|
+
{ name: 'compile', test: /error: cannot find symbol|Compilation (?:error|failed)|e: .*\.kt:|\.java:\d+: error:/i, failureCode: 'GRADLE_FAILED', owner: 'app', reason: 'A compile error in the app sources failed the Gradle build.', fix: 'Open the reported file/line in the log and fix the compile error, then rebuild.' },
|
|
40
|
+
];
|
|
41
|
+
const XCODE_SIGNATURES = [
|
|
42
|
+
{ name: 'scheme-missing', test: /does not contain a scheme named|Scheme .* is not currently configured|The project .* does not contain a scheme/i, failureCode: 'XCODEBUILD_FAILED', owner: 'environment', reason: 'The requested Xcode scheme was not found.', fix: 'Pass the correct -scheme/-workspace (run `xcodebuild -list` to see schemes), then rebuild.' },
|
|
43
|
+
{ name: 'signing', test: /Code Sign(?:ing)? error|requires a (?:development team|provisioning profile)|No (?:signing certificate|profiles for|account for team)|Signing for .* requires a development team/i, failureCode: 'XCODEBUILD_FAILED', owner: 'user', reason: 'Xcode code signing / provisioning is not configured.', fix: 'Set a development team and provisioning settings only if your simulator build configuration requires them.' },
|
|
44
|
+
{ name: 'simulator-runtime', test: /Unable to find a destination|no simulator runtime|cannot be located on disk.*iphonesimulator|iOS \d+\.\d+ (?:simulator )?runtime (?:is )?not (?:installed|available)|Unsupported SDK/i, failureCode: 'SIMULATOR_RUNTIME_MISSING', owner: 'environment', reason: 'No usable iOS simulator runtime/destination for the build.', fix: 'Install a matching iOS simulator runtime in Xcode (Settings → Platforms) or pick an available destination, then rebuild.' },
|
|
45
|
+
{ name: 'compile', test: /error: .*\.(?:m|mm|swift|h|c|cpp):|Command CompileC failed|Swift Compiler Error|fatal error: '.*' file not found/i, failureCode: 'XCODEBUILD_FAILED', owner: 'app', reason: 'A compile error in the iOS sources failed the build.', fix: 'Open the reported file/line in the xcodebuild log and fix the compile error, then rebuild.' },
|
|
46
|
+
];
|
|
47
|
+
const COCOAPODS_SIGNATURES = [
|
|
48
|
+
{ name: 'pods-incompatible', test: /CocoaPods could not find compatible versions|Unable to find a specification for|could not find compatible versions for pod/i, failureCode: 'DEPENDENCY_INSTALL_REQUIRED', owner: 'app', reason: 'CocoaPods could not resolve compatible pod versions.', fix: 'Run `pod repo update` then `pod install`; adjust the Podfile constraints if the conflict persists.' },
|
|
49
|
+
{ name: 'pods-out-of-sync', test: /sandbox is not in sync|run .?pod install.?|The .* Pods directory/i, failureCode: 'DEPENDENCY_INSTALL_REQUIRED', owner: 'environment', reason: 'CocoaPods sandbox is out of sync with the Podfile.', fix: 'Run `pod install` in the ios/ directory, then rebuild.' },
|
|
50
|
+
];
|
|
51
|
+
const FLUTTER_SIGNATURES = [
|
|
52
|
+
{ name: 'sdk-missing', test: /Flutter SDK not found|command not found: flutter|Unable to locate the Flutter SDK|flutter: command not found/i, failureCode: 'BUILD_COMMAND_UNAVAILABLE', owner: 'environment', reason: 'The Flutter SDK is not available on PATH.', fix: 'Install Flutter and ensure `flutter` is on PATH (`flutter doctor`), then rebuild.' },
|
|
53
|
+
{ name: 'pub-solve', test: /version solving failed|Because .* depends on|pub get failed|Could not (?:resolve|find package)/i, failureCode: 'DEPENDENCY_INSTALL_REQUIRED', owner: 'app', reason: 'Dart/Flutter package resolution (pub get) failed.', fix: 'Fix the pubspec.yaml version constraints, run `flutter pub get`, then rebuild.' },
|
|
54
|
+
{ name: 'gradle-delegate', test: /Gradle task assemble\w+ failed|A problem occurred (?:configuring|evaluating) (?:root )?project/i, failureCode: 'GRADLE_FAILED', owner: 'app', reason: 'The Android Gradle build inside `flutter build` failed.', fix: 'Open the Gradle output in the log, fix the Android build error (SDK/dependency/signing), then rebuild.' },
|
|
55
|
+
];
|
|
56
|
+
const EXPO_SIGNATURES = [
|
|
57
|
+
{ name: 'prebuild-required', test: /No native (?:android|ios) (?:project|directory)|run (?:npx )?expo prebuild|CNG|Continuous Native Generation|android.*directory.*(?:missing|not exist)/i, failureCode: 'EXPO_PREBUILD_REQUIRED', owner: 'swipium', reason: 'Expo project has no native directory to build.', fix: 'Run `npx expo prebuild` (or `npx expo run:*`, which prebuilds) to generate the native project, then rebuild.' },
|
|
58
|
+
{ name: 'metro', test: /Unable to resolve module|Metro (?:bundler )?(?:has )?encountered|Cannot find module .* from .* Metro|Bundling failed/i, failureCode: 'METRO_FAILED', owner: 'app', reason: 'Metro bundling failed during the Expo build.', fix: 'Fix the unresolved module / bundling error (check imports + `node_modules`), then rebuild.' },
|
|
59
|
+
{ name: 'config', test: /Invalid (?:app\.json|app config|Expo config)|ConfigError|Failed to read the app config/i, failureCode: 'BUILD_FAILED', owner: 'app', reason: 'Expo app config (app.json/app.config) is invalid.', fix: 'Fix the Expo config error reported in the log, then rebuild.' },
|
|
60
|
+
];
|
|
61
|
+
const NODE_INSTALL_SIGNATURES = [
|
|
62
|
+
{ name: 'peer-conflict', test: /ERESOLVE|peer dep|unable to resolve dependency tree/i, failureCode: 'DEPENDENCY_INSTALL_REQUIRED', owner: 'app', reason: 'JS dependency resolution failed (peer/version conflict).', fix: 'Resolve the dependency conflict (align versions, or install with the appropriate flag), then re-run.' },
|
|
63
|
+
{ name: 'network', test: /ETIMEDOUT|ENOTFOUND|network.*(?:error|timeout)|registry\.npmjs\.org/i, failureCode: 'DEPENDENCY_INSTALL_REQUIRED', owner: 'environment', reason: 'JS dependency install failed to reach the registry.', fix: 'Restore network/registry access, then re-run the dependency install.' },
|
|
64
|
+
{ name: 'generic', test: /npm ERR!|error Command failed|ERR_PNPM|Cannot find module/i, failureCode: 'DEPENDENCY_INSTALL_REQUIRED', owner: 'environment', reason: 'JS dependency install failed.', fix: 'Read the install error in the log, fix it, then re-run the dependency install.' },
|
|
65
|
+
];
|
|
66
|
+
const SIGNATURES_BY_TOOL = {
|
|
67
|
+
gradle: GRADLE_SIGNATURES,
|
|
68
|
+
xcodebuild: XCODE_SIGNATURES,
|
|
69
|
+
// flutter / expo android builds delegate to Gradle, so append Gradle signatures after the
|
|
70
|
+
// framework-specific ones (framework signatures win when both match).
|
|
71
|
+
flutter: [...FLUTTER_SIGNATURES, ...GRADLE_SIGNATURES, ...XCODE_SIGNATURES],
|
|
72
|
+
expo: [...EXPO_SIGNATURES, ...GRADLE_SIGNATURES, ...XCODE_SIGNATURES],
|
|
73
|
+
cocoapods: COCOAPODS_SIGNATURES,
|
|
74
|
+
'node-install': NODE_INSTALL_SIGNATURES,
|
|
75
|
+
unknown: [],
|
|
76
|
+
};
|
|
77
|
+
/** Tool-default code/owner/fix when no specific signature matched. */
|
|
78
|
+
function toolDefault(tool) {
|
|
79
|
+
switch (tool) {
|
|
80
|
+
case 'gradle': return { failureCode: 'GRADLE_FAILED', owner: 'app', reason: 'Gradle build failed.', fix: 'Open the Gradle log artifact and fix the reported error (SDK/dependency/compile/signing), then rebuild.' };
|
|
81
|
+
case 'xcodebuild': return { failureCode: 'XCODEBUILD_FAILED', owner: 'app', reason: 'xcodebuild failed.', fix: 'Open the xcodebuild log artifact and fix the reported error (scheme/signing/simulator/compile), then rebuild.' };
|
|
82
|
+
case 'flutter': return { failureCode: 'FLUTTER_BUILD_FAILED', owner: 'app', reason: 'flutter build failed.', fix: 'Open the flutter build log artifact and fix the reported error, then rebuild.' };
|
|
83
|
+
case 'cocoapods': return { failureCode: 'DEPENDENCY_INSTALL_REQUIRED', owner: 'environment', reason: 'CocoaPods install failed.', fix: 'Run `pod install` in the ios/ directory and resolve the reported error, then rebuild.' };
|
|
84
|
+
case 'expo': return { failureCode: 'BUILD_FAILED', owner: 'app', reason: 'Expo build failed.', fix: 'Open the build log artifact and fix the reported error, then rebuild.' };
|
|
85
|
+
case 'node-install': return { failureCode: 'DEPENDENCY_INSTALL_REQUIRED', owner: 'environment', reason: 'Dependency install failed.', fix: 'Read the install error in the log, fix it, then re-run.' };
|
|
86
|
+
default: return { failureCode: 'BUILD_FAILED', owner: 'app', reason: 'Build from source failed.', fix: 'Open the build log artifact, fix the compile/config error, then re-run. A build failure is NOT a test failure.' };
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Extract the lines from a build log that actually describe the failure. Prefers lines that
|
|
91
|
+
* mention errors/failures; falls back to the last `maxLines` lines so the tail is never empty.
|
|
92
|
+
*/
|
|
93
|
+
export function relevantLogTail(log, maxLines = 30) {
|
|
94
|
+
const lines = log.split(/\r?\n/);
|
|
95
|
+
const errRe = /error|FAILURE|Could not|failed|fatal|ERR!|exception|✗|not found|unable to|requires/i;
|
|
96
|
+
const hits = lines.filter((l) => l.trim() && errRe.test(l));
|
|
97
|
+
const chosen = hits.length ? hits.slice(-maxLines) : lines.filter((l) => l.trim()).slice(-maxLines);
|
|
98
|
+
return chosen.join('\n').slice(-4000);
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Analyze a failed build step's log into a typed, owned, actionable blocker. `timedOut` short-
|
|
102
|
+
* circuits to BUILD_TIMED_OUT (the log rarely explains a timeout). Otherwise we match the
|
|
103
|
+
* tool's signatures most-specific-first, then fall back to the tool default.
|
|
104
|
+
*/
|
|
105
|
+
export function analyzeBuildFailure(opts) {
|
|
106
|
+
const tool = buildLogTool(opts.step);
|
|
107
|
+
const relevantTail = relevantLogTail(opts.log);
|
|
108
|
+
if (opts.timedOut) {
|
|
109
|
+
return { failureCode: 'BUILD_TIMED_OUT', owner: 'environment', reason: 'Build exceeded its time budget.', tool, signal: 'timeout', relevantTail, fix: 'Increase the build timeout, warm caches, or build once manually then re-run against the artifact.' };
|
|
110
|
+
}
|
|
111
|
+
for (const sig of SIGNATURES_BY_TOOL[tool]) {
|
|
112
|
+
if (sig.test.test(opts.log)) {
|
|
113
|
+
return { failureCode: sig.failureCode, owner: sig.owner, reason: sig.reason, fix: sig.fix, relevantTail, signal: sig.name, tool };
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
const def = toolDefault(tool);
|
|
117
|
+
return { ...def, relevantTail, signal: null, tool };
|
|
118
|
+
}
|
|
119
|
+
//# sourceMappingURL=parseBuildLog.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"parseBuildLog.js","sourceRoot":"","sources":["../../src/build/parseBuildLog.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
// Build-from-source planner (roadmap §4.5) — propose the EXACT commands that turn a source
|
|
2
|
+
// project into an installable artifact, per framework + platform, with prerequisites
|
|
3
|
+
// (dependency install, Expo prebuild, CocoaPods) and the artifact globs the build will produce.
|
|
4
|
+
//
|
|
5
|
+
// PURE planning: `buildPlan()` only reads the filesystem + checks toolchain presence. It never
|
|
6
|
+
// runs a build. This makes command selection unit-testable, so an agent can show the plan and ask
|
|
7
|
+
// minutes compiling.
|
|
8
|
+
import { existsSync, readdirSync } from 'node:fs';
|
|
9
|
+
import { join, basename } from 'node:path';
|
|
10
|
+
import { detectFramework } from '../context/detect.js';
|
|
11
|
+
import { which } from '../lib/android.js';
|
|
12
|
+
function hasFile(root, ...rel) {
|
|
13
|
+
return rel.some((r) => existsSync(join(root, r)));
|
|
14
|
+
}
|
|
15
|
+
/** Pick the package manager from lockfiles (npm default). */
|
|
16
|
+
function nodeInstallStep(root) {
|
|
17
|
+
const pm = existsSync(join(root, 'pnpm-lock.yaml'))
|
|
18
|
+
? 'pnpm'
|
|
19
|
+
: existsSync(join(root, 'yarn.lock'))
|
|
20
|
+
? 'yarn'
|
|
21
|
+
: 'npm';
|
|
22
|
+
const argv = pm === 'npm' ? ['npm', 'install'] : [pm, 'install'];
|
|
23
|
+
return { label: 'install JS dependencies', command: argv.join(' '), argv, cwd: root, optionalIfPresent: 'node_modules' };
|
|
24
|
+
}
|
|
25
|
+
/** Best-effort iOS scheme/workspace discovery for xcodebuild. */
|
|
26
|
+
function iosWorkspace(root) {
|
|
27
|
+
const iosDir = existsSync(join(root, 'ios')) ? join(root, 'ios') : root;
|
|
28
|
+
let workspace;
|
|
29
|
+
let project;
|
|
30
|
+
try {
|
|
31
|
+
for (const f of readdirSync(iosDir)) {
|
|
32
|
+
if (f.endsWith('.xcworkspace'))
|
|
33
|
+
workspace = join(iosDir, f);
|
|
34
|
+
else if (f.endsWith('.xcodeproj'))
|
|
35
|
+
project = join(iosDir, f);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
catch {
|
|
39
|
+
/* none */
|
|
40
|
+
}
|
|
41
|
+
const base = workspace ? basename(workspace, '.xcworkspace') : project ? basename(project, '.xcodeproj') : undefined;
|
|
42
|
+
return { workspace, project, scheme: base, dir: iosDir };
|
|
43
|
+
}
|
|
44
|
+
function podInstallStep(root) {
|
|
45
|
+
const iosDir = existsSync(join(root, 'ios')) ? join(root, 'ios') : root;
|
|
46
|
+
if (!existsSync(join(iosDir, 'Podfile')))
|
|
47
|
+
return null;
|
|
48
|
+
return { label: 'install CocoaPods', command: 'pod install', argv: ['pod', 'install'], cwd: iosDir, optionalIfPresent: 'Pods' };
|
|
49
|
+
}
|
|
50
|
+
function xcodebuildStep(root, variant) {
|
|
51
|
+
const { workspace, project, scheme, dir } = iosWorkspace(root);
|
|
52
|
+
const notes = [];
|
|
53
|
+
if (!scheme)
|
|
54
|
+
return { step: null, notes: ['Could not find an .xcworkspace/.xcodeproj — pass the scheme/workspace explicitly.'] };
|
|
55
|
+
const config = variant === 'release' ? 'Release' : 'Debug';
|
|
56
|
+
const argv = ['xcodebuild', '-scheme', scheme, '-sdk', 'iphonesimulator', '-configuration', config, '-derivedDataPath', 'build', 'build'];
|
|
57
|
+
if (workspace)
|
|
58
|
+
argv.splice(1, 0, '-workspace', basename(workspace));
|
|
59
|
+
else if (project)
|
|
60
|
+
argv.splice(1, 0, '-project', basename(project));
|
|
61
|
+
notes.push(`Using scheme "${scheme}" (best-effort) — override if your scheme differs.`);
|
|
62
|
+
return { step: { label: 'build iOS simulator app', command: argv.join(' '), argv, cwd: dir }, notes };
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Produce a build plan for the given platform. Async because it checks toolchain presence.
|
|
66
|
+
*/
|
|
67
|
+
export async function buildPlan(opts) {
|
|
68
|
+
const { projectRoot: root, platform } = opts;
|
|
69
|
+
const variant = opts.variant ?? 'debug';
|
|
70
|
+
const framework = detectFramework(root);
|
|
71
|
+
const notes = [];
|
|
72
|
+
const prerequisites = [];
|
|
73
|
+
const missingToolchain = [];
|
|
74
|
+
const base = (over = {}) => ({
|
|
75
|
+
framework, platform, variant, prerequisites, build: null,
|
|
76
|
+
expectedArtifactGlobs: [], toolchainOk: missingToolchain.length === 0, missingToolchain, notes, ...over,
|
|
77
|
+
});
|
|
78
|
+
if (framework === 'unknown') {
|
|
79
|
+
return base({ failureCode: 'UNSUPPORTED_FRAMEWORK', notes: ['No supported mobile framework detected at this root.'] });
|
|
80
|
+
}
|
|
81
|
+
// Node-based frameworks need JS deps installed first.
|
|
82
|
+
const nodeBased = framework === 'expo' || framework === 'bare-react-native';
|
|
83
|
+
if (nodeBased)
|
|
84
|
+
prerequisites.push(nodeInstallStep(root));
|
|
85
|
+
if (platform === 'android') {
|
|
86
|
+
const apkGlobs = ['android/app/build/outputs/apk/**/*.apk', 'app/build/outputs/apk/**/*.apk'];
|
|
87
|
+
const flutterGlobs = ['build/app/outputs/flutter-apk/*.apk'];
|
|
88
|
+
const gradleArg = variant === 'release' ? 'assembleRelease' : 'assembleDebug';
|
|
89
|
+
switch (framework) {
|
|
90
|
+
case 'expo': {
|
|
91
|
+
// No native android dir → expo run:android prebuilds; otherwise it reuses it.
|
|
92
|
+
if (!hasFile(root, 'android'))
|
|
93
|
+
notes.push('No android/ directory — expo run:android will prebuild it (EXPO_PREBUILD).');
|
|
94
|
+
const argv = ['npx', 'expo', 'run:android', '--variant', variant];
|
|
95
|
+
return base({ build: { label: 'build + run Android (Expo)', command: argv.join(' '), argv, cwd: root }, expectedArtifactGlobs: apkGlobs });
|
|
96
|
+
}
|
|
97
|
+
case 'bare-react-native':
|
|
98
|
+
case 'native-android': {
|
|
99
|
+
if (!hasFile(root, 'android/gradlew', 'gradlew')) {
|
|
100
|
+
return base({ failureCode: 'BUILD_COMMAND_UNAVAILABLE', notes: ['No gradlew found — run from the Android project or add the Gradle wrapper.'] });
|
|
101
|
+
}
|
|
102
|
+
const cwd = existsSync(join(root, 'android')) ? join(root, 'android') : root;
|
|
103
|
+
const argv = ['./gradlew', gradleArg];
|
|
104
|
+
return base({ build: { label: `Gradle ${gradleArg}`, command: argv.join(' '), argv, cwd }, expectedArtifactGlobs: apkGlobs });
|
|
105
|
+
}
|
|
106
|
+
case 'flutter': {
|
|
107
|
+
if (!(await which('flutter')))
|
|
108
|
+
missingToolchain.push('flutter');
|
|
109
|
+
prerequisites.unshift({ label: 'flutter pub get', command: 'flutter pub get', argv: ['flutter', 'pub', 'get'], cwd: root });
|
|
110
|
+
const argv = ['flutter', 'build', 'apk', `--${variant}`];
|
|
111
|
+
return base({ build: { label: 'flutter build apk', command: argv.join(' '), argv, cwd: root }, expectedArtifactGlobs: flutterGlobs, toolchainOk: missingToolchain.length === 0 });
|
|
112
|
+
}
|
|
113
|
+
default:
|
|
114
|
+
return base({ failureCode: 'BUILD_COMMAND_UNAVAILABLE' });
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
// ---- iOS (simulator-first) ----
|
|
118
|
+
const appGlobs = ['ios/build/**/*.app', 'build/**/*.app', 'build/ios/iphonesimulator/*.app'];
|
|
119
|
+
if (!(await which('xcodebuild')) && framework !== 'flutter')
|
|
120
|
+
missingToolchain.push('xcodebuild');
|
|
121
|
+
switch (framework) {
|
|
122
|
+
case 'expo': {
|
|
123
|
+
if (!hasFile(root, 'ios'))
|
|
124
|
+
notes.push('No ios/ directory — expo run:ios will prebuild it (EXPO_PREBUILD).');
|
|
125
|
+
const argv = ['npx', 'expo', 'run:ios', '--no-bundler'];
|
|
126
|
+
return base({ build: { label: 'build + run iOS simulator (Expo)', command: argv.join(' '), argv, cwd: root }, expectedArtifactGlobs: appGlobs });
|
|
127
|
+
}
|
|
128
|
+
case 'bare-react-native':
|
|
129
|
+
case 'native-ios': {
|
|
130
|
+
const pod = podInstallStep(root);
|
|
131
|
+
if (pod)
|
|
132
|
+
prerequisites.push(pod);
|
|
133
|
+
const { step, notes: xnotes } = xcodebuildStep(root, variant);
|
|
134
|
+
notes.push(...xnotes);
|
|
135
|
+
if (!step)
|
|
136
|
+
return base({ failureCode: 'BUILD_COMMAND_UNAVAILABLE' });
|
|
137
|
+
return base({ build: step, expectedArtifactGlobs: appGlobs });
|
|
138
|
+
}
|
|
139
|
+
case 'flutter': {
|
|
140
|
+
if (!(await which('flutter')))
|
|
141
|
+
missingToolchain.push('flutter');
|
|
142
|
+
prerequisites.unshift({ label: 'flutter pub get', command: 'flutter pub get', argv: ['flutter', 'pub', 'get'], cwd: root });
|
|
143
|
+
const argv = ['flutter', 'build', 'ios', '--simulator', `--${variant}`];
|
|
144
|
+
return base({ build: { label: 'flutter build ios --simulator', command: argv.join(' '), argv, cwd: root }, expectedArtifactGlobs: ['build/ios/iphonesimulator/*.app'], toolchainOk: missingToolchain.length === 0 });
|
|
145
|
+
}
|
|
146
|
+
default:
|
|
147
|
+
return base({ failureCode: 'BUILD_COMMAND_UNAVAILABLE' });
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
//# sourceMappingURL=plan.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"plan.js","sourceRoot":"","sources":["../../src/build/plan.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import { ciMutationAllowed } from '../report/policy.js';
|
|
2
|
+
const MUTATING_CI_STEPS = new Set(['networkOffline', 'networkOnline', 'seed', 'restartApp']);
|
|
3
|
+
const VAR_REF = /\$\{([^}]+)\}/g;
|
|
4
|
+
function variableBearingValues(step) {
|
|
5
|
+
switch (step.kind) {
|
|
6
|
+
case 'tap':
|
|
7
|
+
return [step.selector];
|
|
8
|
+
case 'tapOcrText':
|
|
9
|
+
case 'assertVisible':
|
|
10
|
+
case 'assertNotVisible':
|
|
11
|
+
case 'assertOcrText':
|
|
12
|
+
case 'scrollTo':
|
|
13
|
+
case 'waitForVisible':
|
|
14
|
+
return [step.query];
|
|
15
|
+
case 'wait':
|
|
16
|
+
return step.query ? [step.query] : [];
|
|
17
|
+
case 'inputText':
|
|
18
|
+
return [step.value, step.into].filter((v) => !!v);
|
|
19
|
+
case 'openUrl':
|
|
20
|
+
return [step.url];
|
|
21
|
+
case 'assertVisual':
|
|
22
|
+
return [step.description];
|
|
23
|
+
default:
|
|
24
|
+
return [];
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
export function ciMutatingSteps(flow) {
|
|
28
|
+
const all = [...flow.setup, ...flow.steps, ...flow.teardown];
|
|
29
|
+
const out = [];
|
|
30
|
+
all.forEach((step, i) => {
|
|
31
|
+
if (!MUTATING_CI_STEPS.has(step.kind))
|
|
32
|
+
return;
|
|
33
|
+
out.push({
|
|
34
|
+
flow: flow.name,
|
|
35
|
+
step: i + 1,
|
|
36
|
+
kind: step.kind,
|
|
37
|
+
reason: `${step.kind} changes device/app/test state and requires .swipium/policy.json ciAllowMutations`,
|
|
38
|
+
});
|
|
39
|
+
});
|
|
40
|
+
return out;
|
|
41
|
+
}
|
|
42
|
+
export function validateCiMutationPolicy(flows, policy) {
|
|
43
|
+
const violations = flows.flatMap((flow) => ciMutatingSteps(flow).filter((v) => !ciMutationAllowed(policy, v.kind)));
|
|
44
|
+
return { ok: violations.length === 0, violations };
|
|
45
|
+
}
|
|
46
|
+
export function ciRequiredVariables(flow) {
|
|
47
|
+
const all = [...flow.setup, ...flow.steps, ...flow.teardown];
|
|
48
|
+
const out = [];
|
|
49
|
+
all.forEach((step, i) => {
|
|
50
|
+
for (const value of variableBearingValues(step)) {
|
|
51
|
+
for (const match of value.matchAll(VAR_REF)) {
|
|
52
|
+
out.push({
|
|
53
|
+
flow: flow.name,
|
|
54
|
+
step: i + 1,
|
|
55
|
+
kind: step.kind,
|
|
56
|
+
variable: match[1],
|
|
57
|
+
reason: `${step.kind} references \${${match[1]}}; set it in the CI environment before running Swipium.`,
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
});
|
|
62
|
+
return out;
|
|
63
|
+
}
|
|
64
|
+
export function validateCiVariables(flows, env = process.env, variables = {}) {
|
|
65
|
+
const missing = flows
|
|
66
|
+
.flatMap((flow) => ciRequiredVariables(flow))
|
|
67
|
+
.filter((v) => {
|
|
68
|
+
const explicit = variables[v.variable];
|
|
69
|
+
if (explicit != null && explicit !== '')
|
|
70
|
+
return false;
|
|
71
|
+
return env[v.variable] == null || env[v.variable] === '';
|
|
72
|
+
});
|
|
73
|
+
return { ok: missing.length === 0, missing };
|
|
74
|
+
}
|
|
75
|
+
export function validateCiParallelPack(pack) {
|
|
76
|
+
if (!pack.parallel)
|
|
77
|
+
return { ok: true, violations: [] };
|
|
78
|
+
return {
|
|
79
|
+
ok: false,
|
|
80
|
+
violations: [
|
|
81
|
+
`pack "${pack.name}" sets parallel:true, but CI pack execution currently uses one shared device/session/artifacts directory. Use parallel:false or run a device matrix with isolated simulator UDID, WDA port, artifacts dir, session id, and logs.`,
|
|
82
|
+
],
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
//# sourceMappingURL=preflight.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"preflight.js","sourceRoot":"","sources":["../../src/ci/preflight.ts"],"names":[],"mappings":"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"}
|