Skip to content

Commit 20129eb

Browse files
committed
feat(templates): add universal-large launch template
1 parent b27032f commit 20129eb

11 files changed

Lines changed: 649 additions & 0 deletions

File tree

launch-templates/linux.yaml

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,51 @@ common-js-init-steps: &common-js-init-steps
4040
- name: Install Browsers (if needed)
4141
uses: 'nrwl/nx-cloud-workflows/v5/workflow-steps/install-browsers/main.yaml'
4242

43+
common-universal-init-steps: &common-universal-init-steps
44+
- name: Checkout
45+
uses: 'nrwl/nx-cloud-workflows/v5/workflow-steps/checkout/main.yaml'
46+
- name: Restore Node Modules Cache
47+
uses: 'nrwl/nx-cloud-workflows/v5/workflow-steps/cache/main.yaml'
48+
inputs:
49+
key: 'package-lock.json|yarn.lock|pnpm-lock.yaml|patches/**|.yarn/patches/**'
50+
paths: 'node_modules'
51+
base-branch: 'main'
52+
- name: Restore Browser Binary Cache
53+
uses: 'nrwl/nx-cloud-workflows/v5/workflow-steps/cache/main.yaml'
54+
inputs:
55+
key: 'package-lock.json|yarn.lock|pnpm-lock.yaml|"browsers"'
56+
paths: |
57+
'../.cache/Cypress'
58+
base-branch: 'main'
59+
- name: Restore Rust Cache
60+
uses: 'nrwl/nx-cloud-workflows/v5/workflow-steps/cache/main.yaml'
61+
inputs:
62+
key: '"2" | Cargo.lock | rust-toolchain.toml'
63+
paths: '~/.cargo'
64+
base-branch: 'main'
65+
- name: Restore Gradle Dependencies Cache
66+
uses: 'nrwl/nx-cloud-workflows/v5/workflow-steps/cache/main.yaml'
67+
inputs:
68+
key: '"1" | gradle/wrapper/gradle-wrapper.properties | gradle/libs.versions.toml | gradle.properties | settings.gradle.kts | build.gradle.kts'
69+
paths: '~/.gradle/caches'
70+
base-branch: 'main'
71+
- name: Restore Gradle Wrapper Cache
72+
uses: 'nrwl/nx-cloud-workflows/v5/workflow-steps/cache/main.yaml'
73+
inputs:
74+
key: '"1" | gradle/wrapper/gradle-wrapper.properties'
75+
paths: '~/.gradle/wrapper'
76+
base-branch: 'main'
77+
- name: Install Mise (if config present)
78+
uses: 'nrwl/nx-cloud-workflows/v5/workflow-steps/install-mise-if-present/main.yaml'
79+
- name: Install Rust (if Rust project)
80+
uses: 'nrwl/nx-cloud-workflows/v5/workflow-steps/install-rust-if-present/main.yaml'
81+
- name: Install Node (if JS project)
82+
uses: 'nrwl/nx-cloud-workflows/v5/workflow-steps/install-node-if-present/main.yaml'
83+
- name: Install Node Modules (if lock file)
84+
uses: 'nrwl/nx-cloud-workflows/v5/workflow-steps/install-node-modules-if-present/main.yaml'
85+
- name: Install Java (if JVM project)
86+
uses: 'nrwl/nx-cloud-workflows/v5/workflow-steps/install-java-if-present/main.yaml'
87+
4388
launch-templates:
4489
linux-small-js:
4590
resource-class: 'docker_linux_amd64/small'
@@ -125,3 +170,7 @@ launch-templates:
125170
resource-class: 'docker_linux_amd64/extra_large+'
126171
image: 'ubuntu22.04-node20.19-v2'
127172
init-steps: *common-dotnet-init-steps
173+
universal-large:
174+
resource-class: 'docker_linux_amd64/large'
175+
image: 'ubuntu22.04-node20.19-v2'
176+
init-steps: *common-universal-init-steps
Lines changed: 148 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,148 @@
1+
const { platform, arch, tmpdir } = require('os');
2+
const { execSync } = require('child_process');
3+
const { existsSync, writeFileSync } = require('fs');
4+
5+
const jvmMarkers = [
6+
'build.gradle',
7+
'build.gradle.kts',
8+
'settings.gradle',
9+
'settings.gradle.kts',
10+
'pom.xml',
11+
];
12+
13+
if (!jvmMarkers.some((f) => existsSync(f))) {
14+
console.log(
15+
'No JVM project detected (no build.gradle, build.gradle.kts, settings.gradle*, or pom.xml). Skipping Java install.',
16+
);
17+
return;
18+
}
19+
20+
if (
21+
existsSync('mise.toml') ||
22+
existsSync('.mise.toml') ||
23+
existsSync('.tool-versions')
24+
) {
25+
console.log(
26+
'Mise config detected — Java is expected to be managed via mise. Skipping auto java=<version> install to avoid overwriting the user config.',
27+
);
28+
return;
29+
}
30+
31+
const javaVersion = process.env.NX_CLOUD_INPUT_java_version || '21';
32+
console.log(`JVM project detected. Installing Java ${javaVersion} via mise...`);
33+
34+
// Write a mise.toml so the inlined mise install picks up the tool.
35+
writeFileSync('mise.toml', `[tools]\njava = "${javaVersion}"\n`, {
36+
encoding: 'utf-8',
37+
});
38+
39+
// --- inlined install-mise logic ---
40+
41+
const miseGhVersion =
42+
process.env['NX_CLOUD_INPUT_mise-version'] || 'v2025.12.2';
43+
const installArgs = process.env['NX_CLOUD_INPUT_install-args'] || '';
44+
45+
const MISE_INSTALL_DIR = '$HOME/.local/bin';
46+
const MISE_SHIM_DIR = '$HOME/.local/share/mise/shims';
47+
const TMP_DIR = tmpdir();
48+
49+
process.env.MISE_TRUSTED_CONFIG_PATHS = process.cwd();
50+
process.env.MISE_YES = '1';
51+
52+
function retryWithBackoff(
53+
fn,
54+
maxRetries = 3,
55+
retryDelayMs = 1000,
56+
fnName = 'operation',
57+
) {
58+
let lastError;
59+
for (let attempt = 1; attempt <= maxRetries; attempt++) {
60+
try {
61+
fn();
62+
if (attempt > 1)
63+
console.log(`> ${fnName} succeeded on attempt ${attempt}`);
64+
return;
65+
} catch (error) {
66+
lastError = error;
67+
console.error(`> ${fnName} failed on attempt ${attempt}/${maxRetries}`);
68+
console.error(` Error: ${error.message}`);
69+
if (attempt < maxRetries) {
70+
const delay = retryDelayMs * Math.pow(2, attempt - 1);
71+
console.log(`> Retrying in ${delay}ms...`);
72+
execSync(`sleep ${delay / 1000}`, { stdio: 'inherit' });
73+
}
74+
}
75+
}
76+
throw lastError;
77+
}
78+
79+
if (!miseGhVersion.startsWith('v')) {
80+
console.error(`Invalid mise_version: ${miseGhVersion}`);
81+
process.exit(1);
82+
}
83+
84+
function getVersionUrl(_platform, _arch) {
85+
let resolvedPlatform;
86+
let resolvedArch;
87+
if (_platform === 'darwin') resolvedPlatform = 'macos';
88+
else if (_platform === 'win32') resolvedPlatform = 'windows';
89+
else resolvedPlatform = 'linux';
90+
91+
if (_arch === 'x64' || _arch === 'arm64') resolvedArch = _arch;
92+
else {
93+
console.error('Unsupported architecture: ', _arch);
94+
process.exit(1);
95+
}
96+
97+
const version = `${miseGhVersion}-${resolvedPlatform}-${resolvedArch}`;
98+
const url = `https://github.com/jdx/mise/releases/download/${miseGhVersion}/mise-${version}.tar.gz`;
99+
console.log(`> Resolved mise version to download as: ${version}`);
100+
return url;
101+
}
102+
103+
function downloadMise(downloadUrl) {
104+
console.log(`> Downloading mise from ${downloadUrl}`);
105+
execSync(`mkdir -p ${MISE_INSTALL_DIR}`, { stdio: 'inherit' });
106+
retryWithBackoff(
107+
() => {
108+
execSync(`curl -fsSL ${downloadUrl} | tar -xzf - -C ${TMP_DIR}`, {
109+
stdio: 'inherit',
110+
});
111+
},
112+
3,
113+
1000,
114+
'mise download',
115+
);
116+
execSync(`mv ${TMP_DIR}/mise/bin/mise ${MISE_INSTALL_DIR}/mise`, {
117+
stdio: 'inherit',
118+
});
119+
}
120+
121+
function setupMise(installCommandArgs) {
122+
execSync(`chmod +x ${MISE_INSTALL_DIR}/mise`, { stdio: 'inherit' });
123+
execSync(`mkdir -p ${MISE_SHIM_DIR}`, { stdio: 'inherit' });
124+
125+
const newPATH = `${MISE_INSTALL_DIR}:${MISE_SHIM_DIR}:$PATH`;
126+
const setPath = `export PATH="${newPATH}" && echo PATH="${newPATH}" >> $NX_CLOUD_ENV`;
127+
const setMiseEnvVars = `echo "MISE_YES=1" >> $NX_CLOUD_ENV && echo "MISE_TRUSTED_CONFIG_PATHS=$HOME/workspace" >> $NX_CLOUD_ENV`;
128+
const whichMise = `echo "mise is located at $(which mise)"`;
129+
const miseVersion = `echo "mise version is: $(mise version)"`;
130+
const installMiseTools = `mise install ${installCommandArgs}`;
131+
132+
execSync(
133+
[setPath, setMiseEnvVars, whichMise, miseVersion, installMiseTools].join(
134+
' && ',
135+
),
136+
{ stdio: 'inherit' },
137+
);
138+
}
139+
140+
try {
141+
const dlUrl = getVersionUrl(platform(), arch());
142+
downloadMise(dlUrl);
143+
setupMise(installArgs);
144+
} catch (error) {
145+
console.error('> Failed to install Java via mise:');
146+
console.error(error);
147+
process.exit(1);
148+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
name: Install Java (if JVM project present)
2+
description: Installs Java via mise when a Gradle or Maven project is detected (build.gradle, build.gradle.kts, settings.gradle*, or pom.xml). Otherwise skips.
3+
inputs:
4+
- name: java_version
5+
description: 'Java version to install (passed to mise as java=<version>).'
6+
default: '21'
7+
8+
definition:
9+
using: 'node'
10+
main: workflow-steps/install-java-if-present/main.js
Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
const { platform, arch, tmpdir } = require('os');
2+
const { execSync } = require('child_process');
3+
const { existsSync } = require('fs');
4+
5+
const miseMarkers = ['mise.toml', '.mise.toml', '.tool-versions'];
6+
7+
if (!miseMarkers.some((f) => existsSync(f))) {
8+
console.log(
9+
'No mise config detected (no mise.toml, .mise.toml, or .tool-versions). Skipping mise install.',
10+
);
11+
return;
12+
}
13+
14+
// --- inlined install-mise logic (minus setToolVersions, since we use the
15+
// existing mise config file from the repo) ---
16+
17+
const runInstall = process.env['NX_CLOUD_INPUT_auto-install']
18+
? process.env['NX_CLOUD_INPUT_auto-install'] === 'true'
19+
: true;
20+
const miseGhVersion =
21+
process.env['NX_CLOUD_INPUT_mise-version'] || 'v2025.12.2';
22+
const installArgs = process.env['NX_CLOUD_INPUT_install-args'] || '';
23+
24+
const MISE_INSTALL_DIR = '$HOME/.local/bin';
25+
const MISE_SHIM_DIR = '$HOME/.local/share/mise/shims';
26+
const TMP_DIR = tmpdir();
27+
28+
process.env.MISE_TRUSTED_CONFIG_PATHS = process.cwd();
29+
process.env.MISE_YES = '1';
30+
31+
function retryWithBackoff(
32+
fn,
33+
maxRetries = 3,
34+
retryDelayMs = 1000,
35+
fnName = 'operation',
36+
) {
37+
let lastError;
38+
for (let attempt = 1; attempt <= maxRetries; attempt++) {
39+
try {
40+
fn();
41+
if (attempt > 1)
42+
console.log(`> ${fnName} succeeded on attempt ${attempt}`);
43+
return;
44+
} catch (error) {
45+
lastError = error;
46+
console.error(`> ${fnName} failed on attempt ${attempt}/${maxRetries}`);
47+
console.error(` Error: ${error.message}`);
48+
if (attempt < maxRetries) {
49+
const delay = retryDelayMs * Math.pow(2, attempt - 1);
50+
console.log(`> Retrying in ${delay}ms...`);
51+
execSync(`sleep ${delay / 1000}`, { stdio: 'inherit' });
52+
}
53+
}
54+
}
55+
console.error(`> ${fnName} failed after ${maxRetries} attempts`);
56+
throw lastError;
57+
}
58+
59+
if (!miseGhVersion.startsWith('v')) {
60+
console.error(`Invalid mise_version: ${miseGhVersion}`);
61+
process.exit(1);
62+
}
63+
64+
function getVersionUrl(_platform, _arch) {
65+
let resolvedPlatform;
66+
let resolvedArch;
67+
if (_platform === 'darwin') resolvedPlatform = 'macos';
68+
else if (_platform === 'win32') resolvedPlatform = 'windows';
69+
else resolvedPlatform = 'linux';
70+
71+
if (_arch === 'x64' || _arch === 'arm64') resolvedArch = _arch;
72+
else {
73+
console.error('Unsupported architecture: ', _arch);
74+
process.exit(1);
75+
}
76+
77+
const version = `${miseGhVersion}-${resolvedPlatform}-${resolvedArch}`;
78+
const url = `https://github.com/jdx/mise/releases/download/${miseGhVersion}/mise-${version}.tar.gz`;
79+
console.log(`> Resolved mise version to download as: ${version}`);
80+
return url;
81+
}
82+
83+
function downloadMise(downloadUrl) {
84+
console.log(`> Downloading mise from ${downloadUrl}`);
85+
execSync(`mkdir -p ${MISE_INSTALL_DIR}`, { stdio: 'inherit' });
86+
retryWithBackoff(
87+
() => {
88+
execSync(`curl -fsSL ${downloadUrl} | tar -xzf - -C ${TMP_DIR}`, {
89+
stdio: 'inherit',
90+
});
91+
},
92+
3,
93+
1000,
94+
'mise download',
95+
);
96+
console.log(`> Download successful! Moving binary to: ${MISE_INSTALL_DIR}`);
97+
execSync(`mv ${TMP_DIR}/mise/bin/mise ${MISE_INSTALL_DIR}/mise`, {
98+
stdio: 'inherit',
99+
});
100+
}
101+
102+
function setupMise(autoInstall, installCommandArgs) {
103+
console.log('> Setting up mise...\n\n');
104+
execSync(`chmod +x ${MISE_INSTALL_DIR}/mise`, { stdio: 'inherit' });
105+
execSync(`mkdir -p ${MISE_SHIM_DIR}`, { stdio: 'inherit' });
106+
107+
const newPATH = `${MISE_INSTALL_DIR}:${MISE_SHIM_DIR}:$PATH`;
108+
const setPath = `export PATH="${newPATH}" && echo PATH="${newPATH}" >> $NX_CLOUD_ENV`;
109+
const setMiseEnvVars = `echo "MISE_YES=1" >> $NX_CLOUD_ENV && echo "MISE_TRUSTED_CONFIG_PATHS=$HOME/workspace" >> $NX_CLOUD_ENV`;
110+
const whichMise = `echo "mise is located at $(which mise)"`;
111+
const miseVersion = `echo "mise version is: $(mise version)"`;
112+
const installMiseTools = autoInstall
113+
? `mise install ${installCommandArgs}`
114+
: `echo "Skipping auto install. You will need to manually run mise install"`;
115+
116+
execSync(
117+
[setPath, setMiseEnvVars, whichMise, miseVersion, installMiseTools].join(
118+
' && ',
119+
),
120+
{ stdio: 'inherit' },
121+
);
122+
console.log('\n> Finished setting up mise!');
123+
}
124+
125+
try {
126+
const dlUrl = getVersionUrl(platform(), arch());
127+
downloadMise(dlUrl);
128+
setupMise(runInstall, installArgs);
129+
} catch (error) {
130+
console.error('> Failed to install mise: ');
131+
console.error(error);
132+
process.exit(1);
133+
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
name: Install Mise (if mise config present)
2+
description: Installs mise and any tools defined in mise.toml, .mise.toml, or .tool-versions. Skips if no config is detected.
3+
4+
definition:
5+
using: 'node'
6+
main: workflow-steps/install-mise-if-present/main.js

0 commit comments

Comments
 (0)