Skip to content

Commit

Permalink
feat: add YAML support for configurations
Browse files Browse the repository at this point in the history
  • Loading branch information
prototypicalpro committed Aug 26, 2020
1 parent 3dd930e commit 10fd1c3
Show file tree
Hide file tree
Showing 12 changed files with 285 additions and 19 deletions.
72 changes: 67 additions & 5 deletions __tests__/getConfig.test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import getConfig from '../src/getConfig'
import * as path from 'path'
import * as fs from 'fs'
import * as yaml from 'js-yaml'
import nock from 'nock'

describe('getConfig', () => {
Expand All @@ -12,7 +13,15 @@ describe('getConfig', () => {
expect(res).toMatchObject(expected)
})

test('getConfig returns a config from a URL', async () => {
test('getConfig returns a config from a YAML', async () => {
const filepath = path.resolve(__dirname, 'testconfig.yaml')
const expected = yaml.safeLoad(await fs.promises.readFile(filepath, 'utf8'))
const res = await getConfig({configFile: filepath})

expect(res).toMatchObject(expected as object)
})

test('getConfig returns a JSON config from a URL', async () => {
// TODO: change this to point to the new relic repo when it goes public
const url =
'https://raw.githubusercontent.com/aperture-science-incorporated/.github/master/repolinter.json'
Expand All @@ -29,21 +38,74 @@ describe('getConfig', () => {
scope.done()
})

test('getConfig returns a YAML config from a URL', async () => {
// TODO: change this to point to the new relic repo when it goes public
const url =
'https://raw.githubusercontent.com/aperture-science-incorporated/.github/master/repolinter.yaml'
const filepath = path.resolve(__dirname, 'testconfig.yaml')
const expected = yaml.safeLoad(await fs.promises.readFile(filepath, 'utf8'))
const scope = nock('https://raw.githubusercontent.com')
.get('/aperture-science-incorporated/.github/master/repolinter.yaml')
.replyWithFile(200, filepath)

const res = await getConfig({configUrl: url})

expect(res).toMatchObject(expected as object)

scope.done()
})

test('getConfig fails with an invalid file', async () => {
const filepath = 'notafile'

expect(async () => getConfig({configFile: filepath})).rejects.toThrowError()
await expect(async () =>
getConfig({configFile: filepath})
).rejects.toThrowError()
})

test('getConfig failed with an invalid url', async () => {
const url = 'notadomain'

expect(async () => getConfig({configUrl: url})).rejects.toThrowError()
await expect(async () => getConfig({configUrl: url})).rejects.toThrowError()
})

test('getConfig fails with an invalid json structure', async () => {
test('getConfig failed with an rejecting url', async () => {
const url = 'https://www.example.com'
const scope = nock(url).get('/').reply(404)

await expect(async () => getConfig({configUrl: url})).rejects.toThrowError()
scope.done()
})

test('getConfig fails with an invalid json', async () => {
const filepath = path.resolve(__dirname, 'invalidtestconfig.json')

expect(async () => getConfig({configFile: filepath})).rejects.toThrowError()
await expect(async () =>
getConfig({configFile: filepath})
).rejects.toThrowError()
})

test('getConfig fails with an invalid json syntax', async () => {
const filepath = path.resolve(__dirname, 'invalidsyntaxtestconfig.json')

await expect(async () =>
getConfig({configFile: filepath})
).rejects.toThrowError()
})

test('getConfig fails with an invalid yaml', async () => {
const filepath = path.resolve(__dirname, 'invalidtestconfig.yaml')

await expect(async () =>
getConfig({configFile: filepath})
).rejects.toThrowError()
})

test('getConfig fails with an invalid yaml syntax', async () => {
const filepath = path.resolve(__dirname, 'invalidsyntaxtestconfig.yaml')

await expect(async () =>
getConfig({configFile: filepath})
).rejects.toThrowError()
})
})
46 changes: 46 additions & 0 deletions __tests__/invalidsyntaxtestconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
{
"$schema": "https://raw.githubusercontent.com/prototypicalpro/repolinter/master/rulesets/schema.json",
"version": 2,
"the-axioms": {
"linguist":"language",
"licensee":"license",
"packagers":"packager"
},
"the-rules": {
"code-of-conduct-file-up-to-date": {
"level": "error",
"rule": {
"type": "file-hash",
"options": {
"globsAny": [
"{docs/,.github/,}CODEOFCONDUCT*",
"{docs/,.github/,}CODE-OF-CONDUCT*",
"{docs/,.github/,}CODE_OF_CONDUCT*"
],
"nocase": true,
"hash": "c0b76cd474db37b060a909aba86a85f60381bbdd46ce1575dde2f6e86e319c63"
}
},
"fix": {
"type": "file-create",
"options": {
"file": "CODE_OF_CONDUCT.md",
"replace": true,
"text": { "url": "https://raw.githubusercontent.com/aperture-science-incorporated/.github/master/CODE_OF_CONDUCT.md" }
}
}
},
"community-header-present": {
"level": "error",
"rule": {
"type": "file-starts-with",
"options": {
"globsAll": ["README*"],
"nocase": true,
"lineCount": 1,
"patterns": ["\\[\\s*\\!\\[[a-z0-9\\s]+\\]\\(\\s*[\\/\\.a-z0-9\\-\\_\\~:]+\\s*\\)\\s*]\\(\\s*https:\\/\\/opensource\\.newrelic\\.com\\/oss-category\\/#([\\/\\.a-z0-9\\-\\_\\~]+)\\s*\\)"],
"human-readable-pattern": "Open source category header (see https://opensource.newrelic.com/oss-category)",
"flags": "i",
"succeed-on-non-existent": false
}
}
41 changes: 41 additions & 0 deletions __tests__/invalidsyntaxtestconfig.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
---
asdasd
"$schema": https://raw.githubusercontent.com/prototypicalpro/repolinter/master/rulesets/schema.json
version: 2
axioms:
linguist: language
licensee: license
packagers: packager
the-rules:
code-of-conduct-file-up-to-date:
level: error
rule:
type: file-hash
options:
globsAny:
- "{docs/,.github/,}CODEOFCONDUCT*"
- "{docs/,.github/,}CODE-OF-CONDUCT*"
- "{docs/,.github/,}CODE_OF_CONDUCT*"
nocase: true
hash: c0b76cd474db37b060a909aba86a85f60381bbdd46ce1575dde2f6e86e319c63
fix:
type: file-create
options:
file: CODE_OF_CONDUCT.md
replace: true
text:
url: https://raw.githubusercontent.com/aperture-science-incorporated/.github/master/CODE_OF_CONDUCT.md
community-header-present:
level: error
rule:
type: file-starts-with
options:
globsAll:
- README*
nocase: true
lineCount: 1
patterns:
- "\\[\\s*\\!\\[[a-z0-9\\s]+\\]\\(\\s*[\\/\\.a-z0-9\\-\\_\\~:]+\\s*\\)\\s*]\\(\\s*https:\\/\\/opensource\\.newrelic\\.com\\/oss-category\\/#([\\/\\.a-z0-9\\-\\_\\~]+)\\s*\\)"
human-readable-pattern: Open source category header (see https://opensource.newrelic.com/oss-category)
flags: i
succeed-on-non-existent: false
40 changes: 40 additions & 0 deletions __tests__/invalidtestconfig.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
---
"$schema": https://raw.githubusercontent.com/prototypicalpro/repolinter/master/rulesets/schema.json
version: 2
axioms:
linguist: language
licensee: license
packagers: packager
the-rules:
code-of-conduct-file-up-to-date:
level: error
rule:
type: file-hash
options:
globsAny:
- "{docs/,.github/,}CODEOFCONDUCT*"
- "{docs/,.github/,}CODE-OF-CONDUCT*"
- "{docs/,.github/,}CODE_OF_CONDUCT*"
nocase: true
hash: c0b76cd474db37b060a909aba86a85f60381bbdd46ce1575dde2f6e86e319c63
fix:
type: file-create
options:
file: CODE_OF_CONDUCT.md
replace: true
text:
url: https://raw.githubusercontent.com/aperture-science-incorporated/.github/master/CODE_OF_CONDUCT.md
community-header-present:
level: error
rule:
type: file-starts-with
options:
globsAll:
- README*
nocase: true
lineCount: 1
patterns:
- "\\[\\s*\\!\\[[a-z0-9\\s]+\\]\\(\\s*[\\/\\.a-z0-9\\-\\_\\~:]+\\s*\\)\\s*]\\(\\s*https:\\/\\/opensource\\.newrelic\\.com\\/oss-category\\/#([\\/\\.a-z0-9\\-\\_\\~]+)\\s*\\)"
human-readable-pattern: Open source category header (see https://opensource.newrelic.com/oss-category)
flags: i
succeed-on-non-existent: false
40 changes: 40 additions & 0 deletions __tests__/testconfig.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
---
"$schema": https://raw.githubusercontent.com/prototypicalpro/repolinter/master/rulesets/schema.json
version: 2
axioms:
linguist: language
licensee: license
packagers: packager
rules:
code-of-conduct-file-up-to-date:
level: error
rule:
type: file-hash
options:
globsAny:
- "{docs/,.github/,}CODEOFCONDUCT*"
- "{docs/,.github/,}CODE-OF-CONDUCT*"
- "{docs/,.github/,}CODE_OF_CONDUCT*"
nocase: true
hash: c0b76cd474db37b060a909aba86a85f60381bbdd46ce1575dde2f6e86e319c63
fix:
type: file-create
options:
file: CODE_OF_CONDUCT.md
replace: true
text:
url: https://raw.githubusercontent.com/aperture-science-incorporated/.github/master/CODE_OF_CONDUCT.md
community-header-present:
level: error
rule:
type: file-starts-with
options:
globsAll:
- README*
nocase: true
lineCount: 1
patterns:
- "\\[\\s*\\!\\[[a-z0-9\\s]+\\]\\(\\s*[\\/\\.a-z0-9\\-\\_\\~:]+\\s*\\)\\s*]\\(\\s*https:\\/\\/opensource\\.newrelic\\.com\\/oss-category\\/#([\\/\\.a-z0-9\\-\\_\\~]+)\\s*\\)"
human-readable-pattern: Open source category header (see https://opensource.newrelic.com/oss-category)
flags: i
succeed-on-non-existent: false
4 changes: 2 additions & 2 deletions action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -29,15 +29,15 @@ inputs:
config_file:
required: false
description: >
A path to the JSON Repolinter ruleset to use, relative to the workflow
A path to the JSON or YAML Repolinter ruleset to use, relative to the workflow
working directory (i.e. under `$GITHUB_WORKSPACE`).
This option is mutually exclusive with config_url. If this option and
config-url are not specified, Repolinter's default ruleset will be used.
config_url:
required: false
description: >
A URL to pull the JSON Repolinter ruleset from. This URL must be accessible
A URL to pull the JSON or YAML Repolinter ruleset from. This URL must be accessible
by the actions runner and return raw JSON file on GET.
This option can be used to pull a ruleset from GitHub using the
Expand Down
25 changes: 20 additions & 5 deletions dist/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -297,13 +297,14 @@ Object.defineProperty(exports, "__esModule", ({ value: true }));
const node_fetch_1 = __importDefault(__webpack_require__(467));
const fs = __importStar(__webpack_require__(5747));
const core = __importStar(__webpack_require__(2186));
const yaml = __importStar(__webpack_require__(1917));
const repolinter_1 = __webpack_require__(430);
/**
* Load a repolinter configuration from either a file or URL,
* return the validated deserialized configuration.
* @param where.configFile The file path to the config, relative to the current working directory. Mutually exclusive with where.configUrl.
* @param where.configUrl The URL to load fhe config from. Mutually exclusive with where.configFile
* @returns A deserialized JSON configuration object if one was found. If the configuration does not exist or does not pass validation this function will throw an error.
* @returns A deserialized JSON or YAML configuration object if one was found. If the configuration does not exist or does not pass validation this function will throw an error.
*/
function getConfig(where) {
return __awaiter(this, void 0, void 0, function* () {
Expand Down Expand Up @@ -338,13 +339,27 @@ function getConfig(where) {
core.debug('Using default config');
return null;
}
// parse it
let ret;
// attempt to parse both JSON and YAML
let ret = null;
let jsonError;
let yamlError;
try {
ret = JSON.parse(contents);
}
catch (e) {
throw new Error(`Unable to parse JSON from file ${where.configFile} with error ${e.toString()}`);
jsonError = e;
}
if (!ret) {
try {
ret = yaml.safeLoad(contents);
}
catch (e) {
yamlError = e;
}
}
// throw if neither worked
if (!ret) {
throw new Error(`Unable to parse JSON/YAML from file ${where.configFile} with error JSON error "${jsonError && jsonError.toString()}" and YAML error "${yamlError && yamlError.toString()}"`);
}
// validate the config using repolinters validator
const validationResult = yield repolinter_1.validateConfig(ret);
Expand Down Expand Up @@ -508,7 +523,7 @@ function run(disableRetry) {
process.exitCode = 0;
}
// set the outputs for this action
core.setOutput("errored" /* ERRORED */, false);
core.setOutput("errored" /* ERRORED */, result.errored);
core.setOutput("passed" /* PASSED */, result.passed);
core.setOutput("json_output" /* JSON_OUTPUT */, repolinter_1.jsonFormatter.formatOutput(result, true));
}
Expand Down
2 changes: 1 addition & 1 deletion dist/index.js.map

Large diffs are not rendered by default.

5 changes: 5 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
"@octokit/plugin-retry": "^3.0.3",
"@octokit/rest": "^18.0.4",
"@octokit/types": "^5.4.1",
"@types/js-yaml": "^3.12.5",
"@types/node-fetch": "^2.5.7",
"node-fetch": "^2.6.0",
"repolinter": "github:newrelic-forks/repolinter#master"
Expand Down
Loading

0 comments on commit 10fd1c3

Please sign in to comment.