Skip to content

Commit

Permalink
Merge pull request #80 from Renato66/feat/json-config
Browse files Browse the repository at this point in the history
Feat/json config
  • Loading branch information
Renato66 committed May 10, 2024
2 parents 30beb16 + 7cb2c29 commit e5af195
Show file tree
Hide file tree
Showing 20 changed files with 324 additions and 31 deletions.
15 changes: 15 additions & 0 deletions .github/workflows/auto-label.json5
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
labelsSynonyms: {
bug: ['error', 'need fix', 'not working'],
enhancement: ['upgrade'],
question: ['help', 'how can i']
},
labelsNotAllowed: [
'documentation',
'duplicate',
'good first issue',
'help wanted',
'invalid'
],
defaultLabels: ['triage']
}
20 changes: 20 additions & 0 deletions .github/workflows/auto-label.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
name: Labeling new issue

on:
issues:
types: ['opened']
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
sparse-checkout: |
.github/workflows/
# .github/workflows/auto-label.json5
# .github/workflows/auto-label.jsonc
# .github/workflows/auto-label.json
sparse-checkout-cone-mode: false
- uses: Renato66/auto-label@main
with:
repo-token: ${{ secrets.GITHUB_TOKEN }}
2 changes: 2 additions & 0 deletions .prettierignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
src/__mock__/config/invalid/invalid3.json
readme.md
93 changes: 72 additions & 21 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,22 +2,14 @@

![Unit test](https://github.com/Renato66/auto-label/workflows/Unit%20test/badge.svg)
[![Auto Label](https://github.com/Renato66/auto-label/workflows/Labeling%20new%20issue/badge.svg)](https://github.com/Renato66/auto-label)
[![codecov](https://codecov.io/gh/Renato66/auto-label/branch/master/graph/badge.svg)](https://codecov.io/gh/Renato66/auto-label)

![image](https://user-images.githubusercontent.com/9284273/79672530-57c1db80-81a9-11ea-900c-3b4f73984e0a.png)

The Auto label action will check for every new issue and automatically adds a label based on the body of the issue. This means that finding specific issues will be much easier.

> [!WARNING]
> The main branch is being refactored, use the stable one at [master](https://github.com/Renato66/auto-label/tree/master) subscribe to [v3](https://github.com/Renato66/auto-label/issues/75) to get the latest version when it's released
## Creating

Check out the app to make a YAML file [here](https://renato66.github.io/auto-label/).

or

add a file to `.github/workflows/issue.yml`
Add a file to `.github/workflows/auto-label.yml`

```yml
name: Labeling new issue
Expand All @@ -28,24 +20,48 @@ jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: Renato66/auto-label@v2
- uses: actions/checkout@v4
with:
sparse-checkout: |
.github/workflows
sparse-checkout-cone-mode: false
- uses: Renato66/auto-label@v3
with:
repo-token: ${{ secrets.GITHUB_TOKEN }}
ignore-comments: true
labels-synonyms: '{"bug":["error","need fix","not working"],"enhancement":["upgrade"],"question":["help"]}'
labels-not-allowed: '["good first issue"]'
default-labels: '["help wanted"]'
```

Add a config file to `.github/workflows/auto-label.json5`

```json5
// see inputs for more examples
{
labelsSynonyms: {
bug: ['error', 'need fix', 'not working'],
enhancement: ['upgrade'],
question: ['help', 'how can i']
},
labelsNotAllowed: [
'documentation',
'duplicate',
'good first issue',
'help wanted',
'invalid'
],
defaultLabels: ['triage'],
ignoreComments: true
}
```

## Inputs

| Name | Description | Required | Default | Examples |
| ------------------ | ----------------------------------- | -------- | ------- | :------------------------: |
| repo-token | GitHub token for the repository | true | - | [...](#repo-token) |
| ignore-comments | Ignore labels inside issue comments | false | true | [...](#ignore-comments) |
| labels-synonyms | Text synonyms for labels | false | - | [...](#labels-synonyms) |
| labels-not-allowed | Labels to ignore | false | - | [...](#labels-not-allowed) |
| default-labels | Labels that will always be set | false | - | [...](#default-labels) |
| Name | Description | Required | Default | Examples |
| ------------------ | ----------------------------------- | -------- | ---------------------------------- | :------------------------: |
| repo-token | GitHub token for the repository | true | - | [...](#repo-token) |
| configuration-file | Configuration file path | true | .github/workflows/auto-label.json5 | [...](#configuration-file) |
| ignore-comments | Ignore labels inside issue comments | false | true | [...](#ignore-comments) |
| labels-synonyms | Text synonyms for labels | false | - | [...](#labels-synonyms) |
| labels-not-allowed | Labels to ignore | false | - | [...](#labels-not-allowed) |
| default-labels | Labels that will always be set | false | - | [...](#default-labels) |

### Repo Token

Expand All @@ -55,6 +71,41 @@ Repo token is provided automatically by GitHub; just need to add
repo-token: ${{ secrets.GITHUB_TOKEN }}
```

### Configuration File

Configuration file can be created at any place at your repository, it will need another action to get the file like:

```yml
- uses: actions/checkout@v4
with:
sparse-checkout: |
.github/workflows/
sparse-checkout-cone-mode: false
```

and it will look for any file named auto-label with the extension `JSON` or `JSON5` or `JSONC` but you can also define a specific extension

```yml
- uses: actions/checkout@v4
with:
sparse-checkout: |
.github/workflows/auto-label.json5
sparse-checkout-cone-mode: false
```

to set another place to store your configuration file, you should checkout and point with `configuration-file` input:

```yml
- uses: actions/checkout@v4
with:
sparse-checkout: |
src/actions/configuration.json
sparse-checkout-cone-mode: false
- uses: Renato66/auto-label@v3
with:
configuration-file: 'src/actions/configuration.json'
```

#### Change bot appearance

If you want to change who added the labels, you can provide a user token
Expand Down
Binary file modified bun.lockb
Binary file not shown.
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
},
"dependencies": {
"@actions/core": "1.10.1",
"@actions/github": "6.0.0"
"@actions/github": "6.0.0",
"json5": "^2.2.3"
}
}
8 changes: 8 additions & 0 deletions src/__mock__/config/auto-label.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"labelsSynonyms": {
"bug": ["error"]
},
"labelsNotAllowed": ["documentation"],
"defaultLabels": ["triage"],
"ignoreComments": true
}
13 changes: 13 additions & 0 deletions src/__mock__/config/auto-label.json5
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
// comment test
labelsSynonyms: {
bug: [
'error'
// trailing comma
]
},
// single quote
labelsNotAllowed: ['documentation'],
defaultLabels: ['triage'],
ignoreComments: true
}
9 changes: 9 additions & 0 deletions src/__mock__/config/auto-label.jsonc
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
// comment test
"labelsSynonyms": {
"bug": ["error"]
},
"labelsNotAllowed": ["documentation"],
"defaultLabels": ["triage"],
"ignoreComments": true
}
1 change: 1 addition & 0 deletions src/__mock__/config/empty.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{}
6 changes: 6 additions & 0 deletions src/__mock__/config/invalid/invalid1.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"labels-synonyms": "expected: Record<string, string[]>",
"labels-not-allowed": "expected: string[]",
"default-labels": "expected: string[]",
"ignoreComments": "expected: boolean"
}
1 change: 1 addition & 0 deletions src/__mock__/config/invalid/invalid2.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
"invalid json"
1 change: 1 addition & 0 deletions src/__mock__/config/invalid/invalid3.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
not-valid-json
8 changes: 8 additions & 0 deletions src/__mock__/config/valid/valid.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"labelsSynonyms": {
"bug": ["error"]
},
"labelsNotAllowed": ["documentation"],
"defaultLabels": ["triage"],
"ignoreComments": true
}
28 changes: 24 additions & 4 deletions src/domain/getConfigFile.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,26 @@ describe('getConfigFile', () => {
})
test('returns empty array when labels-not-allowed input is empty', () => {
mock.module('@actions/core', () => ({
getInput: jest.fn(() => undefined),
getBooleanInput: jest.fn(() => undefined)
getInput: jest.fn((input: string) => {
const options: Record<string, string> = {
'repo-token': 'mockedToken',
'configuration-file': 'src/__mock__/config/empty.json',
'labels-not-allowed': ''
}
return options[input] || undefined
})
}))
const result1 = getConfigFile()
expect(result1.labelsNotAllowed).toEqual([])
mock.module('@actions/core', () => ({
getInput: jest.fn(() => '')
getInput: jest.fn((input: string) => {
const options: Record<string, any> = {
'repo-token': 'mockedToken',
'configuration-file': 'src/__mock__/config/empty.json',
'labels-not-allowed': undefined
}
return options[input] || undefined
})
}))
const result2 = getConfigFile()
expect(result2.labelsNotAllowed).toEqual([])
Expand All @@ -23,7 +36,14 @@ describe('getConfigFile', () => {
test('returns parsed array from labels-not-allowed input', () => {
const labels = ['label1', 'label2']
mock.module('@actions/core', () => ({
getInput: jest.fn(() => JSON.stringify(labels))
getInput: jest.fn((input: string) => {
const options: Record<string, string> = {
'repo-token': 'mockedToken',
'configuration-file': 'src/__mock__/config/empty.json',
'labels-not-allowed': JSON.stringify(labels)
}
return options[input] || undefined
})
}))
const result = getConfigFile()
expect(result.labelsNotAllowed).toEqual(labels)
Expand Down
18 changes: 16 additions & 2 deletions src/domain/getConfigFile.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,32 @@
import { getInput } from './getInput'
import { getLabelConfigs } from './getLabelConfigs'

export const getConfigFile = () => {
export type Config = {
labelsNotAllowed: string[]
defaultLabels: string[]
labelsSynonyms: Record<string, string[]>
ignoreComments: boolean
}

export const getConfigFile = (): Config => {
const configPath = getInput<string>(
'configuration-file',
'.github/workflows/'
)
const labelsNotAllowed = getInput<string[]>('labels-not-allowed', [])
const defaultLabels = getInput<string[]>('default-labels', [])
const labelsSynonyms = getInput<Record<string, string[]>>(
'labels-synonyms',
{}
)
const ignoreComments = getInput('ignore-comments', true)
const config = getLabelConfigs(configPath)

return {
labelsNotAllowed,
defaultLabels,
labelsSynonyms,
ignoreComments
ignoreComments,
...config
}
}
2 changes: 1 addition & 1 deletion src/domain/getInput.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,6 @@ export const getInput = <T>(field: string, fallback: T): T => {
case 'boolean':
return getBooleanInput(field, fallback) as T
default:
return core.getInput(field) as T
return (core.getInput(field) as T) || fallback
}
}
52 changes: 52 additions & 0 deletions src/domain/getLabelConfigs.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import { expect, describe, test, mock, jest } from 'bun:test'
import { getLabelConfigs } from './getLabelConfigs'
import * as core from '@actions/core'

const configurationPath = 'src/__mock__/config'
const defaultConfig = {
labelsSynonyms: {
bug: ['error']
},
labelsNotAllowed: ['documentation'],
defaultLabels: ['triage'],
ignoreComments: true
}
describe('getLabelConfigs', () => {
test('should return label configurations from a valid JSON folder path', () => {
const options = [`${configurationPath}/`, `${configurationPath}`]
options.forEach((elem) => {
const result = getLabelConfigs(elem)
expect(result).toEqual(defaultConfig)
})
})

test('should return label configurations from a valid JSONC file path', () => {
const result = getLabelConfigs(`${configurationPath}/auto-label.jsonc`)
expect(result).toEqual(defaultConfig)
})

test('should return label configurations from a valid JSON5 file path', () => {
const result = getLabelConfigs(`${configurationPath}/auto-label.json5`)
expect(result).toEqual(defaultConfig)
})

test('should return an empty object if the configuration file is not valid', () => {
const options = [
`${configurationPath}/invalid/invalid1.json`,
`${configurationPath}/invalid/invalid2.json`
]
options.forEach((elem) => {
const result = getLabelConfigs(elem)
expect(result).toEqual({})
})
})

test('should send an warning if file is not readable', () => {
mock.module('@actions/core', () => ({
warning: jest.fn()
}))
const result = getLabelConfigs(`${configurationPath}/invalid/invalid3.json`)
expect(result).toEqual({})
mock.module('@actions/core', () => core)
})
})
Loading

0 comments on commit e5af195

Please sign in to comment.