Skip to content

Commit

Permalink
Merge pull request #15 from kanga333/match-mode
Browse files Browse the repository at this point in the history
Introduce the mode option to change the behavior of getting a variable
  • Loading branch information
kanga333 authored Nov 15, 2020
2 parents a71b5a5 + f7e9750 commit 1a4ecdb
Show file tree
Hide file tree
Showing 7 changed files with 386 additions and 19 deletions.
78 changes: 78 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -114,3 +114,81 @@ jobs:
run: |
echo ${{ env.environment }}
echo ${{ steps.export.outputs.environment }}
test-readme-example3:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v1
- uses: ./
id: export
with:
key: "first"
map: |
{
"first": {
"env1": "value1",
"env2": "value2"
},
".*": {
"env1": "value1_overwrite",
"env3": "value3"
}
}
export_to: env
mode: first_match
- name: Echo environment and output
run: |
test "${{ env.env1 }}" = "value1"
test "${{ env.env2 }}" = "value2"
test "${{ env.env3 }}" = ""
test-readme-example4:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v1
- uses: ./
id: export
with:
key: "first"
map: |
{
"first": {
"env1": "value1",
"env2": "value2"
},
".*": {
"env1": "value1_overwrite",
"env3": "value3"
}
}
export_to: env
mode: overwrite
- name: Echo environment and output
run: |
test "${{ env.env1 }}" = "value1_overwrite"
test "${{ env.env2 }}" = "value2"
test "${{ env.env3 }}" = "value3"
test-readme-example5:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v1
- uses: ./
id: export
with:
key: "first"
map: |
{
"first": {
"env1": "value1",
"env2": "value2"
},
".*": {
"env1": "value1_overwrite",
"env3": "value3"
}
}
export_to: env
mode: fill
- name: Echo environment and output
run: |
test "${{ env.env1 }}" = "value1"
test "${{ env.env2 }}" = "value2"
test "${{ env.env3 }}" = "value3"
116 changes: 116 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -77,3 +77,119 @@ jobs:
```
The variables can be exported to log, env and output. (Default is `log,env`)

### Switching the behavior of getting the variable

The `mode` option can be used to change the behavior of getting variables.
`first_match`, `overwrite` and `fill` are valid values.

#### first_match mode (default)

`first_match` evaluates the regular expression of a key in order from the top and gets the variable for the first key to be matched.

```yaml
on: [push]
name: Export variables to output and environment and log
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: kanga333/variable-mapper@master
id: export
with:
key: "first"
map: |
{
"first": {
"env1": "value1",
"env2": "value2"
},
".*": {
"env1": "value1_overwrite",
"env3": "value3"
}
}
export_to: env
mode: first_match
- name: Echo environment and output
run: |
echo ${{ env.env1 }}
echo ${{ env.env2 }}
echo ${{ env.env3 }}
```

In this workflow, only `env1:value1` and `env2:value2` are exported as env.

#### overwrite mode

`overwrite` evaluates the regular expression of the keys in order from the top, and then merges the variables associated with the matched keys in turn. If the same variable is defined, the later evaluated value is overwritten.

```yaml
on: [push]
name: Export variables to output and environment and log
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: kanga333/variable-mapper@master
id: export
with:
key: "first"
map: |
{
"first": {
"env1": "value1",
"env2": "value2"
},
".*": {
"env1": "value1_overwrite",
"env3": "value3"
}
}
export_to: env
mode: overwrite
- name: Echo environment and output
run: |
echo ${{ env.env1 }}
echo ${{ env.env2 }}
echo ${{ env.env3 }}
```

In this workflow, `env1:value1_overwrite`, `env2:value2` and `env2:value2` export as env.

#### fill mode

`fill` evaluates the regular expression of the keys in order from the top, and then merges the variables associated with the matched keys in turn. If the same variable is defined, later evaluated values are ignored and the first evaluated value takes precedence.

```yaml
on: [push]
name: Export variables to output and environment and log
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: kanga333/variable-mapper@master
id: export
with:
key: "first"
map: |
{
"first": {
"env1": "value1",
"env2": "value2"
},
".*": {
"env1": "value1_overwrite",
"env3": "value3"
}
}
export_to: env
mode: overwrite
- name: Echo environment and output
run: |
echo ${{ env.env1 }}
echo ${{ env.env2 }}
echo ${{ env.env3 }}
```

In this workflow, `env1:value1`, `env2:value2` and `env2:value2` export as env.
47 changes: 45 additions & 2 deletions __tests__/mapper.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@ import {JSONMapper} from '../src/mapper'

describe('JSONMapper', () => {
const mapper = new JSONMapper(
'{"k.y":{"env1":"value1"},".*":{"env2":"value2"}}'
'{"k.y":{"env1":"value1"},".*":{"env2":"value2"}}',
'first_match'
)

it('JSONMapper holds the order of keys', () => {
Expand All @@ -23,7 +24,49 @@ describe('JSONMapper', () => {

it('JSONMapper should throw an exception on invalid input', () => {
expect(() => {
new JSONMapper('{"invalid":"schema"}')
new JSONMapper('{"invalid":"schema"}', 'first_match')
}).toThrow()
})

describe('Overwrite Matcher', () => {
const overwrite = new JSONMapper(
'{"k.y":{"env1":"value1","env2":"value2"},".*":{"env2":"overwrite"}}',
'overwrite'
)

it('Overwrite Matcher can match and overwrite multiple values', () => {
const got = overwrite.match('key')
if (!got) {
throw new Error('No match')
}
expect(got.key).toBe('k.y\n.*')
expect(got.variables).toMatchObject(
new Map([
['env1', 'value1'],
['env2', 'overwrite']
])
)
})
})

describe('Fill Matcher', () => {
const overwrite = new JSONMapper(
'{"k.y":{"env1":"value1"},".*":{"env1":"not_overwrite", "env2":"fill"}}',
'fill'
)

it('Overwrite Matcher can match and overwrite multiple values', () => {
const got = overwrite.match('key')
if (!got) {
throw new Error('No match')
}
expect(got.key).toBe('.*\nk.y')
expect(got.variables).toMatchObject(
new Map([
['env1', 'value1'],
['env2', 'fill']
])
)
})
})
})
3 changes: 3 additions & 0 deletions action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@ inputs:
export_to:
description: 'Comma-separated list of targets to export variables to. log, env and output are valid values.'
default: 'log,env'
mode:
description: 'Specify the behavior of getting the variable. first_match, overwrite and fill are valid values.'
default: 'first_match'
runs:
using: 'node12'
main: 'dist/index.js'
74 changes: 66 additions & 8 deletions dist/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -404,6 +404,55 @@ class KeyVariablesPair {
fn(variable[0], variable[1]);
}
}
merge(kvp) {
this.variables = new Map([
...this.variables.entries(),
...kvp.variables.entries()
]);
this.key = `${this.key}\n${kvp.key}`;
}
}
class FirstMatch {
match(key, pairs) {
for (const param of pairs) {
const ok = param.match(key);
if (ok) {
return param;
}
}
}
}
class Overwrite {
match(key, pairs) {
let pair;
for (const param of pairs) {
const ok = param.match(key);
if (ok) {
if (pair === undefined) {
pair = param;
continue;
}
pair.merge(param);
}
}
return pair;
}
}
class Fill {
match(key, pairs) {
let pair;
for (const param of pairs.reverse()) {
const ok = param.match(key);
if (ok) {
if (pair === undefined) {
pair = param;
continue;
}
pair.merge(param);
}
}
return pair;
}
}
class Mapper {
validate(input) {
Expand All @@ -413,12 +462,7 @@ class Mapper {
throw new Error(`Validation failed: ${ajv.errorsText()}`);
}
match(key) {
for (const param of this.pairs) {
const ok = param.match(key);
if (ok) {
return param;
}
}
return this.matcher.match(key, this.pairs);
}
}
Mapper.schema = {
Expand All @@ -429,8 +473,21 @@ Mapper.schema = {
}
};
class JSONMapper extends Mapper {
constructor(rawJSON) {
constructor(rawJSON, mode) {
super();
switch (mode) {
case 'first_match':
this.matcher = new FirstMatch();
break;
case 'overwrite':
this.matcher = new Overwrite();
break;
case 'fill':
this.matcher = new Fill();
break;
default:
throw new Error(`Unexpected mode: ${mode}`);
}
const parsed = JSON.parse(rawJSON);
this.validate(parsed);
const tmpPairs = new Array();
Expand Down Expand Up @@ -656,7 +713,8 @@ function run() {
const map = core.getInput('map');
const key = core.getInput('key');
const to = core.getInput('export_to');
const params = new mapper_1.JSONMapper(map);
const mode = core.getInput('mode');
const params = new mapper_1.JSONMapper(map, mode);
const matched = params.match(key);
if (!matched) {
core.info(`No match for the ${key}`);
Expand Down
3 changes: 2 additions & 1 deletion src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,9 @@ function run(): void {
const map: string = core.getInput('map')
const key: string = core.getInput('key')
const to: string = core.getInput('export_to')
const mode: string = core.getInput('mode')

const params = new JSONMapper(map)
const params = new JSONMapper(map, mode)
const matched = params.match(key)
if (!matched) {
core.info(`No match for the ${key}`)
Expand Down
Loading

0 comments on commit 1a4ecdb

Please sign in to comment.