Skip to content

Commit 76cee5b

Browse files
committed
create standalone action for wsl steps
1 parent 9259b3c commit 76cee5b

File tree

5 files changed

+283
-57
lines changed

5 files changed

+283
-57
lines changed

.github/actions/wsl-run/.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
node_modules/

.github/actions/wsl-run/action.yml

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
name: 'WSL Run Action'
2+
description: 'Runs GitHub actions in WSL environment'
3+
inputs:
4+
uses:
5+
description: 'The action to run in WSL'
6+
required: false
7+
with:
8+
description: 'Input parameters for the action'
9+
required: false
10+
run:
11+
description: 'Commands to run in WSL bash shell'
12+
required: false
13+
runs:
14+
using: 'node20'
15+
main: 'wsl-run-action.js'

.github/actions/wsl-run/package.json

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
{
2+
"name": "wsl-run-action",
3+
"version": "1.0.0",
4+
"description": "GitHub action to run commands or other actions in WSL environment",
5+
"main": "wsl-run-action.js",
6+
"scripts": {
7+
"test": "echo \"Error: no test specified\" && exit 1"
8+
},
9+
"keywords": [
10+
"github",
11+
"action",
12+
"wsl"
13+
],
14+
"author": "",
15+
"license": "MIT",
16+
"dependencies": {
17+
"@actions/core": "^1.10.1",
18+
"@actions/exec": "^1.1.1"
19+
}
20+
}
Lines changed: 176 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,176 @@
1+
/**
2+
* GitHub action to run other actions in WSL environment
3+
* @param {string} uses - Name of GitHub action to run (e.g. 'actions/checkout@v4')
4+
* @param {string} with - Input parameters to pass to the action in key=value format, supporting =, :, and = delimiters
5+
* @param {string} run - Commands to run in WSL bash shell
6+
* @return {Promise<void>} Promise that resolves when action completes
7+
*/
8+
const core = require('@actions/core');
9+
const exec = require('@actions/exec');
10+
11+
// Define WSL environment variables once at the top level
12+
const baseWslEnv = [
13+
'GITHUB_WORKSPACE/p',
14+
'GITHUB_ACTION',
15+
'GITHUB_ACTIONS',
16+
'GITHUB_ACTOR',
17+
'GITHUB_REPOSITORY',
18+
'GITHUB_EVENT_NAME',
19+
'GITHUB_EVENT_PATH/p',
20+
'GITHUB_SHA',
21+
'GITHUB_REF',
22+
'GITHUB_TOKEN',
23+
'GITHUB_RUN_ID',
24+
'GITHUB_RUN_NUMBER',
25+
'RUNNER_OS',
26+
'RUNNER_TEMP/p',
27+
'RUNNER_TOOL_CACHE/p',
28+
'CI',
29+
'GITHUB_DEBUG',
30+
'ACTIONS_RUNNER_DEBUG',
31+
'ACTIONS_STEP_DEBUG'
32+
];
33+
34+
async function run() {
35+
try {
36+
// Get action inputs
37+
const uses = core.getInput('uses');
38+
const withInputs = core.getInput('with');
39+
const runCommand = core.getInput('run');
40+
41+
// Validate inputs
42+
if (runCommand && (uses || withInputs)) {
43+
throw new Error('The "run" input cannot be used together with "uses" or "with" inputs');
44+
}
45+
46+
if (!runCommand && !uses) {
47+
throw new Error('Either "run" or "uses" input must be provided');
48+
}
49+
50+
// If run command is provided, execute it directly in WSL
51+
if (runCommand) {
52+
core.info('Running command in WSL environment');
53+
core.debug(`Command: ${runCommand}`);
54+
55+
// Set up basic environment variables for WSL
56+
const wslEnv = baseWslEnv.join(':');
57+
58+
process.env.WSLENV = process.env.WSLENV ? `${process.env.WSLENV}:${wslEnv}` : wslEnv;
59+
60+
await exec.exec('wsl.exe', ['bash', '-c', runCommand], {
61+
env: process.env
62+
});
63+
64+
core.info('Command completed successfully');
65+
return;
66+
}
67+
68+
// Original action execution logic for 'uses'
69+
core.info(`Running action ${uses} in WSL environment`);
70+
71+
// Parse action name and version
72+
const [owner, repo, version] = uses.split(/[@/]/g);
73+
core.debug(`Parsed action: owner=${owner}, repo=${repo}, version=${version}`);
74+
75+
// Set up environment variables from with inputs
76+
const env = {};
77+
if (withInputs) {
78+
core.debug('Parsing with inputs:');
79+
core.debug(withInputs);
80+
81+
// Parse key-value pairs with flexible delimiters
82+
const inputs = withInputs
83+
.split(/[\n,]/)
84+
.map(line => line.trim())
85+
.filter(line => line.length > 0)
86+
.reduce((acc, line) => {
87+
const match = line.match(/^([^=:]+)(?:=|\s*:\s*|\s+=\s+)(.+)$/);
88+
if (match) {
89+
const [, key, value] = match;
90+
acc[key.trim()] = value.trim();
91+
}
92+
return acc;
93+
}, {});
94+
95+
for (const [key, value] of Object.entries(inputs)) {
96+
const envKey = `INPUT_${key.toUpperCase().replace(/-/g, '_')}`;
97+
env[envKey] = value;
98+
core.debug(`Setting env var: ${envKey}=${value}`);
99+
}
100+
}
101+
102+
// Add environment variables to WSLENV
103+
const wslEnv = [
104+
...baseWslEnv,
105+
...Object.keys(env).map(key => key.slice(6))
106+
].join(':');
107+
108+
process.env.WSLENV = process.env.WSLENV ? `${process.env.WSLENV}:${wslEnv}` : wslEnv;
109+
core.debug(`Set WSLENV: ${process.env.WSLENV}`);
110+
111+
// Clone and install the action in WSL
112+
core.info('Cloning and installing action in WSL...');
113+
await exec.exec('wsl.exe', ['bash', '-c', `
114+
set -e
115+
mkdir -p ~/actions/${owner}/${repo}
116+
cd ~/actions/${owner}/${repo}
117+
git clone --depth 1 --branch ${version} https://github.com/${owner}/${repo}.git .
118+
# Install dependencies if needed
119+
if [ -f "package.json" ]; then
120+
npm install
121+
npm run build || true
122+
fi
123+
# First check for dist/index.js
124+
if [ -f "dist/index.js" ]; then
125+
echo "MAIN_FILE=dist/index.js" >> $GITHUB_ENV
126+
else
127+
# Fall back to checking action.yml for entry point
128+
for action_file in action.yml action.yaml; do
129+
if [ -f "$action_file" ]; then
130+
MAIN_FILE=$(grep "main:" "$action_file" | sed 's/main:[[:space:]]*//;s/^["'\'']*//;s/["'\''].*$//')
131+
if [ ! -z "$MAIN_FILE" ]; then
132+
echo "Entry point from $action_file: $MAIN_FILE"
133+
echo "MAIN_FILE=$MAIN_FILE" >> $GITHUB_ENV
134+
break
135+
fi
136+
fi
137+
done
138+
fi
139+
`], {
140+
env: {
141+
...process.env,
142+
...env
143+
}
144+
});
145+
146+
// Run the action
147+
core.info('Running action...');
148+
const debugScript = process.env.GITHUB_DEBUG === 'true' ? 'env' : '';
149+
await exec.exec('wsl.exe', ['bash', '-c', `
150+
set -e
151+
cd ~/actions/${owner}/${repo}
152+
${debugScript}
153+
if [ -f "$MAIN_FILE" ]; then
154+
node "$MAIN_FILE"
155+
else
156+
echo "Could not find entry point at $MAIN_FILE. Contents of directory:"
157+
ls -R
158+
exit 1
159+
fi
160+
`], {
161+
env: {
162+
...process.env,
163+
...env
164+
}
165+
});
166+
167+
core.info('Action completed successfully');
168+
169+
} catch (error) {
170+
core.error('Action failed with error:');
171+
core.error(error);
172+
core.setFailed(error.message);
173+
}
174+
}
175+
176+
run();

.github/workflows/pr-setup-wsl-tests.yml

Lines changed: 71 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,6 @@ jobs:
1818
- "20"
1919
os:
2020
- windows-2022
21-
defaults:
22-
run:
23-
# Actions passes commands as a script with windows line endings, so we need to convert them to unix line endings
24-
shell: wsl.exe bash --noprofile --norc -euo pipefail -c "touch ~/.env && source ~/.env; GITHUB_TOKEN=${{ github.token }} RUNNER_DEBUG=${{ env.RUNNER_DEBUG }} exec $(script="$(wslpath '{0}')" && sed -i 's/\r$//' "$script" && echo "$script")"
2521

2622
steps:
2723
- name: Install Ubuntu for WSL2
@@ -39,66 +35,84 @@ jobs:
3935
Invoke-WebRequest -Uri $downloadUrl -OutFile $filename
4036
Expand-Archive -Path $filename -DestinationPath .\
4137
.\ubuntu.exe install --root
42-
- name: Setup Ubuntu Shell Environment
43-
shell: pwsh
44-
run: |
45-
$envVars = @"
46-
export CI=true
47-
export GITHUB_ACTIONS=true
48-
export GITHUB_WORKSPACE=$(wsl.exe wslpath -a "$env:GITHUB_WORKSPACE")
49-
export RUNNER_OS=Linux
50-
export RUNNER_TEMP=$(wsl.exe wslpath -a "$env:RUNNER_TEMP")
51-
export RUNNER_TOOL_CACHE=$(wsl.exe wslpath -a "$env:RUNNER_TOOL_CACHE")
52-
"@
53-
wsl.exe bash -c "echo '$envVars' > ~/.env"
38+
5439
- name: Checkout code
40+
uses: actions/checkout@v4
41+
with:
42+
fetch-depth: 1
43+
ref: ${{ github.sha }}
44+
45+
- name: Setup WSL Run Action
46+
shell: pwsh
5547
run: |
56-
git clone --depth 1 --single-branch https://github.com/${{ github.repository }}.git .
57-
git fetch --depth 1 origin ${{ github.sha }}
58-
git checkout ${{ github.sha }}
48+
cd .github/actions/wsl-run
49+
npm install
50+
# Install Node.js and git in WSL environment
51+
wsl.exe bash -c "curl -fsSL https://deb.nodesource.com/setup_20.x | bash - && apt-get install -y nodejs git"
52+
5953
- name: Install node ${{ matrix.node-version }}
60-
run: |
61-
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.1/install.sh | bash
62-
echo 'export NVM_DIR="$HOME/.nvm"' >> ~/.env
63-
echo '[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"' >> ~/.env
64-
source ~/.env
65-
nvm install ${{ matrix.node-version }}
54+
uses: ./.github/actions/wsl-run
55+
with:
56+
uses: actions/setup-node@v4
57+
with: |
58+
node-version: ${{ matrix.node-version }}
59+
6660
- name: Bundle Deps
67-
run: |
68-
mkdir -p ~/prepare-release-action
69-
git clone --depth 1 https://github.com/lando/prepare-release-action.git ~/prepare-release-action
70-
cd ~/prepare-release-action
71-
export INPUT_PLUGIN=true
72-
export INPUT_VERSION=dev
73-
export INPUT_SYNC=false
74-
export INPUT_BUNDLE-DEPENDENCIES=true
75-
node dist/index.js
61+
uses: ./.github/actions/wsl-run
62+
with:
63+
run: |
64+
mkdir -p ~/prepare-release-action
65+
git clone --depth 1 https://github.com/lando/prepare-release-action.git ~/prepare-release-action
66+
cd ~/prepare-release-action
67+
env \
68+
INPUT_LANDO-PLUGIN=true \
69+
INPUT_VERSION=dev \
70+
INPUT_SYNC=false \
71+
INPUT_BUNDLE-DEPENDENCIES=true \
72+
node dist/index.js
73+
7674
- name: Install pkg dependencies
77-
run: npm clean-install --prefer-offline --frozen-lockfile --production
75+
uses: ./.github/actions/wsl-run
76+
with:
77+
run: npm clean-install --prefer-offline --frozen-lockfile --production
78+
7879
- name: Package into node binary
80+
uses: ./.github/actions/wsl-run
7981
id: pkg-action
80-
run: |
81-
npm install -g @yao-pkg/[email protected]
82-
pkg bin/lando --target node${{ matrix.node-version }}-linux-x64 --options dns-result-order=ipv4first --output lando
83-
echo "PKG_OUTPUT=lando" >> ${{ github.env }}
82+
with:
83+
run: |
84+
npm install -g @yao-pkg/[email protected]
85+
pkg bin/lando --target node${{ matrix.node-version }}-linux-x64 --options dns-result-order=ipv4first --output lando
86+
echo "PKG_OUTPUT=lando" >> $GITHUB_ENV
87+
8488
- name: Install full deps
85-
run: npm clean-install --prefer-offline --frozen-lockfile
89+
uses: ./.github/actions/wsl-run
90+
with:
91+
run: npm clean-install --prefer-offline --frozen-lockfile
92+
8693
- name: Setup lando ${{ steps.pkg-action.outputs.file }}
87-
run: |
88-
mkdir -p ~/setup-lando
89-
git clone --depth 1 https://github.com/lando/setup-lando.git ~/setup-lando
90-
cd ~/setup-lando
91-
export INPUT_AUTO_SETUP=false
92-
export INPUT_LANDO_VERSION="${{ steps.pkg-action.outputs.file }}"
93-
export INPUT_TELEMETRY=false
94-
node dist/index.js
94+
uses: ./.github/actions/wsl-run
95+
with:
96+
run: |
97+
mkdir -p ~/setup-lando
98+
git clone --depth 1 https://github.com/lando/setup-lando.git ~/setup-lando
99+
cd ~/setup-lando
100+
env \
101+
INPUT_AUTO-SETUP=false \
102+
INPUT_LANDO-VERSION="${{ steps.pkg-action.outputs.file }}" \
103+
INPUT_TELEMETRY=false \
104+
node dist/index.js
105+
95106
- name: Run Leia Tests
96-
run: |
97-
mkdir -p ~/run-leia-action
98-
git clone --depth 1 https://github.com/lando/run-leia-action.git ~/run-leia-action
99-
cd ~/run-leia-action
100-
export INPUT_LEIA_TEST="./examples/${{ matrix.leia-test }}/README.md"
101-
export INPUT_CLEANUP_HEADER="Destroy tests"
102-
export INPUT_SHELL="bash"
103-
export INPUT_STDIN=true
104-
node dist/index.js
107+
uses: ./.github/actions/wsl-run
108+
with:
109+
run: |
110+
mkdir -p ~/run-leia-action
111+
git clone --depth 1 https://github.com/lando/run-leia-action.git ~/run-leia-action
112+
cd ~/run-leia-action
113+
env \
114+
INPUT_LEIA-TEST="./examples/${{ matrix.leia-test }}/README.md" \
115+
INPUT_CLEANUP-HEADER="Destroy tests" \
116+
INPUT_SHELL="bash" \
117+
INPUT_STDIN=true \
118+
node dist/index.js

0 commit comments

Comments
 (0)