Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Factor out handlebars helpers into separate module #220

Merged
merged 1 commit into from Nov 9, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/slack.yml
@@ -1,7 +1,7 @@
username: GitHub-CI
icon_url: https://octodex.github.com/images/femalecodertocat.png

pretext: Triggered via {{eventName}} by {{actor}} {{or action "action"}} {{ref}} `{{diffRef}}`
pretext: Triggered via {{eventName}} by {{actor}} {{default action "action"}} {{ref}} `{{diffRef}}`
title: GitHub Actions
title_link: https://support.github.com

Expand All @@ -11,7 +11,7 @@ text: |
{{#if payload.commits}}
*Commits*
{{#each payload.commits}}
<{{this.url}}|`{{limitTo this.id 8}}`> - {{this.message}}
<{{this.url}}|`{{truncate this.id 8}}`> - {{this.message}}
{{/each}}
{{/if}}
Expand Down
4 changes: 4 additions & 0 deletions Makefile
Expand Up @@ -27,6 +27,10 @@ test:
test.only:
npm test -- $(TEST_REGEX)

## test.package - Run ncc compiled code.
test.package:
npm run package:test

## build - Build and package.
build:
npm run build && npm run package
Expand Down
10 changes: 7 additions & 3 deletions README.md
Expand Up @@ -112,8 +112,12 @@ ones:

- `icon` converts a job status into an icon eg. `{{icon jobStatus}}`
- `json` dumps the value as a JSON string eg. `{{json payload.commits}}`
- `limitTo` cuts the string at the limit eg. `{{limitTo sha 8}}`
- `or` allows a alternative or default value eg. `{{or headRef baseRef}}`
- `truncate` cuts the string at the limit eg. `{{truncate sha 8}}`
- `default` allows a alternative or default value eg. `{{default headRef "master"}}`
- `pluralize` outputs different text based on item count eg. `{{pluralize requested_reviewers "reviewer" "reviewers"}}` (if only singular form is given plural is derived by adding an "s")

- `eq`, `neq`, `not`, `and`, and `or` can be used as logical operators eg. `{{#if (and (not has_issues) (or has_pages has_wiki))}}yes{{else}}no{{/if}}`
- `#ifeq` and `#ifneq` test for variable equality or not eg. `{{#ifneq event_name "create"}}yes{{else}}no{{/ifneq}}`

**Example Using Config File**

Expand Down Expand Up @@ -188,7 +192,7 @@ icons:
*Notes:*

* If template expressions occur at the start of a string the string must be double-quoted eg. `pretext: "{{eventName}} triggered by {{actor}}"`
* Use [YAML multiline string formats](https://yaml-multiline.info/) `|`, `>`, `|-` and `>-` or double-quotes `"\n"` to control how new lines
* Use [YAML multiline string formats](https://yaml-multiline.info/) `|`, `>`, `|-` and `>-` or double-quotes `"\n"` to control new lines
* Use `~` (tilde) character to control whitepace when looping see [Whitespace control](https://handlebarsjs.com/guide/expressions.html#whitespace-control)

### Conditionals (`if`)
Expand Down
19 changes: 9 additions & 10 deletions __tests__/config.test.ts
Expand Up @@ -11,18 +11,18 @@ const jobStatus = 'failure'
const jobSteps = {
'install-deps': {
outputs: {},
outcome: 'skipped',
conclusion: 'skipped'
outcome: 'success',
conclusion: 'success'
},
hooks: {
outputs: {},
outcome: 'skipped',
conclusion: 'skipped'
outcome: 'cancelled',
conclusion: 'cancelled'
},
lint: {
outputs: {},
outcome: 'skipped',
conclusion: 'skipped'
outcome: 'failure',
conclusion: 'failure'
},
types: {
outputs: {},
Expand All @@ -36,8 +36,8 @@ const jobSteps = {
},
'integration-test': {
outputs: {},
outcome: 'skipped',
conclusion: 'skipped'
outcome: 'failure',
conclusion: 'failure'
}
}
const channel = '#github-ci'
Expand Down Expand Up @@ -122,8 +122,7 @@ test('custom config of slack action', async () => {
{
short: false,
title: 'Job Steps',
value:
':heavy_minus_sign: install-deps\n:heavy_minus_sign: hooks\n:heavy_minus_sign: lint\n:heavy_minus_sign: types\n:heavy_minus_sign: unit-test\n:heavy_minus_sign: integration-test\n'
value: ':white_check_mark: install-deps\n:x: hooks\n:grimacing: lint\n:grimacing: integration-test\n'
},
{
short: true,
Expand Down
8 changes: 5 additions & 3 deletions __tests__/fixtures/slack.yml
@@ -1,7 +1,7 @@
username: GitHub-CI
icon_url: https://octodex.github.com/images/mona-the-rivetertocat.png

pretext: Triggered via {{eventName}} by {{actor}} {{or action "action"}} {{ref}} `{{diffRef}}`
pretext: Triggered via {{eventName}} by {{actor}} {{default action "action"}} {{ref}} `{{diffRef}}`
title: GitHub Actions
title_link: https://support.github.com

Expand All @@ -11,7 +11,7 @@ text: |
{{#if payload.commits}}
*Commits*
{{#each payload.commits}}
<{{this.url}}|`{{limitTo this.id 8}}`> - {{this.message}}
<{{this.url}}|`{{truncate this.id 8}}`> - {{this.message}}
{{/each}}
{{/if}}
Expand All @@ -20,7 +20,9 @@ fallback: |-
fields:
- title: Job Steps
value: "{{#each jobSteps}}{{icon this.outcome}} {{@key}}\n{{/each}}"
value: |-
{{#each jobSteps}}{{#ifneq this.outcome 'skipped'}}{{icon this.outcome}} {{@key}}
{{/ifneq}}{{/each}}
short: false
- title: Workflow
value: "<{{{workflowUrl}}}|{{workflow}}>"
Expand Down
157 changes: 157 additions & 0 deletions __tests__/handlebars.test.ts
@@ -0,0 +1,157 @@
import Handlebars from '../src/handlebars'

const data = {
foo: 'bar',
fu: 'bar',
obj: {
a: 'b',
c: 123,
d: ['x', 'y', 'z']
},
text: 'this is a long line of text',
uuid: 'CFE20509-E7CF-4401-9733-7615EF3E8A25',
want: 0,
t: true,
f: false,
empty: [],
commits: ['088fcd5a5bc73a6733edcc58d0d30869ddbe2e2f'],
numbers: [1, 2, 3, 4],
letters: ['abc', 'def', 'ghi'],
foobars: [
{foo: true, bar: 1},
{foo: false, bar: 3},
{foo: true, bar: 3}
],
attendees: ['dave', 'mike', 'jane', 'betty'],
items: [1, 2, 3]
}

// utilities
test('json stringify', () => {
const template = Handlebars.compile('{{{json obj}}}')
const text = template(data)
expect(text).toStrictEqual('{"a":"b","c":123,"d":["x","y","z"]}')
})

test('truncate uuid', () => {
const template = Handlebars.compile('{{truncate uuid 8}}')
const text = template(data)
expect(text).toStrictEqual('CFE20509')
})

test('default is not needed', () => {
const template = Handlebars.compile('{{default want "fallback"}}')
const text = template(data)
expect(text).toStrictEqual('0')
})

test('default is needed', () => {
const template = Handlebars.compile('{{default fallback "fallback"}}')
const text = template(data)
expect(text).toStrictEqual('fallback')
})

test('pluralize empty list', () => {
const template = Handlebars.compile('{{pluralize empty}}')
const text = template(data)
expect(text).toStrictEqual('no items')
})

test('pluralize commits', () => {
const template = Handlebars.compile('{{pluralize commits "commit"}}')
const text = template(data)
expect(text).toStrictEqual('1 commit')
})

test('pluralize attendees', () => {
const template = Handlebars.compile('{{pluralize attendees "attendee"}}')
const text = template(data)
expect(text).toStrictEqual('4 attendees')
})

test('pluralize people', () => {
const template = Handlebars.compile('{{pluralize attendees "person" "people"}}')
const text = template(data)
expect(text).toStrictEqual('4 people')
})

// equality
test('eq is true', () => {
const template = Handlebars.compile('{{#if (eq foo fu)}}yes{{else}}no{{/if}}')
const text = template(data)
expect(text).toStrictEqual('yes')
})

test('eq is false', () => {
const template = Handlebars.compile('{{#if (eq foo "foo")}}yes{{else}}no{{/if}}')
const text = template(data)
expect(text).toStrictEqual('no')
})

test('neq is true', () => {
const template = Handlebars.compile('{{#if (neq foo fu)}}yes{{else}}no{{/if}}')
const text = template(data)
expect(text).toStrictEqual('no')
})

test('neq is false', () => {
const template = Handlebars.compile('{{#if (neq foo "foo")}}yes{{else}}no{{/if}}')
const text = template(data)
expect(text).toStrictEqual('yes')
})

// boolean operators
test('not false', () => {
const template = Handlebars.compile('{{#if (not f)}}yes{{else}}no{{/if}}')
const text = template(data)
expect(text).toStrictEqual('yes')
})

test('not true', () => {
const template = Handlebars.compile('{{#if (not t)}}yes{{else}}no{{/if}}')
const text = template(data)
expect(text).toStrictEqual('no')
})

test('not false and (true or false)', () => {
const template = Handlebars.compile('{{#if (and (not f) (or t f))}}yes{{else}}no{{/if}}')
const text = template(data)
expect(text).toStrictEqual('yes')
})

test('or is true', () => {
const template = Handlebars.compile('{{#if (or t f)}}yes{{else}}no{{/if}}')
const text = template(data)
expect(text).toStrictEqual('yes')
})

test('and is false', () => {
const template = Handlebars.compile('{{#if (and t f)}}yes{{else}}no{{/if}}')
const text = template(data)
expect(text).toStrictEqual('no')
})

// conditionals
test('#ifeq is true', () => {
const template = Handlebars.compile('{{#ifeq foo fu}}yes{{else}}no{{/ifeq}}')
const text = template(data)
expect(text).toStrictEqual('yes')
})

test('#ifeq is false', () => {
const template = Handlebars.compile('{{#ifeq foo "foo"}}yes{{else}}no{{/ifeq}}')
const text = template(data)
expect(text).toStrictEqual('no')
})

test('#ifneq is true', () => {
const template = Handlebars.compile('{{#ifneq foo fu}}yes{{else}}no{{/ifneq}}')
const text = template(data)
expect(text).toStrictEqual('no')
})

test('#ifneq is false', () => {
const template = Handlebars.compile('{{#ifneq foo "foo"}}yes{{else}}no{{/ifneq}}')
const text = template(data)
expect(text).toStrictEqual('yes')
})
15 changes: 7 additions & 8 deletions __tests__/inputs.test.ts
Expand Up @@ -11,8 +11,8 @@ const jobStatus = 'in progress'
const jobSteps = {
'install-deps': {
outputs: {},
outcome: 'skipped',
conclusion: 'skipped'
outcome: 'success',
conclusion: 'success'
},
hooks: {
outputs: {},
Expand All @@ -31,13 +31,13 @@ const jobSteps = {
},
'unit-test': {
outputs: {},
outcome: 'skipped',
conclusion: 'skipped'
outcome: 'failure',
conclusion: 'failure'
},
'integration-test': {
outputs: {},
outcome: 'skipped',
conclusion: 'skipped'
outcome: 'cancelled',
conclusion: 'cancelled'
}
}
const channel = '#deploy'
Expand Down Expand Up @@ -115,8 +115,7 @@ test('custom config of slack action', async () => {
{
short: false,
title: 'Job Steps',
value:
':heavy_minus_sign: install-deps\n:heavy_minus_sign: hooks\n:heavy_minus_sign: lint\n:heavy_minus_sign: types\n:heavy_minus_sign: unit-test\n:heavy_minus_sign: integration-test\n'
value: ':white_check_mark: install-deps\n:grimacing: unit-test\n:x: integration-test\n'
},
{
short: true,
Expand Down