mirror of
https://github.com/diegosouzapw/OmniRoute.git
synced 2026-08-29 18:42:17 +03:00
Compare commits
1 Commits
fix/releas
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9dc6500ebd |
17
.github/workflows/electron-release.yml
vendored
17
.github/workflows/electron-release.yml
vendored
@@ -4,10 +4,6 @@ on:
|
||||
push:
|
||||
tags:
|
||||
- "v*"
|
||||
# A dispatch builds the ref it is dispatched ON (`gh workflow run … --ref v3.8.50` rebuilds
|
||||
# that tag; `--ref main` builds the repaired line). The ref is deliberately NOT an input:
|
||||
# CodeQL flags an input-controlled checkout next to the npm cache on the default branch as
|
||||
# cache poisoning (actions/cache-poisoning/poisonable-step), and `github.ref` is trusted.
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
version:
|
||||
@@ -19,6 +15,11 @@ on:
|
||||
required: false
|
||||
default: true
|
||||
type: boolean
|
||||
build_ref:
|
||||
description: "Git ref to BUILD from (default: the version tag). Set to a branch when the tag itself cannot build — e.g. a lockfile that was already broken when it was cut — and the assets must come from the repaired line"
|
||||
required: false
|
||||
default: ""
|
||||
type: string
|
||||
|
||||
# Least-privilege default: read-only at the top level; each job grants the writes it
|
||||
# needs (build/release upload assets, publish-npm forwards npm provenance / packages
|
||||
@@ -85,6 +86,9 @@ jobs:
|
||||
- uses: actions/checkout@v7
|
||||
with:
|
||||
persist-credentials: false
|
||||
# workflow_dispatch: build the tag being (re)built, not the dispatching branch. On a
|
||||
# tag push this resolves to the same commit.
|
||||
ref: ${{ inputs.build_ref || needs.validate.outputs.version }}
|
||||
- name: Setup Node
|
||||
uses: actions/setup-node@v7
|
||||
with:
|
||||
@@ -170,6 +174,9 @@ jobs:
|
||||
- uses: actions/checkout@v7
|
||||
with:
|
||||
persist-credentials: false
|
||||
# workflow_dispatch: build the tag being (re)built, not the dispatching branch. On a
|
||||
# tag push this resolves to the same commit.
|
||||
ref: ${{ inputs.build_ref || needs.validate.outputs.version }}
|
||||
- name: Setup Node
|
||||
uses: actions/setup-node@v7
|
||||
with:
|
||||
@@ -356,6 +363,8 @@ jobs:
|
||||
with:
|
||||
persist-credentials: false
|
||||
fetch-depth: 0
|
||||
# Source archives + SBOM come from the tag being released, not the dispatching branch.
|
||||
ref: ${{ inputs.build_ref || needs.validate.outputs.version }}
|
||||
|
||||
# `merge-multiple` is deliberately OFF. It resolves same-name collisions by ARRIVAL
|
||||
# ORDER, and the two macOS jobs each emit their own `latest-mac.yml` listing only their
|
||||
|
||||
15
.github/workflows/npm-publish.yml
vendored
15
.github/workflows/npm-publish.yml
vendored
@@ -273,11 +273,20 @@ jobs:
|
||||
if-no-files-found: error
|
||||
|
||||
- name: Attach SBOM to GitHub Release
|
||||
if: steps.resolve.outputs.skip != 'true' && github.event_name == 'release'
|
||||
# Not only on the `release` event: the v3.8.50 package shipped through a
|
||||
# workflow_dispatch (staged publish, 11 attempts) and this step was skipped, so the
|
||||
# GitHub Release carried no SBOM until it was attached by hand from the run's
|
||||
# `sbom-npm` artifact. Attach whenever a release for the published tag exists.
|
||||
if: steps.resolve.outputs.skip != 'true' && (github.event_name == 'release' || github.event_name == 'workflow_dispatch')
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
TAG: ${{ github.ref_name }}
|
||||
run: gh release upload "$TAG" sbom-npm.cdx.json --clobber
|
||||
TAG: ${{ github.event_name == 'release' && github.ref_name || format('v{0}', inputs.version) }}
|
||||
run: |
|
||||
if ! gh release view "$TAG" --repo "$GITHUB_REPOSITORY" >/dev/null 2>&1; then
|
||||
echo "::notice::no GitHub Release for $TAG yet — SBOM stays on the sbom-npm workflow artifact"
|
||||
exit 0
|
||||
fi
|
||||
gh release upload "$TAG" sbom-npm.cdx.json --repo "$GITHUB_REPOSITORY" --clobber
|
||||
|
||||
# WS1.2/WS1.3 (#7065 class): the artifact that is about to be published must
|
||||
# BOOT. build:cli already assembled dist/ above; this packs+installs+boots the
|
||||
|
||||
1
changelog.d/fixes/v3850-sbom-attach-on-dispatch.md
Normal file
1
changelog.d/fixes/v3850-sbom-attach-on-dispatch.md
Normal file
@@ -0,0 +1 @@
|
||||
- npm publish workflow: the CycloneDX SBOM is attached to the GitHub Release on `workflow_dispatch` publishes too (when a release for the tag exists), not only on the `release` event — v3.8.50 shipped through a staged dispatch and its release carried no SBOM until it was attached by hand from the run's `sbom-npm` artifact
|
||||
@@ -123,46 +123,6 @@ function discoverPackagedExecutable() {
|
||||
throw new Error(`Packaged Electron smoke check does not support ${platform()}.`);
|
||||
}
|
||||
|
||||
/**
|
||||
* The packaged app opens SQLite lazily: `/login` (the readiness URL) never touches the
|
||||
* database, so a smoke that only waits for readiness sees no "[DB] Driver: ..." line at
|
||||
* all and `assertNativeDriverSelected` cannot tell a native driver from nothing (v3.8.50
|
||||
* re-attach, run 33251755872: every leg green up to the smoke, then this). After readiness
|
||||
* the smoke now requests a DB-backed endpoint and waits for the driver line to appear.
|
||||
*/
|
||||
export const DB_TOUCH_PATH = "/api/monitoring/health";
|
||||
const DB_DRIVER_LINE_PATTERN = /\[DB\] Driver: /;
|
||||
|
||||
export async function waitForDriverLine(getLogs, { timeoutMs = 15_000, pollMs = 250 } = {}) {
|
||||
const startedAt = Date.now();
|
||||
while (Date.now() - startedAt < timeoutMs) {
|
||||
const logs = getLogs();
|
||||
assertNoFatalLogs(logs);
|
||||
if (DB_DRIVER_LINE_PATTERN.test(logs)) return logs;
|
||||
await sleep(pollMs);
|
||||
}
|
||||
throw new Error(
|
||||
`Packaged Electron app logged no "[DB] Driver: ..." line within ${timeoutMs}ms of touching ` +
|
||||
`${DB_TOUCH_PATH} — the database never opened, so the SQLite driver cannot be verified.`
|
||||
);
|
||||
}
|
||||
|
||||
async function openDatabaseForSmoke({ logs, smokeUrl }) {
|
||||
const touchUrl = new URL(DB_TOUCH_PATH, smokeUrl).toString();
|
||||
try {
|
||||
const response = await fetchWithTimeout(touchUrl, 5_000);
|
||||
console.log(
|
||||
`[electron-smoke] touched ${touchUrl} (HTTP ${response.status}) to open the database`
|
||||
);
|
||||
} catch (error) {
|
||||
console.log(
|
||||
`[electron-smoke] touching ${touchUrl} failed (${error instanceof Error ? error.message : String(error)}) — waiting for the driver line anyway`
|
||||
);
|
||||
}
|
||||
await waitForDriverLine(() => logs.value);
|
||||
console.log("[electron-smoke] database opened — driver line captured");
|
||||
}
|
||||
|
||||
async function fetchWithTimeout(url, timeoutMs) {
|
||||
const controller = new AbortController();
|
||||
const timeout = setTimeout(() => controller.abort(), timeoutMs);
|
||||
@@ -517,7 +477,6 @@ async function waitForReady({ logs, smokeUrl, timeoutMs, settleMs, exitState })
|
||||
if (response.status === 200) {
|
||||
assertNoFatalLogs(logs.value);
|
||||
console.log(`[electron-smoke] ready: ${smokeUrl} returned HTTP 200`);
|
||||
await openDatabaseForSmoke({ logs, smokeUrl });
|
||||
await settleAfterReady({
|
||||
getExitState: () => ({ exitCode: exitState.exitCode, signalCode: exitState.signalCode }),
|
||||
logs,
|
||||
@@ -547,14 +506,7 @@ async function waitForReady({ logs, smokeUrl, timeoutMs, settleMs, exitState })
|
||||
* by the single-launch path and the cold-restart (two-launch) path so both
|
||||
* exercise identical spawn/readiness/shutdown behavior.
|
||||
*/
|
||||
async function launchAndCollectLogs({
|
||||
appExecutable,
|
||||
smokeUrl,
|
||||
dataDir,
|
||||
timeoutMs,
|
||||
settleMs,
|
||||
streamLogs,
|
||||
}) {
|
||||
async function launchAndCollectLogs({ appExecutable, smokeUrl, dataDir, timeoutMs, settleMs, streamLogs }) {
|
||||
const smokeEnv = buildSmokeEnv({ dataDir });
|
||||
await assertPortIsFree(smokeUrl);
|
||||
await ensureSmokeEnvDirs(smokeEnv, dataDir);
|
||||
@@ -616,14 +568,7 @@ async function main() {
|
||||
!process.env.ELECTRON_SMOKE_DATA_DIR && process.env.ELECTRON_SMOKE_KEEP_DATA !== "1";
|
||||
|
||||
try {
|
||||
await launchAndCollectLogs({
|
||||
appExecutable,
|
||||
smokeUrl,
|
||||
dataDir,
|
||||
timeoutMs,
|
||||
settleMs,
|
||||
streamLogs,
|
||||
});
|
||||
await launchAndCollectLogs({ appExecutable, smokeUrl, dataDir, timeoutMs, settleMs, streamLogs });
|
||||
|
||||
if (!coldRestart) return;
|
||||
|
||||
|
||||
@@ -7,8 +7,6 @@ import {
|
||||
FATAL_LOG_PATTERNS,
|
||||
LINUX_EXECUTABLE_NAMES,
|
||||
stopApp,
|
||||
waitForDriverLine,
|
||||
DB_TOUCH_PATH,
|
||||
} from "../../scripts/dev/smoke-electron-packaged.mjs";
|
||||
|
||||
test("electron smoke discovers the default Linux executable name", () => {
|
||||
@@ -99,24 +97,3 @@ test("electron smoke flags startup logs missing any driver selection line", () =
|
||||
/no '\[DB\] Driver: \.\.\.' line/
|
||||
);
|
||||
});
|
||||
|
||||
test("electron smoke waits for the [DB] Driver line after touching a DB-backed endpoint", async () => {
|
||||
assert.equal(DB_TOUCH_PATH, "/api/monitoring/health");
|
||||
let logs = "[electron] [Server] [STARTUP] ready\n";
|
||||
setTimeout(() => {
|
||||
logs += "[electron] [Server] [DB] Driver: better-sqlite3 | file: /tmp/x/storage.sqlite\n";
|
||||
}, 60);
|
||||
const seen = await waitForDriverLine(() => logs, { timeoutMs: 2_000, pollMs: 20 });
|
||||
assert.match(seen, /\[DB\] Driver: better-sqlite3/);
|
||||
});
|
||||
|
||||
test("electron smoke fails clearly when the database never opens", async () => {
|
||||
await assert.rejects(
|
||||
() =>
|
||||
waitForDriverLine(() => "[electron] [Server] [STARTUP] ready\n", {
|
||||
timeoutMs: 120,
|
||||
pollMs: 20,
|
||||
}),
|
||||
/logged no "\[DB\] Driver: \.\.\." line within 120ms/
|
||||
);
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user