Skip to content

Commit

Permalink
create standalone action for wsl steps
Browse files Browse the repository at this point in the history
  • Loading branch information
AaronFeledy committed Dec 10, 2024
1 parent 9259b3c commit 76cee5b
Show file tree
Hide file tree
Showing 5 changed files with 283 additions and 57 deletions.
1 change: 1 addition & 0 deletions .github/actions/wsl-run/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
node_modules/
15 changes: 15 additions & 0 deletions .github/actions/wsl-run/action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
name: 'WSL Run Action'
description: 'Runs GitHub actions in WSL environment'
inputs:
uses:
description: 'The action to run in WSL'
required: false
with:
description: 'Input parameters for the action'
required: false
run:
description: 'Commands to run in WSL bash shell'
required: false
runs:
using: 'node20'
main: 'wsl-run-action.js'
20 changes: 20 additions & 0 deletions .github/actions/wsl-run/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
{
"name": "wsl-run-action",
"version": "1.0.0",
"description": "GitHub action to run commands or other actions in WSL environment",
"main": "wsl-run-action.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [
"github",
"action",
"wsl"
],
"author": "",
"license": "MIT",
"dependencies": {
"@actions/core": "^1.10.1",
"@actions/exec": "^1.1.1"
}
}
176 changes: 176 additions & 0 deletions .github/actions/wsl-run/wsl-run-action.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,176 @@
/**
* GitHub action to run other actions in WSL environment
* @param {string} uses - Name of GitHub action to run (e.g. 'actions/checkout@v4')
* @param {string} with - Input parameters to pass to the action in key=value format, supporting =, :, and = delimiters
* @param {string} run - Commands to run in WSL bash shell
* @return {Promise<void>} Promise that resolves when action completes
*/
const core = require('@actions/core');
const exec = require('@actions/exec');

// Define WSL environment variables once at the top level
const baseWslEnv = [
'GITHUB_WORKSPACE/p',
'GITHUB_ACTION',
'GITHUB_ACTIONS',
'GITHUB_ACTOR',
'GITHUB_REPOSITORY',
'GITHUB_EVENT_NAME',
'GITHUB_EVENT_PATH/p',
'GITHUB_SHA',
'GITHUB_REF',
'GITHUB_TOKEN',
'GITHUB_RUN_ID',
'GITHUB_RUN_NUMBER',
'RUNNER_OS',
'RUNNER_TEMP/p',
'RUNNER_TOOL_CACHE/p',
'CI',
'GITHUB_DEBUG',
'ACTIONS_RUNNER_DEBUG',
'ACTIONS_STEP_DEBUG'
];

async function run() {
try {
// Get action inputs
const uses = core.getInput('uses');
const withInputs = core.getInput('with');
const runCommand = core.getInput('run');

// Validate inputs
if (runCommand && (uses || withInputs)) {
throw new Error('The "run" input cannot be used together with "uses" or "with" inputs');
}

if (!runCommand && !uses) {
throw new Error('Either "run" or "uses" input must be provided');
}

// If run command is provided, execute it directly in WSL
if (runCommand) {
core.info('Running command in WSL environment');
core.debug(`Command: ${runCommand}`);

// Set up basic environment variables for WSL
const wslEnv = baseWslEnv.join(':');

process.env.WSLENV = process.env.WSLENV ? `${process.env.WSLENV}:${wslEnv}` : wslEnv;

await exec.exec('wsl.exe', ['bash', '-c', runCommand], {
env: process.env
});

core.info('Command completed successfully');
return;
}

// Original action execution logic for 'uses'
core.info(`Running action ${uses} in WSL environment`);

// Parse action name and version
const [owner, repo, version] = uses.split(/[@/]/g);
core.debug(`Parsed action: owner=${owner}, repo=${repo}, version=${version}`);

// Set up environment variables from with inputs
const env = {};
if (withInputs) {
core.debug('Parsing with inputs:');
core.debug(withInputs);

// Parse key-value pairs with flexible delimiters
const inputs = withInputs
.split(/[\n,]/)
.map(line => line.trim())
.filter(line => line.length > 0)
.reduce((acc, line) => {
const match = line.match(/^([^=:]+)(?:=|\s*:\s*|\s+=\s+)(.+)$/);
if (match) {
const [, key, value] = match;
acc[key.trim()] = value.trim();
}
return acc;
}, {});

for (const [key, value] of Object.entries(inputs)) {
const envKey = `INPUT_${key.toUpperCase().replace(/-/g, '_')}`;
env[envKey] = value;
core.debug(`Setting env var: ${envKey}=${value}`);
}
}

// Add environment variables to WSLENV
const wslEnv = [
...baseWslEnv,
...Object.keys(env).map(key => key.slice(6))
].join(':');

process.env.WSLENV = process.env.WSLENV ? `${process.env.WSLENV}:${wslEnv}` : wslEnv;
core.debug(`Set WSLENV: ${process.env.WSLENV}`);

// Clone and install the action in WSL
core.info('Cloning and installing action in WSL...');
await exec.exec('wsl.exe', ['bash', '-c', `
set -e
mkdir -p ~/actions/${owner}/${repo}
cd ~/actions/${owner}/${repo}
git clone --depth 1 --branch ${version} https://github.com/${owner}/${repo}.git .
# Install dependencies if needed
if [ -f "package.json" ]; then
npm install
npm run build || true
fi
# First check for dist/index.js
if [ -f "dist/index.js" ]; then
echo "MAIN_FILE=dist/index.js" >> $GITHUB_ENV
else
# Fall back to checking action.yml for entry point
for action_file in action.yml action.yaml; do
if [ -f "$action_file" ]; then
MAIN_FILE=$(grep "main:" "$action_file" | sed 's/main:[[:space:]]*//;s/^["'\'']*//;s/["'\''].*$//')
if [ ! -z "$MAIN_FILE" ]; then
echo "Entry point from $action_file: $MAIN_FILE"
echo "MAIN_FILE=$MAIN_FILE" >> $GITHUB_ENV
break
fi
fi
done
fi
`], {
env: {
...process.env,
...env
}
});

// Run the action
core.info('Running action...');
const debugScript = process.env.GITHUB_DEBUG === 'true' ? 'env' : '';
await exec.exec('wsl.exe', ['bash', '-c', `
set -e
cd ~/actions/${owner}/${repo}
${debugScript}
if [ -f "$MAIN_FILE" ]; then
node "$MAIN_FILE"
else
echo "Could not find entry point at $MAIN_FILE. Contents of directory:"
ls -R
exit 1
fi
`], {
env: {
...process.env,
...env
}
});

core.info('Action completed successfully');

} catch (error) {
core.error('Action failed with error:');
core.error(error);
core.setFailed(error.message);
}
}

run();
128 changes: 71 additions & 57 deletions .github/workflows/pr-setup-wsl-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,6 @@ jobs:
- "20"
os:
- windows-2022
defaults:
run:
# Actions passes commands as a script with windows line endings, so we need to convert them to unix line endings
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")"

steps:
- name: Install Ubuntu for WSL2
Expand All @@ -39,66 +35,84 @@ jobs:
Invoke-WebRequest -Uri $downloadUrl -OutFile $filename
Expand-Archive -Path $filename -DestinationPath .\
.\ubuntu.exe install --root
- name: Setup Ubuntu Shell Environment
shell: pwsh
run: |
$envVars = @"
export CI=true
export GITHUB_ACTIONS=true
export GITHUB_WORKSPACE=$(wsl.exe wslpath -a "$env:GITHUB_WORKSPACE")
export RUNNER_OS=Linux
export RUNNER_TEMP=$(wsl.exe wslpath -a "$env:RUNNER_TEMP")
export RUNNER_TOOL_CACHE=$(wsl.exe wslpath -a "$env:RUNNER_TOOL_CACHE")
"@
wsl.exe bash -c "echo '$envVars' > ~/.env"
- name: Checkout code
uses: actions/checkout@v4
with:
fetch-depth: 1
ref: ${{ github.sha }}

- name: Setup WSL Run Action
shell: pwsh
run: |
git clone --depth 1 --single-branch https://github.com/${{ github.repository }}.git .
git fetch --depth 1 origin ${{ github.sha }}
git checkout ${{ github.sha }}
cd .github/actions/wsl-run
npm install
# Install Node.js and git in WSL environment
wsl.exe bash -c "curl -fsSL https://deb.nodesource.com/setup_20.x | bash - && apt-get install -y nodejs git"
- name: Install node ${{ matrix.node-version }}
run: |
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.1/install.sh | bash
echo 'export NVM_DIR="$HOME/.nvm"' >> ~/.env
echo '[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"' >> ~/.env
source ~/.env
nvm install ${{ matrix.node-version }}
uses: ./.github/actions/wsl-run
with:
uses: actions/setup-node@v4
with: |
node-version: ${{ matrix.node-version }}
- name: Bundle Deps
run: |
mkdir -p ~/prepare-release-action
git clone --depth 1 https://github.com/lando/prepare-release-action.git ~/prepare-release-action
cd ~/prepare-release-action
export INPUT_PLUGIN=true
export INPUT_VERSION=dev
export INPUT_SYNC=false
export INPUT_BUNDLE-DEPENDENCIES=true
node dist/index.js
uses: ./.github/actions/wsl-run
with:
run: |
mkdir -p ~/prepare-release-action
git clone --depth 1 https://github.com/lando/prepare-release-action.git ~/prepare-release-action
cd ~/prepare-release-action
env \
INPUT_LANDO-PLUGIN=true \
INPUT_VERSION=dev \
INPUT_SYNC=false \
INPUT_BUNDLE-DEPENDENCIES=true \
node dist/index.js
- name: Install pkg dependencies
run: npm clean-install --prefer-offline --frozen-lockfile --production
uses: ./.github/actions/wsl-run
with:
run: npm clean-install --prefer-offline --frozen-lockfile --production

- name: Package into node binary
uses: ./.github/actions/wsl-run
id: pkg-action
run: |
npm install -g @yao-pkg/[email protected]
pkg bin/lando --target node${{ matrix.node-version }}-linux-x64 --options dns-result-order=ipv4first --output lando
echo "PKG_OUTPUT=lando" >> ${{ github.env }}
with:
run: |
npm install -g @yao-pkg/[email protected]
pkg bin/lando --target node${{ matrix.node-version }}-linux-x64 --options dns-result-order=ipv4first --output lando
echo "PKG_OUTPUT=lando" >> $GITHUB_ENV
- name: Install full deps
run: npm clean-install --prefer-offline --frozen-lockfile
uses: ./.github/actions/wsl-run
with:
run: npm clean-install --prefer-offline --frozen-lockfile

- name: Setup lando ${{ steps.pkg-action.outputs.file }}
run: |
mkdir -p ~/setup-lando
git clone --depth 1 https://github.com/lando/setup-lando.git ~/setup-lando
cd ~/setup-lando
export INPUT_AUTO_SETUP=false
export INPUT_LANDO_VERSION="${{ steps.pkg-action.outputs.file }}"
export INPUT_TELEMETRY=false
node dist/index.js
uses: ./.github/actions/wsl-run
with:
run: |
mkdir -p ~/setup-lando
git clone --depth 1 https://github.com/lando/setup-lando.git ~/setup-lando
cd ~/setup-lando
env \
INPUT_AUTO-SETUP=false \
INPUT_LANDO-VERSION="${{ steps.pkg-action.outputs.file }}" \
INPUT_TELEMETRY=false \
node dist/index.js
- name: Run Leia Tests
run: |
mkdir -p ~/run-leia-action
git clone --depth 1 https://github.com/lando/run-leia-action.git ~/run-leia-action
cd ~/run-leia-action
export INPUT_LEIA_TEST="./examples/${{ matrix.leia-test }}/README.md"
export INPUT_CLEANUP_HEADER="Destroy tests"
export INPUT_SHELL="bash"
export INPUT_STDIN=true
node dist/index.js
uses: ./.github/actions/wsl-run
with:
run: |
mkdir -p ~/run-leia-action
git clone --depth 1 https://github.com/lando/run-leia-action.git ~/run-leia-action
cd ~/run-leia-action
env \
INPUT_LEIA-TEST="./examples/${{ matrix.leia-test }}/README.md" \
INPUT_CLEANUP-HEADER="Destroy tests" \
INPUT_SHELL="bash" \
INPUT_STDIN=true \
node dist/index.js

0 comments on commit 76cee5b

Please sign in to comment.