Skip to content

Add support for V1 mapping #2

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

Merged
merged 3 commits into from
Dec 13, 2022
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.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
58 changes: 50 additions & 8 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,10 @@ const { default: Ajv } = require('ajv')
const { ErrorWithCause } = require('pony-cause')
const { parse: yamlParse } = require('yaml')

const { socketYmlSchemaV1 } = require('./lib/v1')

/**
* @typedef SocketYmlGitHub
* @property {boolean} [beta] beta opt in field
* @property {boolean} [enabled] enable/disable the Socket.dev GitHub app entirely
* @property {boolean} [projectReportsEnabled] enable/disable Github app project report checks
* @property {boolean} [pullRequestAlertsEnabled] enable/disable GitHub app pull request alert checks
Expand All @@ -31,22 +32,21 @@ const socketYmlSchema = {
projectIgnorePaths: {
type: 'array',
items: { type: 'string' },
nullable: true,
nullable: true
},
issueRules: {
type: 'object',
nullable: true,
required: [],
additionalProperties: { type: 'boolean' },
additionalProperties: { type: 'boolean' }
},
githubApp: {
type: 'object',
nullable: true,
properties: {
beta: { type: 'boolean', nullable: true },
enabled: { type: 'boolean', nullable: true },
projectReportsEnabled: { type: 'boolean', nullable: true },
pullRequestAlertsEnabled: { type: 'boolean', nullable: true },
enabled: { type: 'boolean', nullable: true, default: true },
projectReportsEnabled: { type: 'boolean', nullable: true, default: true },
pullRequestAlertsEnabled: { type: 'boolean', nullable: true, default: true },
},
required: [],
additionalProperties: false,
Expand All @@ -56,15 +56,27 @@ const socketYmlSchema = {
additionalProperties: false,
}

const ajv = new Ajv({
const ajvOptions = /** @type {const} */ ({
allErrors: true,
coerceTypes: 'array',
logger: false,
useDefaults: true
})

const ajv = new Ajv({
...ajvOptions,
removeAdditional: 'failing',
})

const validate = ajv.compile(socketYmlSchema)

// We want to be strict and fail rather than removeAdditional when we parse a possible v1 config – only fallback to it when it actually matches well
const ajvV1 = new Ajv({
...ajvOptions
})

const validateV1 = ajvV1.compile(socketYmlSchemaV1)

/**
* @param {string} filePath
* @returns {Promise<SocketYml|undefined>}
Expand Down Expand Up @@ -101,6 +113,13 @@ async function parseSocketConfig (fileContent) {
throw new ErrorWithCause('Error when parsing socket.yml config', { cause: err })
}

if (parsedContent && typeof parsedContent === 'object' && !('version' in parsedContent)) {
const parsedV1 = await parseV1SocketConfig(parsedContent)
if (parsedV1) {
return parsedV1
}
}

if (!validate(parsedContent)) {
throw new SocketValidationError(
'Invalid config definition',
Expand Down Expand Up @@ -146,6 +165,29 @@ class SocketValidationError extends Error {
}
}

/**
* @param {object} parsedV1Content
* @returns {Promise<SocketYml | undefined>}
*/
async function parseV1SocketConfig (parsedV1Content) {
if (!validateV1(parsedV1Content)) {
return
}

/** @type {SocketYml} */
const v2 = {
version: 2,
projectIgnorePaths: parsedV1Content?.ignore ?? [],
issueRules: parsedV1Content?.issues ?? {},
githubApp: {
enabled: parsedV1Content?.enabled,
pullRequestAlertsEnabled: parsedV1Content?.pullRequestAlertsEnabled,
projectReportsEnabled: parsedV1Content?.projectReportsEnabled
}
}
return v2
}

module.exports = {
parseSocketConfig,
readSocketConfig,
Expand Down
40 changes: 40 additions & 0 deletions lib/v1.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
'use strict'

/**
* @typedef SocketYmlV1
* @property {string[]} [ignore]
* @property {{ [issueName: string]: boolean }} [issues]
* @property {boolean} [beta] unused v1 option
* @property {boolean} [enabled] enable/disable the Socket.dev GitHub app entirely
* @property {boolean} [projectReportsEnabled] enable/disable Github app project report checks
* @property {boolean} [pullRequestAlertsEnabled] enable/disable GitHub app pull request alert checks
*/

/** @type {import('ajv').JSONSchemaType<SocketYmlV1>} */
const socketYmlSchemaV1 = {
$schema: 'http://json-schema.org/draft-07/schema#',
type: 'object',
properties: {
ignore: {
type: 'array',
items: { type: 'string' },
nullable: true,
},
issues: {
type: 'object',
nullable: true,
required: [],
additionalProperties: { type: 'boolean' },
},
beta: { type: 'boolean', nullable: true, default: true },
enabled: { type: 'boolean', nullable: true, default: true },
projectReportsEnabled: { type: 'boolean', nullable: true, default: true },
pullRequestAlertsEnabled: { type: 'boolean', nullable: true, default: true },
},
minProperties: 1,
additionalProperties: false,
}

module.exports = {
socketYmlSchemaV1
}
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,8 @@
"index.js",
"index.d.ts",
"index.d.ts.map",
"schema.json"
"schema.json",
"lib/*"
],
"scripts": {
"build:0": "run-s clean",
Expand Down
21 changes: 19 additions & 2 deletions test/parse.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,12 @@ const {
chai.use(chaiAsPromised)
chai.should()

describe('readSocketConfig()', () => {
describe('parseSocketConfig()', () => {
it('should read and parse socket.yml', async () => {
const fileContent = await readFile(path.resolve(__dirname, 'sample.yml'), 'utf8')

await parseSocketConfig(fileContent).should.eventually.become({
'githubApp': {
'beta': false,
'enabled': true,
'projectReportsEnabled': true,
'pullRequestAlertsEnabled': true,
Expand All @@ -36,6 +35,24 @@ describe('readSocketConfig()', () => {
})
})

it('should read and parse socket.yml v1', async () => {
const fileContent = await readFile(path.resolve(__dirname, 'sample-v1.yml'), 'utf8')

await parseSocketConfig(fileContent).should.eventually.become({
'githubApp': {
'enabled': true,
'projectReportsEnabled': false,
'pullRequestAlertsEnabled': true,
},
'issueRules': {},
'projectIgnorePaths': [
'foo',
'bar',
],
'version': 2,
})
})

it('should throw on invalid document structure', async () => {
await parseSocketConfig(`
projectIgnorePaths: true
Expand Down
1 change: 0 additions & 1 deletion test/read.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ describe('readSocketConfig()', () => {
it('should read and parse socket.yml', async () => {
await readSocketConfig(path.resolve(__dirname, 'sample.yml')).should.eventually.become({
'githubApp': {
'beta': false,
'enabled': true,
'projectReportsEnabled': true,
'pullRequestAlertsEnabled': true,
Expand Down
5 changes: 5 additions & 0 deletions test/sample-v1.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
ignore:
- foo
- bar
projectReportsEnabled: false
beta: true
2 changes: 1 addition & 1 deletion test/sample.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ version: 2

projectIgnorePaths:
- workspaces/test*
- '!workspaces/test-framework'
- "!workspaces/test-framework"

issueRules:
unresolvedRequire: false
Expand Down