@restormel/testing-github-action 0.1.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 +82 -0
- package/action.yml +98 -0
- package/dist/fork-policy.d.ts +7 -0
- package/dist/fork-policy.d.ts.map +1 -0
- package/dist/fork-policy.js +7 -0
- package/dist/fork-policy.js.map +1 -0
- package/dist/main.d.ts +2 -0
- package/dist/main.d.ts.map +1 -0
- package/dist/main.js +8 -0
- package/dist/main.js.map +1 -0
- package/dist/run-ci.d.ts +6 -0
- package/dist/run-ci.d.ts.map +1 -0
- package/dist/run-ci.js +143 -0
- package/dist/run-ci.js.map +1 -0
- package/package.json +41 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) Allotment Technology Ltd
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
# `@restormel/testing-github-action`
|
|
2
|
+
|
|
3
|
+
Composite GitHub Action that runs the **same inline runner** as the local CLI (`testing run`): load `restormel-testing.yaml`, execute browser goals, write **`report.json`**, **`summary.md`**, **`github-summary.md`**, **`junit.xml`**, plus `run.json` / `traces.json`, append a **GitHub step summary**, and **fail the step** when the suite verdict is not `passed`.
|
|
4
|
+
|
|
5
|
+
There is **no hosted control plane** in this MVP; `poll_interval_seconds` and `timeout_minutes` inputs are reserved for documentation alignment only.
|
|
6
|
+
|
|
7
|
+
## Usage
|
|
8
|
+
|
|
9
|
+
Prerequisites in your workflow (before this action):
|
|
10
|
+
|
|
11
|
+
1. Checkout the repository.
|
|
12
|
+
2. Install Node (20+) and pnpm (or your package manager).
|
|
13
|
+
3. `pnpm install` and `pnpm run build:packages` so `packages/github-action/dist/` exists.
|
|
14
|
+
4. `pnpm --filter @restormel/testing-browser-playwright exec playwright install chromium` (or equivalent) for browser goals.
|
|
15
|
+
|
|
16
|
+
**Keys / `judge_rubric` (optional):** pass through env (never log values), e.g.:
|
|
17
|
+
|
|
18
|
+
```yaml
|
|
19
|
+
env:
|
|
20
|
+
RESTORMEL_KEYS_API_BASE_URL: ${{ secrets.RESTORMEL_KEYS_API_BASE_URL }}
|
|
21
|
+
RESTORMEL_KEYS_API_TOKEN: ${{ secrets.RESTORMEL_KEYS_API_TOKEN }}
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
Or set `RESTORMEL_TESTING_OPENAI_FALLBACK=1` and `OPENAI_API_KEY` only with explicit team approval (documented escape hatch).
|
|
25
|
+
|
|
26
|
+
Then:
|
|
27
|
+
|
|
28
|
+
```yaml
|
|
29
|
+
- uses: ./packages/github-action
|
|
30
|
+
with:
|
|
31
|
+
suite: web-critical
|
|
32
|
+
environment: local
|
|
33
|
+
target_url: ${{ secrets.PREVIEW_URL }} # optional; never log the secret value
|
|
34
|
+
commit_sha: ${{ github.sha }}
|
|
35
|
+
pr_number: ${{ github.event.pull_request.number }}
|
|
36
|
+
repository: ${{ github.repository }}
|
|
37
|
+
fork_pr_policy: skip
|
|
38
|
+
is_fork_pr: ${{ github.event.pull_request.head.repo.fork }}
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
## Inputs (summary)
|
|
42
|
+
|
|
43
|
+
| Input | Purpose |
|
|
44
|
+
|--------|---------|
|
|
45
|
+
| `suite` | **Required.** Suite id from config. |
|
|
46
|
+
| `environment` | Optional environment id (defaults to suite’s). |
|
|
47
|
+
| `target_url` | Optional safe `base_url` override (e.g. preview). |
|
|
48
|
+
| `commit_sha` | Recorded on the run (defaults to `GITHUB_SHA`). |
|
|
49
|
+
| `pr_number` | Shown in the step summary only. |
|
|
50
|
+
| `repository` | Recorded on the run (defaults to `GITHUB_REPOSITORY`). |
|
|
51
|
+
| `config_path` | Config file relative to `working_directory`. |
|
|
52
|
+
| `working_directory` | Subdirectory of the workspace to run from. |
|
|
53
|
+
| `fork_pr_policy` | `skip` (default) or `run` — see below. |
|
|
54
|
+
| `is_fork_pr` | Pass `github.event.pull_request.head.repo.fork` on PR workflows. |
|
|
55
|
+
| `poll_interval_seconds` | Ignored (reserved). |
|
|
56
|
+
| `timeout_minutes` | Ignored (reserved); use job timeout. |
|
|
57
|
+
|
|
58
|
+
## Outputs
|
|
59
|
+
|
|
60
|
+
- `verdict` — `passed` \| `failed` \| `indeterminate` \| `skipped` \| `error`
|
|
61
|
+
- `run_id` — UUID from `RunRecord` when the suite ran
|
|
62
|
+
- `skipped` — `true` when fork policy skipped execution
|
|
63
|
+
|
|
64
|
+
## Exit codes
|
|
65
|
+
|
|
66
|
+
- `0` — Suite **passed**, or fork policy **skipped** (intentionally green).
|
|
67
|
+
- `1` — Suite **failed** or **indeterminate**.
|
|
68
|
+
- `2` — Config / usage error before a successful run record.
|
|
69
|
+
|
|
70
|
+
## Fork PR safety
|
|
71
|
+
|
|
72
|
+
On `pull_request` workflows from **forks**, GitHub does not expose your repository secrets to the job. The default **`fork_pr_policy: skip`** avoids running browser suites when `is_fork_pr` is true, so contributors are not blocked by missing secrets or unreachable private URLs.
|
|
73
|
+
|
|
74
|
+
Set **`fork_pr_policy: run`** only when the suite is safe without secrets and targets a **public** URL. Do not rely on this for `pull_request_target` without a separate security review.
|
|
75
|
+
|
|
76
|
+
## GitHub Checks API
|
|
77
|
+
|
|
78
|
+
This MVP surfaces results via **step summary** Markdown and exit codes, not the GitHub **Checks** REST API. Richer check runs or annotations would be a separate optional integration later.
|
|
79
|
+
|
|
80
|
+
## See also
|
|
81
|
+
|
|
82
|
+
- [`examples/github-actions/README.md`](../../examples/github-actions/README.md)
|
package/action.yml
ADDED
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
name: Restormel Testing
|
|
2
|
+
description: >
|
|
3
|
+
Run a Restormel / Testing browser suite inline in the job (MVP): load repo config,
|
|
4
|
+
execute the runner, write run.json / traces under .restormel-testing/runs/, append a
|
|
5
|
+
GitHub step summary, and fail the step on failed or indeterminate verdicts.
|
|
6
|
+
No hosted control plane — polling inputs are reserved for a future orchestration mode.
|
|
7
|
+
author: Restormel
|
|
8
|
+
|
|
9
|
+
branding:
|
|
10
|
+
icon: check-square
|
|
11
|
+
color: gray-dark
|
|
12
|
+
|
|
13
|
+
inputs:
|
|
14
|
+
suite:
|
|
15
|
+
description: Suite id from your restormel-testing config (required).
|
|
16
|
+
required: true
|
|
17
|
+
environment:
|
|
18
|
+
description: Environment id to run against (omit to use the suite default).
|
|
19
|
+
required: false
|
|
20
|
+
default: ""
|
|
21
|
+
target_url:
|
|
22
|
+
description: >
|
|
23
|
+
Optional base URL override for the chosen environment (e.g. Vercel preview).
|
|
24
|
+
Must be https (or http for local). Do not embed credentials in the URL.
|
|
25
|
+
required: false
|
|
26
|
+
default: ""
|
|
27
|
+
commit_sha:
|
|
28
|
+
description: Commit recorded on the run (defaults to GITHUB_SHA when unset).
|
|
29
|
+
required: false
|
|
30
|
+
default: ""
|
|
31
|
+
pr_number:
|
|
32
|
+
description: Pull request number for the step summary only (optional).
|
|
33
|
+
required: false
|
|
34
|
+
default: ""
|
|
35
|
+
repository:
|
|
36
|
+
description: Repository slug recorded on the run (defaults to GITHUB_REPOSITORY when unset).
|
|
37
|
+
required: false
|
|
38
|
+
default: ""
|
|
39
|
+
config_path:
|
|
40
|
+
description: Path to restormel-testing.yaml (or .json) relative to working_directory.
|
|
41
|
+
required: false
|
|
42
|
+
default: restormel-testing.yaml
|
|
43
|
+
working_directory:
|
|
44
|
+
description: Subdirectory of the repository to run from (relative to GITHUB_WORKSPACE).
|
|
45
|
+
required: false
|
|
46
|
+
default: "."
|
|
47
|
+
fork_pr_policy:
|
|
48
|
+
description: >
|
|
49
|
+
skip (default) — do not run browser suites when is_fork_pr is true (safe when secrets
|
|
50
|
+
or private previews are required). run — execute anyway (you must use only public URLs
|
|
51
|
+
and expect secrets to be unavailable on fork workflows).
|
|
52
|
+
required: false
|
|
53
|
+
default: skip
|
|
54
|
+
is_fork_pr:
|
|
55
|
+
description: >
|
|
56
|
+
Set to the string 'true' when github.event.pull_request.head.repo.fork is true.
|
|
57
|
+
Ignored outside pull_request workflows.
|
|
58
|
+
required: false
|
|
59
|
+
default: "false"
|
|
60
|
+
poll_interval_seconds:
|
|
61
|
+
description: Reserved for a future hosted runner; ignored for inline MVP execution.
|
|
62
|
+
required: false
|
|
63
|
+
default: "30"
|
|
64
|
+
timeout_minutes:
|
|
65
|
+
description: Reserved for future use; prefer job defaults.timeout-minutes or workflow timeout.
|
|
66
|
+
required: false
|
|
67
|
+
default: "60"
|
|
68
|
+
|
|
69
|
+
outputs:
|
|
70
|
+
verdict:
|
|
71
|
+
description: passed, failed, indeterminate, skipped (fork policy), or error
|
|
72
|
+
value: ${{ steps.exec.outputs.verdict }}
|
|
73
|
+
run_id:
|
|
74
|
+
description: Run record id when the suite executed; empty when skipped or error before run
|
|
75
|
+
value: ${{ steps.exec.outputs.run_id }}
|
|
76
|
+
skipped:
|
|
77
|
+
description: "true" when the fork PR policy skipped execution
|
|
78
|
+
value: ${{ steps.exec.outputs.skipped }}
|
|
79
|
+
|
|
80
|
+
runs:
|
|
81
|
+
using: composite
|
|
82
|
+
steps:
|
|
83
|
+
- id: exec
|
|
84
|
+
shell: bash
|
|
85
|
+
run: node "${{ github.action_path }}/dist/main.js"
|
|
86
|
+
env:
|
|
87
|
+
RESTORMEL_TESTING_SUITE: ${{ inputs.suite }}
|
|
88
|
+
RESTORMEL_TESTING_ENVIRONMENT: ${{ inputs.environment }}
|
|
89
|
+
RESTORMEL_TESTING_TARGET_URL: ${{ inputs.target_url }}
|
|
90
|
+
RESTORMEL_TESTING_COMMIT_SHA: ${{ inputs.commit_sha }}
|
|
91
|
+
RESTORMEL_TESTING_PR_NUMBER: ${{ inputs.pr_number }}
|
|
92
|
+
RESTORMEL_TESTING_REPOSITORY: ${{ inputs.repository }}
|
|
93
|
+
RESTORMEL_TESTING_CONFIG: ${{ inputs.config_path }}
|
|
94
|
+
RESTORMEL_TESTING_WORKING_DIRECTORY: ${{ inputs.working_directory }}
|
|
95
|
+
RESTORMEL_TESTING_FORK_PR_POLICY: ${{ inputs.fork_pr_policy }}
|
|
96
|
+
RESTORMEL_TESTING_IS_FORK_PR: ${{ inputs.is_fork_pr }}
|
|
97
|
+
RESTORMEL_TESTING_POLL_INTERVAL_SECONDS: ${{ inputs.poll_interval_seconds }}
|
|
98
|
+
RESTORMEL_TESTING_TIMEOUT_MINUTES: ${{ inputs.timeout_minutes }}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/** How to treat pull requests from repository forks (secrets are not available to fork workflows by default). */
|
|
2
|
+
export type ForkPrPolicy = "skip" | "run";
|
|
3
|
+
/**
|
|
4
|
+
* When policy is `skip` and the run is identified as a fork PR, the action should not execute the suite.
|
|
5
|
+
*/
|
|
6
|
+
export declare function shouldSkipForkPr(policy: ForkPrPolicy, isForkPr: boolean): boolean;
|
|
7
|
+
//# sourceMappingURL=fork-policy.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fork-policy.d.ts","sourceRoot":"","sources":["../src/fork-policy.ts"],"names":[],"mappings":"AAAA,iHAAiH;AACjH,MAAM,MAAM,YAAY,GAAG,MAAM,GAAG,KAAK,CAAC;AAE1C;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,YAAY,EAAE,QAAQ,EAAE,OAAO,GAAG,OAAO,CAEjF"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fork-policy.js","sourceRoot":"","sources":["../src/fork-policy.ts"],"names":[],"mappings":"AAGA;;GAEG;AACH,MAAM,UAAU,gBAAgB,CAAC,MAAoB,EAAE,QAAiB;IACtE,OAAO,MAAM,KAAK,MAAM,IAAI,QAAQ,CAAC;AACvC,CAAC"}
|
package/dist/main.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"main.d.ts","sourceRoot":"","sources":["../src/main.ts"],"names":[],"mappings":""}
|
package/dist/main.js
ADDED
package/dist/main.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"main.js","sourceRoot":"","sources":["../src/main.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAE3C,KAAK,YAAY,EAAE,CAAC,IAAI,CACtB,CAAC,IAAI,EAAE,EAAE;IACP,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACrB,CAAC,EACD,CAAC,CAAC,EAAE,EAAE;IACJ,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IACjB,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CACF,CAAC"}
|
package/dist/run-ci.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"run-ci.d.ts","sourceRoot":"","sources":["../src/run-ci.ts"],"names":[],"mappings":"AAoCA;;;GAGG;AACH,wBAAsB,YAAY,IAAI,OAAO,CAAC,MAAM,CAAC,CAiIpD"}
|
package/dist/run-ci.js
ADDED
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
import { appendFileSync, mkdirSync } from "node:fs";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
import { keysAdapterOptionsFromProcessEnv } from "@restormel/testing-keys-adapter";
|
|
4
|
+
import { buildGithubStepSummaryMarkdown, writeRunReportBundle } from "@restormel/testing-report";
|
|
5
|
+
import { runLocalSuite } from "@restormel/testing-runner";
|
|
6
|
+
import { shouldSkipForkPr } from "./fork-policy.js";
|
|
7
|
+
const EXIT_OK = 0;
|
|
8
|
+
const EXIT_FAILED = 1;
|
|
9
|
+
const EXIT_USAGE = 2;
|
|
10
|
+
function getenv(name) {
|
|
11
|
+
const v = process.env[name];
|
|
12
|
+
return v === undefined || v.trim() === "" ? undefined : v;
|
|
13
|
+
}
|
|
14
|
+
function appendSummary(line) {
|
|
15
|
+
const p = process.env.GITHUB_STEP_SUMMARY;
|
|
16
|
+
if (p) {
|
|
17
|
+
appendFileSync(p, `${line}\n`, "utf8");
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
function appendOutput(pairs) {
|
|
21
|
+
const p = process.env.GITHUB_OUTPUT;
|
|
22
|
+
if (!p)
|
|
23
|
+
return;
|
|
24
|
+
for (const [k, v] of Object.entries(pairs)) {
|
|
25
|
+
appendFileSync(p, `${k}=${v}\n`, "utf8");
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
function parseForkPolicy(raw) {
|
|
29
|
+
const v = (raw ?? "skip").toLowerCase();
|
|
30
|
+
return v === "run" ? "run" : "skip";
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* CI entrypoint driven by environment variables (set from `action.yml`).
|
|
34
|
+
* Inline execution only — no polling or hosted control plane.
|
|
35
|
+
*/
|
|
36
|
+
export async function runCiFromEnv() {
|
|
37
|
+
const workspace = process.env.GITHUB_WORKSPACE ?? process.cwd();
|
|
38
|
+
const policy = parseForkPolicy(getenv("RESTORMEL_TESTING_FORK_PR_POLICY"));
|
|
39
|
+
const forkRaw = getenv("RESTORMEL_TESTING_IS_FORK_PR")?.trim().toLowerCase();
|
|
40
|
+
const isForkPr = forkRaw === "true" || forkRaw === "1" || forkRaw === "yes";
|
|
41
|
+
if (shouldSkipForkPr(policy, isForkPr)) {
|
|
42
|
+
appendSummary("## Restormel Testing");
|
|
43
|
+
appendSummary("");
|
|
44
|
+
appendSummary("**Status:** skipped (fork PR safe mode)");
|
|
45
|
+
appendSummary("");
|
|
46
|
+
appendSummary("This workflow run targets a **fork** pull request. By default the action does not run browser suites so you are not surprised by missing secrets or unreachable private preview URLs.");
|
|
47
|
+
appendSummary("");
|
|
48
|
+
appendSummary("To run on forks anyway, set input `fork_pr_policy: run` and ensure the suite uses only **public** targets and **no repository secrets**.");
|
|
49
|
+
appendSummary("");
|
|
50
|
+
appendSummary("Prefer `pull_request` (not `pull_request_target`) unless you fully understand the security model.");
|
|
51
|
+
appendOutput({ verdict: "skipped", run_id: "", skipped: "true" });
|
|
52
|
+
return EXIT_OK;
|
|
53
|
+
}
|
|
54
|
+
const wd = getenv("RESTORMEL_TESTING_WORKING_DIRECTORY") ?? ".";
|
|
55
|
+
const root = join(workspace, wd);
|
|
56
|
+
process.chdir(root);
|
|
57
|
+
const suite = getenv("RESTORMEL_TESTING_SUITE");
|
|
58
|
+
if (!suite) {
|
|
59
|
+
console.error("RESTORMEL_TESTING_SUITE is required when the action runs the suite.");
|
|
60
|
+
appendSummary("## Restormel Testing");
|
|
61
|
+
appendSummary("**Error:** `suite` input is required.");
|
|
62
|
+
appendOutput({ verdict: "error", run_id: "", skipped: "false" });
|
|
63
|
+
return EXIT_USAGE;
|
|
64
|
+
}
|
|
65
|
+
const configPath = getenv("RESTORMEL_TESTING_CONFIG") ?? "restormel-testing.yaml";
|
|
66
|
+
const environmentId = getenv("RESTORMEL_TESTING_ENVIRONMENT");
|
|
67
|
+
const targetUrl = getenv("RESTORMEL_TESTING_TARGET_URL");
|
|
68
|
+
const commitSha = getenv("RESTORMEL_TESTING_COMMIT_SHA") ?? process.env.GITHUB_SHA;
|
|
69
|
+
const repository = getenv("RESTORMEL_TESTING_REPOSITORY") ?? process.env.GITHUB_REPOSITORY;
|
|
70
|
+
const prNumber = getenv("RESTORMEL_TESTING_PR_NUMBER");
|
|
71
|
+
const pollHint = getenv("RESTORMEL_TESTING_POLL_INTERVAL_SECONDS");
|
|
72
|
+
const timeoutHint = getenv("RESTORMEL_TESTING_TIMEOUT_MINUTES");
|
|
73
|
+
if (pollHint !== undefined || timeoutHint !== undefined) {
|
|
74
|
+
console.warn("Note: poll_interval_seconds and timeout_minutes are ignored for the inline MVP; use the job / workflow timeout instead.");
|
|
75
|
+
}
|
|
76
|
+
const artifactDir = getenv("RESTORMEL_TESTING_ARTIFACT_DIR") ??
|
|
77
|
+
join(workspace, ".restormel-testing", "runs", `gha-${process.env.GITHUB_RUN_ID ?? "local"}-${process.env.GITHUB_RUN_ATTEMPT ?? "0"}`);
|
|
78
|
+
mkdirSync(artifactDir, { recursive: true });
|
|
79
|
+
const keysAdapterOptions = keysAdapterOptionsFromProcessEnv();
|
|
80
|
+
const result = await runLocalSuite({
|
|
81
|
+
configPath,
|
|
82
|
+
suiteId: suite,
|
|
83
|
+
environmentId,
|
|
84
|
+
targetUrlOverride: targetUrl,
|
|
85
|
+
commitSha,
|
|
86
|
+
repository,
|
|
87
|
+
trigger: "ci",
|
|
88
|
+
artifactDir,
|
|
89
|
+
headless: true,
|
|
90
|
+
keysAdapterOptions,
|
|
91
|
+
});
|
|
92
|
+
if (!result.ok || result.run === undefined) {
|
|
93
|
+
appendSummary("## Restormel Testing");
|
|
94
|
+
appendSummary("");
|
|
95
|
+
appendSummary("**Verdict:** error (config or runner failure)");
|
|
96
|
+
appendSummary("");
|
|
97
|
+
appendSummary("```text");
|
|
98
|
+
appendSummary(result.errors.join("\n") || "(no message)");
|
|
99
|
+
appendSummary("```");
|
|
100
|
+
appendOutput({ verdict: "error", run_id: "", skipped: "false" });
|
|
101
|
+
for (const w of result.warnings)
|
|
102
|
+
console.warn(w);
|
|
103
|
+
return EXIT_USAGE;
|
|
104
|
+
}
|
|
105
|
+
const run = result.run;
|
|
106
|
+
const repoHint = repository ?? "org/repo";
|
|
107
|
+
let reproduce = `testing run --suite ${suite} --config ${configPath} --ci`;
|
|
108
|
+
if (environmentId !== undefined)
|
|
109
|
+
reproduce += ` --environment ${environmentId}`;
|
|
110
|
+
if (targetUrl !== undefined)
|
|
111
|
+
reproduce += ` --target-url '${targetUrl.replace(/'/g, "'\\''")}'`;
|
|
112
|
+
reproduce += ` --commit-sha <sha> --repository ${repoHint}`;
|
|
113
|
+
await writeRunReportBundle(artifactDir, {
|
|
114
|
+
run,
|
|
115
|
+
traces: result.traces,
|
|
116
|
+
warnings: result.warnings.length > 0 ? result.warnings : undefined,
|
|
117
|
+
suite: result.suiteMeta,
|
|
118
|
+
reproduction: {
|
|
119
|
+
report_command: `testing report ${artifactDir}`,
|
|
120
|
+
notes: reproduce,
|
|
121
|
+
},
|
|
122
|
+
});
|
|
123
|
+
const summaryMd = buildGithubStepSummaryMarkdown({
|
|
124
|
+
run,
|
|
125
|
+
suite: result.suiteMeta,
|
|
126
|
+
warnings: result.warnings.length > 0 ? result.warnings : undefined,
|
|
127
|
+
ciContext: { prNumber, targetUrl },
|
|
128
|
+
reproduceCommand: reproduce,
|
|
129
|
+
artifactDirHint: artifactDir,
|
|
130
|
+
});
|
|
131
|
+
const summaryPath = process.env.GITHUB_STEP_SUMMARY;
|
|
132
|
+
if (summaryPath) {
|
|
133
|
+
appendFileSync(summaryPath, `${summaryMd}\n`, "utf8");
|
|
134
|
+
}
|
|
135
|
+
appendOutput({ verdict: run.verdict, run_id: run.id, skipped: "false" });
|
|
136
|
+
for (const w of result.warnings)
|
|
137
|
+
console.warn(w);
|
|
138
|
+
if (run.verdict !== "passed") {
|
|
139
|
+
return EXIT_FAILED;
|
|
140
|
+
}
|
|
141
|
+
return EXIT_OK;
|
|
142
|
+
}
|
|
143
|
+
//# sourceMappingURL=run-ci.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"run-ci.js","sourceRoot":"","sources":["../src/run-ci.ts"],"names":[],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@restormel/testing-github-action",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "GitHub Action entrypoint for Restormel / Testing (inline runner MVP).",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"repository": {
|
|
7
|
+
"type": "git",
|
|
8
|
+
"url": "https://github.com/Allotment-Technology-Ltd/restormel-testing.git",
|
|
9
|
+
"directory": "packages/github-action"
|
|
10
|
+
},
|
|
11
|
+
"bugs": {
|
|
12
|
+
"url": "https://github.com/Allotment-Technology-Ltd/restormel-testing/issues"
|
|
13
|
+
},
|
|
14
|
+
"homepage": "https://github.com/Allotment-Technology-Ltd/restormel-testing/tree/main/packages/github-action#readme",
|
|
15
|
+
"publishConfig": {
|
|
16
|
+
"access": "public"
|
|
17
|
+
},
|
|
18
|
+
"type": "module",
|
|
19
|
+
"main": "./dist/main.js",
|
|
20
|
+
"types": "./dist/main.d.ts",
|
|
21
|
+
"files": [
|
|
22
|
+
"dist",
|
|
23
|
+
"action.yml"
|
|
24
|
+
],
|
|
25
|
+
"engines": {
|
|
26
|
+
"node": ">=20"
|
|
27
|
+
},
|
|
28
|
+
"dependencies": {
|
|
29
|
+
"@restormel/testing-keys-adapter": "0.1.0",
|
|
30
|
+
"@restormel/testing-report": "0.1.0",
|
|
31
|
+
"@restormel/testing-runner": "0.1.0"
|
|
32
|
+
},
|
|
33
|
+
"devDependencies": {
|
|
34
|
+
"typescript": "^5.7.0"
|
|
35
|
+
},
|
|
36
|
+
"scripts": {
|
|
37
|
+
"build": "tsc -b tsconfig.json",
|
|
38
|
+
"typecheck": "tsc -b tsconfig.json",
|
|
39
|
+
"test": "node -e \"process.exit(0);\""
|
|
40
|
+
}
|
|
41
|
+
}
|