@omega.js/desktop 0.50.0 → 0.51.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/assets/css/tokens/_index.scss +1 -1
- package/dist/assets/themes/base/_includes/frontend/sections/account-section-header.html +4 -1
- package/dist/assets/themes/base/_includes/frontend/sections/footer.html +13 -6
- package/dist/assets/themes/base/_includes/frontend/sections/nav.html +10 -8
- package/dist/assets/themes/base/_includes/global/sections/account.html +3 -1
- package/dist/assets/themes/base/_includes/global/sections/app-sidebar.html +12 -8
- package/dist/assets/themes/base/_includes/global/sections/app-topbar.html +10 -6
- package/dist/assets/themes/base/_includes/global/sections/page-header.html +8 -4
- package/dist/assets/themes/base/_layouts/backend/pages/dashboard/index.html +24 -24
- package/dist/assets/themes/base/_layouts/frontend/pages/about.html +10 -10
- package/dist/assets/themes/base/_layouts/frontend/pages/account/index.html +35 -35
- package/dist/assets/themes/base/_layouts/frontend/pages/alternatives/index.html +4 -4
- package/dist/assets/themes/base/_layouts/frontend/pages/auth/signin.html +1 -1
- package/dist/assets/themes/base/_layouts/frontend/pages/auth/signup.html +4 -4
- package/dist/assets/themes/base/_layouts/frontend/pages/contact.html +3 -3
- package/dist/assets/themes/base/_layouts/frontend/pages/download.html +34 -33
- package/dist/assets/themes/base/_layouts/frontend/pages/extension/index.html +11 -11
- package/dist/assets/themes/base/_layouts/frontend/pages/legal/document.html +1 -1
- package/dist/assets/themes/base/_layouts/frontend/pages/status.html +1 -1
- package/dist/assets/themes/base/_layouts/frontend/pages/team/index.html +9 -7
- package/dist/assets/themes/base/_layouts/frontend/pages/team/member.html +5 -3
- package/dist/assets/themes/base/_sections/about/letter/section.html +1 -1
- package/dist/assets/themes/base/_sections/about/letter/section.json5 +4 -4
- package/dist/assets/themes/base/_sections/marketing/bento/section.html +1 -1
- package/dist/assets/themes/base/_sections/marketing/bento/section.json5 +15 -15
- package/dist/assets/themes/base/_sections/marketing/cta/section.json5 +1 -1
- package/dist/assets/themes/base/_sections/marketing/hero/section.html +6 -6
- package/dist/assets/themes/base/_sections/marketing/hero/section.json5 +10 -10
- package/dist/assets/themes/base/_sections/marketing/product-demo/section.html +1 -1
- package/dist/assets/themes/base/_sections/marketing/product-demo/section.json5 +2 -2
- package/dist/assets/themes/base/_sections/marketing/stats/section.html +1 -1
- package/dist/assets/themes/base/_sections/marketing/stats/section.json5 +5 -5
- package/dist/assets/themes/base/_sections/marketing/trusted-by/section.html +1 -1
- package/dist/assets/themes/base/_sections/marketing/trusted-by/section.json5 +2 -2
- package/dist/assets/themes/neobrutalism/_layouts/frontend/pages/index.html +10 -10
- package/dist/assets/themes/newsflash/_layouts/frontend/pages/index.html +10 -10
- package/dist/assets/themes/newsflash/_sections/marketing/desks/section.html +2 -2
- package/dist/assets/themes/newsflash/_sections/marketing/desks/section.json5 +4 -4
- package/dist/build.js +69 -28
- package/dist/cli-run.js +20 -13
- package/dist/cli.js +12 -7
- package/dist/commands/build.js +0 -2
- package/dist/commands/deploy.js +116 -44
- package/dist/commands/finalize-release.js +5 -4
- package/dist/commands/launch.js +12 -7
- package/dist/commands/lib/deploy-precheck.js +66 -34
- package/dist/commands/lib/ensure-target.js +71 -11
- package/dist/commands/package.js +0 -1
- package/dist/commands/publish.js +11 -4
- package/dist/commands/release.js +99 -252
- package/dist/commands/runner.js +42 -5
- package/dist/commands/sign-windows.js +46 -15
- package/dist/commands/test.js +4 -3
- package/dist/commands/validate-certs.js +291 -115
- package/dist/config/page-template.html +4 -0
- package/dist/defaults/.github/workflows/build.yml +144 -64
- package/dist/defaults/AGENTS.md +3 -2
- package/dist/defaults/_.gitignore +4 -2
- package/dist/defaults/config/certs/README.md +25 -45
- package/dist/defaults/config/omega.json5 +66 -32
- package/dist/defaults/hooks/deploy/pre.js +10 -0
- package/dist/defaults/src/assets/scss/main.scss +12 -2
- package/dist/defaults/src/integrations/tray/index.js +1 -1
- package/dist/gulp/main.js +13 -25
- package/dist/gulp/tasks/audit.js +18 -6
- package/dist/gulp/tasks/build-config.js +181 -60
- package/dist/gulp/tasks/bundle.js +108 -36
- package/dist/gulp/tasks/release.js +86 -4
- package/dist/gulp/tasks/sass.js +11 -0
- package/dist/hooks/lib/notarize-tools.js +137 -0
- package/dist/hooks/notarize-artifacts.js +57 -0
- package/dist/hooks/notarize.js +59 -8
- package/dist/lib/auth-persistence.js +25 -0
- package/dist/lib/client-bridge.js +11 -8
- package/dist/lib/deep-link.js +15 -8
- package/dist/lib/protocol.js +7 -1
- package/dist/lib/restart-manager/install.js +6 -3
- package/dist/lib/sign-helpers/auto-unlock.js +65 -27
- package/dist/lib/sign-helpers/console-lock.js +34 -0
- package/dist/lib/sign-helpers/exec-with-limit.js +68 -0
- package/dist/lib/sign-helpers/resolve-icons.js +6 -4
- package/dist/lib/tray.js +7 -6
- package/dist/main.js +16 -0
- package/dist/preload.js +8 -0
- package/dist/renderer.js +16 -4
- package/dist/runner/job-started.js +104 -0
- package/dist/test/fixtures/consumer-app/config/omega.json5 +7 -0
- package/dist/test/fixtures/consumer-app/package.json +1 -1
- package/dist/test/fixtures/consumer-app/src/assets/js/components/main/index.js +7 -1
- package/dist/test/harness/main-entry.js +2 -1
- package/dist/test/harness/renderer-preload.js +12 -3
- package/dist/test/runners/boot.js +101 -11
- package/dist/test/runners/electron.js +1 -1
- package/dist/test/suites/boot/consumer-app-boots.test.js +54 -0
- package/dist/test/suites/build/audit.test.js +45 -6
- package/dist/test/suites/build/auth-persistence-resolve.test.js +119 -0
- package/dist/test/suites/build/auto-unlock.test.js +105 -0
- package/dist/test/suites/build/boot-runner-timeout.test.js +253 -0
- package/dist/test/suites/build/brand-scss.test.js +106 -0
- package/dist/test/suites/build/build-config.test.js +146 -36
- package/dist/test/suites/build/build-json-bake.test.js +245 -0
- package/dist/test/suites/build/build-verbs.test.js +48 -15
- package/dist/test/suites/build/build-workflow-jobs.test.js +190 -0
- package/dist/test/suites/build/cli.test.js +32 -10
- package/dist/test/suites/build/config-schema.test.js +4 -4
- package/dist/test/suites/build/console-lock.test.js +51 -0
- package/dist/test/suites/build/defaults-scaffold.test.js +71 -2
- package/dist/test/suites/build/deploy-direct.test.js +241 -0
- package/dist/test/suites/build/deploy-dispatch.test.js +287 -0
- package/dist/test/suites/build/deploy-hook.test.js +169 -0
- package/dist/test/suites/build/ensure-target.test.js +14 -2
- package/dist/test/suites/build/env-delivery.test.js +19 -10
- package/dist/test/suites/build/env-watch.test.js +18 -7
- package/dist/test/suites/build/esm-only-dependency.test.js +127 -0
- package/dist/test/suites/build/exec-with-limit.test.js +53 -0
- package/dist/test/suites/build/finalize-release.test.js +2 -2
- package/dist/test/suites/build/get-config.test.js +120 -8
- package/dist/test/suites/build/github-utils.test.js +12 -6
- package/dist/test/suites/build/license-stamp.test.js +6 -4
- package/dist/test/suites/build/manager.test.js +88 -68
- package/dist/test/suites/build/manifest-deps.test.js +116 -0
- package/dist/test/suites/build/merge-line-files.test.js +27 -4
- package/dist/test/suites/build/notarize-artifacts.test.js +135 -0
- package/dist/test/suites/build/notarize-tools.test.js +38 -0
- package/dist/test/suites/build/notarize.test.js +207 -0
- package/dist/test/suites/build/release-pipeline.test.js +38 -60
- package/dist/test/suites/build/release-skipped-upload.test.js +107 -0
- package/dist/test/suites/build/resolve-icons.test.js +35 -35
- package/dist/test/suites/build/runner-job-guard.test.js +182 -0
- package/dist/test/suites/build/runner.test.js +25 -2
- package/dist/test/suites/build/sentry.test.js +8 -3
- package/dist/test/suites/build/setup-scripts.test.js +3 -0
- package/dist/test/suites/build/sign-windows.test.js +92 -8
- package/dist/test/suites/build/test-stealth.test.js +17 -11
- package/dist/test/suites/build/url-helpers.test.js +37 -17
- package/dist/test/suites/build/validate-certs.test.js +428 -55
- package/dist/test/suites/build/validate-config.test.js +3 -3
- package/dist/test/suites/main/auth-flow.test.js +12 -0
- package/dist/test/suites/main/auth-persistence.test.js +14 -17
- package/dist/test/suites/main/auto-updater.test.js +2 -2
- package/dist/test/suites/main/boot-sequence.test.js +1 -1
- package/dist/test/suites/main/client-bridge.integration.test.js +5 -82
- package/dist/test/suites/main/client-bridge.test.js +19 -6
- package/dist/test/suites/main/deep-link.test.js +54 -0
- package/dist/test/suites/main/startup-paths-and-ua.test.js +1 -1
- package/dist/test/suites/main/url-helpers.test.js +81 -72
- package/dist/test/suites/renderer/cross-context-helpers.test.js +19 -16
- package/dist/utils/build-pipeline.js +10 -10
- package/dist/utils/github.js +12 -51
- package/dist/utils/load-env.js +66 -0
- package/dist/utils/mode-helpers.js +43 -111
- package/dist/utils/platform.js +37 -0
- package/dist/utils/runner-env.js +2 -1
- package/dist/utils/runner-job-guard.js +149 -0
- package/dist/utils/ship-keys.js +52 -0
- package/dist/utils/test-stealth.js +5 -3
- package/dist/utils/url-helpers.js +33 -17
- package/dist/vendor/config/bundle-id.js +53 -0
- package/dist/vendor/config/client-config.js +141 -0
- package/dist/vendor/config/company.js +334 -15
- package/dist/vendor/config/dev-facts.js +48 -0
- package/dist/vendor/config/env-delivery.js +231 -9
- package/dist/vendor/config/env-retired.js +137 -0
- package/dist/vendor/config/env-rules.js +22 -3
- package/dist/vendor/config/env-schema.js +234 -117
- package/dist/vendor/config/env.js +55 -26
- package/dist/vendor/config/environment.js +189 -0
- package/dist/vendor/config/hooks.js +13 -11
- package/dist/vendor/config/index.js +121 -44
- package/dist/vendor/config/load.js +366 -115
- package/dist/vendor/config/merge.js +2 -2
- package/dist/vendor/config/order.js +3 -3
- package/dist/vendor/config/platforms.js +276 -0
- package/dist/vendor/config/repo.js +226 -104
- package/dist/vendor/config/retired-keys.js +232 -27
- package/dist/vendor/config/schema.js +525 -99
- package/dist/vendor/config/site-global.js +63 -53
- package/dist/vendor/config/targets.js +187 -0
- package/dist/vendor/config/validate.js +119 -59
- package/dist/vendor/devkit/argv.js +118 -0
- package/dist/vendor/devkit/attach-log-file.js +21 -13
- package/dist/vendor/devkit/brand-tokens.js +278 -0
- package/dist/vendor/devkit/brand-version.js +264 -0
- package/dist/vendor/devkit/build-json.js +91 -0
- package/dist/vendor/devkit/bundle.js +48 -0
- package/dist/vendor/devkit/certificate-expiry.js +108 -0
- package/dist/vendor/devkit/certs.js +16 -194
- package/dist/vendor/devkit/ci-workflows.js +124 -8
- package/dist/vendor/devkit/cli-router.js +3 -3
- package/dist/vendor/devkit/defaults-engine.js +69 -7
- package/dist/vendor/devkit/deploy-follow.js +297 -0
- package/dist/vendor/devkit/deploy-precheck.js +23 -8
- package/dist/vendor/devkit/deploy-record.js +11 -27
- package/dist/vendor/devkit/deploy-snapshot.js +661 -0
- package/dist/vendor/devkit/deploy.js +445 -75
- package/dist/vendor/devkit/git-auth.js +73 -0
- package/dist/vendor/devkit/git-remote.js +95 -0
- package/dist/vendor/devkit/github-repo.js +290 -0
- package/dist/vendor/devkit/local.js +47 -0
- package/dist/vendor/devkit/merge-line-files.js +23 -16
- package/dist/vendor/devkit/omega-bin.js +18 -3
- package/dist/vendor/devkit/pack-local.js +391 -0
- package/dist/vendor/devkit/preludes/index.js +120 -0
- package/dist/vendor/devkit/preludes/origin-heal.js +156 -0
- package/dist/vendor/devkit/service-account.js +43 -0
- package/dist/vendor/devkit/ship-plan.js +112 -0
- package/dist/vendor/devkit/signing-env.js +180 -0
- package/dist/vendor/devkit/signing-tree.js +92 -0
- package/dist/vendor/devkit/target-seams.js +142 -0
- package/dist/vendor/devkit/target-secrets.js +235 -50
- package/dist/vendor/devkit/test/esm-only-fixture.js +48 -0
- package/dist/vendor/devkit/test/fixtures/esm-only-package/browser.js +19 -0
- package/dist/vendor/devkit/test/fixtures/esm-only-package/index.js +20 -0
- package/dist/vendor/devkit/test/fixtures/esm-only-package/package.json +13 -0
- package/dist/vendor/monitoring/env.js +20 -10
- package/dist/vendor/monitoring/main.js +1 -1
- package/dist/vendor/monitoring/preload.js +1 -1
- package/dist/vendor/monitoring/renderer.js +1 -1
- package/docs/analytics.md +1 -1
- package/docs/auto-updater.md +5 -5
- package/docs/boot-sequence.md +1 -1
- package/docs/build-system.md +15 -7
- package/docs/client-bridge.md +9 -7
- package/docs/config-schema.md +4 -4
- package/docs/css.md +8 -2
- package/docs/deep-link.md +12 -4
- package/docs/environment-detection.md +32 -24
- package/docs/hooks.md +3 -1
- package/docs/icons.md +7 -7
- package/docs/index.md +61 -23
- package/docs/installer-options.md +24 -21
- package/docs/logging.md +5 -5
- package/docs/releasing.md +25 -17
- package/docs/runner.md +40 -5
- package/docs/shared/brands.md +12 -6
- package/docs/shared/breaking-changes.md +375 -21
- package/docs/shared/config.md +757 -199
- package/docs/shared/deploys.md +194 -91
- package/docs/shared/icons.md +18 -0
- package/docs/shared/local-dev.md +24 -6
- package/docs/shared/logging.md +9 -6
- package/docs/shared/monitoring.md +27 -13
- package/docs/shared/publishing.md +3 -3
- package/docs/shared/rulings.md +2 -2
- package/docs/shared/testing.md +1 -1
- package/docs/shared/theming.md +26 -1
- package/docs/shared/translation.md +49 -7
- package/docs/shared/updates.md +1 -1
- package/docs/signing.md +59 -33
- package/docs/test-framework.md +10 -5
- package/docs/themes.md +15 -1
- package/package.json +18 -12
- package/bin/omega-desktop +0 -2
- package/dist/commands/push-secrets.js +0 -141
- package/dist/test/suites/build/deliver-certs.test.js +0 -95
- package/dist/test/suites/build/derive-signing-env.test.js +0 -122
- package/dist/test/suites/build/push-secrets.test.js +0 -226
- package/dist/test/suites/build/resolve-signing-cert.test.js +0 -342
- package/dist/utils/deliver-certs.js +0 -69
- package/dist/utils/derive-signing-env.js +0 -56
- package/dist/utils/resolve-signing-cert.js +0 -175
- package/dist/vendor/config/desktop-artifacts.js +0 -110
- package/dist/vendor/config/instances.js +0 -208
- /package/dist/defaults/config/icons/{macos → mac}/dmg.png +0 -0
- /package/dist/defaults/config/icons/{macos → mac}/icon.png +0 -0
- /package/dist/defaults/config/icons/{macos → mac}/tray.png +0 -0
package/dist/preload.js
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
// Wires contextBridge so renderer code can call `window.desktop.ipc.invoke(...)` without nodeIntegration.
|
|
4
4
|
|
|
5
5
|
const LoggerLite = require('./lib/logger-lite.js');
|
|
6
|
+
const { ENVIRONMENT_VAR } = require('./vendor/config/environment.js');
|
|
6
7
|
|
|
7
8
|
function Manager() {
|
|
8
9
|
const self = this;
|
|
@@ -27,6 +28,13 @@ Manager.prototype.initialize = async function () {
|
|
|
27
28
|
// Expose a stable, namespaced surface to the renderer.
|
|
28
29
|
// Real impl in pass 2 will type the channel list and proxy storage through here.
|
|
29
30
|
contextBridge.exposeInMainWorld('desktop', {
|
|
31
|
+
// The RUNNING environment, for the one context that cannot read it: a page has
|
|
32
|
+
// no `process`, so its Manager answers `OMEGA_BUILD_JSON.config.environment`,
|
|
33
|
+
// the word the BUILD was for. A test lane boots a production artifact with
|
|
34
|
+
// `OMEGA_ENVIRONMENT=testing`, so the two differ there, and a preload is Node
|
|
35
|
+
// ([#925](https://github.com/Omega-JS-Stack/omega/issues/925)). The renderer
|
|
36
|
+
// bootstrap applies this over the baked word, so it answers what main answers.
|
|
37
|
+
environment: process.env[ENVIRONMENT_VAR] || null,
|
|
30
38
|
ipc: {
|
|
31
39
|
invoke: (channel, payload) => ipcRenderer.invoke(channel, payload),
|
|
32
40
|
// Returns an unsubscribe fn (docs/ipc.md contract — same shape as the
|
package/dist/renderer.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// Renderer-process Manager singleton.
|
|
2
2
|
// Consumer entry (per view): `new (require('@omega.js/desktop/renderer'))().initialize()`.
|
|
3
|
-
// Reads window.OMEGA_BUILD_JSON.config (
|
|
3
|
+
// Reads window.OMEGA_BUILD_JSON.config (the one dist/build.js the view's shell loads, #743), bootstraps @omega.js/client + auth.
|
|
4
4
|
//
|
|
5
5
|
// Auth bridge:
|
|
6
6
|
// - On init, asks main "I'm at UID X (or null), are we in sync?" via desktop:auth:sync-request.
|
|
@@ -32,11 +32,23 @@ Manager.prototype.initialize = async function (overrides) {
|
|
|
32
32
|
const self = this;
|
|
33
33
|
|
|
34
34
|
// Merge runtime overrides on top of build-time config.
|
|
35
|
-
// OMEGA_BUILD_JSON
|
|
36
|
-
//
|
|
37
|
-
|
|
35
|
+
// OMEGA_BUILD_JSON comes off the window: the view's shell loads the ONE
|
|
36
|
+
// `dist/build.js` ahead of this bundle (#743), which is also what makes it
|
|
37
|
+
// readable from DevTools.
|
|
38
|
+
const buildJson = (typeof window !== 'undefined' && window.OMEGA_BUILD_JSON) || {};
|
|
38
39
|
self.config = Object.assign({}, buildJson.config || {}, overrides || {});
|
|
39
40
|
|
|
41
|
+
// The RUNNING environment beats the baked one, exactly as it does in main
|
|
42
|
+
// ([#925](https://github.com/Omega-JS-Stack/omega/issues/925)). A page has no
|
|
43
|
+
// `process`, so `isTesting()` here reads `config.environment`, the word the
|
|
44
|
+
// BUILD was for; the preload does have it and hands it over on the bridge, so a
|
|
45
|
+
// test lane booting a production artifact gets the same answer in this renderer
|
|
46
|
+
// that main gives. No second signal: it is the one input, one context removed.
|
|
47
|
+
const runningEnvironment = (typeof window !== 'undefined' && window.desktop?.environment) || null;
|
|
48
|
+
if (runningEnvironment) {
|
|
49
|
+
self.config.environment = runningEnvironment;
|
|
50
|
+
}
|
|
51
|
+
|
|
40
52
|
self.logger.log('Initializing @omega.js/desktop (renderer)...');
|
|
41
53
|
|
|
42
54
|
// Boot @omega.js/client so Firebase Auth is available in this renderer.
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
// The self-hosted signer's job-started hook
|
|
2
|
+
// ([#875](https://github.com/Omega-JS-Stack/omega/issues/875)): the box refuses
|
|
3
|
+
// any job that is not a trusted dispatch, before the job's first step runs.
|
|
4
|
+
//
|
|
5
|
+
// The runner runs this file through `ACTIONS_RUNNER_HOOK_JOB_STARTED`, an
|
|
6
|
+
// absolute path in the runner's own `<runner dir>\.env`. A nonzero exit fails
|
|
7
|
+
// the job with this script's output and NOTHING of the job runs: no checkout,
|
|
8
|
+
// no install, and no signtool call against the EV token. GitHub documents the
|
|
9
|
+
// hook at https://docs.github.com/en/actions/how-tos/manage-runners/self-hosted-runners/run-scripts
|
|
10
|
+
// (the docs name `.sh` and `.ps1`; the runner ALSO handles `.js`, running it
|
|
11
|
+
// with its OWN bundled node, per `GetDefaultShellForScript` in
|
|
12
|
+
// `src/Runner.Common/HostContext.cs` of actions/runner v2.319.1, the version
|
|
13
|
+
// `omega runner install` pins). So this is one plain Node file, no PowerShell,
|
|
14
|
+
// and the unit suite runs it on any platform.
|
|
15
|
+
//
|
|
16
|
+
// The three checks, every one of which must pass:
|
|
17
|
+
// GITHUB_EVENT_NAME the one trusted dispatch: `workflow_dispatch`
|
|
18
|
+
// GITHUB_REPOSITORY listed in allowed-repos.txt
|
|
19
|
+
// GITHUB_ACTOR listed in allowed-actors.txt
|
|
20
|
+
// All three are the job's standard environment, exported to the hook by the
|
|
21
|
+
// runner's `_contextEnvAllowlist` (`src/Runner.Worker/GitHubContext.cs`:
|
|
22
|
+
// `actor`, `event_name`, `repository`).
|
|
23
|
+
//
|
|
24
|
+
// Node BUILTINS only, on purpose: this file is installed beside the runner, in
|
|
25
|
+
// the runner home, where there is no `node_modules` to resolve `fs-jetpack`
|
|
26
|
+
// from, and the runner's own node runs it, not the box's.
|
|
27
|
+
const fs = require('fs');
|
|
28
|
+
const path = require('path');
|
|
29
|
+
|
|
30
|
+
// ONE trusted event (#923): every publish path (`omega deploy`, a CMS button, a
|
|
31
|
+
// plain HTTP call) dispatches `workflow_dispatch` at the deploy ref, and its
|
|
32
|
+
// actor is the deploy token's user, the same account the box owner signs in as.
|
|
33
|
+
const DISPATCH_EVENTS = ['workflow_dispatch'];
|
|
34
|
+
|
|
35
|
+
const REPOS_FILE = 'allowed-repos.txt';
|
|
36
|
+
const ACTORS_FILE = 'allowed-actors.txt';
|
|
37
|
+
|
|
38
|
+
// One entry per line, `#` comments and blank lines dropped. An unreadable file
|
|
39
|
+
// reads as NO entries, which refuses every job: a guard that cannot read its
|
|
40
|
+
// allow list allows nothing.
|
|
41
|
+
function readList(file) {
|
|
42
|
+
let raw;
|
|
43
|
+
try {
|
|
44
|
+
raw = fs.readFileSync(file, 'utf8');
|
|
45
|
+
} catch (e) {
|
|
46
|
+
return [];
|
|
47
|
+
}
|
|
48
|
+
return raw.split(/\r?\n/)
|
|
49
|
+
.map((line) => line.replace(/#.*$/, '').trim())
|
|
50
|
+
.filter(Boolean);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// `owner/name`, or `owner/*` for every repo of one owner, which is the scope a
|
|
54
|
+
// runner registration already has, and the line `omega runner install` writes.
|
|
55
|
+
// Narrowing it to individual repos is an edit of the file, by hand.
|
|
56
|
+
function repoMatches(repository, entry) {
|
|
57
|
+
const listed = entry.toLowerCase();
|
|
58
|
+
const seen = String(repository || '').toLowerCase();
|
|
59
|
+
if (listed.endsWith('/*')) return seen.startsWith(listed.slice(0, -1));
|
|
60
|
+
return seen === listed;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// The verdict, as data: `{ allowed, line }`, one line whatever the answer, so
|
|
64
|
+
// the caller below is only an exit code and a `console.log`.
|
|
65
|
+
function checkJob(env, lists) {
|
|
66
|
+
const { repos = [], actors = [], reposFile = REPOS_FILE, actorsFile = ACTORS_FILE } = lists || {};
|
|
67
|
+
const event = env.GITHUB_EVENT_NAME || '';
|
|
68
|
+
const repository = env.GITHUB_REPOSITORY || '';
|
|
69
|
+
const actor = env.GITHUB_ACTOR || '';
|
|
70
|
+
|
|
71
|
+
if (!DISPATCH_EVENTS.includes(event)) {
|
|
72
|
+
return { allowed: false, line: `Refusing this job: GITHUB_EVENT_NAME is "${event}", and this runner serves ${DISPATCH_EVENTS.join(' and ')} only.` };
|
|
73
|
+
}
|
|
74
|
+
if (repos.length === 0) {
|
|
75
|
+
return { allowed: false, line: `Refusing this job: ${reposFile} lists no repository, so this runner allows none. Run \`npx omega runner install\` on the box, or add one \`owner/name\` per line.` };
|
|
76
|
+
}
|
|
77
|
+
if (!repos.some((entry) => repoMatches(repository, entry))) {
|
|
78
|
+
return { allowed: false, line: `Refusing this job: GITHUB_REPOSITORY is "${repository}", which is not listed in ${reposFile}.` };
|
|
79
|
+
}
|
|
80
|
+
if (actors.length === 0) {
|
|
81
|
+
return { allowed: false, line: `Refusing this job: ${actorsFile} lists no actor, so this runner allows none. Run \`npx omega runner install\` on the box, or add one login per line.` };
|
|
82
|
+
}
|
|
83
|
+
if (!actors.some((entry) => entry.toLowerCase() === actor.toLowerCase())) {
|
|
84
|
+
return { allowed: false, line: `Refusing this job: GITHUB_ACTOR is "${actor}", which is not listed in ${actorsFile}.` };
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
return { allowed: true, line: `Allowing this job: ${event} on ${repository} by ${actor}.` };
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// The allow lists sit BESIDE this file, in the runner home the install writes
|
|
91
|
+
// them to, so the hook needs no configuration of its own to find them.
|
|
92
|
+
function loadLists(dir) {
|
|
93
|
+
const reposFile = path.join(dir, REPOS_FILE);
|
|
94
|
+
const actorsFile = path.join(dir, ACTORS_FILE);
|
|
95
|
+
return { repos: readList(reposFile), actors: readList(actorsFile), reposFile, actorsFile };
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
if (require.main === module) {
|
|
99
|
+
const verdict = checkJob(process.env, loadLists(__dirname));
|
|
100
|
+
console.log(verdict.line);
|
|
101
|
+
process.exit(verdict.allowed ? 0 : 1);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
module.exports = { checkJob, loadLists, readList, repoMatches, DISPATCH_EVENTS, REPOS_FILE, ACTORS_FILE };
|
|
@@ -6,6 +6,12 @@
|
|
|
6
6
|
brand: {
|
|
7
7
|
id: 'desktop-fixture',
|
|
8
8
|
name: 'Desktop Fixture Consumer',
|
|
9
|
+
// The .deb target needs a homepage and a maintainer (#872): build-config
|
|
10
|
+
// refuses the config without them, so the fixture spells both.
|
|
11
|
+
url: 'https://desktop-fixture.test',
|
|
12
|
+
contact: {
|
|
13
|
+
email: 'support@desktop-fixture.test',
|
|
14
|
+
},
|
|
9
15
|
images: {
|
|
10
16
|
// Empty → build-config falls back to @omega.js/desktop's bundled default icon (no icon file shipped).
|
|
11
17
|
icon: '',
|
|
@@ -27,6 +33,7 @@
|
|
|
27
33
|
cloud: { provider: 'firebase', config: {} },
|
|
28
34
|
targets: {
|
|
29
35
|
desktop: {
|
|
36
|
+
type: 'desktop',
|
|
30
37
|
startup: {
|
|
31
38
|
mode: 'normal',
|
|
32
39
|
},
|
|
@@ -1,7 +1,13 @@
|
|
|
1
1
|
// Minimal main-window renderer entry for the boot-layer self-test fixture.
|
|
2
2
|
const Manager = require('@omega.js/desktop/renderer');
|
|
3
3
|
|
|
4
|
-
new Manager()
|
|
4
|
+
const manager = new Manager();
|
|
5
|
+
manager.initialize();
|
|
6
|
+
|
|
7
|
+
// #925 pins that this renderer answers the lane's environment and not the word
|
|
8
|
+
// baked into the bundle, so the boot inspect needs a handle on the Manager the
|
|
9
|
+
// answer is given on.
|
|
10
|
+
window.__omegaManager = manager;
|
|
5
11
|
|
|
6
12
|
// #111 — pins that the vendored core module resolves through the renderer's
|
|
7
13
|
// `__main_assets__` alias AND runs: with no .omega-shell in this window the
|
|
@@ -19,7 +19,8 @@ const { app, BrowserWindow, ipcMain } = require('electron');
|
|
|
19
19
|
// steals keyboard focus app-wide even when no window is ever focused. This file
|
|
20
20
|
// only initializes its Manager after whenReady (too late: activation fires when
|
|
21
21
|
// the app finishes launching), so flip the accessory policy here at require time.
|
|
22
|
-
// This process is always a test run (runners/electron.js
|
|
22
|
+
// This process is always a test run (runners/electron.js spawns it naming
|
|
23
|
+
// OMEGA_ENVIRONMENT=testing, the one environment input), so
|
|
23
24
|
// the shared predicate needs no Manager. OMEGA_TEST_SHOW=1 opts back into normal
|
|
24
25
|
// activation along with visible windows.
|
|
25
26
|
if (process.platform === 'darwin' && require('../../utils/test-stealth.js')()) {
|
|
@@ -67,10 +67,19 @@ try {
|
|
|
67
67
|
? require(process.env.OMEGA_TEST_RENDERER_MANAGER_PATH)
|
|
68
68
|
: require('@omega.js/desktop/renderer');
|
|
69
69
|
testManager = new RendererManager();
|
|
70
|
-
// Seed config
|
|
71
|
-
//
|
|
70
|
+
// Seed config the way a real BUILD bakes it, so the URL helpers have the same
|
|
71
|
+
// inputs here that they have in a shipped renderer. Tests can mutate this via
|
|
72
|
+
// __emTestManager.config.set().
|
|
73
|
+
// `environment` is the build fact every OMEGA surface bakes
|
|
74
|
+
// ([#817](https://github.com/Omega-JS-Stack/omega/issues/817)), which is
|
|
75
|
+
// what a real renderer (no process.env) answers from.
|
|
76
|
+
// `dev.ports` is the resolved local map, whose floor is @omega.js/config's
|
|
77
|
+
// classic numbers ([#834](https://github.com/Omega-JS-Stack/omega/issues/834)):
|
|
78
|
+
// nothing carries a browser-side copy of them any more, so an artifact
|
|
79
|
+
// without the map cannot reach a localhost port at all.
|
|
72
80
|
testManager.config = {
|
|
73
|
-
|
|
81
|
+
environment: 'production',
|
|
82
|
+
dev: { ports: { ...require('../../vendor/config/index.js').CLASSIC_PORTS } },
|
|
74
83
|
brand: { url: 'https://example.com' },
|
|
75
84
|
cloud: { provider: 'firebase', config: { projectId: 'demo-app', authDomain: 'demo-app.firebaseapp.com' } },
|
|
76
85
|
};
|
|
@@ -28,6 +28,13 @@ const chalk = require('chalk').default;
|
|
|
28
28
|
const distSnapshot = require('../utils/dist-snapshot.js');
|
|
29
29
|
const { renderEvent } = require('./render-event.js');
|
|
30
30
|
|
|
31
|
+
// How long a booted app gets to say anything at all before the run is declared
|
|
32
|
+
// failed. Generous: the app under test is the consumer's real one, cold.
|
|
33
|
+
const DEFAULT_BOOT_TIMEOUT_MS = 60000;
|
|
34
|
+
|
|
35
|
+
// How long the child gets to go down politely before SIGKILL.
|
|
36
|
+
const KILL_GRACE_MS = 2000;
|
|
37
|
+
|
|
31
38
|
async function runBootTests({ tests, suites, projectRoot, frameworkDistRoot }) {
|
|
32
39
|
suites = suites || [];
|
|
33
40
|
|
|
@@ -148,7 +155,7 @@ async function bootProject({ tests, suites, effectiveRoot, frameworkDistRoot })
|
|
|
148
155
|
// OMEGA_TEST_BOOT_SPEC — JSON file with the test definitions
|
|
149
156
|
// Argv would be cleaner but Electron rejects unknown CLI flags.
|
|
150
157
|
const childEnv = Object.assign({}, process.env, {
|
|
151
|
-
|
|
158
|
+
OMEGA_ENVIRONMENT: 'testing', // the one environment input (#817): this lane names it
|
|
152
159
|
OMEGA_TEST_BOOT: '1', // boot-runner-specific dispatch marker (main.js reads this to load the harness instead of doing normal init)
|
|
153
160
|
OMEGA_TEST_BOOT_HARNESS: bootEntry,
|
|
154
161
|
OMEGA_TEST_BOOT_SPEC: specFile,
|
|
@@ -171,8 +178,27 @@ async function bootProject({ tests, suites, effectiveRoot, frameworkDistRoot })
|
|
|
171
178
|
// @omega.js/desktop's main.js detects OMEGA_TEST_BOOT and `require()`s the boot harness itself after init.
|
|
172
179
|
const args = [testApp.appRoot];
|
|
173
180
|
|
|
181
|
+
return runBootChild({ electronBin, args, childEnv, effectiveRoot, specFile, skipEvents, testCount });
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
// Spawn the booted app, render what its harness emits, and end the run.
|
|
185
|
+
//
|
|
186
|
+
// A boot that never produces harness output is a FAILED run with a report, never a
|
|
187
|
+
// hung runner ([#907](https://github.com/Omega-JS-Stack/omega/issues/907)): the child
|
|
188
|
+
// can block inside initialize(), long before main.js requires the harness, so the
|
|
189
|
+
// per-test timeout in harness/boot-entry.js never gets the chance to fire. The report
|
|
190
|
+
// quotes the last line of the booted app's runtime.log, which is the one clue about
|
|
191
|
+
// where it stopped.
|
|
192
|
+
//
|
|
193
|
+
// The budget is IDLE time, never total run time: every harness line rearms it, so a
|
|
194
|
+
// healthy suite that legitimately runs longer than the budget is left alone and only
|
|
195
|
+
// SILENCE for a whole budget fails the run.
|
|
196
|
+
//
|
|
197
|
+
// `spawnFn`, `timeoutMs` and `killGraceMs` are the seams the build-layer suite drives
|
|
198
|
+
// (suites/build/boot-runner-timeout.test.js), the way the deploy modules take an execFn.
|
|
199
|
+
function runBootChild({ electronBin, args, childEnv, effectiveRoot, specFile, skipEvents, testCount, spawnFn = spawn, timeoutMs = bootTimeoutMs(), killGraceMs = KILL_GRACE_MS }) {
|
|
174
200
|
return new Promise((resolve) => {
|
|
175
|
-
const child =
|
|
201
|
+
const child = spawnFn(electronBin, args, {
|
|
176
202
|
cwd: effectiveRoot,
|
|
177
203
|
env: childEnv,
|
|
178
204
|
stdio: ['ignore', 'pipe', 'pipe'],
|
|
@@ -184,44 +210,108 @@ async function bootProject({ tests, suites, effectiveRoot, frameworkDistRoot })
|
|
|
184
210
|
// Suites the module skipped whole: reported before the run they never join.
|
|
185
211
|
skipEvents.forEach((evt) => renderEvent(evt, counts));
|
|
186
212
|
|
|
187
|
-
|
|
213
|
+
let timer = null;
|
|
214
|
+
|
|
215
|
+
// Rearmed by every harness line below, so the budget measures SILENCE.
|
|
216
|
+
function armBudget() {
|
|
217
|
+
clearTimeout(timer);
|
|
218
|
+
timer = setTimeout(() => {
|
|
219
|
+
console.log(chalk.red(` ✗ boot: no harness output after ${Math.round(timeoutMs / 1000)}s; last runtime.log line: "${lastRuntimeLogLine(effectiveRoot)}"`));
|
|
220
|
+
counts.failed += testCount;
|
|
221
|
+
// Detached BEFORE the counts are handed out: a line the child emits
|
|
222
|
+
// while it is being killed must not move numbers already reported.
|
|
223
|
+
cleanup();
|
|
224
|
+
endChild(child, killGraceMs);
|
|
225
|
+
resolve(counts);
|
|
226
|
+
}, timeoutMs);
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
function onStdout(chunk) {
|
|
188
230
|
buffer += chunk.toString();
|
|
189
231
|
let nl;
|
|
190
232
|
while ((nl = buffer.indexOf('\n')) >= 0) {
|
|
191
233
|
const line = buffer.slice(0, nl);
|
|
192
234
|
buffer = buffer.slice(nl + 1);
|
|
193
235
|
if (line.startsWith('__EM_TEST__')) {
|
|
236
|
+
armBudget();
|
|
194
237
|
renderEvent(JSON.parse(line.slice('__EM_TEST__'.length)), counts);
|
|
195
238
|
} else if (process.env.OMEGA_TEST_DEBUG && line.trim().length > 0) {
|
|
196
239
|
process.stdout.write(chalk.gray(` ${line}\n`));
|
|
197
240
|
}
|
|
198
241
|
}
|
|
199
|
-
}
|
|
242
|
+
}
|
|
200
243
|
|
|
201
|
-
|
|
244
|
+
function onStderr(chunk) {
|
|
202
245
|
if (process.env.OMEGA_TEST_DEBUG) {
|
|
203
246
|
process.stderr.write(chalk.gray(`[boot:stderr] ${chunk.toString()}`));
|
|
204
247
|
}
|
|
205
|
-
}
|
|
248
|
+
}
|
|
206
249
|
|
|
207
|
-
|
|
250
|
+
function onError(err) {
|
|
208
251
|
console.log(chalk.red(` ✗ Failed to spawn boot harness: ${err.message}`));
|
|
209
252
|
counts.failed += 1;
|
|
210
253
|
cleanup();
|
|
211
254
|
resolve(counts);
|
|
212
|
-
}
|
|
255
|
+
}
|
|
213
256
|
|
|
214
|
-
|
|
257
|
+
function onExit() {
|
|
215
258
|
cleanup();
|
|
216
259
|
resolve(counts);
|
|
217
|
-
}
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
child.stdout.on('data', onStdout);
|
|
263
|
+
child.stderr.on('data', onStderr);
|
|
264
|
+
child.on('error', onError);
|
|
265
|
+
child.on('exit', onExit);
|
|
266
|
+
|
|
267
|
+
armBudget();
|
|
218
268
|
|
|
219
269
|
function cleanup() {
|
|
270
|
+
clearTimeout(timer);
|
|
271
|
+
child.stdout.removeListener('data', onStdout);
|
|
272
|
+
child.stderr.removeListener('data', onStderr);
|
|
273
|
+
child.removeListener('error', onError);
|
|
274
|
+
child.removeListener('exit', onExit);
|
|
220
275
|
try { fs.unlinkSync(specFile); } catch (_) { /* ignore */ }
|
|
221
276
|
}
|
|
222
277
|
});
|
|
223
278
|
}
|
|
224
279
|
|
|
280
|
+
// The boot budget, overridable with OMEGA_TEST_BOOT_TIMEOUT_MS the way
|
|
281
|
+
// OMEGA_TEST_SKIP_BUILD opts out of the rebuild above.
|
|
282
|
+
function bootTimeoutMs() {
|
|
283
|
+
const override = Number(process.env.OMEGA_TEST_BOOT_TIMEOUT_MS);
|
|
284
|
+
return Number.isFinite(override) && override > 0 ? override : DEFAULT_BOOT_TIMEOUT_MS;
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
// The last non-empty line of the booted app's runtime log: where a blocked boot got to.
|
|
288
|
+
// A boot that died before the logger opened a file has none, which is itself the report.
|
|
289
|
+
function lastRuntimeLogLine(effectiveRoot) {
|
|
290
|
+
let contents;
|
|
291
|
+
try {
|
|
292
|
+
contents = fs.readFileSync(path.join(effectiveRoot, 'logs', 'runtime.log'), 'utf8');
|
|
293
|
+
} catch (_) {
|
|
294
|
+
return '(no runtime.log)';
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
const lines = contents.split('\n');
|
|
298
|
+
for (let i = lines.length - 1; i >= 0; i -= 1) {
|
|
299
|
+
if (lines[i].trim().length > 0) return lines[i].trim();
|
|
300
|
+
}
|
|
301
|
+
return '(runtime.log is empty)';
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
// End a child that outlived its budget. Polite first, then SIGKILL: the direct child
|
|
305
|
+
// is the orphan the hang used to leave behind. The grace timer is unref'd so it never
|
|
306
|
+
// holds the runner open on its own.
|
|
307
|
+
function endChild(child, killGraceMs) {
|
|
308
|
+
try { child.kill(); } catch (_) { /* already gone */ }
|
|
309
|
+
const grace = setTimeout(() => {
|
|
310
|
+
try { child.kill('SIGKILL'); } catch (_) { /* already gone */ }
|
|
311
|
+
}, killGraceMs);
|
|
312
|
+
if (typeof grace.unref === 'function') grace.unref();
|
|
313
|
+
}
|
|
314
|
+
|
|
225
315
|
// Serialize the boot-bound renderer suites (`view: '<name>'`) for the spec file, the same
|
|
226
316
|
// shape main-entry.js ships to the harness page (plus the view name). A suite the module
|
|
227
317
|
// skipped whole runs nothing and reports its test count as skipped, exactly as the harness
|
|
@@ -411,4 +501,4 @@ function removeFixtureDeps(links) {
|
|
|
411
501
|
}
|
|
412
502
|
}
|
|
413
503
|
|
|
414
|
-
module.exports = { runBootTests };
|
|
504
|
+
module.exports = { runBootTests, runBootChild };
|
|
@@ -36,7 +36,7 @@ function runElectronTests({ harnessEntry, suiteFiles, rendererSuiteFiles, filter
|
|
|
36
36
|
}
|
|
37
37
|
|
|
38
38
|
const childEnv = Object.assign({}, process.env, {
|
|
39
|
-
|
|
39
|
+
OMEGA_ENVIRONMENT: 'testing', // the one environment input (#817): this lane names it
|
|
40
40
|
ELECTRON_NO_ATTACH_CONSOLE: '1',
|
|
41
41
|
NODE_OPTIONS: '',
|
|
42
42
|
});
|
|
@@ -95,5 +95,59 @@ module.exports = defineCases({
|
|
|
95
95
|
expect(bundle.includes('data-shell-dismiss')).toBe(true);
|
|
96
96
|
},
|
|
97
97
|
},
|
|
98
|
+
|
|
99
|
+
{
|
|
100
|
+
// #925: the lane spawns this child with OMEGA_ENVIRONMENT=testing and the
|
|
101
|
+
// artifact it boots was BUILT production, so the booted app used to answer
|
|
102
|
+
// `production` and every isTesting() gate in it was silently off. The proof
|
|
103
|
+
// is a gate that writes to the log: auth persistence resolves to `none` in a
|
|
104
|
+
// test run alone, and that is the line the booted app records. (The emulator
|
|
105
|
+
// line the bridge logs next is out of reach here, because the fixture's
|
|
106
|
+
// `cloud.config` is empty and this boot never initializes Firebase auth.)
|
|
107
|
+
description: 'the booted app runs in the lane environment, not the one baked into its bundle (#925)',
|
|
108
|
+
inspect: async ({ manager, expect, projectRoot }) => {
|
|
109
|
+
const fs = require('fs');
|
|
110
|
+
const path = require('path');
|
|
111
|
+
|
|
112
|
+
expect(manager.isTesting()).toBe(true);
|
|
113
|
+
expect(manager.config.environment).toBe('production'); // the artifact IS a production build
|
|
114
|
+
|
|
115
|
+
const log = fs.readFileSync(path.join(projectRoot, 'logs', 'runtime.log'), 'utf8');
|
|
116
|
+
expect(log.includes('auth persistence: none (test mode)')).toBe(true);
|
|
117
|
+
},
|
|
118
|
+
},
|
|
119
|
+
|
|
120
|
+
{
|
|
121
|
+
// #925: a page has no `process`, so its Manager reads the baked word. The
|
|
122
|
+
// preload hands the running one over on `window.desktop`, and the renderer
|
|
123
|
+
// bootstrap applies it, so this window answers what main answers.
|
|
124
|
+
description: 'the main window renderer answers the lane environment too (#925)',
|
|
125
|
+
inspect: async ({ manager, expect }) => {
|
|
126
|
+
const { BrowserWindow } = require('electron');
|
|
127
|
+
|
|
128
|
+
// The window is created in the consumer's initialize().then(), and its
|
|
129
|
+
// bootstrap sets the config a moment later; poll for both, the way the
|
|
130
|
+
// view test above polls for the window.
|
|
131
|
+
let answer = null;
|
|
132
|
+
let win = null;
|
|
133
|
+
for (let i = 0; i < 40; i++) {
|
|
134
|
+
win = manager.windows.get('main') || BrowserWindow.getAllWindows()[0];
|
|
135
|
+
if (win && !win.isDestroyed() && !win.webContents.isLoading()) {
|
|
136
|
+
answer = await win.webContents.executeJavaScript(
|
|
137
|
+
'window.__omegaManager && window.__omegaManager.config ? window.__omegaManager.getEnvironment() : null',
|
|
138
|
+
);
|
|
139
|
+
if (answer) break;
|
|
140
|
+
}
|
|
141
|
+
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
const baked = await win.webContents.executeJavaScript('window.OMEGA_BUILD_JSON.config.environment');
|
|
145
|
+
const bridged = await win.webContents.executeJavaScript('window.desktop.environment');
|
|
146
|
+
|
|
147
|
+
expect(baked).toBe('production'); // what the build baked
|
|
148
|
+
expect(bridged).toBe('testing'); // what the preload read off the lane
|
|
149
|
+
expect(answer).toBe('testing'); // what the renderer's Manager answers
|
|
150
|
+
},
|
|
151
|
+
},
|
|
98
152
|
],
|
|
99
153
|
});
|
|
@@ -31,7 +31,7 @@ function stageConsumer(overrides = {}, desktopOverrides = {}) {
|
|
|
31
31
|
brand: { id: 'testapp', name: 'TestApp', images: { icon: '' } },
|
|
32
32
|
app: { appId: 'com.test.app', productName: 'TestApp' },
|
|
33
33
|
};
|
|
34
|
-
const merged = { ...baseConfig, ...overrides, targets: { desktop: desktopOverrides } };
|
|
34
|
+
const merged = { ...baseConfig, ...overrides, targets: { desktop: { type: 'desktop', ...desktopOverrides } } };
|
|
35
35
|
jetpack.write(path.join(tmp, 'config', 'omega.json5'), JSON.stringify(merged));
|
|
36
36
|
|
|
37
37
|
return tmp;
|
|
@@ -42,7 +42,12 @@ function runAudit(cwd, env = {}) {
|
|
|
42
42
|
const origCwd = process.cwd();
|
|
43
43
|
// Force build/publish env off — minimal scaffolds don't include icons/cert files.
|
|
44
44
|
// Tests that want to exercise publish-mode checks pass env explicitly.
|
|
45
|
-
|
|
45
|
+
// OMEGA_ENVIRONMENT is NAMED here, not blanked: it is the ONE environment
|
|
46
|
+
// input ([#817](https://github.com/Omega-JS-Stack/omega/issues/817)), every
|
|
47
|
+
// lane sets it, and an audit run is a dev-lane read. Naming it also keeps
|
|
48
|
+
// the value from leaking between cases, because src/build.js writes it at
|
|
49
|
+
// load from whichever lane flags were set when it was required.
|
|
50
|
+
const baseEnv = { OMEGA_ENVIRONMENT: 'development', OMEGA_BUILD_MODE: '', OMEGA_IS_PUBLISH: '', OMEGA_IS_SERVER: '' };
|
|
46
51
|
const allEnv = { ...baseEnv, ...env };
|
|
47
52
|
const origEnv = {};
|
|
48
53
|
for (const k of Object.keys(allEnv)) {
|
|
@@ -64,6 +69,22 @@ function runAudit(cwd, env = {}) {
|
|
|
64
69
|
});
|
|
65
70
|
}
|
|
66
71
|
|
|
72
|
+
// The audit REPORTS through the logger, so a case that reads the report reads
|
|
73
|
+
// the console the logger writes to (warnings on `warn`, the ok line on `log`).
|
|
74
|
+
async function runAuditCapturing(cwd, env = {}) {
|
|
75
|
+
const lines = [];
|
|
76
|
+
const original = { log: console.log, warn: console.warn };
|
|
77
|
+
console.log = (...args) => lines.push(args.join(' '));
|
|
78
|
+
console.warn = (...args) => lines.push(args.join(' '));
|
|
79
|
+
|
|
80
|
+
try {
|
|
81
|
+
const err = await runAudit(cwd, env);
|
|
82
|
+
return { err, output: lines.join('\n') };
|
|
83
|
+
} finally {
|
|
84
|
+
Object.assign(console, original);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
67
88
|
module.exports = defineCases({
|
|
68
89
|
type: 'suite',
|
|
69
90
|
layer: 'build',
|
|
@@ -81,6 +102,24 @@ module.exports = defineCases({
|
|
|
81
102
|
}
|
|
82
103
|
},
|
|
83
104
|
},
|
|
105
|
+
{
|
|
106
|
+
// #911: the task took only `errors` off validateConfig, so a consumer
|
|
107
|
+
// read `audit ok (0 warnings)` while the validator's list named real
|
|
108
|
+
// findings (a key the schema does not declare, which is what a typo
|
|
109
|
+
// looks like). The report is both lists now.
|
|
110
|
+
name: 'prints the validator\'s warnings and counts them (#911)',
|
|
111
|
+
run: async (ctx) => {
|
|
112
|
+
const tmp = stageConsumer({ brand: { id: 'testapp', name: 'TestApp' } }, { notAKey: true });
|
|
113
|
+
try {
|
|
114
|
+
const { err, output } = await runAuditCapturing(tmp);
|
|
115
|
+
ctx.expect(err).toBeNull();
|
|
116
|
+
ctx.expect(output).toMatch(/notAKey/);
|
|
117
|
+
ctx.expect(output).toMatch(/audit ok \(1 warning\)/);
|
|
118
|
+
} finally {
|
|
119
|
+
fs.rmSync(tmp, { recursive: true, force: true });
|
|
120
|
+
}
|
|
121
|
+
},
|
|
122
|
+
},
|
|
84
123
|
{
|
|
85
124
|
name: 'fails when brand.id is missing',
|
|
86
125
|
run: async (ctx) => {
|
|
@@ -121,10 +160,10 @@ module.exports = defineCases({
|
|
|
121
160
|
},
|
|
122
161
|
},
|
|
123
162
|
{
|
|
124
|
-
name: 'publish mode:
|
|
163
|
+
name: 'publish mode: a bare `releases: {}` passes, since the repo derives as `<brand.id>-releases` (#799, #883)',
|
|
125
164
|
run: async (ctx) => {
|
|
126
165
|
const tmp = stageConsumer(
|
|
127
|
-
{ brand: { id: 'acme', name: 'Acme', images: { icon: 'icon.png' } }, repo: {
|
|
166
|
+
{ brand: { id: 'acme', name: 'Acme', images: { icon: 'icon.png' } }, repo: { provider: 'github', org: 'Acme-Org' } },
|
|
128
167
|
{ releases: {} },
|
|
129
168
|
);
|
|
130
169
|
jetpack.write(path.join(tmp, 'icon.png'), 'stub');
|
|
@@ -219,12 +258,12 @@ module.exports = defineCases({
|
|
|
219
258
|
run: async (ctx) => {
|
|
220
259
|
const tmp = stageConsumer(
|
|
221
260
|
{ brand: { id: 'testapp', name: 'TestApp' }, app: { appId: 'com.test.app', productName: 'TestApp' } },
|
|
222
|
-
{ platforms: {
|
|
261
|
+
{ platforms: { windows: { signing: { strategy: 'banana' } } } },
|
|
223
262
|
);
|
|
224
263
|
try {
|
|
225
264
|
const err = await runAudit(tmp);
|
|
226
265
|
ctx.expect(err).toBeDefined();
|
|
227
|
-
ctx.expect(err.message).toMatch(/platforms\.
|
|
266
|
+
ctx.expect(err.message).toMatch(/platforms\.windows\.signing\.strategy "banana" is not allowed/);
|
|
228
267
|
} finally {
|
|
229
268
|
fs.rmSync(tmp, { recursive: true, force: true });
|
|
230
269
|
}
|