Skip to content

Commit 616fa81

Browse files
authored
Use spawn not exec to run commands (#88)
* minor: use spawn to stream larger output rather than exec which buffers it * test: verify distinct error code is returned from large output test * test: breakout additional integration tests to run in parallel * test: dont pass/fail PRs for coverage yet
1 parent a25f198 commit 616fa81

File tree

7 files changed

+196
-81
lines changed

7 files changed

+196
-81
lines changed

.github/codecov.yml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,3 +5,8 @@ comment:
55
layout: 'diff, flags'
66
behavior: default
77
require_changes: true
8+
coverage:
9+
# don't pass/fail PRs for coverage yet
10+
status:
11+
project: off
12+
patch: off

.github/workflows/ci_cd.yml

Lines changed: 152 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ on:
44

55
jobs:
66
# runs on branch pushes only
7-
ci_unuit:
7+
ci_unit:
88
name: Run Unit Tests
99
if: startsWith(github.ref, 'refs/heads')
1010
runs-on: ubuntu-latest
@@ -24,6 +24,157 @@ jobs:
2424
directory: ./coverage/
2525
verbose: true
2626

27+
ci_integration_envvar:
28+
name: Run Integration Env Var Tests
29+
if: startsWith(github.ref, 'refs/heads')
30+
runs-on: ubuntu-latest
31+
steps:
32+
- name: Checkout
33+
uses: actions/checkout@v2
34+
- name: Setup Node.js
35+
uses: actions/setup-node@v1
36+
with:
37+
node-version: 16
38+
- name: Install dependencies
39+
run: npm ci
40+
- name: env-vars-passed-through
41+
uses: ./
42+
env:
43+
NODE_OPTIONS: '--max_old_space_size=3072'
44+
with:
45+
timeout_minutes: 1
46+
max_attempts: 2
47+
command: node -e 'console.log(process.env.NODE_OPTIONS)'
48+
49+
ci_integration_large_output:
50+
name: Run Integration Large Output Tests
51+
if: startsWith(github.ref, 'refs/heads')
52+
runs-on: ubuntu-latest
53+
steps:
54+
- name: Checkout
55+
uses: actions/checkout@v2
56+
- name: Setup Node.js
57+
uses: actions/setup-node@v1
58+
with:
59+
node-version: 16
60+
- name: Install dependencies
61+
run: npm ci
62+
- name: Test 100MiB of output can be processed
63+
id: large-output
64+
continue-on-error: true
65+
uses: ./
66+
with:
67+
max_attempts: 1
68+
timeout_minutes: 5
69+
command: 'make -C ./test-data/large-output bytes-102400'
70+
- name: Assert test had expected result
71+
uses: nick-invision/assert-action@v1
72+
with:
73+
expected: failure
74+
actual: ${{ steps.large-output.outcome }}
75+
- name: Assert exit code is expected
76+
uses: nick-invision/assert-action@v1
77+
with:
78+
expected: 2
79+
actual: ${{ steps.large-output.outputs.exit_code }}
80+
81+
ci_integration_retry_on_exit_code:
82+
name: Run Integration retry_on_exit_code Tests
83+
if: startsWith(github.ref, 'refs/heads')
84+
runs-on: ubuntu-latest
85+
steps:
86+
- name: Checkout
87+
uses: actions/checkout@v2
88+
- name: Setup Node.js
89+
uses: actions/setup-node@v1
90+
with:
91+
node-version: 16
92+
- name: Install dependencies
93+
run: npm ci
94+
- name: retry_on_exit_code (with expected error code)
95+
id: retry_on_exit_code_expected
96+
uses: ./
97+
continue-on-error: true
98+
with:
99+
timeout_minutes: 1
100+
retry_on_exit_code: 2
101+
max_attempts: 3
102+
command: node -e "process.exit(2)"
103+
- uses: nick-invision/assert-action@v1
104+
with:
105+
expected: failure
106+
actual: ${{ steps.retry_on_exit_code_expected.outcome }}
107+
- uses: nick-invision/assert-action@v1
108+
with:
109+
expected: 3
110+
actual: ${{ steps.retry_on_exit_code_expected.outputs.total_attempts }}
111+
112+
- name: retry_on_exit_code (with unexpected error code)
113+
id: retry_on_exit_code_unexpected
114+
uses: ./
115+
continue-on-error: true
116+
with:
117+
timeout_minutes: 1
118+
retry_on_exit_code: 2
119+
max_attempts: 3
120+
command: node -e "process.exit(1)"
121+
- uses: nick-invision/assert-action@v1
122+
with:
123+
expected: failure
124+
actual: ${{ steps.retry_on_exit_code_unexpected.outcome }}
125+
- uses: nick-invision/assert-action@v1
126+
with:
127+
expected: 1
128+
actual: ${{ steps.retry_on_exit_code_unexpected.outputs.total_attempts }}
129+
130+
ci_integration_continue_on_error:
131+
name: Run Integration continue_on_error Tests
132+
if: startsWith(github.ref, 'refs/heads')
133+
runs-on: ubuntu-latest
134+
steps:
135+
- name: Checkout
136+
uses: actions/checkout@v2
137+
- name: Setup Node.js
138+
uses: actions/setup-node@v1
139+
with:
140+
node-version: 16
141+
- name: Install dependencies
142+
run: npm ci
143+
- name: happy-path (continue_on_error)
144+
id: happy_path_continue_on_error
145+
uses: ./
146+
with:
147+
command: node -e "process.exit(0)"
148+
timeout_minutes: 1
149+
continue_on_error: true
150+
- name: sad-path (continue_on_error)
151+
id: sad_path_continue_on_error
152+
uses: ./
153+
with:
154+
command: node -e "process.exit(33)"
155+
timeout_minutes: 1
156+
continue_on_error: true
157+
- name: Verify continue_on_error returns correct exit code on success
158+
uses: nick-invision/assert-action@v1
159+
with:
160+
expected: 0
161+
actual: ${{ steps.happy_path_continue_on_error.outputs.exit_code }}
162+
- name: Verify continue_on_error exits with correct outcome on success
163+
uses: nick-invision/assert-action@v1
164+
with:
165+
expected: success
166+
actual: ${{ steps.happy_path_continue_on_error.outcome }}
167+
- name: Verify continue_on_error returns correct exit code on error
168+
uses: nick-invision/assert-action@v1
169+
with:
170+
expected: 33
171+
actual: ${{ steps.sad_path_continue_on_error.outputs.exit_code }}
172+
- name: Verify continue_on_error exits with successful outcome when an error occurs
173+
uses: nick-invision/assert-action@v1
174+
with:
175+
expected: success
176+
actual: ${{ steps.sad_path_continue_on_error.outcome }}
177+
27178
ci_integration:
28179
name: Run Integration Tests
29180
if: startsWith(github.ref, 'refs/heads')
@@ -98,42 +249,6 @@ jobs:
98249
command: node -e "process.exit(1)"
99250
on_retry_command: node -e "console.log('this is a retry command')"
100251

101-
- name: retry_on_exit_code (with expected error code)
102-
id: retry_on_exit_code_expected
103-
uses: ./
104-
continue-on-error: true
105-
with:
106-
timeout_minutes: 1
107-
retry_on_exit_code: 2
108-
max_attempts: 3
109-
command: node -e "process.exit(2)"
110-
- uses: nick-invision/assert-action@v1
111-
with:
112-
expected: failure
113-
actual: ${{ steps.retry_on_exit_code_expected.outcome }}
114-
- uses: nick-invision/assert-action@v1
115-
with:
116-
expected: 3
117-
actual: ${{ steps.retry_on_exit_code_expected.outputs.total_attempts }}
118-
119-
- name: retry_on_exit_code (with unexpected error code)
120-
id: retry_on_exit_code_unexpected
121-
uses: ./
122-
continue-on-error: true
123-
with:
124-
timeout_minutes: 1
125-
retry_on_exit_code: 2
126-
max_attempts: 3
127-
command: node -e "process.exit(1)"
128-
- uses: nick-invision/assert-action@v1
129-
with:
130-
expected: failure
131-
actual: ${{ steps.retry_on_exit_code_unexpected.outcome }}
132-
- uses: nick-invision/assert-action@v1
133-
with:
134-
expected: 1
135-
actual: ${{ steps.retry_on_exit_code_unexpected.outputs.total_attempts }}
136-
137252
- name: on-retry-cmd (on-retry fails)
138253
id: on-retry-cmd-fails
139254
uses: ./
@@ -161,41 +276,6 @@ jobs:
161276
expected: failure
162277
actual: ${{ steps.sad_path_error.outcome }}
163278

164-
- name: happy-path (continue_on_error)
165-
id: happy_path_continue_on_error
166-
uses: ./
167-
with:
168-
command: node -e "process.exit(0)"
169-
timeout_minutes: 1
170-
continue_on_error: true
171-
- name: sad-path (continue_on_error)
172-
id: sad_path_continue_on_error
173-
uses: ./
174-
with:
175-
command: node -e "process.exit(33)"
176-
timeout_minutes: 1
177-
continue_on_error: true
178-
- name: Verify continue_on_error returns correct exit code on success
179-
uses: nick-invision/assert-action@v1
180-
with:
181-
expected: 0
182-
actual: ${{ steps.happy_path_continue_on_error.outputs.exit_code }}
183-
- name: Verify continue_on_error exits with correct outcome on success
184-
uses: nick-invision/assert-action@v1
185-
with:
186-
expected: success
187-
actual: ${{ steps.happy_path_continue_on_error.outcome }}
188-
- name: Verify continue_on_error returns correct exit code on error
189-
uses: nick-invision/assert-action@v1
190-
with:
191-
expected: 33
192-
actual: ${{ steps.sad_path_continue_on_error.outputs.exit_code }}
193-
- name: Verify continue_on_error exits with successful outcome when an error occurs
194-
uses: nick-invision/assert-action@v1
195-
with:
196-
expected: success
197-
actual: ${{ steps.sad_path_continue_on_error.outcome }}
198-
199279
- name: retry_on (timeout) fails early if error encountered
200280
id: retry_on_timeout_fail
201281
uses: ./

dist/index.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -778,8 +778,8 @@ function runCmd(attempt) {
778778
done = false;
779779
(0, core_1.debug)("Running command ".concat(COMMAND, " on ").concat(OS, " using shell ").concat(executable));
780780
child = attempt > 1 && NEW_COMMAND_ON_RETRY
781-
? (0, child_process_1.exec)(NEW_COMMAND_ON_RETRY, { shell: executable })
782-
: (0, child_process_1.exec)(COMMAND, { shell: executable });
781+
? (0, child_process_1.spawn)(NEW_COMMAND_ON_RETRY, { shell: executable })
782+
: (0, child_process_1.spawn)(COMMAND, { shell: executable });
783783
(_a = child.stdout) === null || _a === void 0 ? void 0 : _a.on('data', function (data) {
784784
process.stdout.write(data);
785785
});

sample.env

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,11 @@
1+
# these are the bare minimum envvars required
12
INPUT_TIMEOUT_MINUTES=1
23
INPUT_MAX_ATTEMPTS=3
34
INPUT_COMMAND="node -e 'process.exit(99)'"
4-
INPUT_RETRY_WAIT_SECONDS=10
5-
SHELL=pwsh
6-
INPUT_POLLING_INTERVAL_SECONDS=1
7-
INPUT_RETRY_ON=any
5+
INPUT_CONTINUE_ON_ERROR=false
6+
7+
# these are optional
8+
#INPUT_RETRY_WAIT_SECONDS=10
9+
#SHELL=pwsh
10+
#INPUT_POLLING_INTERVAL_SECONDS=1
11+
#INPUT_RETRY_ON=any

src/index.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { getInput, error, warning, info, debug, setOutput } from '@actions/core';
2-
import { exec, execSync } from 'child_process';
2+
import { execSync, spawn } from 'child_process';
33
import ms from 'milliseconds';
44
import kill from 'tree-kill';
55

@@ -137,8 +137,8 @@ async function runCmd(attempt: number) {
137137
debug(`Running command ${COMMAND} on ${OS} using shell ${executable}`);
138138
const child =
139139
attempt > 1 && NEW_COMMAND_ON_RETRY
140-
? exec(NEW_COMMAND_ON_RETRY, { shell: executable })
141-
: exec(COMMAND, { shell: executable });
140+
? spawn(NEW_COMMAND_ON_RETRY, { shell: executable })
141+
: spawn(COMMAND, { shell: executable });
142142

143143
child.stdout?.on('data', (data) => {
144144
process.stdout.write(data);

test-data/large-output/Makefile

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
SHELL = bash
2+
3+
# this tests fix for the following issues
4+
# https://github.com/nick-fields/retry/issues/76
5+
# https://github.com/nick-fields/retry/issues/84
6+
7+
bytes-%:
8+
for i in {1..$*}; do cat kibibyte.txt; done; exit 2
9+
.PHONY: bytes-%
10+
11+
lines-%:
12+
for i in {1..$*}; do echo a; done; exit 2
13+
.PHONY: lines-%
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
1: 0000 aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
2+
2: 0081 aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
3+
3: 0162 aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
4+
4: 243 aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
5+
5: 324 aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
6+
6: 405 aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
7+
7: 486 aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
8+
8: 567 aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
9+
9: 648 aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
10+
a: 729 aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
11+
b: 810 aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
12+
c: 891 aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
13+
d: 972 aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa

0 commit comments

Comments
 (0)