Skip to content

Commit 566b34e

Browse files
Fix #83: Add support for custom shell
This allows to specify the shell as `cpa.sh {0}` and then use the regular `run` syntax to run commands inside the VM.
1 parent 4006af8 commit 566b34e

File tree

9 files changed

+208
-31
lines changed

9 files changed

+208
-31
lines changed

.github/workflows/ci.yml

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -548,3 +548,45 @@ jobs:
548548
sync_files: false
549549
shutdown_vm: false
550550
run: true
551+
552+
shell-mode:
553+
timeout-minutes: 5
554+
name: Test running the action in shell mode
555+
runs-on: ubuntu-latest
556+
defaults:
557+
run:
558+
shell: cpa.sh {0}
559+
560+
steps:
561+
- name: Checkout
562+
uses: actions/checkout@v6
563+
with:
564+
persist-credentials: false
565+
566+
- shell: bash
567+
run: |
568+
sudo apt update
569+
sudo apt install -y dosfstools rsync fdisk
570+
571+
- name: Start VM
572+
uses: ./
573+
with:
574+
operating_system: freebsd
575+
architecture: x86-64
576+
version: '15.0'
577+
hypervisor: qemu
578+
shutdown_vm: false
579+
run: echo "Starting VM"
580+
581+
- name: Verify VM configuration
582+
run: |
583+
uname -a
584+
[ "$(uname)" = "FreeBSD" ]
585+
[ "$(uname -r | cut -d- -f1)" = "15.0" ]
586+
[ "$(uname -m)" = "amd64" ]
587+
588+
- name: Create file in VM
589+
run: touch shell_mode_test.txt
590+
591+
- name: Check file in subsequent step
592+
run: test -f shell_mode_test.txt

action.yml

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,19 +3,19 @@ description: Provides cross platform runner
33
author: Jacob Carlborg
44
inputs:
55
run:
6-
required: true
6+
required: false
77
description: |
88
Runs command-line programs using the operating system's shell.
99
This will be executed inside the virtual machine.
1010
operating_system:
11-
required: true
11+
required: false
1212
description: The type of operating system to run the job on
1313
architecture:
1414
required: false
1515
description: The architecture of the operating system.
1616
default: x86-64
1717
version:
18-
required: true
18+
required: false
1919
description: The version of the operating system to use
2020
shell:
2121
required: false
@@ -57,7 +57,6 @@ inputs:
5757
required: false
5858
description: |
5959
Specifies if the VM should be shutdown after the action has been run.
60-
default: true
6160
6261
runs:
6362
using: node20

changelog.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,10 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
55
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
66

77
## [Unreleased]
8+
### Added
9+
- Add support for running the action as a custom shell ([#23](https://github.com/cross-platform-actions/action/issues/23)).
10+
This allows to run multiple steps in the same job without having to invoke
11+
the action multiple times.
812

913
## [0.32.0] - 2025-12-21
1014
### Added

cpa.sh

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
#!/bin/bash
2+
3+
export INPUT_RUN="$(cat $1)"
4+
export CPA_SHELL_MODE=true
5+
6+
node "$GITHUB_ACTION_PATH/dist/index.js"

dist/index.js

Lines changed: 54 additions & 9 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

dist/index.js.map

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

readme.md

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ Some of the features that this action supports include:
1313
- Allows to use default shell or Bash shell
1414
- Low boot overhead
1515
- Fast execution
16-
- Using the action in multiple steps in the same job
16+
- Using the action in multiple steps in the same job by using a custom shell
1717

1818
## `Usage`
1919

@@ -61,6 +61,9 @@ on: [push]
6161
jobs:
6262
test:
6363
runs-on: ubuntu-latest
64+
defaults:
65+
run:
66+
shell: cpa.sh {0}
6467
strategy:
6568
matrix:
6669
os:
@@ -108,13 +111,14 @@ jobs:
108111
shell: bash
109112
memory: 5G
110113
cpu_count: 4
111-
run: |
112-
uname -a
113-
echo $SHELL
114-
pwd
115-
ls -lah
116-
whoami
117-
env | sort
114+
115+
- run: |
116+
uname -a
117+
echo $SHELL
118+
pwd
119+
ls -lah
120+
whoami
121+
env | sort
118122
```
119123
120124
Different platforms need to run on different runners, so see the

src/action/action.ts

Lines changed: 72 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,9 @@ export class Action {
5555
async run(): Promise<void> {
5656
core.startGroup('Setting up VM')
5757
core.debug('Running action')
58+
5859
const runPreparer = this.createRunPreparer()
60+
runPreparer.setupEnvironment()
5961
runPreparer.createInputHash()
6062
runPreparer.validateInputHash()
6163

@@ -106,7 +108,9 @@ export class Action {
106108
core.info('VM is ready')
107109
try {
108110
core.endGroup()
109-
await this.runCommand(vm)
111+
if (this.input.hasRun) {
112+
await this.runCommand(vm)
113+
}
110114
} finally {
111115
core.startGroup('Tearing down VM')
112116
await vm.synchronizeBack()
@@ -239,9 +243,14 @@ export class Action {
239243
}
240244

241245
private createRunPreparer(): RunPreparer {
242-
const cls = runPreparerFor({isRunning: vmModule.Vm.isRunning})
246+
const isRunning = vmModule.Vm.isRunning
247+
const cls = runPreparerFor({isRunning})
248+
const environmentSetup = environmentSetupFor({
249+
isRunning,
250+
isShellMode: process.env['CPA_SHELL_MODE'] === 'true'
251+
})
243252
core.debug(`Using run preparer: ${cls.name}`)
244-
return new cls(this, this.operatingSystem)
253+
return new cls(this, this.operatingSystem, environmentSetup)
245254
}
246255
}
247256

@@ -261,7 +270,45 @@ function runPreparerFor({
261270
return isRunning ? LiveRunPreparer : InitialRunPreparer
262271
}
263272

273+
function environmentSetupFor({
274+
isRunning,
275+
isShellMode
276+
}: {
277+
isRunning: boolean
278+
isShellMode: boolean
279+
}): EnvironmentSetup {
280+
if (isShellMode) return new ShellEnvironmentSetup()
281+
return isRunning ? new LiveEnvironmentSetup() : new InitialEnvironmentSetup()
282+
}
283+
284+
interface EnvironmentSetup {
285+
setup(): void
286+
}
287+
288+
class ShellEnvironmentSetup implements EnvironmentSetup {
289+
setup(): void {
290+
// noop
291+
}
292+
}
293+
294+
class InitialEnvironmentSetup implements EnvironmentSetup {
295+
setup(): void {
296+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
297+
core.addPath(process.env['GITHUB_ACTION_PATH']!)
298+
}
299+
}
300+
301+
class LiveEnvironmentSetup implements EnvironmentSetup {
302+
setup(): void {
303+
core.warning(
304+
'Invoking the action multiple times is deprecated. Please use the ' +
305+
'shell integration instead.'
306+
)
307+
}
308+
}
309+
264310
interface RunPreparer {
311+
setupEnvironment(): void
265312
createInputHash(): void
266313
validateInputHash(): void
267314
download(): [Promise<string>, Promise<string>, Promise<string>]
@@ -276,10 +323,20 @@ interface RunPreparer {
276323
class InitialRunPreparer implements RunPreparer {
277324
private readonly action: Action
278325
private readonly operatingSystem: os.OperatingSystem
326+
private readonly environmentSetup: EnvironmentSetup
279327

280-
constructor(action: Action, operatingSystem: os.OperatingSystem) {
328+
constructor(
329+
action: Action,
330+
operatingSystem: os.OperatingSystem,
331+
environmentSetup: EnvironmentSetup
332+
) {
281333
this.action = action
282334
this.operatingSystem = operatingSystem
335+
this.environmentSetup = environmentSetup
336+
}
337+
338+
setupEnvironment(): void {
339+
this.environmentSetup.setup()
283340
}
284341

285342
createInputHash(): void {
@@ -318,9 +375,19 @@ class InitialRunPreparer implements RunPreparer {
318375
// Used when the VM is already running
319376
class LiveRunPreparer implements RunPreparer {
320377
private readonly action: Action
378+
private readonly environmentSetup: EnvironmentSetup
321379

322-
constructor(action: Action) {
380+
constructor(
381+
action: Action,
382+
_operatingSystem: os.OperatingSystem,
383+
environmentSetup: EnvironmentSetup
384+
) {
323385
this.action = action
386+
this.environmentSetup = environmentSetup
387+
}
388+
389+
setupEnvironment(): void {
390+
this.environmentSetup.setup()
324391
}
325392

326393
createInputHash(): void {

0 commit comments

Comments
 (0)