Skip to content

Commit 80af0bb

Browse files
committed
Add regex support to include/exclude (replaces starts_with)
Also: - Adds proper unit tests
1 parent 6e5830e commit 80af0bb

File tree

10 files changed

+419
-86
lines changed

10 files changed

+419
-86
lines changed

.github/workflows/build-test.yml

+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
name: 'build-test'
2+
on:
3+
pull_request:
4+
push:
5+
branches:
6+
- main
7+
- 'releases/*'
8+
9+
jobs:
10+
build-test:
11+
runs-on: ubuntu-latest
12+
steps:
13+
- uses: actions/checkout@v3
14+
- run: |
15+
npm install
16+
- run: |
17+
npm run all

.github/workflows/test.yml .github/workflows/e2e.yml

+21-12
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,11 @@
1-
name: 'build-test'
1+
name: 'e2e'
22
on:
3-
pull_request:
43
push:
54
branches:
65
- main
76
- 'releases/*'
87

98
jobs:
10-
build:
11-
runs-on: ubuntu-latest
12-
steps:
13-
- uses: actions/checkout@v3
14-
- run: |
15-
npm install
16-
- run: |
17-
npm run all
18-
199
test-exclude:
2010
runs-on: ubuntu-latest
2111
steps:
@@ -55,7 +45,7 @@ jobs:
5545
[[ "${PREF_SECRET_3}" != "" ]] && echo "PREF_SECRET_3 should be unset, got ${PREF_SECRET_3}" && exit 1
5646
true
5747
shell: bash
58-
48+
5949
test-convert:
6050
runs-on: ubuntu-latest
6151
steps:
@@ -73,6 +63,25 @@ jobs:
7363
true
7464
shell: bash
7565

66+
test-convert-prefix:
67+
runs-on: ubuntu-latest
68+
steps:
69+
- uses: actions/checkout@v3
70+
- name: Export secrets to env variables (starts with, include)
71+
uses: ./
72+
with:
73+
prefix: MY_
74+
convert_prefix: false
75+
convert: lower
76+
secrets: ${{ toJSON(secrets) }}
77+
- name: Verify secrets to env variables (starts with, include)
78+
run: |
79+
[[ "${MY_secret_1}" != "VALUE_1" ]] && echo "Could not export MY_secret_1 secret, value is ${MY_secret_1}" && exit 1
80+
[[ "${MY_secret_2}" != "VALUE_2" ]] && echo "Could not export MY_secret_2 secret, value is ${MY_secret_2}" && exit 1
81+
[[ "${MY_secret_3}" != "VALUE_3" ]] && echo "Could not export MY_secret_3 secret, value is ${MY_secret_3}" && exit 1
82+
true
83+
shell: bash
84+
7685
# These jobs always fail, for now we just use it to check if the output is the expected
7786
test-errors:
7887
runs-on: ubuntu-latest

README.md

+14-25
Original file line numberDiff line numberDiff line change
@@ -71,30 +71,32 @@ steps:
7171

7272
**Include or exclude secrets:**
7373

74-
Exclude defined secret(s) from list of secrets (comma separated).
74+
Exclude defined secret(s) from list of secrets (comma separated, supports regex).
7575

7676
```yaml
7777
steps:
7878
- uses: actions/checkout@v3
7979
- uses: oNaiPs/secrets-to-env-action@v1
8080
with:
8181
secrets: ${{ toJSON(secrets) }}
82-
exclude: MY_SECRET, MY_OTHER_SECRET
82+
exclude: MY_SECRET, MY_OTHER_SECRETS*
8383
# MY_SECRET is not exported
8484
```
8585

86-
**Only** include secret(s) from list of secrets (comma separated).
86+
**Only** include secret(s) from list of secrets (comma separated, supports regex).
8787

8888
```yaml
8989
steps:
9090
- uses: actions/checkout@v3
9191
- uses: oNaiPs/secrets-to-env-action@v1
9292
with:
9393
secrets: ${{ toJSON(secrets) }}
94-
include: MY_SECRET, MY_OTHER_SECRET
94+
include: MY_SECRET, MY_OTHER_SECRETS*
9595
- run: echo "Value of MY_SECRET: $MY_SECRET"
9696
```
9797

98+
To export secrets that start with a given string, you can use `include: PREFIX_*`.
99+
98100
NOTE: If specified secret does not exist, it is ignored.
99101

100102
**Add a prefix:**
@@ -111,20 +113,22 @@ steps:
111113
- run: echo "Value of PREFIXED_MY_SECRET: $PREFIXED_MY_SECRET"
112114
```
113115

114-
**Only export secrets that start with a given string:**
116+
**Convert:**
115117

118+
Converts all exported secrets according to a [template](https://github.com/blakeembrey/change-case#core).
119+
Available: `lower, upper, camel, constant, pascal, snake`.
120+
116121
```yaml
117122
steps:
118123
- uses: actions/checkout@v3
119124
- uses: oNaiPs/secrets-to-env-action@v1
120125
with:
121126
secrets: ${{ toJSON(secrets) }}
122-
starts_with: PREFIX_
123-
- run: env
124-
# observe that only vars with PREFIX_ were exported
127+
convert: lower
128+
- run: echo "Value of my_secret: $my_secret"
125129
```
126130

127-
**Only apply string conversions (see below) for secrets that start with a given string:**
131+
**Include or skip the prefix on conversion (default is true):**
128132

129133
```yaml
130134
steps:
@@ -133,28 +137,13 @@ steps:
133137
with:
134138
secrets: ${{ toJSON(secrets) }}
135139
starts_with: PREFIX_
136-
starts_with_convert_prefix: false
137140
convert: lower
141+
convert_prefix: false
138142
- run: env
139143
# observe that only vars with PREFIX_ were exported
140144
# E.g. secret with PREFIX_KEY_1 would become PREFIX_key_1
141145
```
142146

143-
**Convert:**
144-
145-
Converts all exported secrets according to a [template](https://github.com/blakeembrey/change-case#core).
146-
Available: `lower, upper, camel, constant, pascal, snake`.
147-
148-
```yaml
149-
steps:
150-
- uses: actions/checkout@v3
151-
- uses: oNaiPs/secrets-to-env-action@v1
152-
with:
153-
secrets: ${{ toJSON(secrets) }}
154-
convert: lower
155-
- run: echo "Value of my_secret: $my_secret"
156-
```
157-
158147
## How it works
159148

160149
This action uses the input in `secrets` to read all the secrets in the JSON format, and exporting all the variables one by one.

__tests__/main.test.ts

+212-11
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,215 @@
11
import * as cp from 'child_process'
22
import * as path from 'path'
3-
import {expect, test} from '@jest/globals'
4-
5-
// shows how the runner will run a javascript action with env / stdout protocol
6-
test('test runs', () => {
7-
process.env['INPUT_SECRETS'] = '{"AAA": "123"}'
8-
const np = process.execPath
9-
const ip = path.join(__dirname, '..', 'lib', 'main.js')
10-
const options: cp.ExecFileSyncOptions = {
11-
env: process.env
12-
}
13-
console.log(cp.execFileSync(np, [ip], options).toString())
3+
import {expect, jest, test} from '@jest/globals'
4+
import * as core from '@actions/core'
5+
import main from '../src/main'
6+
7+
jest.mock('@actions/core')
8+
9+
let mockedCore: jest.Mocked<typeof core>
10+
11+
jest.mocked(core.debug).mockImplementation(s => console.log(`DEBUG: ${s}`))
12+
jest.mocked(core.info).mockImplementation(s => console.log(`INFO: ${s}`))
13+
jest.mocked(core.warning).mockImplementation(s => console.log(`WARNING: ${s}`))
14+
15+
function mockInputs(inputs: {[key: string]: string}) {
16+
jest.mocked(core.getInput).mockImplementation(s => inputs[s] || '')
17+
}
18+
19+
describe('secrets-to-env-action', () => {
20+
let inputSecrets: {[key: string]: string}
21+
let newSecrets: {[key: string]: string}
22+
23+
beforeEach(() => {
24+
inputSecrets = {
25+
MY_SECRET_1: 'VALUE_1',
26+
MY_SECRET_2: 'VALUE_2',
27+
my_low_secret_1: 'low_value_1'
28+
}
29+
30+
newSecrets = {}
31+
jest
32+
.mocked(core.exportVariable)
33+
.mockImplementation((k, v) => (newSecrets[k] = v))
34+
})
35+
36+
it('exports all variables', () => {
37+
mockInputs({
38+
secrets: JSON.stringify(inputSecrets)
39+
})
40+
main()
41+
expect(newSecrets).toEqual(inputSecrets)
42+
})
43+
44+
it('excludes variables (single)', () => {
45+
mockInputs({
46+
secrets: JSON.stringify(inputSecrets),
47+
exclude: 'MY_SECRET_1'
48+
})
49+
main()
50+
delete inputSecrets.MY_SECRET_1
51+
expect(newSecrets).toEqual(inputSecrets)
52+
})
53+
54+
it('excludes variables (array)', () => {
55+
mockInputs({
56+
secrets: JSON.stringify(inputSecrets),
57+
exclude: 'MY_SECRET_1,MY_SECRET_2,ignore'
58+
})
59+
main()
60+
delete inputSecrets.MY_SECRET_1
61+
delete inputSecrets.MY_SECRET_2
62+
expect(newSecrets).toEqual(inputSecrets)
63+
})
64+
65+
it('excludes variables (regex)', () => {
66+
mockInputs({
67+
secrets: JSON.stringify(inputSecrets),
68+
exclude: 'MY_SECRET_*,ignore'
69+
})
70+
main()
71+
delete inputSecrets.MY_SECRET_1
72+
delete inputSecrets.MY_SECRET_2
73+
expect(newSecrets).toEqual(inputSecrets)
74+
})
75+
76+
it('includes variables (single)', () => {
77+
mockInputs({
78+
secrets: JSON.stringify(inputSecrets),
79+
include: 'MY_SECRET_1'
80+
})
81+
main()
82+
83+
expect(newSecrets).toEqual({
84+
MY_SECRET_1: inputSecrets.MY_SECRET_1
85+
})
86+
})
87+
88+
it('includes variables (array)', () => {
89+
mockInputs({
90+
secrets: JSON.stringify(inputSecrets),
91+
include: 'MY_SECRET_1, MY_SECRET_2, ignore'
92+
})
93+
main()
94+
95+
expect(newSecrets).toEqual({
96+
MY_SECRET_1: inputSecrets.MY_SECRET_1,
97+
MY_SECRET_2: inputSecrets.MY_SECRET_2
98+
})
99+
})
100+
101+
it('includes variables (regex)', () => {
102+
mockInputs({
103+
secrets: JSON.stringify(inputSecrets),
104+
include: 'MY_SECRET_*'
105+
})
106+
main()
107+
108+
expect(newSecrets).toEqual({
109+
MY_SECRET_1: inputSecrets.MY_SECRET_1,
110+
MY_SECRET_2: inputSecrets.MY_SECRET_2
111+
})
112+
})
113+
114+
it('adds a prefix', () => {
115+
mockInputs({
116+
secrets: JSON.stringify(inputSecrets),
117+
prefix: 'PREF_',
118+
include: 'MY_SECRET_1, MY_SECRET_2'
119+
})
120+
main()
121+
122+
expect(newSecrets).toEqual({
123+
PREF_MY_SECRET_1: inputSecrets.MY_SECRET_1,
124+
PREF_MY_SECRET_2: inputSecrets.MY_SECRET_2
125+
})
126+
})
127+
128+
it('converts key (lower)', () => {
129+
mockInputs({
130+
secrets: JSON.stringify(inputSecrets),
131+
include: 'MY_SECRET_1, MY_SECRET_2',
132+
convert: 'lower'
133+
})
134+
main()
135+
136+
expect(newSecrets).toEqual({
137+
my_secret_1: inputSecrets.MY_SECRET_1,
138+
my_secret_2: inputSecrets.MY_SECRET_2
139+
})
140+
})
141+
142+
it('converts key (camel)', () => {
143+
mockInputs({
144+
secrets: JSON.stringify(inputSecrets),
145+
include: 'MY_SECRET_1, MY_SECRET_2',
146+
convert: 'camel'
147+
})
148+
main()
149+
150+
expect(newSecrets).toEqual({
151+
mySecret_1: inputSecrets.MY_SECRET_1,
152+
mySecret_2: inputSecrets.MY_SECRET_2
153+
})
154+
})
155+
156+
it('converts key (pascal)', () => {
157+
mockInputs({
158+
secrets: JSON.stringify(inputSecrets),
159+
include: 'MY_SECRET_1, MY_SECRET_2',
160+
convert: 'pascal'
161+
})
162+
main()
163+
164+
expect(newSecrets).toEqual({
165+
MySecret_1: inputSecrets.MY_SECRET_1,
166+
MySecret_2: inputSecrets.MY_SECRET_2
167+
})
168+
})
169+
170+
it('converts key (snake)', () => {
171+
mockInputs({
172+
secrets: JSON.stringify(inputSecrets),
173+
include: 'MY_SECRET_1, MY_SECRET_2',
174+
convert: 'snake'
175+
})
176+
main()
177+
178+
expect(newSecrets).toEqual({
179+
my_secret_1: inputSecrets.MY_SECRET_1,
180+
my_secret_2: inputSecrets.MY_SECRET_2
181+
})
182+
})
183+
184+
it('converts prefix', () => {
185+
mockInputs({
186+
secrets: JSON.stringify(inputSecrets),
187+
include: 'MY_SECRET_1, MY_SECRET_2',
188+
prefix: 'PREFIX_',
189+
convert: 'snake',
190+
convert_prefix: 'true'
191+
})
192+
main()
193+
194+
expect(newSecrets).toEqual({
195+
prefix_my_secret_1: inputSecrets.MY_SECRET_1,
196+
prefix_my_secret_2: inputSecrets.MY_SECRET_2
197+
})
198+
})
199+
200+
it('does not convert prefix', () => {
201+
mockInputs({
202+
secrets: JSON.stringify(inputSecrets),
203+
include: 'MY_SECRET_1, MY_SECRET_2',
204+
prefix: 'PREFIX_',
205+
convert: 'snake',
206+
convert_prefix: 'false'
207+
})
208+
main()
209+
210+
expect(newSecrets).toEqual({
211+
PREFIX_my_secret_1: inputSecrets.MY_SECRET_1,
212+
PREFIX_my_secret_2: inputSecrets.MY_SECRET_2
213+
})
214+
})
14215
})

0 commit comments

Comments
 (0)