Skip to content

Commit

Permalink
feat: merge branch 'feature/generate-issue' into develop
Browse files Browse the repository at this point in the history
  • Loading branch information
prototypicalpro committed Jul 27, 2020
2 parents 182ef88 + 8cb2477 commit 0fc573b
Show file tree
Hide file tree
Showing 14 changed files with 278 additions and 22 deletions.
2 changes: 1 addition & 1 deletion .eslintrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
"parserOptions": {
"ecmaVersion": 9,
"sourceType": "module",
"project": "./tsconfig.json"
"project": "./tsconfig.eslint.json"
},
"rules": {
"eslint-comments/no-use": "off",
Expand Down
2 changes: 2 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,6 @@ jobs:
run: ls -lah
- name: Linter
uses: ./
with:
config-url: https://raw.githubusercontent.com/aperture-science-incorporated/.github/master/repolinter.json

42 changes: 42 additions & 0 deletions __tests__/getConfig.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import getConfig from '../src/getConfig'
import * as path from 'path'
import * as fs from 'fs'
import fetch from 'node-fetch'

describe('getConfig', () => {
test('getConfig returns a config from a JSON file', async () => {
const filepath = path.resolve(__dirname, 'testconfig.json')
const expected = JSON.parse(await fs.promises.readFile(filepath, 'utf8'))
const res = await getConfig({configFile: filepath})

expect(res).toMatchObject(expected)
})

test('getConfig returns a 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'
const expected = await (await fetch(url)).json()
const res = await getConfig({configUrl: url})

expect(res).toMatchObject(expected)
})

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

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()
})

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

expect(async () => getConfig({configFile: filepath})).rejects.toThrowError()
})
})
49 changes: 49 additions & 0 deletions __tests__/invalidtestconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
{
"$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
}
}
}
}
}
49 changes: 49 additions & 0 deletions __tests__/testconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
{
"$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
}
}
}
}
}
12 changes: 7 additions & 5 deletions action.yml
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
name: 'Repolinter Action'
description: 'Provide a description here'
description: 'Runs Repolinter against a repository, then uses the results to open an issue.'
author: 'New Relic Opensource'
inputs:
milliseconds: # change this
required: true
description: 'input description here'
default: 'default value if applicable'
config-file: # change this
required: false
description: 'The filename of the Repolinter configuration to use, relative to the repository this action is being run on. Mutually exclusive with configUrl.'
config-url:
required: false
description: 'The URL to pull the Repolinter configuration from. The URL must be publicly accessible. Mutually exclusive with configFile.'
runs:
using: 'node12'
main: 'dist/index.js'
2 changes: 1 addition & 1 deletion dist/index.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion dist/index.js.map

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion jest.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,4 @@ module.exports = {
'^.+\\.ts$': 'ts-jest'
},
verbose: true
}
}
35 changes: 25 additions & 10 deletions package-lock.json

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

4 changes: 3 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
"build": "tsc",
"format": "prettier --write **/*.ts",
"format-check": "prettier --check **/*.ts",
"lint": "eslint src/**/*.ts",
"lint": "eslint src/**/*.ts __tests__/**/*.ts --fix",
"package": "rm -rf dist && ncc build --source-map -m",
"test": "jest",
"all": "npm run build && npm run format && npm run lint && npm run package && npm test"
Expand All @@ -26,6 +26,8 @@
"license": "MIT",
"dependencies": {
"@actions/core": "^1.2.4",
"@types/node-fetch": "^2.5.7",
"node-fetch": "^2.6.0",
"repolinter": "github:prototypicalpro/repolinter#master"
},
"devDependencies": {
Expand Down
70 changes: 70 additions & 0 deletions src/getConfig.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
import fetch from 'node-fetch'
import * as fs from 'fs'
import * as core from '@actions/core'
import {validateConfig} from 'repolinter'

/**
* 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.
*/
export default async function getConfig(where: {
configFile?: string
configUrl?: string
}): Promise<object | null> {
// get the config file contents
let contents
if (where.configFile) {
core.debug(`Reading config file ${where.configFile}`)
// read the file
try {
contents = await fs.promises.readFile(where.configFile, 'utf8')
} catch {
throw new Error(`Unable to open file ${where.configFile}`)
}
} else if (where.configUrl) {
core.debug(`Reading config url ${where.configUrl}`)
// fetch the data from the URL
try {
const res = await fetch(where.configUrl)
if (!res.ok) {
throw new Error(
`Failed to fetch from ${where.configUrl} with status code ${res.status} (${res.statusText})`
)
}
contents = await res.text()
} catch (e) {
throw new Error(
`Got error when retrieving data from ${
where.configUrl
}: ${e.toString()}`
)
}
}
// if neither parameters are present, return null
else {
core.debug('Using default config')
return null
}
// parse it
let ret
try {
ret = JSON.parse(contents)
} catch (e) {
throw new Error(
`Unable to parse JSON from file ${
where.configFile
} with error ${e.toString()}`
)
}
// validate the config using repolinters validator
const validationResult = await validateConfig(ret)
if (!validationResult.passed) {
throw new Error(
`Configuration validation failed with error ${validationResult.error}`
)
}
return ret
}
21 changes: 19 additions & 2 deletions src/main.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,27 @@
import * as core from '@actions/core'
import {lint} from 'repolinter'
import {lint, resultFormatter} from 'repolinter'
import getConfig from './getConfig'

const INPUT_CONFIG_URL = 'config-url'
const INPUT_CONFIG_FILE = 'config-file'

async function run(): Promise<void> {
// load the configuration from file or url, depending on which one is configured
let config
try {
config = await getConfig({
configFile: core.getInput(INPUT_CONFIG_FILE),
configUrl: core.getInput(INPUT_CONFIG_URL)
})
} catch (e) {
return core.setFailed(e)
}

try {
const result = await lint('.')
const result = await lint('.', undefined, true, config)
core.debug(JSON.stringify(result))
// print the formatted result
core.info(resultFormatter.formatOutput(result, true))
} catch (error) {
core.setFailed(error.message)
}
Expand Down
8 changes: 8 additions & 0 deletions tsconfig.eslint.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"extends": "./tsconfig.json",
"compilerOptions": {
"rootDir": "."
},
"include": ["src/**/*.ts", "__tests__/**/*.ts"],
"exclude": []
}

0 comments on commit 0fc573b

Please sign in to comment.