@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
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
// Build-layer tests for the canonical build verbs (build / package / publish).
|
|
2
2
|
// The synced projectScripts are thin `omega <verb>` aliases, so each verb must
|
|
3
|
-
// run the pipeline ITSELF
|
|
3
|
+
// run the pipeline ITSELF (clean, gulp task) and never shell back to
|
|
4
4
|
// `npm run build` / `npm run publish` (that would recurse forever).
|
|
5
5
|
//
|
|
6
6
|
// There is no `setup` step (#675): the local scaffold runs inside the gulp
|
|
7
|
-
// `defaults` task.
|
|
7
|
+
// `defaults` task. Nothing COPIES signing material any more (#891): the tree
|
|
8
|
+
// is read in place and the env load derived the paths to it.
|
|
8
9
|
|
|
9
10
|
const path = require('path');
|
|
10
11
|
const fs = require('fs');
|
|
@@ -26,14 +27,18 @@ function recorder(log) {
|
|
|
26
27
|
const record = (type) => (options, step) => { log.push(step.task ? `${type}:${step.task}` : type); };
|
|
27
28
|
return {
|
|
28
29
|
clean: record('clean'),
|
|
29
|
-
|
|
30
|
+
'ship-keys': record('ship-keys'),
|
|
30
31
|
'validate-certs': record('validate-certs'),
|
|
31
32
|
gulp: record('gulp'),
|
|
32
33
|
};
|
|
33
34
|
}
|
|
34
35
|
|
|
35
36
|
async function withEnv(run) {
|
|
36
|
-
|
|
37
|
+
// OMEGA_ENVIRONMENT rides the list because it is the ONE environment input
|
|
38
|
+
// ([#817](https://github.com/Omega-JS-Stack/omega/issues/817)) and
|
|
39
|
+
// src/build.js WRITES it at load from the lane, so clearing a lane flag
|
|
40
|
+
// without clearing it leaves the previous lane's word in the process.
|
|
41
|
+
const keys = ['OMEGA_ENVIRONMENT', 'OMEGA_BUILD_MODE', 'OMEGA_IS_PUBLISH'];
|
|
37
42
|
const previous = keys.map((key) => [key, process.env[key]]);
|
|
38
43
|
keys.forEach((key) => delete process.env[key]);
|
|
39
44
|
try {
|
|
@@ -51,21 +56,21 @@ module.exports = defineCases({
|
|
|
51
56
|
description: 'build verbs — the CLI owns the pipeline and its env flags',
|
|
52
57
|
tests: [
|
|
53
58
|
{
|
|
54
|
-
name: 'build: OMEGA_BUILD_MODE + clean →
|
|
59
|
+
name: 'build: OMEGA_BUILD_MODE + clean → gulp build',
|
|
55
60
|
run: (ctx) => {
|
|
56
61
|
const plan = build.plan({});
|
|
57
62
|
ctx.expect(plan.env.OMEGA_BUILD_MODE).toBe('true');
|
|
58
63
|
ctx.expect(plan.steps.map((s) => (s.task ? `${s.type}:${s.task}` : s.type)))
|
|
59
|
-
.toEqual(['clean', '
|
|
64
|
+
.toEqual(['clean', 'gulp:build']);
|
|
60
65
|
},
|
|
61
66
|
},
|
|
62
67
|
{
|
|
63
|
-
name: 'package: OMEGA_BUILD_MODE + clean →
|
|
68
|
+
name: 'package: OMEGA_BUILD_MODE + clean → gulp packageBuild',
|
|
64
69
|
run: (ctx) => {
|
|
65
70
|
const plan = pkg.plan({});
|
|
66
71
|
ctx.expect(plan.env.OMEGA_BUILD_MODE).toBe('true');
|
|
67
72
|
ctx.expect(plan.steps.map((s) => (s.task ? `${s.type}:${s.task}` : s.type)))
|
|
68
|
-
.toEqual(['clean', '
|
|
73
|
+
.toEqual(['clean', 'gulp:packageBuild']);
|
|
69
74
|
},
|
|
70
75
|
},
|
|
71
76
|
{
|
|
@@ -73,26 +78,54 @@ module.exports = defineCases({
|
|
|
73
78
|
run: (ctx) => {
|
|
74
79
|
const plan = pkg.plan({ quick: true });
|
|
75
80
|
ctx.expect(plan.steps.map((s) => (s.task ? `${s.type}:${s.task}` : s.type)))
|
|
76
|
-
.toEqual(['clean', '
|
|
77
|
-
ctx.expect(pkg.plan({ q: true }).steps[
|
|
81
|
+
.toEqual(['clean', 'gulp:packageQuick']);
|
|
82
|
+
ctx.expect(pkg.plan({ q: true }).steps[1].task).toBe('packageQuick');
|
|
78
83
|
},
|
|
79
84
|
},
|
|
80
85
|
{
|
|
81
|
-
name: 'publish: both flags +
|
|
86
|
+
name: 'publish: both flags + ship-keys → validate-certs → gulp publish (no clean)',
|
|
82
87
|
run: (ctx) => {
|
|
83
88
|
const plan = publish.plan({});
|
|
84
89
|
ctx.expect(plan.env.OMEGA_BUILD_MODE).toBe('true');
|
|
85
90
|
ctx.expect(plan.env.OMEGA_IS_PUBLISH).toBe('true');
|
|
86
91
|
ctx.expect(plan.steps.map((s) => (s.task ? `${s.type}:${s.task}` : s.type)))
|
|
87
|
-
.toEqual(['
|
|
92
|
+
.toEqual(['ship-keys', 'validate-certs', 'gulp:publish']);
|
|
88
93
|
},
|
|
89
94
|
},
|
|
90
95
|
{
|
|
91
|
-
name: 'publish --local: clean →
|
|
96
|
+
name: 'publish --local: clean → ship-keys → validate-certs → gulp publish',
|
|
92
97
|
run: (ctx) => {
|
|
93
98
|
const plan = publish.plan({ local: true });
|
|
94
99
|
ctx.expect(plan.steps.map((s) => (s.task ? `${s.type}:${s.task}` : s.type)))
|
|
95
|
-
.toEqual(['clean', '
|
|
100
|
+
.toEqual(['clean', 'ship-keys', 'validate-certs', 'gulp:publish']);
|
|
101
|
+
},
|
|
102
|
+
},
|
|
103
|
+
// #867: a shipped format with no credential is a release that dies on a
|
|
104
|
+
// runner, so publish refuses FIRST, before a minute of build time, naming
|
|
105
|
+
// the key, the declaration that requires it, and the walk that collects it.
|
|
106
|
+
// The SAME JS runs in both lanes: CI's `npm run release:local` is this verb.
|
|
107
|
+
{
|
|
108
|
+
name: 'publish refuses a declared format with no ship credential, naming the key and the walk (#867)',
|
|
109
|
+
run: (ctx) => {
|
|
110
|
+
const { assertShipKeys } = require(path.join(__dirname, '..', '..', '..', 'utils', 'ship-keys.js'));
|
|
111
|
+
const config = { platforms: { linux: { formats: { snap: { channels: ['stable'] } } } } };
|
|
112
|
+
|
|
113
|
+
let message = '';
|
|
114
|
+
try {
|
|
115
|
+
assertShipKeys({ config, env: {} });
|
|
116
|
+
} catch (error) {
|
|
117
|
+
message = error.message;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
ctx.expect(message).toContain('SNAPCRAFT_STORE_CREDENTIALS (required by platforms.linux.formats.snap)');
|
|
121
|
+
ctx.expect(message).toContain('omega manage --service publishing');
|
|
122
|
+
|
|
123
|
+
// With the credential, the same declaration ships
|
|
124
|
+
ctx.expect(assertShipKeys({ config, env: { SNAPCRAFT_STORE_CREDENTIALS: 'blob' } }).length > 0).toBe(true);
|
|
125
|
+
|
|
126
|
+
// And a brand that never mentions the snap owes nothing: the default
|
|
127
|
+
// format is on, but nothing in its config makes the credential due
|
|
128
|
+
ctx.expect(assertShipKeys({ config: {}, env: {} }).length > 0).toBe(true);
|
|
96
129
|
},
|
|
97
130
|
},
|
|
98
131
|
{
|
|
@@ -104,7 +137,7 @@ module.exports = defineCases({
|
|
|
104
137
|
ctx.expect(process.env.OMEGA_BUILD_MODE).toBe('true');
|
|
105
138
|
ctx.expect(process.env.OMEGA_IS_PUBLISH).toBe('true');
|
|
106
139
|
});
|
|
107
|
-
ctx.expect(log).toEqual(['clean', '
|
|
140
|
+
ctx.expect(log).toEqual(['clean', 'ship-keys', 'validate-certs', 'gulp:publish']);
|
|
108
141
|
},
|
|
109
142
|
},
|
|
110
143
|
{
|
|
@@ -17,6 +17,7 @@ const jetpack = require('fs-jetpack');
|
|
|
17
17
|
const yaml = require('js-yaml');
|
|
18
18
|
|
|
19
19
|
const { copyDefaults } = require('../../../commands/lib/ensure-target.js');
|
|
20
|
+
const { composeWorkflow } = require('../../../vendor/devkit/ci-workflows.js');
|
|
20
21
|
const defineCases = require('../../../vendor/devkit/test/define-cases.js');
|
|
21
22
|
|
|
22
23
|
// GitHub takes `needs` as a string or as a list; the graph question is the same.
|
|
@@ -51,5 +52,194 @@ module.exports = defineCases({
|
|
|
51
52
|
ctx.expect(needsOf(jobs['windows-strategy'])).toContain('build');
|
|
52
53
|
},
|
|
53
54
|
},
|
|
55
|
+
// The Windows legs of this workflow force `shell: cmd`
|
|
56
|
+
// ([#872](https://github.com/Omega-JS-Stack/omega/issues/872)), and cmd cannot
|
|
57
|
+
// execute the extension-less `sfw` Socket's action caches on Windows: every
|
|
58
|
+
// windows job died on `'sfw' is not recognized`. devkit renders the shim that
|
|
59
|
+
// copies the binary to `sfw.exe` beside the action step, so the check is on the
|
|
60
|
+
// WRITTEN file, standalone and composed alike.
|
|
61
|
+
{
|
|
62
|
+
name: 'every job that runs sfw carries the Windows cmd shim, standalone and composed (#872)',
|
|
63
|
+
run: async (ctx) => {
|
|
64
|
+
const tmp = fs.mkdtempSync(path.join(os.tmpdir(), 'desktop-workflow-firewall-'));
|
|
65
|
+
await copyDefaults(tmp);
|
|
66
|
+
const scaffolded = jetpack.read(path.join(tmp, '.github', 'workflows', 'build.yml'));
|
|
67
|
+
|
|
68
|
+
for (const workflow of [scaffolded, composeWorkflow(scaffolded, { targetPath: 'targets/desktop', targetName: 'desktop' })]) {
|
|
69
|
+
// A step the shim broke would not parse at all, so the parse IS an assertion
|
|
70
|
+
const { jobs } = yaml.load(workflow);
|
|
71
|
+
|
|
72
|
+
for (const job of Object.values(jobs)) {
|
|
73
|
+
const steps = job.steps || [];
|
|
74
|
+
const install = steps.findIndex((step) => /\bsfw npm(?:\.cmd)? (ci|install)\b/.test(String(step.run || '')));
|
|
75
|
+
if (install === -1) {
|
|
76
|
+
continue;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
const firewall = steps.findIndex((step) => String(step.uses || '').startsWith('SocketDev/action@'));
|
|
80
|
+
const shim = steps.findIndex((step) => String(step.run || '').includes('firewall-path-binary'));
|
|
81
|
+
|
|
82
|
+
ctx.expect(firewall).not.toBe(-1);
|
|
83
|
+
ctx.expect(shim).not.toBe(-1);
|
|
84
|
+
ctx.expect(firewall < shim && shim < install).toBe(true);
|
|
85
|
+
ctx.expect(steps[shim].shell).toBe('cmd');
|
|
86
|
+
ctx.expect(steps[shim].if).toContain('Windows');
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
fs.rmSync(tmp, { recursive: true, force: true });
|
|
91
|
+
},
|
|
92
|
+
},
|
|
93
|
+
// The workflow env carries the mac credentials as the base64 secrets themselves,
|
|
94
|
+
// and only the mac job decodes them to disk
|
|
95
|
+
// ([#872](https://github.com/Omega-JS-Stack/omega/issues/872)). A leg that never
|
|
96
|
+
// signs for mac must not hold them: electron-builder would sign with the cert,
|
|
97
|
+
// and the precheck would be handed a .p8 no filesystem can answer for.
|
|
98
|
+
{
|
|
99
|
+
name: 'the mac credentials are blanked on the linux and windows legs, and gated on mac (#872)',
|
|
100
|
+
run: async (ctx) => {
|
|
101
|
+
const tmp = fs.mkdtempSync(path.join(os.tmpdir(), 'desktop-workflow-creds-'));
|
|
102
|
+
await copyDefaults(tmp);
|
|
103
|
+
const { jobs } = yaml.load(jetpack.read(path.join(tmp, '.github', 'workflows', 'build.yml')));
|
|
104
|
+
const steps = jobs.build.steps;
|
|
105
|
+
|
|
106
|
+
const stepOn = (os_, command) => steps.find((step) => String(step.if || '').includes(os_) && String(step.run || '').includes(command));
|
|
107
|
+
|
|
108
|
+
const linux = stepOn('ubuntu-latest', 'npm run release:local');
|
|
109
|
+
ctx.expect(linux.env.CSC_LINK).toBe('');
|
|
110
|
+
ctx.expect(linux.env.APPLE_API_KEY).toBe('');
|
|
111
|
+
|
|
112
|
+
const windows = stepOn('windows-latest', 'npm run package');
|
|
113
|
+
ctx.expect(windows.env.CSC_LINK).toBe('');
|
|
114
|
+
ctx.expect(windows.env.APPLE_API_KEY).toBe('');
|
|
115
|
+
|
|
116
|
+
// The mac leg is the one that decodes them, and it points at each file only
|
|
117
|
+
// when that secret EXISTS (#872): decoding an empty secret writes an empty
|
|
118
|
+
// file and `security import` of one dies with "parameters not valid".
|
|
119
|
+
// A MISSING one exits 1 (#891): a mac build this framework ships is signed
|
|
120
|
+
// and notarized, and the message names the command that fixes it.
|
|
121
|
+
const decode = stepOn('macos-latest', 'base64 --decode');
|
|
122
|
+
ctx.expect(decode.run).toContain('if [ -n "${{ secrets.CSC_LINK }}" ]; then');
|
|
123
|
+
ctx.expect(decode.run).toContain('if [ -n "${{ secrets.APPLE_API_KEY }}" ]; then');
|
|
124
|
+
// The standalone verb is gone (#891): the deploy precheck pushes them.
|
|
125
|
+
ctx.expect(decode.run).toContain('No CSC_LINK secret: run omega deploy from targets/desktop');
|
|
126
|
+
ctx.expect(decode.run).toContain('No APPLE_API_KEY secret: run omega deploy from targets/desktop');
|
|
127
|
+
ctx.expect(decode.run).not.toContain('push-secrets');
|
|
128
|
+
ctx.expect(decode.run.match(/exit 1/g).length).toBe(2);
|
|
129
|
+
ctx.expect(decode.run).not.toContain('this build will not be signed');
|
|
130
|
+
|
|
131
|
+
const mac = stepOn('macos-latest', 'npm run release:local');
|
|
132
|
+
ctx.expect(mac.env.CSC_LINK).toBe("${{ secrets.CSC_LINK != '' && 'config/certs/dev-id.p12' || '' }}");
|
|
133
|
+
ctx.expect(mac.env.APPLE_API_KEY).toBe("${{ secrets.APPLE_API_KEY != '' && 'config/certs/AuthKey.p8' || '' }}");
|
|
134
|
+
|
|
135
|
+
fs.rmSync(tmp, { recursive: true, force: true });
|
|
136
|
+
},
|
|
137
|
+
},
|
|
138
|
+
// The firewall spawns the command it is given LITERALLY on Windows, with no
|
|
139
|
+
// PATHEXT resolution, and the only `npm` on a Windows runner's PATH is
|
|
140
|
+
// `npm.cmd` (#872): under cmd, bare `npm` is "Command 'npm' not found in PATH".
|
|
141
|
+
{
|
|
142
|
+
name: 'every cmd-shelled install names npm.cmd, every other one stays bare npm (#872)',
|
|
143
|
+
run: async (ctx) => {
|
|
144
|
+
const tmp = fs.mkdtempSync(path.join(os.tmpdir(), 'desktop-workflow-npmcmd-'));
|
|
145
|
+
await copyDefaults(tmp);
|
|
146
|
+
const { jobs } = yaml.load(jetpack.read(path.join(tmp, '.github', 'workflows', 'build.yml')));
|
|
147
|
+
|
|
148
|
+
for (const job of Object.values(jobs)) {
|
|
149
|
+
const jobShell = job.defaults?.run?.shell;
|
|
150
|
+
|
|
151
|
+
for (const step of job.steps || []) {
|
|
152
|
+
const run = String(step.run || '');
|
|
153
|
+
if (!run.includes('sfw npm')) {
|
|
154
|
+
continue;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
const underCmd = (step.shell || jobShell) === 'cmd';
|
|
158
|
+
ctx.expect(run.includes('sfw npm.cmd ')).toBe(underCmd);
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
// And the two legs that DO run under cmd are still there to be checked.
|
|
163
|
+
ctx.expect(jobs.build.steps.some((step) => step.shell === 'cmd' && String(step.run || '').includes('sfw npm.cmd ci'))).toBe(true);
|
|
164
|
+
ctx.expect(jobs['windows-sign'].defaults.run.shell).toBe('cmd');
|
|
165
|
+
// The self-hosted signer installs WITHOUT the firewall (#872): its network does
|
|
166
|
+
// not reach Socket's API and the firewall fails closed, while the lockfile it
|
|
167
|
+
// installs was screened by the hosted build jobs of the same run.
|
|
168
|
+
ctx.expect(jobs['windows-sign'].steps.some((step) => String(step.run || '').trim() === 'npm.cmd ci')).toBe(true);
|
|
169
|
+
ctx.expect(jobs['windows-sign'].steps.some((step) => String(step.run || '').includes('sfw '))).toBe(false);
|
|
170
|
+
ctx.expect(jobs['windows-sign'].steps.some((step) => String(step.uses || '').startsWith('SocketDev/action@'))).toBe(false);
|
|
171
|
+
|
|
172
|
+
fs.rmSync(tmp, { recursive: true, force: true });
|
|
173
|
+
},
|
|
174
|
+
},
|
|
175
|
+
// The trigger half of the signer guard
|
|
176
|
+
// ([#875](https://github.com/Omega-JS-Stack/omega/issues/875)): the box that
|
|
177
|
+
// holds the EV token is reachable by a DISPATCH and nothing else, so a
|
|
178
|
+
// `push` or `pull_request` trigger added to this file later has to SKIP the
|
|
179
|
+
// sign job rather than sign a stray build with it.
|
|
180
|
+
{
|
|
181
|
+
name: 'the sign job runs on a dispatch only, and a skipped sign job still reaches finalize (#875)',
|
|
182
|
+
run: async (ctx) => {
|
|
183
|
+
const tmp = fs.mkdtempSync(path.join(os.tmpdir(), 'desktop-workflow-signer-guard-'));
|
|
184
|
+
await copyDefaults(tmp);
|
|
185
|
+
const { jobs } = yaml.load(jetpack.read(path.join(tmp, '.github', 'workflows', 'build.yml')));
|
|
186
|
+
|
|
187
|
+
const gate = jobs['windows-sign'].if;
|
|
188
|
+
// The ONE trusted event (#923), ANDed onto the rest so the strategy and
|
|
189
|
+
// platform gates still hold on a dispatch.
|
|
190
|
+
ctx.expect(gate).toContain("&& github.event_name == 'workflow_dispatch'");
|
|
191
|
+
ctx.expect(gate).not.toContain('repository_dispatch');
|
|
192
|
+
ctx.expect(gate).toContain("needs.windows-strategy.outputs.strategy != 'local'");
|
|
193
|
+
|
|
194
|
+
// A SKIP, never a failure: finalize reaches its `if` through `always()`
|
|
195
|
+
// and gates on the BUILD's result, so the unsigned Windows artifact the
|
|
196
|
+
// build job uploaded still finishes the run.
|
|
197
|
+
ctx.expect(jobs.finalize.if).toContain('always()');
|
|
198
|
+
ctx.expect(jobs.finalize.if).toContain("needs.build.result == 'success'");
|
|
199
|
+
ctx.expect(jobs.finalize.if).not.toContain('needs.windows-sign.result');
|
|
200
|
+
|
|
201
|
+
fs.rmSync(tmp, { recursive: true, force: true });
|
|
202
|
+
},
|
|
203
|
+
},
|
|
204
|
+
// The template matches its three siblings in shape
|
|
205
|
+
// ([#880](https://github.com/Omega-JS-Stack/omega/issues/880)): the same
|
|
206
|
+
// header, the same one dispatch trigger, a version log, and a bound on
|
|
207
|
+
// every job. Read off the scaffolded render, like every case above.
|
|
208
|
+
{
|
|
209
|
+
name: 'the scaffolded workflow carries the sibling header, the one dispatch trigger, a version log and a timeout per job (#880)',
|
|
210
|
+
run: async (ctx) => {
|
|
211
|
+
const tmp = fs.mkdtempSync(path.join(os.tmpdir(), 'desktop-workflow-shape-'));
|
|
212
|
+
await copyDefaults(tmp);
|
|
213
|
+
const scaffolded = jetpack.read(path.join(tmp, '.github', 'workflows', 'build.yml'));
|
|
214
|
+
const doc = yaml.load(scaffolded);
|
|
215
|
+
|
|
216
|
+
// The header opens the file, above `name:`, the way backend's does.
|
|
217
|
+
ctx.expect(scaffolded.startsWith('# Deliberate deploys (D13):')).toBe(true);
|
|
218
|
+
ctx.expect(scaffolded).toContain("Regenerated by every verb's ensureTarget");
|
|
219
|
+
|
|
220
|
+
// The one dispatch trigger (#923), carrying the `platforms` input.
|
|
221
|
+
// js-yaml 4 keeps `on` a plain string key (YAML 1.2 drops the
|
|
222
|
+
// `on`/`off` booleans YAML 1.1 had), so `doc.on` is the trigger map.
|
|
223
|
+
ctx.expect(Object.keys(doc.on)).toEqual(['workflow_dispatch']);
|
|
224
|
+
ctx.expect(doc.on.workflow_dispatch.inputs).toHaveProperty('platforms');
|
|
225
|
+
|
|
226
|
+
// ONE version log for all three legs of the build matrix, under an
|
|
227
|
+
// explicit `shell: bash` (the cmd forcing is for npm, this step reads).
|
|
228
|
+
const log = doc.jobs.build.steps.find((step) => step.name === 'Log versions');
|
|
229
|
+
ctx.expect(log).toBeDefined();
|
|
230
|
+
ctx.expect(log.shell).toBe('bash');
|
|
231
|
+
for (const command of ['node -v', 'npm -v', 'node "${{ github.workspace }}/node_modules/@omega.js/desktop/bin/omega" version']) {
|
|
232
|
+
ctx.expect(log.run).toContain(command);
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
// No job holds a runner for GitHub's six-hour default.
|
|
236
|
+
const unbounded = Object.entries(doc.jobs)
|
|
237
|
+
.filter(([, job]) => typeof job['timeout-minutes'] !== 'number')
|
|
238
|
+
.map(([name]) => name);
|
|
239
|
+
ctx.expect(unbounded).toEqual([]);
|
|
240
|
+
|
|
241
|
+
fs.rmSync(tmp, { recursive: true, force: true });
|
|
242
|
+
},
|
|
243
|
+
},
|
|
54
244
|
],
|
|
55
245
|
});
|
|
@@ -51,30 +51,52 @@ module.exports = defineCases({
|
|
|
51
51
|
},
|
|
52
52
|
},
|
|
53
53
|
{
|
|
54
|
-
name: 'bin/omega
|
|
54
|
+
name: 'bin/omega exists',
|
|
55
55
|
run: (ctx) => {
|
|
56
|
-
const binFile = path.join(root, 'bin', 'omega
|
|
56
|
+
const binFile = path.join(root, 'bin', 'omega');
|
|
57
57
|
ctx.expect(fs.existsSync(binFile)).toBeTruthy();
|
|
58
58
|
},
|
|
59
59
|
},
|
|
60
60
|
{
|
|
61
|
-
name: 'bin/omega
|
|
61
|
+
name: 'bin/omega is executable',
|
|
62
62
|
run: (ctx) => {
|
|
63
63
|
// NTFS has no execute bit, so the mode carries nothing to assert on a
|
|
64
64
|
// Windows checkout — the existence case above still runs everywhere.
|
|
65
65
|
if (process.platform === 'win32') ctx.skip('NTFS has no execute bit — `stat.mode & 0o100` is meaningless on Windows');
|
|
66
|
-
const stat = fs.statSync(path.join(root, 'bin', 'omega
|
|
66
|
+
const stat = fs.statSync(path.join(root, 'bin', 'omega'));
|
|
67
67
|
ctx.expect((stat.mode & 0o100) !== 0).toBeTruthy();
|
|
68
68
|
},
|
|
69
69
|
},
|
|
70
70
|
{
|
|
71
|
-
name: 'cli-run
|
|
71
|
+
name: 'cli-run declares its value-less flags and claims neither --help nor --version (the router owns both)',
|
|
72
72
|
run: (ctx) => {
|
|
73
|
-
// The
|
|
74
|
-
//
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
73
|
+
// The parse the bin really performs (#920). The built-ins it replaced
|
|
74
|
+
// printed an empty stub and version "0.0.0" instead of reaching the
|
|
75
|
+
// alias table / the router's generated help (wave-6 D1).
|
|
76
|
+
const { BOOLEAN_FLAGS } = require(path.join(root, 'dist', 'cli-run.js'));
|
|
77
|
+
const { parseArgv } = require('../../../vendor/devkit/argv.js');
|
|
78
|
+
const parse = (args) => parseArgv(args, { booleans: BOOLEAN_FLAGS });
|
|
79
|
+
|
|
80
|
+
// A value-less flag never swallows the next positional.
|
|
81
|
+
const scoped = parse(['test', '--extended', 'mgr:build/cli']);
|
|
82
|
+
ctx.expect(scoped.extended).toBe(true);
|
|
83
|
+
ctx.expect(scoped._.join(' ')).toBe('test mgr:build/cli');
|
|
84
|
+
|
|
85
|
+
// A value flag keeps its value in the SPACE-separated form CI writes
|
|
86
|
+
// (src/defaults/.github/workflows/build.yml).
|
|
87
|
+
const signing = parse(['sign-windows', '--in', 'release', '--out', 'release/signed']);
|
|
88
|
+
ctx.expect(signing.in).toBe('release');
|
|
89
|
+
ctx.expect(signing.out).toBe('release/signed');
|
|
90
|
+
ctx.expect(parse(['finalize-release', '--signed-dir', 'release/signed']).signedDir).toBe('release/signed');
|
|
91
|
+
|
|
92
|
+
// Every value-LESS flag is declared, so none of them can eat the token
|
|
93
|
+
// after it: `omega logs --tail runtime` keeps the log name.
|
|
94
|
+
const tailed = parse(['logs', '--tail', 'runtime']);
|
|
95
|
+
ctx.expect(tailed.tail).toBe(true);
|
|
96
|
+
ctx.expect(tailed._.join(' ')).toBe('logs runtime');
|
|
97
|
+
|
|
98
|
+
// And --help reaches the router rather than a built-in.
|
|
99
|
+
ctx.expect(parse(['deploy', '--help']).help).toBe(true);
|
|
78
100
|
},
|
|
79
101
|
},
|
|
80
102
|
{
|
|
@@ -113,12 +113,12 @@ module.exports = defineCases({
|
|
|
113
113
|
},
|
|
114
114
|
},
|
|
115
115
|
{
|
|
116
|
-
name: 'resolved: has platforms.
|
|
116
|
+
name: 'resolved: has platforms.windows.signing block (Windows-specific signing config)',
|
|
117
117
|
run: (ctx) => {
|
|
118
118
|
ctx.expect(ctx.state.cfg.platforms).toBeTruthy();
|
|
119
|
-
ctx.expect(ctx.state.cfg.platforms.
|
|
120
|
-
ctx.expect(ctx.state.cfg.platforms.
|
|
121
|
-
ctx.expect(['self-hosted', 'cloud', 'local']).toContain(ctx.state.cfg.platforms.
|
|
119
|
+
ctx.expect(ctx.state.cfg.platforms.windows).toBeTruthy();
|
|
120
|
+
ctx.expect(ctx.state.cfg.platforms.windows.signing).toBeTruthy();
|
|
121
|
+
ctx.expect(['self-hosted', 'cloud', 'local']).toContain(ctx.state.cfg.platforms.windows.signing.strategy);
|
|
122
122
|
},
|
|
123
123
|
},
|
|
124
124
|
{
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
// Build-layer tests for the locked-console refusal. The process list is
|
|
2
|
+
// injected, so both verdicts are provable without a Windows box.
|
|
3
|
+
|
|
4
|
+
const path = require('path');
|
|
5
|
+
const defineCases = require('../../../vendor/devkit/test/define-cases.js');
|
|
6
|
+
|
|
7
|
+
const lock = require(path.join(__dirname, '..', '..', '..', 'lib', 'sign-helpers', 'console-lock.js'));
|
|
8
|
+
|
|
9
|
+
module.exports = defineCases({
|
|
10
|
+
type: 'group',
|
|
11
|
+
layer: 'build',
|
|
12
|
+
description: 'console-lock — LogonUI.exe in the process list is a locked console',
|
|
13
|
+
tests: [
|
|
14
|
+
{
|
|
15
|
+
name: "tasklist's CSV with the lock-screen process reads as locked, without it as not",
|
|
16
|
+
run: (ctx) => {
|
|
17
|
+
ctx.expect(lock.isConsoleLocked('"LogonUI.exe","2012","Console","1","71,284 K"\r\n')).toBe(true);
|
|
18
|
+
ctx.expect(lock.isConsoleLocked('INFO: No tasks are running which match the specified criteria.')).toBe(false);
|
|
19
|
+
ctx.expect(lock.isConsoleLocked('')).toBe(false);
|
|
20
|
+
},
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
name: 'a locked console is refused, naming LogonUI.exe and the fix',
|
|
24
|
+
run: async (ctx) => {
|
|
25
|
+
const ran = [];
|
|
26
|
+
const exec = (out) => async (cmd) => { ran.push(cmd); return out; };
|
|
27
|
+
|
|
28
|
+
let threw;
|
|
29
|
+
try {
|
|
30
|
+
await lock.assertConsoleUnlocked({ platform: 'win32', exec: exec('"LogonUI.exe","2012","Console","1","71,284 K"') });
|
|
31
|
+
} catch (e) { threw = e; }
|
|
32
|
+
ctx.expect(threw).toBeDefined();
|
|
33
|
+
ctx.expect(threw.message).toMatch(/console session is locked/);
|
|
34
|
+
ctx.expect(threw.message).toMatch(/LogonUI\.exe/);
|
|
35
|
+
ctx.expect(threw.message).toMatch(/Unlock the box/);
|
|
36
|
+
// The filter and the headerless CSV are what isConsoleLocked reads.
|
|
37
|
+
ctx.expect(ran).toEqual(['tasklist /fi "IMAGENAME eq LogonUI.exe" /fo csv /nh']);
|
|
38
|
+
|
|
39
|
+
await lock.assertConsoleUnlocked({ platform: 'win32', exec: exec('INFO: No tasks are running which match the specified criteria.') });
|
|
40
|
+
},
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
name: 'off Windows there is no lock screen and nothing is run',
|
|
44
|
+
run: async (ctx) => {
|
|
45
|
+
const ran = [];
|
|
46
|
+
await lock.assertConsoleUnlocked({ platform: 'darwin', exec: async (cmd) => { ran.push(cmd); return '"LogonUI.exe"'; } });
|
|
47
|
+
ctx.expect(ran).toEqual([]);
|
|
48
|
+
},
|
|
49
|
+
},
|
|
50
|
+
],
|
|
51
|
+
});
|
|
@@ -107,8 +107,77 @@ module.exports = defineCases({
|
|
|
107
107
|
const gitignore = jetpack.read(path.join(tmp, '.gitignore'));
|
|
108
108
|
const customPart = gitignore.slice(gitignore.indexOf(CUSTOM_MARKER));
|
|
109
109
|
ctx.expect(customPart).toContain('my-secret-dir/');
|
|
110
|
-
//
|
|
111
|
-
|
|
110
|
+
// The framework block is completely managed ([#926](https://github.com/Omega-JS-Stack/omega/issues/926)):
|
|
111
|
+
// a line inside it that @omega.js/desktop's defaults no longer carry leaves the
|
|
112
|
+
// file. Lines the consumer owns go below the Custom marker.
|
|
113
|
+
ctx.expect(gitignore).not.toContain('user-added-dir/');
|
|
114
|
+
},
|
|
115
|
+
},
|
|
116
|
+
{
|
|
117
|
+
name: 'config/certs/: the target .gitignore hides the material and tracks the README (#913)',
|
|
118
|
+
run: async (ctx) => {
|
|
119
|
+
const { spawnSync } = require('child_process');
|
|
120
|
+
|
|
121
|
+
const tmp = fs.mkdtempSync(path.join(os.tmpdir(), 'desktop-defaults-'));
|
|
122
|
+
await copyDefaults(tmp);
|
|
123
|
+
|
|
124
|
+
const gitignore = jetpack.read(path.join(tmp, '.gitignore'));
|
|
125
|
+
const defaultPart = gitignore.slice(0, gitignore.indexOf(CUSTOM_MARKER));
|
|
126
|
+
ctx.expect(defaultPart).toContain('config/certs/*');
|
|
127
|
+
ctx.expect(defaultPart).toContain('!config/certs/README.md');
|
|
128
|
+
// The framework section is a file consumers edit, and the dotfiles emdash
|
|
129
|
+
// hook bounces one (built by code point so this file carries none either).
|
|
130
|
+
ctx.expect(defaultPart.includes(String.fromCharCode(0x2014))).toBe(false);
|
|
131
|
+
|
|
132
|
+
// The README the scaffold writes says the target .gitignore is what
|
|
133
|
+
// hides this directory, so no sibling .gitignore ships beside it.
|
|
134
|
+
ctx.expect(jetpack.exists(path.join(tmp, 'config', 'certs', 'README.md'))).toBe('file');
|
|
135
|
+
ctx.expect(jetpack.exists(path.join(tmp, 'config', 'certs', '.gitignore'))).toBe(false);
|
|
136
|
+
|
|
137
|
+
// git is the only authority on this: prove it against a real repo.
|
|
138
|
+
jetpack.write(path.join(tmp, 'config', 'certs', 'foo.p12'), 'not a real cert');
|
|
139
|
+
spawnSync('git', ['init', '-q'], { cwd: tmp });
|
|
140
|
+
const ignored = (file) => spawnSync('git', ['check-ignore', '-q', file], { cwd: tmp }).status === 0;
|
|
141
|
+
|
|
142
|
+
ctx.expect(ignored('config/certs/README.md')).toBe(false);
|
|
143
|
+
ctx.expect(ignored('config/certs/foo.p12')).toBe(true);
|
|
144
|
+
},
|
|
145
|
+
},
|
|
146
|
+
{
|
|
147
|
+
name: 'config/certs/: a target scaffolded before #913 converges on the next verb run',
|
|
148
|
+
run: async (ctx) => {
|
|
149
|
+
// Three leftovers each keep the README hidden on their own, so the next
|
|
150
|
+
// verb run heals all three: the old `config/certs/` line, which the
|
|
151
|
+
// marker merge now DROPS with the rest of the retired framework block
|
|
152
|
+
// ([#926](https://github.com/Omega-JS-Stack/omega/issues/926)), the
|
|
153
|
+
// sibling `.gitignore` (a nested ignore file beats the parent), and the
|
|
154
|
+
// README's own sentence, which cited that sibling.
|
|
155
|
+
const tmp = fs.mkdtempSync(path.join(os.tmpdir(), 'desktop-defaults-'));
|
|
156
|
+
const sibling = path.join(tmp, 'config', 'certs', '.gitignore');
|
|
157
|
+
const readme = path.join(tmp, 'config', 'certs', 'README.md');
|
|
158
|
+
|
|
159
|
+
jetpack.write(
|
|
160
|
+
path.join(tmp, '.gitignore'),
|
|
161
|
+
`${DEFAULT_MARKER}\n.env\nconfig/certs/\n*.p12\n\n${CUSTOM_MARKER}\nmy-secret-dir/\n`
|
|
162
|
+
);
|
|
163
|
+
jetpack.write(sibling, '*\n!.gitignore\n');
|
|
164
|
+
jetpack.write(readme, '# `config/certs/`\n\nThe `.gitignore` beside this file ignores everything it holds.\n');
|
|
165
|
+
|
|
166
|
+
await copyDefaults(tmp);
|
|
167
|
+
|
|
168
|
+
const gitignore = jetpack.read(path.join(tmp, '.gitignore'));
|
|
169
|
+
ctx.expect(gitignore.split('\n').some((line) => line.trim() === 'config/certs/')).toBe(false);
|
|
170
|
+
const defaultHalf = gitignore.slice(0, gitignore.indexOf(CUSTOM_MARKER));
|
|
171
|
+
ctx.expect(defaultHalf).toContain('config/certs/*');
|
|
172
|
+
ctx.expect(defaultHalf).toContain('!config/certs/README.md');
|
|
173
|
+
ctx.expect(gitignore).toContain('my-secret-dir/');
|
|
174
|
+
ctx.expect(jetpack.exists(sibling)).toBe(false);
|
|
175
|
+
ctx.expect(jetpack.read(readme)).toContain("The target's `.gitignore` ignores everything here except this file");
|
|
176
|
+
|
|
177
|
+
// Anything else in that sibling is the consumer's, and is never destroyed.
|
|
178
|
+
jetpack.write(sibling, '*\n!.gitignore\n!my-own-note.txt\n');
|
|
179
|
+
await copyDefaults(tmp);
|
|
180
|
+
ctx.expect(jetpack.exists(sibling)).toBe('file');
|
|
112
181
|
},
|
|
113
182
|
},
|
|
114
183
|
{
|