@omega.js/desktop 0.50.0 → 0.52.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 +2 -2
- 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 +176 -42
- 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 +146 -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 +635 -5
- 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 +125 -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 +249 -103
- 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 +425 -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 +505 -75
- package/dist/vendor/devkit/git-auth.js +73 -0
- package/dist/vendor/devkit/git-remote.js +172 -0
- package/dist/vendor/devkit/github-repo.js +290 -0
- package/dist/vendor/devkit/local.js +98 -3
- package/dist/vendor/devkit/lockfile.js +127 -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 +388 -0
- package/dist/vendor/devkit/preludes/index.js +120 -0
- package/dist/vendor/devkit/preludes/origin-heal.js +142 -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 +231 -57
- 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 +29 -19
- package/docs/runner.md +51 -14
- package/docs/shared/brands.md +12 -6
- package/docs/shared/breaking-changes.md +375 -21
- package/docs/shared/config.md +764 -199
- package/docs/shared/deploys.md +217 -91
- package/docs/shared/icons.md +18 -0
- package/docs/shared/local-dev.md +28 -8
- 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 +60 -34
- 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
|
@@ -78,8 +78,8 @@ module.exports = defineCases({
|
|
|
78
78
|
jetpack.remove(realish); // a RED run of this case is what would create it
|
|
79
79
|
try {
|
|
80
80
|
// Every verb that CHANGES the machine — stop kills real listeners under
|
|
81
|
-
// the home
|
|
82
|
-
for (const sub of ['install', 'config', 'register-org', 'start', 'restart', 'stop', 'uninstall'
|
|
81
|
+
// the home.
|
|
82
|
+
for (const sub of ['install', 'config', 'register-org', 'start', 'restart', 'stop', 'uninstall']) {
|
|
83
83
|
let threw;
|
|
84
84
|
try {
|
|
85
85
|
// `_env: {}` is a fixture for the config walk. It is NOT an answer
|
|
@@ -1155,11 +1155,23 @@ module.exports = defineCases({
|
|
|
1155
1155
|
jetpack.write(path.join(home, 'actions-runner-foo', 'config.cmd'), 'rem foo');
|
|
1156
1156
|
jetpack.write(path.join(home, '_template', 'config.cmd'), 'rem template');
|
|
1157
1157
|
|
|
1158
|
+
// The job guard's allow lists are configuration too
|
|
1159
|
+
// ([#875](https://github.com/Omega-JS-Stack/omega/issues/875)): a list
|
|
1160
|
+
// narrowed by hand outlives an uninstall exactly as the `.env` does.
|
|
1161
|
+
// The hook SCRIPT is install state, and the next install writes it back.
|
|
1162
|
+
jetpack.write(path.join(home, 'allowed-repos.txt'), 'Omega-JS-Stack/omega-omega\n');
|
|
1163
|
+
jetpack.write(path.join(home, 'allowed-actors.txt'), 'ianwieds\n');
|
|
1164
|
+
jetpack.write(path.join(home, 'job-started.js'), '// stale copy');
|
|
1165
|
+
|
|
1158
1166
|
await runner.removeRunnerHomeWithRetry(new Set(), home);
|
|
1159
1167
|
|
|
1160
|
-
ctx.expect(jetpack.list(home).sort()).toEqual(['.env', 'logs']);
|
|
1168
|
+
ctx.expect(jetpack.list(home).sort()).toEqual(['.env', 'allowed-actors.txt', 'allowed-repos.txt', 'logs']);
|
|
1161
1169
|
ctx.expect(jetpack.read(path.join(home, '.env'))).toBe('WIN_CSC_KEY_PASSWORD=keep-me');
|
|
1162
1170
|
ctx.expect(jetpack.read(runnerEnv.runnerLogFile(home))).toBe('# omega log\n');
|
|
1171
|
+
ctx.expect(jetpack.read(path.join(home, 'allowed-repos.txt'))).toBe('Omega-JS-Stack/omega-omega\n');
|
|
1172
|
+
|
|
1173
|
+
jetpack.remove(path.join(home, 'allowed-repos.txt'));
|
|
1174
|
+
jetpack.remove(path.join(home, 'allowed-actors.txt'));
|
|
1163
1175
|
|
|
1164
1176
|
// A kept org dir (its deregistration failed) survives beside them.
|
|
1165
1177
|
jetpack.write(path.join(home, 'actions-runner-bar', 'config.cmd'), 'rem bar');
|
|
@@ -1708,6 +1720,9 @@ module.exports = defineCases({
|
|
|
1708
1720
|
const logged = [];
|
|
1709
1721
|
const logger = { log: (m) => logged.push(['log', String(m)]), warn: (m) => logged.push(['warn', String(m)]), error: (m) => logged.push(['error', String(m)]) };
|
|
1710
1722
|
try {
|
|
1723
|
+
// Installed and current, so `start` goes straight to its spawns (#937).
|
|
1724
|
+
jetpack.write(path.join(home, '_template', 'config.cmd'), '@echo off\r\n');
|
|
1725
|
+
jetpack.write(path.join(home, 'config.json'), { actionsRunnerVersion: runner.ACTIONS_RUNNER_VERSION });
|
|
1711
1726
|
let threw;
|
|
1712
1727
|
try {
|
|
1713
1728
|
await runner({ _: ['runner', 'start'], _home: home, _env: {}, _logger: logger, _prompt: {}, _interactive: false });
|
|
@@ -1802,6 +1817,9 @@ module.exports = defineCases({
|
|
|
1802
1817
|
const spawned = [];
|
|
1803
1818
|
const filled = { GH_TOKEN: 'ghp_from_the_box', WIN_EV_TOKEN_PATH: 'a'.repeat(40), WIN_CSC_KEY_PASSWORD: '1234', SIGNTOOL_PATH: 'C:/sdk/signtool.exe' };
|
|
1804
1819
|
try {
|
|
1820
|
+
// Installed and current, so `start` goes straight to its spawns (#937).
|
|
1821
|
+
jetpack.write(path.join(home, '_template', 'config.cmd'), '@echo off\r\n');
|
|
1822
|
+
jetpack.write(path.join(home, 'config.json'), { actionsRunnerVersion: runner.ACTIONS_RUNNER_VERSION });
|
|
1805
1823
|
for (const org of orgs) jetpack.dir(path.join(home, `actions-runner-${org}`));
|
|
1806
1824
|
for (const file of shortcuts) jetpack.write(file, '@echo off\r\n');
|
|
1807
1825
|
|
|
@@ -1851,6 +1869,9 @@ module.exports = defineCases({
|
|
|
1851
1869
|
const filled = { GH_TOKEN: 'ghp_from_the_box', WIN_EV_TOKEN_PATH: 'a'.repeat(40), WIN_CSC_KEY_PASSWORD: '1234', SIGNTOOL_PATH: 'C:/sdk/signtool.exe' };
|
|
1852
1870
|
const aliveDir = path.join(home, 'actions-runner-acme');
|
|
1853
1871
|
try {
|
|
1872
|
+
// Installed and current, so `start` goes straight to its spawns (#937).
|
|
1873
|
+
jetpack.write(path.join(home, '_template', 'config.cmd'), '@echo off\r\n');
|
|
1874
|
+
jetpack.write(path.join(home, 'config.json'), { actionsRunnerVersion: runner.ACTIONS_RUNNER_VERSION });
|
|
1854
1875
|
for (const org of orgs) jetpack.dir(path.join(home, `actions-runner-${org}`));
|
|
1855
1876
|
for (const file of shortcuts) jetpack.write(file, '@echo off\r\n');
|
|
1856
1877
|
|
|
@@ -1895,6 +1916,9 @@ module.exports = defineCases({
|
|
|
1895
1916
|
const logger = { log: (m) => logged.push(['log', String(m)]), warn: (m) => logged.push(['warn', String(m)]), error: (m) => logged.push(['error', String(m)]) };
|
|
1896
1917
|
const filled = { GH_TOKEN: 'ghp_from_the_box', WIN_EV_TOKEN_PATH: 'a'.repeat(40), WIN_CSC_KEY_PASSWORD: '1234', SIGNTOOL_PATH: 'C:/sdk/signtool.exe' };
|
|
1897
1918
|
try {
|
|
1919
|
+
// Installed and current, so `start` goes straight to its spawns (#937).
|
|
1920
|
+
jetpack.write(path.join(home, '_template', 'config.cmd'), '@echo off\r\n');
|
|
1921
|
+
jetpack.write(path.join(home, 'config.json'), { actionsRunnerVersion: runner.ACTIONS_RUNNER_VERSION });
|
|
1898
1922
|
for (const org of orgs) jetpack.dir(path.join(home, `actions-runner-${org}`));
|
|
1899
1923
|
for (const file of shortcuts) jetpack.write(file, '@echo off\r\n');
|
|
1900
1924
|
|
|
@@ -1937,6 +1961,9 @@ module.exports = defineCases({
|
|
|
1937
1961
|
const spawned = [];
|
|
1938
1962
|
const filled = { GH_TOKEN: 'ghp_from_the_box', WIN_EV_TOKEN_PATH: 'a'.repeat(40), WIN_CSC_KEY_PASSWORD: '1234', SIGNTOOL_PATH: 'C:/sdk/signtool.exe' };
|
|
1939
1963
|
try {
|
|
1964
|
+
// Installed and current, so `start` goes straight to its spawns (#937).
|
|
1965
|
+
jetpack.write(path.join(home, '_template', 'config.cmd'), '@echo off\r\n');
|
|
1966
|
+
jetpack.write(path.join(home, 'config.json'), { actionsRunnerVersion: runner.ACTIONS_RUNNER_VERSION });
|
|
1940
1967
|
jetpack.dir(path.join(home, 'actions-runner-acme'));
|
|
1941
1968
|
jetpack.write(shortcut, '@echo off\r\n');
|
|
1942
1969
|
|
|
@@ -2031,6 +2058,9 @@ module.exports = defineCases({
|
|
|
2031
2058
|
const waits = [];
|
|
2032
2059
|
const filled = { GH_TOKEN: 'ghp_from_the_box', WIN_EV_TOKEN_PATH: 'a'.repeat(40), WIN_CSC_KEY_PASSWORD: '1234', SIGNTOOL_PATH: 'C:/sdk/signtool.exe' };
|
|
2033
2060
|
try {
|
|
2061
|
+
// Installed and current, so `start` goes straight to its spawns (#937).
|
|
2062
|
+
jetpack.write(path.join(home, '_template', 'config.cmd'), '@echo off\r\n');
|
|
2063
|
+
jetpack.write(path.join(home, 'config.json'), { actionsRunnerVersion: runner.ACTIONS_RUNNER_VERSION });
|
|
2034
2064
|
jetpack.dir(path.join(home, 'actions-runner-acme'));
|
|
2035
2065
|
jetpack.write(shortcut, '@echo off\r\n');
|
|
2036
2066
|
|
|
@@ -2080,6 +2110,9 @@ module.exports = defineCases({
|
|
|
2080
2110
|
const waits = [];
|
|
2081
2111
|
const filled = { GH_TOKEN: 'ghp_from_the_box', WIN_EV_TOKEN_PATH: 'a'.repeat(40), WIN_CSC_KEY_PASSWORD: '1234', SIGNTOOL_PATH: 'C:/sdk/signtool.exe' };
|
|
2082
2112
|
try {
|
|
2113
|
+
// Installed and current, so `start` goes straight to its spawns (#937).
|
|
2114
|
+
jetpack.write(path.join(home, '_template', 'config.cmd'), '@echo off\r\n');
|
|
2115
|
+
jetpack.write(path.join(home, 'config.json'), { actionsRunnerVersion: runner.ACTIONS_RUNNER_VERSION });
|
|
2083
2116
|
jetpack.dir(path.join(home, 'actions-runner-acme'));
|
|
2084
2117
|
jetpack.write(shortcut, '@echo off\r\n');
|
|
2085
2118
|
|
|
@@ -2118,7 +2151,7 @@ module.exports = defineCases({
|
|
|
2118
2151
|
ctx.expect(startSrc.includes("stdio: 'inherit'")).toBe(false);
|
|
2119
2152
|
ctx.expect(startSrc.includes('spawnSync')).toBe(false);
|
|
2120
2153
|
// ...and install hands off to it rather than foregrounding one org.
|
|
2121
|
-
ctx.expect(src).toContain('await startServices({ ...options, _home: home })');
|
|
2154
|
+
ctx.expect(src).toContain('await startServices({ ...options, _home: home, _reconcileDone: true })');
|
|
2122
2155
|
|
|
2123
2156
|
// The spawn's own options, pinned the same way: the listener is handed
|
|
2124
2157
|
// the runner's private HOME ([#807](https://github.com/Omega-JS-Stack/omega/issues/807))
|
|
@@ -2154,6 +2187,9 @@ module.exports = defineCases({
|
|
|
2154
2187
|
const spawned = [];
|
|
2155
2188
|
const filled = { GH_TOKEN: 'ghp_from_the_box', WIN_EV_TOKEN_PATH: 'a'.repeat(40), WIN_CSC_KEY_PASSWORD: '1234', SIGNTOOL_PATH: 'C:/sdk/signtool.exe' };
|
|
2156
2189
|
try {
|
|
2190
|
+
// Installed and current, so `start` goes straight to its spawns (#937).
|
|
2191
|
+
jetpack.write(path.join(home, '_template', 'config.cmd'), '@echo off\r\n');
|
|
2192
|
+
jetpack.write(path.join(home, 'config.json'), { actionsRunnerVersion: runner.ACTIONS_RUNNER_VERSION });
|
|
2157
2193
|
for (const org of orgs) jetpack.dir(path.join(home, `actions-runner-${org}`));
|
|
2158
2194
|
for (const file of shortcuts) jetpack.write(file, '@echo off\r\n');
|
|
2159
2195
|
|
|
@@ -2206,6 +2242,9 @@ module.exports = defineCases({
|
|
|
2206
2242
|
const spawned = [];
|
|
2207
2243
|
const filled = { GH_TOKEN: 'ghp_from_the_box', WIN_EV_TOKEN_PATH: 'a'.repeat(40), WIN_CSC_KEY_PASSWORD: '1234', SIGNTOOL_PATH: 'C:/sdk/signtool.exe' };
|
|
2208
2244
|
try {
|
|
2245
|
+
// Installed and current, so `start` goes straight to its spawns (#937).
|
|
2246
|
+
jetpack.write(path.join(home, '_template', 'config.cmd'), '@echo off\r\n');
|
|
2247
|
+
jetpack.write(path.join(home, 'config.json'), { actionsRunnerVersion: runner.ACTIONS_RUNNER_VERSION });
|
|
2209
2248
|
jetpack.dir(path.join(home, 'actions-runner-acme'));
|
|
2210
2249
|
jetpack.write(shortcut, '@echo off\r\n');
|
|
2211
2250
|
|
|
@@ -2573,6 +2612,9 @@ module.exports = defineCases({
|
|
|
2573
2612
|
const logger = { log: (m) => logged.push(String(m)), warn: (m) => logged.push(String(m)), error: (m) => logged.push(String(m)) };
|
|
2574
2613
|
const filled = { GH_TOKEN: 'ghp_from_the_box', WIN_EV_TOKEN_PATH: 'a'.repeat(40), WIN_CSC_KEY_PASSWORD: '1234', SIGNTOOL_PATH: 'C:/sdk/signtool.exe' };
|
|
2575
2614
|
try {
|
|
2615
|
+
// Installed and current, so `start` goes straight to its spawns (#937).
|
|
2616
|
+
jetpack.write(path.join(home, '_template', 'config.cmd'), '@echo off\r\n');
|
|
2617
|
+
jetpack.write(path.join(home, 'config.json'), { actionsRunnerVersion: runner.ACTIONS_RUNNER_VERSION });
|
|
2576
2618
|
for (const org of orgs) jetpack.write(path.join(home, `actions-runner-${org}`, 'config.cmd'), '@echo off\r\n');
|
|
2577
2619
|
for (const file of shortcuts) jetpack.write(file, '@echo off\r\n');
|
|
2578
2620
|
ctx.expect(jetpack.exists(path.join(home, 'home'))).toBe(false);
|
|
@@ -2584,10 +2626,21 @@ module.exports = defineCases({
|
|
|
2584
2626
|
});
|
|
2585
2627
|
|
|
2586
2628
|
ctx.expect(fs.readFileSync(path.join(home, 'home', '.gitconfig'), 'utf8')).toBe('[core]\n\tautocrlf = false\n');
|
|
2629
|
+
// The job guard is healed on the same pass
|
|
2630
|
+
// ([#875](https://github.com/Omega-JS-Stack/omega/issues/875)): a box
|
|
2631
|
+
// that installed before it would otherwise come online signing for
|
|
2632
|
+
// anything. Both lines, in one `<runner dir>\.env`.
|
|
2633
|
+
const hook = path.join(home, 'job-started.js');
|
|
2634
|
+
ctx.expect(jetpack.exists(hook)).toBe('file');
|
|
2587
2635
|
for (const org of orgs) {
|
|
2588
|
-
ctx.expect(fs.readFileSync(path.join(home, `actions-runner-${org}`, '.env'), 'utf8')).toBe(`HOME=${path.join(home, 'home')}\n`);
|
|
2636
|
+
ctx.expect(fs.readFileSync(path.join(home, `actions-runner-${org}`, '.env'), 'utf8')).toBe(`HOME=${path.join(home, 'home')}\nACTIONS_RUNNER_HOOK_JOB_STARTED=${hook}\n`);
|
|
2589
2637
|
ctx.expect(logged.join('\n')).toContain(`HOME for ${org}: ${path.join(home, 'home')}`);
|
|
2638
|
+
ctx.expect(logged.join('\n')).toContain(`Job guard for ${org}: ${hook}`);
|
|
2590
2639
|
}
|
|
2640
|
+
// `start` asks GitHub nothing, so the actor list is the operator's to
|
|
2641
|
+
// fill: the file is there with its header, and an empty list refuses.
|
|
2642
|
+
ctx.expect(jetpack.exists(path.join(home, 'allowed-repos.txt'))).toBe('file');
|
|
2643
|
+
ctx.expect(jetpack.exists(path.join(home, 'allowed-actors.txt'))).toBe('file');
|
|
2591
2644
|
} finally {
|
|
2592
2645
|
if (origForce === undefined) delete process.env.OMEGA_RUNNER_FORCE; else process.env.OMEGA_RUNNER_FORCE = origForce;
|
|
2593
2646
|
for (const file of shortcuts) jetpack.remove(file);
|
|
@@ -2595,5 +2648,582 @@ module.exports = defineCases({
|
|
|
2595
2648
|
}
|
|
2596
2649
|
},
|
|
2597
2650
|
},
|
|
2651
|
+
{
|
|
2652
|
+
name: '`start` on a bare box installs: a home with no `_template/config.cmd` hands the whole run to install, once',
|
|
2653
|
+
run: async (ctx) => {
|
|
2654
|
+
// `start` is the one command (#937). A box with nothing installed gets
|
|
2655
|
+
// the install, which itself ends by bringing every org online, so
|
|
2656
|
+
// nothing else of `start` runs: no config walk of its own, no refresh,
|
|
2657
|
+
// no org check, no spawn.
|
|
2658
|
+
const fs = require('fs');
|
|
2659
|
+
const os = require('os');
|
|
2660
|
+
const jetpack = require('fs-jetpack');
|
|
2661
|
+
const runner = require(path.join(__dirname, '..', '..', '..', 'commands', 'runner.js'));
|
|
2662
|
+
|
|
2663
|
+
const home = fs.mkdtempSync(path.join(os.tmpdir(), 'omega-runner-home-'));
|
|
2664
|
+
const origForce = process.env.OMEGA_RUNNER_FORCE;
|
|
2665
|
+
process.env.OMEGA_RUNNER_FORCE = '1';
|
|
2666
|
+
const logged = [];
|
|
2667
|
+
const logger = { log: (m) => logged.push(['log', String(m)]), warn: (m) => logged.push(['warn', String(m)]), error: (m) => logged.push(['error', String(m)]) };
|
|
2668
|
+
const filled = { GH_TOKEN: 'ghp_from_the_box', WIN_EV_TOKEN_PATH: 'a'.repeat(40), WIN_CSC_KEY_PASSWORD: '1234', SIGNTOOL_PATH: 'C:/sdk/signtool.exe' };
|
|
2669
|
+
const installs = [];
|
|
2670
|
+
const spawned = [];
|
|
2671
|
+
let downloads = 0;
|
|
2672
|
+
let discovers = 0;
|
|
2673
|
+
let registers = 0;
|
|
2674
|
+
try {
|
|
2675
|
+
const options = {
|
|
2676
|
+
_: ['runner', 'start'], _home: home, _env: filled, _logger: logger, _interactive: false, _prompt: {},
|
|
2677
|
+
_listeners: () => [],
|
|
2678
|
+
_spawn: (dir) => { spawned.push(dir); return { ok: true, pid: 1 }; },
|
|
2679
|
+
_install: async (o) => { installs.push(o); },
|
|
2680
|
+
_download: async () => { downloads++; },
|
|
2681
|
+
_discoverOrgs: async () => { discovers++; return []; },
|
|
2682
|
+
_registerOrg: async () => { registers++; },
|
|
2683
|
+
};
|
|
2684
|
+
await runner(options);
|
|
2685
|
+
|
|
2686
|
+
ctx.expect(installs.length).toBe(1);
|
|
2687
|
+
ctx.expect(installs[0]).toBe(options); // the same options, untouched
|
|
2688
|
+
ctx.expect(spawned).toEqual([]);
|
|
2689
|
+
ctx.expect(downloads).toBe(0);
|
|
2690
|
+
ctx.expect(discovers).toBe(0);
|
|
2691
|
+
ctx.expect(registers).toBe(0);
|
|
2692
|
+
ctx.expect(jetpack.exists(path.join(home, '.env'))).toBe(false); // start's own config walk never ran
|
|
2693
|
+
} finally {
|
|
2694
|
+
if (origForce === undefined) delete process.env.OMEGA_RUNNER_FORCE; else process.env.OMEGA_RUNNER_FORCE = origForce;
|
|
2695
|
+
jetpack.remove(home);
|
|
2696
|
+
}
|
|
2697
|
+
},
|
|
2698
|
+
},
|
|
2699
|
+
{
|
|
2700
|
+
name: '`start` refreshes a stale actions/runner in place: the template is re-downloaded and copied over each stopped org, its registration kept',
|
|
2701
|
+
run: async (ctx) => {
|
|
2702
|
+
// A bumped ACTIONS_RUNNER_VERSION used to mean `install`, which tears
|
|
2703
|
+
// the box down. The template is re-downloaded and laid over each org dir
|
|
2704
|
+
// instead; `.runner`, `.credentials` and `.env` are the registration and
|
|
2705
|
+
// the template never carries them, so they come through byte-identical.
|
|
2706
|
+
const fs = require('fs');
|
|
2707
|
+
const os = require('os');
|
|
2708
|
+
const jetpack = require('fs-jetpack');
|
|
2709
|
+
const runner = require(path.join(__dirname, '..', '..', '..', 'commands', 'runner.js'));
|
|
2710
|
+
|
|
2711
|
+
const home = fs.mkdtempSync(path.join(os.tmpdir(), 'omega-runner-home-'));
|
|
2712
|
+
const origForce = process.env.OMEGA_RUNNER_FORCE;
|
|
2713
|
+
const origExit = process.exitCode;
|
|
2714
|
+
process.env.OMEGA_RUNNER_FORCE = '1';
|
|
2715
|
+
const hostPrefix = `omega-runner-${os.hostname().toLowerCase()}-`;
|
|
2716
|
+
const shortcut = path.join(SCRATCH_STARTUP_DIR, `${hostPrefix}acme.cmd`);
|
|
2717
|
+
const logged = [];
|
|
2718
|
+
const logger = { log: (m) => logged.push(['log', String(m)]), warn: (m) => logged.push(['warn', String(m)]), error: (m) => logged.push(['error', String(m)]) };
|
|
2719
|
+
const filled = { GH_TOKEN: 'ghp_from_the_box', WIN_EV_TOKEN_PATH: 'a'.repeat(40), WIN_CSC_KEY_PASSWORD: '1234', SIGNTOOL_PATH: 'C:/sdk/signtool.exe' };
|
|
2720
|
+
const templateDir = path.join(home, '_template');
|
|
2721
|
+
const orgDir = path.join(home, 'actions-runner-acme');
|
|
2722
|
+
const downloads = [];
|
|
2723
|
+
const spawned = [];
|
|
2724
|
+
// The registration files, exactly as the preflight leaves `.env`, so a
|
|
2725
|
+
// byte change can only have come from the copy.
|
|
2726
|
+
const kept = {
|
|
2727
|
+
'.runner': '{"agentName":"omega-runner-box-acme"}',
|
|
2728
|
+
'.credentials': '{"scheme":"OAuth"}',
|
|
2729
|
+
'.env': `https_proxy=http://proxy\nHOME=${path.join(home, 'home')}\nACTIONS_RUNNER_HOOK_JOB_STARTED=${path.join(home, 'job-started.js')}\n`,
|
|
2730
|
+
};
|
|
2731
|
+
try {
|
|
2732
|
+
jetpack.write(path.join(templateDir, 'config.cmd'), 'old config');
|
|
2733
|
+
jetpack.write(path.join(home, 'config.json'), { actionsRunnerVersion: '2.300.0', registeredOrgs: ['acme'] });
|
|
2734
|
+
jetpack.write(path.join(orgDir, 'config.cmd'), 'old config');
|
|
2735
|
+
jetpack.write(path.join(orgDir, 'bin', 'Runner.Listener.exe'), 'old listener');
|
|
2736
|
+
for (const [name, content] of Object.entries(kept)) jetpack.write(path.join(orgDir, name), content);
|
|
2737
|
+
jetpack.write(shortcut, '@echo off\r\n');
|
|
2738
|
+
|
|
2739
|
+
await runner({
|
|
2740
|
+
_: ['runner', 'start'], _home: home, _env: filled, _logger: logger, _interactive: false, _prompt: {},
|
|
2741
|
+
_listeners: () => [],
|
|
2742
|
+
_spawn: (dir) => { spawned.push(dir); return { ok: true, pid: 5150 }; },
|
|
2743
|
+
_download: async (dir, h) => {
|
|
2744
|
+
downloads.push([dir, h]);
|
|
2745
|
+
jetpack.write(path.join(dir, 'config.cmd'), 'new config');
|
|
2746
|
+
jetpack.write(path.join(dir, 'bin', 'Runner.Listener.exe'), 'new listener');
|
|
2747
|
+
},
|
|
2748
|
+
_discoverOrgs: async () => ['acme'],
|
|
2749
|
+
_registerOrg: async () => { throw new Error('nothing to register'); },
|
|
2750
|
+
});
|
|
2751
|
+
|
|
2752
|
+
ctx.expect(downloads).toEqual([[templateDir, home]]);
|
|
2753
|
+
ctx.expect(fs.readFileSync(path.join(orgDir, 'config.cmd'), 'utf8')).toBe('new config');
|
|
2754
|
+
ctx.expect(fs.readFileSync(path.join(orgDir, 'bin', 'Runner.Listener.exe'), 'utf8')).toBe('new listener');
|
|
2755
|
+
for (const [name, content] of Object.entries(kept)) {
|
|
2756
|
+
ctx.expect(fs.readFileSync(path.join(orgDir, name), 'utf8')).toBe(content);
|
|
2757
|
+
}
|
|
2758
|
+
ctx.expect(jetpack.read(path.join(home, 'config.json'), 'json').actionsRunnerVersion).toBe(runner.ACTIONS_RUNNER_VERSION);
|
|
2759
|
+
ctx.expect(spawned).toEqual([orgDir]); // and the org still comes online
|
|
2760
|
+
ctx.expect(process.exitCode).toBe(origExit);
|
|
2761
|
+
} finally {
|
|
2762
|
+
if (origForce === undefined) delete process.env.OMEGA_RUNNER_FORCE; else process.env.OMEGA_RUNNER_FORCE = origForce;
|
|
2763
|
+
process.exitCode = origExit;
|
|
2764
|
+
jetpack.remove(shortcut);
|
|
2765
|
+
jetpack.remove(home);
|
|
2766
|
+
}
|
|
2767
|
+
},
|
|
2768
|
+
},
|
|
2769
|
+
{
|
|
2770
|
+
name: '`start` never refreshes an org whose listener is alive: its binaries are locked, so it names `restart` and the version stays unrecorded',
|
|
2771
|
+
run: async (ctx) => {
|
|
2772
|
+
// A live listener holds its dir's binaries open. Copying over them is a
|
|
2773
|
+
// half-updated runner, so that org is skipped with the command that
|
|
2774
|
+
// stops it first, and the box is not called refreshed until every org
|
|
2775
|
+
// dir took the new version.
|
|
2776
|
+
const fs = require('fs');
|
|
2777
|
+
const os = require('os');
|
|
2778
|
+
const jetpack = require('fs-jetpack');
|
|
2779
|
+
const runner = require(path.join(__dirname, '..', '..', '..', 'commands', 'runner.js'));
|
|
2780
|
+
|
|
2781
|
+
const home = fs.mkdtempSync(path.join(os.tmpdir(), 'omega-runner-home-'));
|
|
2782
|
+
const origForce = process.env.OMEGA_RUNNER_FORCE;
|
|
2783
|
+
const origExit = process.exitCode;
|
|
2784
|
+
process.env.OMEGA_RUNNER_FORCE = '1';
|
|
2785
|
+
const hostPrefix = `omega-runner-${os.hostname().toLowerCase()}-`;
|
|
2786
|
+
const orgs = ['acme', 'zeta'];
|
|
2787
|
+
const shortcuts = orgs.map((org) => path.join(SCRATCH_STARTUP_DIR, `${hostPrefix}${org}.cmd`));
|
|
2788
|
+
const logged = [];
|
|
2789
|
+
const logger = { log: (m) => logged.push(['log', String(m)]), warn: (m) => logged.push(['warn', String(m)]), error: (m) => logged.push(['error', String(m)]) };
|
|
2790
|
+
const filled = { GH_TOKEN: 'ghp_from_the_box', WIN_EV_TOKEN_PATH: 'a'.repeat(40), WIN_CSC_KEY_PASSWORD: '1234', SIGNTOOL_PATH: 'C:/sdk/signtool.exe' };
|
|
2791
|
+
const templateDir = path.join(home, '_template');
|
|
2792
|
+
const aliveDir = path.join(home, 'actions-runner-acme');
|
|
2793
|
+
const stoppedDir = path.join(home, 'actions-runner-zeta');
|
|
2794
|
+
try {
|
|
2795
|
+
jetpack.write(path.join(templateDir, 'config.cmd'), 'old config');
|
|
2796
|
+
jetpack.write(path.join(home, 'config.json'), { actionsRunnerVersion: '2.300.0', registeredOrgs: orgs });
|
|
2797
|
+
for (const dir of [aliveDir, stoppedDir]) jetpack.write(path.join(dir, 'config.cmd'), 'old config');
|
|
2798
|
+
for (const file of shortcuts) jetpack.write(file, '@echo off\r\n');
|
|
2799
|
+
|
|
2800
|
+
await runner({
|
|
2801
|
+
_: ['runner', 'start'], _home: home, _env: filled, _logger: logger, _interactive: false, _prompt: {},
|
|
2802
|
+
_listeners: (dir) => (dir === aliveDir ? [{ pid: 4242, sessionId: 1, execPath: path.join(aliveDir, 'bin', 'Runner.Listener.exe') }] : []),
|
|
2803
|
+
_spawn: () => ({ ok: true, pid: 6000 }),
|
|
2804
|
+
_download: async (dir) => { jetpack.write(path.join(dir, 'config.cmd'), 'new config'); },
|
|
2805
|
+
_discoverOrgs: async () => orgs,
|
|
2806
|
+
_registerOrg: async () => { throw new Error('nothing to register'); },
|
|
2807
|
+
});
|
|
2808
|
+
|
|
2809
|
+
ctx.expect(fs.readFileSync(path.join(aliveDir, 'config.cmd'), 'utf8')).toBe('old config'); // untouched
|
|
2810
|
+
ctx.expect(fs.readFileSync(path.join(stoppedDir, 'config.cmd'), 'utf8')).toBe('new config'); // the stopped one took it
|
|
2811
|
+
const skip = logged.map((l) => l[1]).filter((l) => l.includes('npx omega runner restart'));
|
|
2812
|
+
ctx.expect(skip.length).toBe(1);
|
|
2813
|
+
ctx.expect(skip[0]).toContain('acme');
|
|
2814
|
+
ctx.expect(jetpack.read(path.join(home, 'config.json'), 'json').actionsRunnerVersion).toBe('2.300.0');
|
|
2815
|
+
} finally {
|
|
2816
|
+
if (origForce === undefined) delete process.env.OMEGA_RUNNER_FORCE; else process.env.OMEGA_RUNNER_FORCE = origForce;
|
|
2817
|
+
process.exitCode = origExit;
|
|
2818
|
+
for (const file of shortcuts) jetpack.remove(file);
|
|
2819
|
+
jetpack.remove(home);
|
|
2820
|
+
}
|
|
2821
|
+
},
|
|
2822
|
+
},
|
|
2823
|
+
{
|
|
2824
|
+
name: '`start` downloads nothing when the recorded actions/runner version is the pinned one',
|
|
2825
|
+
run: async (ctx) => {
|
|
2826
|
+
// The refresh is for a stale box only: a current one never pays for a
|
|
2827
|
+
// 150 MB download on every start.
|
|
2828
|
+
const fs = require('fs');
|
|
2829
|
+
const os = require('os');
|
|
2830
|
+
const jetpack = require('fs-jetpack');
|
|
2831
|
+
const runner = require(path.join(__dirname, '..', '..', '..', 'commands', 'runner.js'));
|
|
2832
|
+
|
|
2833
|
+
const home = fs.mkdtempSync(path.join(os.tmpdir(), 'omega-runner-home-'));
|
|
2834
|
+
const origForce = process.env.OMEGA_RUNNER_FORCE;
|
|
2835
|
+
const origExit = process.exitCode;
|
|
2836
|
+
process.env.OMEGA_RUNNER_FORCE = '1';
|
|
2837
|
+
const hostPrefix = `omega-runner-${os.hostname().toLowerCase()}-`;
|
|
2838
|
+
const shortcut = path.join(SCRATCH_STARTUP_DIR, `${hostPrefix}acme.cmd`);
|
|
2839
|
+
const logged = [];
|
|
2840
|
+
const logger = { log: (m) => logged.push(['log', String(m)]), warn: (m) => logged.push(['warn', String(m)]), error: (m) => logged.push(['error', String(m)]) };
|
|
2841
|
+
const filled = { GH_TOKEN: 'ghp_from_the_box', WIN_EV_TOKEN_PATH: 'a'.repeat(40), WIN_CSC_KEY_PASSWORD: '1234', SIGNTOOL_PATH: 'C:/sdk/signtool.exe' };
|
|
2842
|
+
const orgDir = path.join(home, 'actions-runner-acme');
|
|
2843
|
+
const spawned = [];
|
|
2844
|
+
let downloads = 0;
|
|
2845
|
+
try {
|
|
2846
|
+
jetpack.write(path.join(home, '_template', 'config.cmd'), 'config');
|
|
2847
|
+
jetpack.write(path.join(home, 'config.json'), { actionsRunnerVersion: runner.ACTIONS_RUNNER_VERSION, registeredOrgs: ['acme'] });
|
|
2848
|
+
jetpack.write(path.join(orgDir, 'config.cmd'), 'config');
|
|
2849
|
+
jetpack.write(shortcut, '@echo off\r\n');
|
|
2850
|
+
|
|
2851
|
+
await runner({
|
|
2852
|
+
_: ['runner', 'start'], _home: home, _env: filled, _logger: logger, _interactive: false, _prompt: {},
|
|
2853
|
+
_listeners: () => [],
|
|
2854
|
+
_spawn: (dir) => { spawned.push(dir); return { ok: true, pid: 7 }; },
|
|
2855
|
+
_download: async () => { downloads++; },
|
|
2856
|
+
_discoverOrgs: async () => ['acme'],
|
|
2857
|
+
_registerOrg: async () => { throw new Error('nothing to register'); },
|
|
2858
|
+
});
|
|
2859
|
+
|
|
2860
|
+
ctx.expect(downloads).toBe(0);
|
|
2861
|
+
ctx.expect(spawned).toEqual([orgDir]);
|
|
2862
|
+
} finally {
|
|
2863
|
+
if (origForce === undefined) delete process.env.OMEGA_RUNNER_FORCE; else process.env.OMEGA_RUNNER_FORCE = origForce;
|
|
2864
|
+
process.exitCode = origExit;
|
|
2865
|
+
jetpack.remove(shortcut);
|
|
2866
|
+
jetpack.remove(home);
|
|
2867
|
+
}
|
|
2868
|
+
},
|
|
2869
|
+
},
|
|
2870
|
+
{
|
|
2871
|
+
name: '`start` registers an admin org the box does not serve yet, honouring OMEGA_RUNNER_ORGS, and nothing already registered',
|
|
2872
|
+
run: async (ctx) => {
|
|
2873
|
+
// A new admin org used to need `install` again. `start` registers the
|
|
2874
|
+
// missing one itself: named by the filter, not yet in registeredOrgs.
|
|
2875
|
+
const fs = require('fs');
|
|
2876
|
+
const os = require('os');
|
|
2877
|
+
const jetpack = require('fs-jetpack');
|
|
2878
|
+
const runner = require(path.join(__dirname, '..', '..', '..', 'commands', 'runner.js'));
|
|
2879
|
+
|
|
2880
|
+
const home = fs.mkdtempSync(path.join(os.tmpdir(), 'omega-runner-home-'));
|
|
2881
|
+
const origForce = process.env.OMEGA_RUNNER_FORCE;
|
|
2882
|
+
const origExit = process.exitCode;
|
|
2883
|
+
process.env.OMEGA_RUNNER_FORCE = '1';
|
|
2884
|
+
const hostPrefix = `omega-runner-${os.hostname().toLowerCase()}-`;
|
|
2885
|
+
const shortcut = path.join(SCRATCH_STARTUP_DIR, `${hostPrefix}acme.cmd`);
|
|
2886
|
+
const logged = [];
|
|
2887
|
+
const logger = { log: (m) => logged.push(['log', String(m)]), warn: (m) => logged.push(['warn', String(m)]), error: (m) => logged.push(['error', String(m)]) };
|
|
2888
|
+
const filled = { GH_TOKEN: 'ghp_from_the_box', WIN_EV_TOKEN_PATH: 'a'.repeat(40), WIN_CSC_KEY_PASSWORD: '1234', SIGNTOOL_PATH: 'C:/sdk/signtool.exe' };
|
|
2889
|
+
const registered = [];
|
|
2890
|
+
try {
|
|
2891
|
+
jetpack.write(path.join(home, '_template', 'config.cmd'), 'config');
|
|
2892
|
+
jetpack.write(path.join(home, 'config.json'), { actionsRunnerVersion: runner.ACTIONS_RUNNER_VERSION, registeredOrgs: ['acme'] });
|
|
2893
|
+
jetpack.write(path.join(home, 'actions-runner-acme', 'config.cmd'), 'config');
|
|
2894
|
+
jetpack.write(shortcut, '@echo off\r\n');
|
|
2895
|
+
|
|
2896
|
+
await runner({
|
|
2897
|
+
_: ['runner', 'start'], _home: home, _env: { ...filled, OMEGA_RUNNER_ORGS: 'acme, Beta' }, _logger: logger, _interactive: false, _prompt: {},
|
|
2898
|
+
_listeners: () => [],
|
|
2899
|
+
_spawn: () => ({ ok: true, pid: 8 }),
|
|
2900
|
+
_download: async () => { throw new Error('the version matches: no download'); },
|
|
2901
|
+
_discoverOrgs: async () => ['acme', 'beta', 'gamma'],
|
|
2902
|
+
_registerOrg: async (o) => { registered.push({ org: o._[2], home: o._home }); },
|
|
2903
|
+
});
|
|
2904
|
+
|
|
2905
|
+
// beta is named and new; acme is already served; gamma is not named.
|
|
2906
|
+
ctx.expect(registered).toEqual([{ org: 'beta', home }]);
|
|
2907
|
+
ctx.expect(process.exitCode).toBe(origExit);
|
|
2908
|
+
} finally {
|
|
2909
|
+
if (origForce === undefined) delete process.env.OMEGA_RUNNER_FORCE; else process.env.OMEGA_RUNNER_FORCE = origForce;
|
|
2910
|
+
process.exitCode = origExit;
|
|
2911
|
+
jetpack.remove(shortcut);
|
|
2912
|
+
jetpack.remove(home);
|
|
2913
|
+
}
|
|
2914
|
+
},
|
|
2915
|
+
},
|
|
2916
|
+
{
|
|
2917
|
+
name: '`start` works offline: an org discovery that throws is ONE skip line, and every registered org still comes up',
|
|
2918
|
+
run: async (ctx) => {
|
|
2919
|
+
// The org check is the only part of `start` that needs GitHub. A box
|
|
2920
|
+
// with no network still gets its listeners.
|
|
2921
|
+
const fs = require('fs');
|
|
2922
|
+
const os = require('os');
|
|
2923
|
+
const jetpack = require('fs-jetpack');
|
|
2924
|
+
const runner = require(path.join(__dirname, '..', '..', '..', 'commands', 'runner.js'));
|
|
2925
|
+
|
|
2926
|
+
const home = fs.mkdtempSync(path.join(os.tmpdir(), 'omega-runner-home-'));
|
|
2927
|
+
const origForce = process.env.OMEGA_RUNNER_FORCE;
|
|
2928
|
+
const origExit = process.exitCode;
|
|
2929
|
+
process.env.OMEGA_RUNNER_FORCE = '1';
|
|
2930
|
+
const hostPrefix = `omega-runner-${os.hostname().toLowerCase()}-`;
|
|
2931
|
+
const orgs = ['acme', 'zeta'];
|
|
2932
|
+
const shortcuts = orgs.map((org) => path.join(SCRATCH_STARTUP_DIR, `${hostPrefix}${org}.cmd`));
|
|
2933
|
+
const logged = [];
|
|
2934
|
+
const logger = { log: (m) => logged.push(['log', String(m)]), warn: (m) => logged.push(['warn', String(m)]), error: (m) => logged.push(['error', String(m)]) };
|
|
2935
|
+
const filled = { GH_TOKEN: 'ghp_from_the_box', WIN_EV_TOKEN_PATH: 'a'.repeat(40), WIN_CSC_KEY_PASSWORD: '1234', SIGNTOOL_PATH: 'C:/sdk/signtool.exe' };
|
|
2936
|
+
const spawned = [];
|
|
2937
|
+
let registers = 0;
|
|
2938
|
+
try {
|
|
2939
|
+
jetpack.write(path.join(home, '_template', 'config.cmd'), 'config');
|
|
2940
|
+
jetpack.write(path.join(home, 'config.json'), { actionsRunnerVersion: runner.ACTIONS_RUNNER_VERSION, registeredOrgs: orgs });
|
|
2941
|
+
for (const org of orgs) jetpack.write(path.join(home, `actions-runner-${org}`, 'config.cmd'), 'config');
|
|
2942
|
+
for (const file of shortcuts) jetpack.write(file, '@echo off\r\n');
|
|
2943
|
+
|
|
2944
|
+
await runner({
|
|
2945
|
+
_: ['runner', 'start'], _home: home, _env: filled, _logger: logger, _interactive: false, _prompt: {},
|
|
2946
|
+
_listeners: () => [],
|
|
2947
|
+
_spawn: (dir) => { spawned.push(dir); return { ok: true, pid: 9 }; },
|
|
2948
|
+
_download: async () => { throw new Error('the version matches: no download'); },
|
|
2949
|
+
_discoverOrgs: async () => { throw new Error('getaddrinfo ENOTFOUND api.github.com'); },
|
|
2950
|
+
_registerOrg: async () => { registers++; },
|
|
2951
|
+
});
|
|
2952
|
+
|
|
2953
|
+
const skips = logged.map((l) => l[1]).filter((l) => /org check skipped/i.test(l));
|
|
2954
|
+
ctx.expect(skips.length).toBe(1);
|
|
2955
|
+
ctx.expect(skips[0]).toContain('ENOTFOUND');
|
|
2956
|
+
ctx.expect(registers).toBe(0);
|
|
2957
|
+
ctx.expect(spawned).toEqual(orgs.map((org) => path.join(home, `actions-runner-${org}`)));
|
|
2958
|
+
ctx.expect(process.exitCode).toBe(origExit);
|
|
2959
|
+
} finally {
|
|
2960
|
+
if (origForce === undefined) delete process.env.OMEGA_RUNNER_FORCE; else process.env.OMEGA_RUNNER_FORCE = origForce;
|
|
2961
|
+
process.exitCode = origExit;
|
|
2962
|
+
for (const file of shortcuts) jetpack.remove(file);
|
|
2963
|
+
jetpack.remove(home);
|
|
2964
|
+
}
|
|
2965
|
+
},
|
|
2966
|
+
},
|
|
2967
|
+
{
|
|
2968
|
+
name: '`start` in a test run never asks GitHub unless both GitHub seams are injected',
|
|
2969
|
+
run: async (ctx) => {
|
|
2970
|
+
// Registration is not home-scoped: a real `registerOrg` with a real
|
|
2971
|
+
// token registers the org on GitHub whatever scratch home the case
|
|
2972
|
+
// made. A test run without `_discoverOrgs` AND `_registerOrg` skips
|
|
2973
|
+
// the org check on one line, the way `uninstall` skips the surfaces no
|
|
2974
|
+
// path redirects.
|
|
2975
|
+
const fs = require('fs');
|
|
2976
|
+
const os = require('os');
|
|
2977
|
+
const jetpack = require('fs-jetpack');
|
|
2978
|
+
const runner = require(path.join(__dirname, '..', '..', '..', 'commands', 'runner.js'));
|
|
2979
|
+
|
|
2980
|
+
const home = fs.mkdtempSync(path.join(os.tmpdir(), 'omega-runner-home-'));
|
|
2981
|
+
const origForce = process.env.OMEGA_RUNNER_FORCE;
|
|
2982
|
+
const origExit = process.exitCode;
|
|
2983
|
+
process.env.OMEGA_RUNNER_FORCE = '1';
|
|
2984
|
+
const logged = [];
|
|
2985
|
+
const logger = { log: (m) => logged.push(['log', String(m)]), warn: (m) => logged.push(['warn', String(m)]), error: (m) => logged.push(['error', String(m)]) };
|
|
2986
|
+
const filled = { GH_TOKEN: 'ghp_from_the_box', WIN_EV_TOKEN_PATH: 'a'.repeat(40), WIN_CSC_KEY_PASSWORD: '1234', SIGNTOOL_PATH: 'C:/sdk/signtool.exe' };
|
|
2987
|
+
let discovers = 0;
|
|
2988
|
+
try {
|
|
2989
|
+
jetpack.write(path.join(home, '_template', 'config.cmd'), 'config');
|
|
2990
|
+
jetpack.write(path.join(home, 'config.json'), { actionsRunnerVersion: runner.ACTIONS_RUNNER_VERSION, registeredOrgs: [] });
|
|
2991
|
+
|
|
2992
|
+
await runner({
|
|
2993
|
+
_: ['runner', 'start'], _home: home, _env: filled, _logger: logger, _interactive: false, _prompt: {},
|
|
2994
|
+
_listeners: () => [],
|
|
2995
|
+
_spawn: () => ({ ok: true, pid: 10 }),
|
|
2996
|
+
_discoverOrgs: async () => { discovers++; return ['acme']; }, // no _registerOrg
|
|
2997
|
+
});
|
|
2998
|
+
|
|
2999
|
+
ctx.expect(discovers).toBe(0);
|
|
3000
|
+
const skips = logged.map((l) => l[1]).filter((l) => /org check skipped/i.test(l));
|
|
3001
|
+
ctx.expect(skips.length).toBe(1);
|
|
3002
|
+
ctx.expect(skips[0]).toContain('_registerOrg');
|
|
3003
|
+
} finally {
|
|
3004
|
+
if (origForce === undefined) delete process.env.OMEGA_RUNNER_FORCE; else process.env.OMEGA_RUNNER_FORCE = origForce;
|
|
3005
|
+
process.exitCode = origExit;
|
|
3006
|
+
jetpack.remove(home);
|
|
3007
|
+
}
|
|
3008
|
+
},
|
|
3009
|
+
},
|
|
3010
|
+
{
|
|
3011
|
+
name: '`self-update` is gone: the dispatcher calls it an unknown subcommand',
|
|
3012
|
+
run: async (ctx) => {
|
|
3013
|
+
// Every runner verb runs as `npx omega runner <verb>` from the box's
|
|
3014
|
+
// clone, so there is no global package for it to update (#937). The
|
|
3015
|
+
// home is one the test guard refuses, so no build of this command,
|
|
3016
|
+
// however old, can run a global npm install from this case.
|
|
3017
|
+
const os = require('os');
|
|
3018
|
+
const jetpack = require('fs-jetpack');
|
|
3019
|
+
const runner = require(path.join(__dirname, '..', '..', '..', 'commands', 'runner.js'));
|
|
3020
|
+
|
|
3021
|
+
const realish = path.join(os.homedir(), 'omega-runner-NOT-A-SCRATCH');
|
|
3022
|
+
let threw;
|
|
3023
|
+
try {
|
|
3024
|
+
await runner({ _: ['runner', 'self-update'], _home: realish });
|
|
3025
|
+
} catch (e) { threw = e; }
|
|
3026
|
+
ctx.expect(threw).toBeDefined();
|
|
3027
|
+
ctx.expect(threw.message).toBe('Unknown runner subcommand: self-update');
|
|
3028
|
+
ctx.expect(jetpack.exists(realish)).toBe(false);
|
|
3029
|
+
},
|
|
3030
|
+
},
|
|
3031
|
+
{
|
|
3032
|
+
name: '`start` called from install (`_reconcileDone`) skips the reconcile: no download and no org check, even on a stale version with a missing org',
|
|
3033
|
+
run: async (ctx) => {
|
|
3034
|
+
// install has just downloaded the template and registered every org, so
|
|
3035
|
+
// its closing start has nothing to reconcile, and a retry of an org that
|
|
3036
|
+
// failed there would print its error a second time.
|
|
3037
|
+
const fs = require('fs');
|
|
3038
|
+
const os = require('os');
|
|
3039
|
+
const jetpack = require('fs-jetpack');
|
|
3040
|
+
const runner = require(path.join(__dirname, '..', '..', '..', 'commands', 'runner.js'));
|
|
3041
|
+
|
|
3042
|
+
const home = fs.mkdtempSync(path.join(os.tmpdir(), 'omega-runner-home-'));
|
|
3043
|
+
const origForce = process.env.OMEGA_RUNNER_FORCE;
|
|
3044
|
+
const origExit = process.exitCode;
|
|
3045
|
+
process.env.OMEGA_RUNNER_FORCE = '1';
|
|
3046
|
+
const hostPrefix = `omega-runner-${os.hostname().toLowerCase()}-`;
|
|
3047
|
+
const shortcut = path.join(SCRATCH_STARTUP_DIR, `${hostPrefix}acme.cmd`);
|
|
3048
|
+
const logged = [];
|
|
3049
|
+
const logger = { log: (m) => logged.push(['log', String(m)]), warn: (m) => logged.push(['warn', String(m)]), error: (m) => logged.push(['error', String(m)]) };
|
|
3050
|
+
const filled = { GH_TOKEN: 'ghp_from_the_box', WIN_EV_TOKEN_PATH: 'a'.repeat(40), WIN_CSC_KEY_PASSWORD: '1234', SIGNTOOL_PATH: 'C:/sdk/signtool.exe' };
|
|
3051
|
+
const orgDir = path.join(home, 'actions-runner-acme');
|
|
3052
|
+
const spawned = [];
|
|
3053
|
+
let downloads = 0;
|
|
3054
|
+
let discovers = 0;
|
|
3055
|
+
let registers = 0;
|
|
3056
|
+
try {
|
|
3057
|
+
jetpack.write(path.join(home, '_template', 'config.cmd'), 'config');
|
|
3058
|
+
jetpack.write(path.join(home, 'config.json'), { actionsRunnerVersion: '2.300.0', registeredOrgs: ['acme'] });
|
|
3059
|
+
jetpack.write(path.join(orgDir, 'config.cmd'), 'config');
|
|
3060
|
+
jetpack.write(shortcut, '@echo off\r\n');
|
|
3061
|
+
|
|
3062
|
+
await runner({
|
|
3063
|
+
_: ['runner', 'start'], _home: home, _env: filled, _logger: logger, _interactive: false, _prompt: {},
|
|
3064
|
+
_reconcileDone: true,
|
|
3065
|
+
_listeners: () => [],
|
|
3066
|
+
_spawn: (dir) => { spawned.push(dir); return { ok: true, pid: 11 }; },
|
|
3067
|
+
_download: async () => { downloads++; },
|
|
3068
|
+
_discoverOrgs: async () => { discovers++; return ['acme', 'beta']; },
|
|
3069
|
+
_registerOrg: async () => { registers++; },
|
|
3070
|
+
});
|
|
3071
|
+
|
|
3072
|
+
ctx.expect(downloads).toBe(0);
|
|
3073
|
+
ctx.expect(discovers).toBe(0);
|
|
3074
|
+
ctx.expect(registers).toBe(0);
|
|
3075
|
+
ctx.expect(jetpack.read(path.join(home, 'config.json'), 'json').actionsRunnerVersion).toBe('2.300.0');
|
|
3076
|
+
ctx.expect(spawned).toEqual([orgDir]); // the spawns still run
|
|
3077
|
+
} finally {
|
|
3078
|
+
if (origForce === undefined) delete process.env.OMEGA_RUNNER_FORCE; else process.env.OMEGA_RUNNER_FORCE = origForce;
|
|
3079
|
+
process.exitCode = origExit;
|
|
3080
|
+
jetpack.remove(shortcut);
|
|
3081
|
+
jetpack.remove(home);
|
|
3082
|
+
}
|
|
3083
|
+
},
|
|
3084
|
+
},
|
|
3085
|
+
{
|
|
3086
|
+
name: '`start` survives a refresh download that fails: one warn, no version recorded, every org still comes up',
|
|
3087
|
+
run: async (ctx) => {
|
|
3088
|
+
// A stale box with no network must still come online: the refresh is
|
|
3089
|
+
// skipped until the next start, never the whole run.
|
|
3090
|
+
const fs = require('fs');
|
|
3091
|
+
const os = require('os');
|
|
3092
|
+
const jetpack = require('fs-jetpack');
|
|
3093
|
+
const runner = require(path.join(__dirname, '..', '..', '..', 'commands', 'runner.js'));
|
|
3094
|
+
|
|
3095
|
+
const home = fs.mkdtempSync(path.join(os.tmpdir(), 'omega-runner-home-'));
|
|
3096
|
+
const origForce = process.env.OMEGA_RUNNER_FORCE;
|
|
3097
|
+
const origExit = process.exitCode;
|
|
3098
|
+
process.env.OMEGA_RUNNER_FORCE = '1';
|
|
3099
|
+
const hostPrefix = `omega-runner-${os.hostname().toLowerCase()}-`;
|
|
3100
|
+
const orgs = ['acme', 'zeta'];
|
|
3101
|
+
const shortcuts = orgs.map((org) => path.join(SCRATCH_STARTUP_DIR, `${hostPrefix}${org}.cmd`));
|
|
3102
|
+
const logged = [];
|
|
3103
|
+
const logger = { log: (m) => logged.push(['log', String(m)]), warn: (m) => logged.push(['warn', String(m)]), error: (m) => logged.push(['error', String(m)]) };
|
|
3104
|
+
const filled = { GH_TOKEN: 'ghp_from_the_box', WIN_EV_TOKEN_PATH: 'a'.repeat(40), WIN_CSC_KEY_PASSWORD: '1234', SIGNTOOL_PATH: 'C:/sdk/signtool.exe' };
|
|
3105
|
+
const spawned = [];
|
|
3106
|
+
try {
|
|
3107
|
+
jetpack.write(path.join(home, '_template', 'config.cmd'), 'old config');
|
|
3108
|
+
jetpack.write(path.join(home, 'config.json'), { actionsRunnerVersion: '2.300.0', registeredOrgs: orgs });
|
|
3109
|
+
for (const org of orgs) jetpack.write(path.join(home, `actions-runner-${org}`, 'config.cmd'), 'old config');
|
|
3110
|
+
for (const file of shortcuts) jetpack.write(file, '@echo off\r\n');
|
|
3111
|
+
|
|
3112
|
+
await runner({
|
|
3113
|
+
_: ['runner', 'start'], _home: home, _env: filled, _logger: logger, _interactive: false, _prompt: {},
|
|
3114
|
+
_listeners: () => [],
|
|
3115
|
+
_spawn: (dir) => { spawned.push(dir); return { ok: true, pid: 12 }; },
|
|
3116
|
+
_download: async () => { throw new Error('curl exit 6'); },
|
|
3117
|
+
_discoverOrgs: async () => orgs,
|
|
3118
|
+
_registerOrg: async () => { throw new Error('nothing to register'); },
|
|
3119
|
+
});
|
|
3120
|
+
|
|
3121
|
+
const warns = logged.filter((l) => l[0] === 'warn' && l[1].includes('curl exit 6'));
|
|
3122
|
+
ctx.expect(warns.length).toBe(1);
|
|
3123
|
+
ctx.expect(jetpack.read(path.join(home, 'config.json'), 'json').actionsRunnerVersion).toBe('2.300.0');
|
|
3124
|
+
for (const org of orgs) ctx.expect(fs.readFileSync(path.join(home, `actions-runner-${org}`, 'config.cmd'), 'utf8')).toBe('old config');
|
|
3125
|
+
ctx.expect(spawned).toEqual(orgs.map((org) => path.join(home, `actions-runner-${org}`)));
|
|
3126
|
+
ctx.expect(process.exitCode).toBe(origExit);
|
|
3127
|
+
} finally {
|
|
3128
|
+
if (origForce === undefined) delete process.env.OMEGA_RUNNER_FORCE; else process.env.OMEGA_RUNNER_FORCE = origForce;
|
|
3129
|
+
process.exitCode = origExit;
|
|
3130
|
+
for (const file of shortcuts) jetpack.remove(file);
|
|
3131
|
+
jetpack.remove(home);
|
|
3132
|
+
}
|
|
3133
|
+
},
|
|
3134
|
+
},
|
|
3135
|
+
{
|
|
3136
|
+
name: '`start` on a bare box in a test run refuses without an injected `_install`, and installs nothing',
|
|
3137
|
+
run: async (ctx) => {
|
|
3138
|
+
// The real install downloads, discovers and registers against GitHub.
|
|
3139
|
+
// A test run reaches it only through the seam, the way deregistration
|
|
3140
|
+
// refuses without its own.
|
|
3141
|
+
const fs = require('fs');
|
|
3142
|
+
const os = require('os');
|
|
3143
|
+
const jetpack = require('fs-jetpack');
|
|
3144
|
+
const runner = require(path.join(__dirname, '..', '..', '..', 'commands', 'runner.js'));
|
|
3145
|
+
|
|
3146
|
+
const home = fs.mkdtempSync(path.join(os.tmpdir(), 'omega-runner-home-'));
|
|
3147
|
+
const origForce = process.env.OMEGA_RUNNER_FORCE;
|
|
3148
|
+
process.env.OMEGA_RUNNER_FORCE = '1';
|
|
3149
|
+
const logger = { log: () => {}, warn: () => {}, error: () => {} };
|
|
3150
|
+
const filled = { GH_TOKEN: 'ghp_from_the_box', WIN_EV_TOKEN_PATH: 'a'.repeat(40), WIN_CSC_KEY_PASSWORD: '1234', SIGNTOOL_PATH: 'C:/sdk/signtool.exe' };
|
|
3151
|
+
try {
|
|
3152
|
+
let threw;
|
|
3153
|
+
try {
|
|
3154
|
+
await runner({ _: ['runner', 'start'], _home: home, _env: filled, _logger: logger, _interactive: false, _prompt: {}, _listeners: () => [], _spawn: () => ({ ok: true, pid: 13 }) });
|
|
3155
|
+
} catch (e) { threw = e; }
|
|
3156
|
+
ctx.expect(threw).toBeDefined();
|
|
3157
|
+
ctx.expect(threw.message).toContain('_install');
|
|
3158
|
+
ctx.expect(jetpack.exists(path.join(home, '_template'))).toBe(false);
|
|
3159
|
+
ctx.expect(jetpack.exists(path.join(home, '.env'))).toBe(false);
|
|
3160
|
+
} finally {
|
|
3161
|
+
if (origForce === undefined) delete process.env.OMEGA_RUNNER_FORCE; else process.env.OMEGA_RUNNER_FORCE = origForce;
|
|
3162
|
+
jetpack.remove(home);
|
|
3163
|
+
}
|
|
3164
|
+
},
|
|
3165
|
+
},
|
|
3166
|
+
{
|
|
3167
|
+
name: '`restart` refreshes a stale actions/runner AFTER its stop, once the listener is gone, and records the version',
|
|
3168
|
+
run: async (ctx) => {
|
|
3169
|
+
// The reconcile is not gated on restart's preflight: after the stop is
|
|
3170
|
+
// exactly when an org's binaries are free to be replaced.
|
|
3171
|
+
const fs = require('fs');
|
|
3172
|
+
const os = require('os');
|
|
3173
|
+
const jetpack = require('fs-jetpack');
|
|
3174
|
+
const runner = require(path.join(__dirname, '..', '..', '..', 'commands', 'runner.js'));
|
|
3175
|
+
|
|
3176
|
+
const home = fs.mkdtempSync(path.join(os.tmpdir(), 'omega-runner-home-'));
|
|
3177
|
+
const origForce = process.env.OMEGA_RUNNER_FORCE;
|
|
3178
|
+
const origExit = process.exitCode;
|
|
3179
|
+
process.env.OMEGA_RUNNER_FORCE = '1';
|
|
3180
|
+
const hostPrefix = `omega-runner-${os.hostname().toLowerCase()}-`;
|
|
3181
|
+
const shortcut = path.join(SCRATCH_STARTUP_DIR, `${hostPrefix}acme.cmd`);
|
|
3182
|
+
const order = [];
|
|
3183
|
+
const logger = {
|
|
3184
|
+
log: (m) => { if (String(m).includes('already stopped')) order.push('stop'); },
|
|
3185
|
+
warn: () => {},
|
|
3186
|
+
error: () => {},
|
|
3187
|
+
};
|
|
3188
|
+
const filled = { GH_TOKEN: 'ghp_from_the_box', WIN_EV_TOKEN_PATH: 'a'.repeat(40), WIN_CSC_KEY_PASSWORD: '1234', SIGNTOOL_PATH: 'C:/sdk/signtool.exe' };
|
|
3189
|
+
const orgDir = path.join(home, 'actions-runner-acme');
|
|
3190
|
+
const spawned = [];
|
|
3191
|
+
try {
|
|
3192
|
+
jetpack.write(path.join(home, '_template', 'config.cmd'), 'old config');
|
|
3193
|
+
jetpack.write(path.join(home, 'config.json'), { actionsRunnerVersion: '2.300.0', registeredOrgs: ['acme'] });
|
|
3194
|
+
jetpack.write(path.join(orgDir, 'config.cmd'), 'old config');
|
|
3195
|
+
jetpack.write(shortcut, '@echo off\r\n');
|
|
3196
|
+
|
|
3197
|
+
// Alive for the first two polls, gone after.
|
|
3198
|
+
let looks = 0;
|
|
3199
|
+
await runner({
|
|
3200
|
+
_: ['runner', 'restart'], _home: home, _env: filled, _logger: logger, _interactive: false, _prompt: {},
|
|
3201
|
+
_delay: async () => {},
|
|
3202
|
+
_listeners: () => {
|
|
3203
|
+
const alive = ++looks <= 2;
|
|
3204
|
+
order.push(alive ? 'alive' : 'gone');
|
|
3205
|
+
return alive ? [{ pid: 909, sessionId: 1, execPath: path.join(orgDir, 'bin', 'Runner.Listener.exe') }] : [];
|
|
3206
|
+
},
|
|
3207
|
+
_spawn: (dir) => { spawned.push(dir); return { ok: true, pid: 14 }; },
|
|
3208
|
+
_download: async (dir) => { order.push('download'); jetpack.write(path.join(dir, 'config.cmd'), 'new config'); },
|
|
3209
|
+
_discoverOrgs: async () => ['acme'],
|
|
3210
|
+
_registerOrg: async () => { throw new Error('nothing to register'); },
|
|
3211
|
+
});
|
|
3212
|
+
|
|
3213
|
+
ctx.expect(order.indexOf('stop')).toBeGreaterThan(-1);
|
|
3214
|
+
ctx.expect(order.indexOf('download')).toBeGreaterThan(order.indexOf('stop'));
|
|
3215
|
+
ctx.expect(order.indexOf('download')).toBeGreaterThan(order.lastIndexOf('alive'));
|
|
3216
|
+
ctx.expect(fs.readFileSync(path.join(orgDir, 'config.cmd'), 'utf8')).toBe('new config');
|
|
3217
|
+
ctx.expect(jetpack.read(path.join(home, 'config.json'), 'json').actionsRunnerVersion).toBe(runner.ACTIONS_RUNNER_VERSION);
|
|
3218
|
+
ctx.expect(spawned).toEqual([orgDir]);
|
|
3219
|
+
ctx.expect(process.exitCode).toBe(origExit);
|
|
3220
|
+
} finally {
|
|
3221
|
+
if (origForce === undefined) delete process.env.OMEGA_RUNNER_FORCE; else process.env.OMEGA_RUNNER_FORCE = origForce;
|
|
3222
|
+
process.exitCode = origExit;
|
|
3223
|
+
jetpack.remove(shortcut);
|
|
3224
|
+
jetpack.remove(home);
|
|
3225
|
+
}
|
|
3226
|
+
},
|
|
3227
|
+
},
|
|
2598
3228
|
],
|
|
2599
3229
|
});
|