Skip to content

Commit

Permalink
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge branch 'main' into ci/upgrade-packagesand-repo-housekeeping
Browse files Browse the repository at this point in the history
CalemRoelofsSB committed Mar 31, 2023
2 parents f87e663 + 6771e03 commit ed74be4
Showing 12 changed files with 654 additions and 172 deletions.
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
name: Build Master - Publish npm
name: Build Main - Publish npm
on:
release:
types:
20 changes: 20 additions & 0 deletions .github/workflows/build-main.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# This workflow will do a clean install of node dependencies, build the source code and run tests across different versions of node
# For more information see: https://help.github.com/actions/language-and-framework-guides/using-nodejs-with-github-actions
name: Build Main - SwaggerHub CLI
on:
push:
branches: [ main ]
jobs:
build:
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [ 16.x, 18.x ]
steps:
- uses: actions/checkout@v2
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v1
with:
node-version: ${{ matrix.node-version }}
- run: npm ci
- run: npm run test
18 changes: 0 additions & 18 deletions .github/workflows/build-master.yaml

This file was deleted.

4 changes: 2 additions & 2 deletions .github/workflows/pull-request.yaml
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
name: Pull Requests - SwaggerHub CLI
on:
pull_request:
branches: [ master ]
branches: [ main ]
jobs:
build:
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [14.x, 16.x, 18.x]
node-version: [ 16.x, 18.x ]
steps:
- uses: actions/checkout@v3
- name: Use Node.js ${{ matrix.node-version }}
12 changes: 8 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
@@ -16,7 +16,7 @@ The SwaggerHub CLI enables teams to build automation and workflows around Swagge
* [Contributing](#contributing)
<!-- tocstop -->
# Requirements
Node.js 14 or later.
Node.js 16.x or later.

# Installation
```sh-session
@@ -331,15 +331,19 @@ ARGUMENTS
OWNER/API_NAME/[VERSION] API Identifier
OPTIONS
-h, --help show CLI help
-c, --fail-on-critical Exit with error code 1 if there are critical standardization errors present
-h, --help show CLI help
DESCRIPTION
When VERSION is not included in the argument, the default version will be validated.
An error will occur if the API version does not exist.
If the flag `-c` or `--failOnCritical` is used and there are standardization
errors with `Critical` severity present, the command will exit with error code `1`.
EXAMPLES
swaggerhub api:validate organization/api/1.0.0
swaggerhub api:validate organization/api
swaggerhub api:validate -c organization/api/1.0.0
swaggerhub api:validate --fail-on-critical organization/api
```

_See code: [src/commands/api/validate.js](https://github.com/SmartBear/swaggerhub-cli/blob/v0.6.5/src/commands/api/validate.js)_
@@ -575,7 +579,7 @@ OPTIONS
DESCRIPTION
See the documentation for configuration files:
https://github.com/SmartBear/swaggerhub-cli/tree/master/examples/integrations
https://github.com/SmartBear/swaggerhub-cli/tree/main/examples/integrations
When VERSION is not included in the argument, the integration will be added to be default API version.
EXAMPLE
400 changes: 331 additions & 69 deletions package-lock.json

Large diffs are not rendered by default.

12 changes: 6 additions & 6 deletions package.json
Original file line number Diff line number Diff line change
@@ -8,20 +8,20 @@
},
"bugs": "https://github.com/SmartBear/swaggerhub-cli/issues",
"dependencies": {
"@oclif/core": "^2.1.4",
"@oclif/plugin-help": "^5.2.4",
"@oclif/plugin-plugins": "^2.3.2",
"@oclif/core": "^2.8.0",
"@oclif/plugin-help": "^5.2.8",
"@oclif/plugin-plugins": "^2.4.3",
"deep-extend": "^0.6.0",
"fs-extra": "^11.1.0",
"inquirer": "^8.0.0",
"js-yaml": "^4.1.0",
"json-templates": "^4.2.0",
"lodash": "^4.17.21",
"node-fetch": "^2.6.8",
"node-fetch": "^2.6.9",
"semver": "^7.3.8"
},
"devDependencies": {
"@oclif/test": "^2.3.6",
"@oclif/test": "^2.3.13",
"chai": "^4.3.7",
"eslint": "^8.32.0",
"eslint-plugin-chai-friendly": "^0.7.2",
@@ -37,7 +37,7 @@
"tmp": "^0.2.1"
},
"engines": {
"node": ">=14.0.0"
"node": ">=16.0.0"
},
"files": [
"/bin",
23 changes: 16 additions & 7 deletions src/commands/api/validate.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
const { Args } = require('@oclif/core')
const { Args, Flags } = require('@oclif/core')
const BaseCommand = require('../../support/command/base-command')
const { getApiIdentifierArg } = require('../../support/command/parse-input')
const { getApi } = require('../../requests/api')
@@ -7,15 +7,15 @@ const { getResponseContent } = require('../../support/command/handle-response')

class ValidateCommand extends BaseCommand {
async run() {
const { args } = await this.parse(ValidateCommand)
const { args, flags } = await this.parse(ValidateCommand)
const apiPath = getApiIdentifierArg(args)
const validPath = await this.ensureVersion(apiPath)
const validationResult = await this.getValidationResult(validPath)
// eslint-disable-next-line immutable/no-let
let hasCritical = false
const validationResultsStr = validationResult.validation
.map(err => {
if (err.severity === 'CRITICAL') hasCritical = true
if (err.severity.toUpperCase() === 'CRITICAL') hasCritical = true
return `${err.line}: \t${err.severity} \t${err.description}`
})
.join('\n')
@@ -24,7 +24,7 @@ class ValidateCommand extends BaseCommand {
}
this.log(validationResultsStr)

if (hasCritical) this.exit(1)
if (hasCritical && flags['fail-on-critical']) this.exit(1)
this.exit(0)
}

@@ -51,11 +51,14 @@ class ValidateCommand extends BaseCommand {
ValidateCommand.description = `get validation result for an API version
When VERSION is not included in the argument, the default version will be validated.
An error will occur if the API version does not exist.
If the flag \`-c\` or \`--failOnCritical\` is used and there are standardization
errors with \`Critical\` severity present, the command will exit with error code \`1\`.
`

ValidateCommand.examples = [
'swaggerhub api:validate organization/api/1.0.0',
'swaggerhub api:validate organization/api'
'swaggerhub api:validate -c organization/api/1.0.0',
'swaggerhub api:validate --fail-on-critical organization/api'
]

ValidateCommand.args = {
@@ -65,6 +68,12 @@ ValidateCommand.args = {
})
}

ValidateCommand.flags = BaseCommand.flags

ValidateCommand.flags = {
'fail-on-critical': Flags.boolean({
char: 'c',
description: 'Exit with error code 1 if there are critical standardization errors present',
default: false
}),
...BaseCommand.flags
}
module.exports = ValidateCommand
2 changes: 1 addition & 1 deletion src/commands/integration/create.js
Original file line number Diff line number Diff line change
@@ -29,7 +29,7 @@ class CreateIntegrationCommand extends BaseCommand {
}

CreateIntegrationCommand.description = `creates a new API integration from a JSON configuration file.
See the documentation for configuration files: https://github.com/SmartBear/swaggerhub-cli/tree/master/examples/integrations
See the documentation for configuration files: https://github.com/SmartBear/swaggerhub-cli/tree/main/examples/integrations
When VERSION is not included in the argument, the integration will be added to be default API version.
`

4 changes: 3 additions & 1 deletion src/utils/definitions.js
Original file line number Diff line number Diff line change
@@ -6,9 +6,11 @@ const { errorMsg } = require('../template-strings')

const specVersionToSpecification = specVersion => {
if (/2.0$/.test(specVersion))
return 'openapi-2.0'
return 'openapi-2.0'
if (/2.\d+.\d+$/.test(specVersion))
return 'asyncapi-2.x.x'
if (/3.1.\d+$/.test(specVersion))
return 'openapi-3.1.0'
return 'openapi-3.0.0'
}

211 changes: 148 additions & 63 deletions test/commands/api/validate.test.js
Original file line number Diff line number Diff line change
@@ -5,42 +5,6 @@ const apiPath = 'example-org/example-api/example-ver'
const heading = 'line \tseverity \tdescription\n\n'

describe('invalid api:validate', () => {
const severity = 'CRITICAL',
warningSeverity = 'WARNING',
description = 'sample description',
line = 10

test.stub(config, 'getConfig', () => ({ SWAGGERHUB_URL: 'https://api.swaggerhub.com' }))
.nock('https://api.swaggerhub.com/apis', { reqheaders: { Accept: 'application/json' } }, api => api
.get(`/${apiPath}/standardization`)
.reply(200, {
validation: [
{ line, description, severity }
]
})
)
.stdout()
.command(['api:validate', apiPath]) // swaggerhub api:validate o/a/v
.exit(1)
.it('should return validation errors, one per line', ctx => {
expect(ctx.stdout).to.contains(`${heading}${line}: \t${severity} \t${description}`)
})

test.stub(config, 'getConfig', () => ({ SWAGGERHUB_URL: 'https://api.swaggerhub.com' }))
.nock('https://api.swaggerhub.com/apis', { reqheaders: { Accept: 'application/json' } }, api => api
.get(`/${apiPath}/standardization`)
.reply(200, {
validation: [
{ line, description, severity: warningSeverity }
]
})
)
.stdout()
.command(['api:validate', apiPath]) // swaggerhub api:validate o/a/v
.exit(0)
.it('should return warning validation errors, one per line with zero exit code', ctx => {
expect(ctx.stdout).to.contains(`${heading}${line}: \t${warningSeverity} \t${description}`)
})

test.stub(config, 'getConfig', () => ({ SWAGGERHUB_URL: 'https://api.swaggerhub.com' }))
.nock('https://api.swaggerhub.com/apis', { reqheaders: { Accept: 'application/json' } }, api => api
@@ -91,36 +55,157 @@ describe('invalid api:validate', () => {
.it('not found returned when fetching default version of API')
})

describe('valid api:validation', () => {
test.stub(config, 'getConfig', () => ({ SWAGGERHUB_URL: 'https://api.swaggerhub.com' }))
.nock('https://api.swaggerhub.com/apis', { reqheaders: { Accept: 'application/json' } }, api => api
.get(`/${apiPath}/standardization`)
.reply(200, {
validation: []
describe('valid api:validate', () => {
const description = 'sample description'
const line = 10

describe('with critical errors present', () => {
const severity = 'critical'

describe('without -c flag', () => {
test.stub(config, 'getConfig', () => ({ SWAGGERHUB_URL: 'https://api.swaggerhub.com' }))
.nock('https://api.swaggerhub.com/apis', { reqheaders: { Accept: 'application/json' } }, api => api
.get(`/${apiPath}/standardization`)
.reply(200, {
validation: [
{ line, description, severity }
]
})
)
.stdout()
.command(['api:validate', apiPath]) // swaggerhub api:validate o/a/v
.exit(0)
.it('should return validation errors, one per line, with exit code 0', ctx => {
expect(ctx.stdout).to.contains(`${heading}${line}: \t${severity} \t${description}`)
})
)
.stdout()
.command(['api:validate', apiPath])
.exit(0)
.it('should return empty result as there is no error', ctx => {
expect(ctx.stdout).to.contains('')
})

describe('with -c flag', () => {
test.stub(config, 'getConfig', () => ({ SWAGGERHUB_URL: 'https://api.swaggerhub.com' }))
.nock('https://api.swaggerhub.com/apis', { reqheaders: { Accept: 'application/json' } }, api => api
.get(`/${apiPath}/standardization`)
.reply(200, {
validation: [
{ line, description, severity }
]
})
)
.stdout()
.command(['api:validate', '-c', apiPath]) // swaggerhub api:validate o/a/v
.exit(1)
.it('should return validation errors, one per line, with exit code 1', ctx => {
expect(ctx.stdout).to.contains(`${heading}${line}: \t${severity} \t${description}`)
})
})

describe('with --fail-on-critical flag', () => {
test.stub(config, 'getConfig', () => ({ SWAGGERHUB_URL: 'https://api.swaggerhub.com' }))
.nock('https://api.swaggerhub.com/apis', { reqheaders: { Accept: 'application/json' } }, api => api
.get(`/${apiPath}/standardization`)
.reply(200, {
validation: [
{ line, description, severity }
]
})
)
.stdout()
.command(['api:validate', '--fail-on-critical', apiPath]) // swaggerhub api:validate o/a/v
.exit(1)
.it('should return validation errors, one per line, with exit code 1', ctx => {
expect(ctx.stdout).to.contains(`${heading}${line}: \t${severity} \t${description}`)
})
})
})

test.stub(config, 'getConfig', () => ({ SWAGGERHUB_URL: 'https://api.swaggerhub.com' }))
.nock('https://api.swaggerhub.com/apis', api => api
.get(`/${apiPath.substring(0, apiPath.lastIndexOf('/'))}/settings/default`)
.reply(200, { version: apiPath.substring(apiPath.lastIndexOf('/')+1) })
)
.nock('https://api.swaggerhub.com/apis', { reqheaders: { Accept: 'application/json' } }, api => api
.get(`/${apiPath}/standardization`)
.reply(200, {
validation: []
describe('without critical errors present', () => {
const severity = 'WARNING'

describe('without -c flag', () => {
test.stub(config, 'getConfig', () => ({ SWAGGERHUB_URL: 'https://api.swaggerhub.com' }))
.nock('https://api.swaggerhub.com/apis', { reqheaders: { Accept: 'application/json' } }, api => api
.get(`/${apiPath}/standardization`)
.reply(200, {
validation: [
{ line, description, severity }
]
})
)
.stdout()
.command(['api:validate', apiPath]) // swaggerhub api:validate o/a/v
.exit(0)
.it('should return warning validation errors, one per line, with exit code 0', ctx => {
expect(ctx.stdout).to.contains(`${heading}${line}: \t${severity} \t${description}`)
})
})

describe('with -c flag', () => {
test.stub(config, 'getConfig', () => ({ SWAGGERHUB_URL: 'https://api.swaggerhub.com' }))
.nock('https://api.swaggerhub.com/apis', { reqheaders: { Accept: 'application/json' } }, api => api
.get(`/${apiPath}/standardization`)
.reply(200, {
validation: [
{ line, description, severity }
]
})
)
.stdout()
.command(['api:validate', '-c', apiPath]) // swaggerhub api:validate o/a/v
.exit(0)
.it('should return warning validation errors, one per line, with exit code 0', ctx => {
expect(ctx.stdout).to.contains(`${heading}${line}: \t${severity} \t${description}`)
})
})

describe('with --fail-on-critical flag', () => {
test.stub(config, 'getConfig', () => ({ SWAGGERHUB_URL: 'https://api.swaggerhub.com' }))
.nock('https://api.swaggerhub.com/apis', { reqheaders: { Accept: 'application/json' } }, api => api
.get(`/${apiPath}/standardization`)
.reply(200, {
validation: [
{ line, description, severity }
]
})
)
.stdout()
.command(['api:validate', '--fail-on-critical', apiPath]) // swaggerhub api:validate o/a/v
.exit(0)
.it('should return warning validation errors, one per line, with exit code 0', ctx => {
expect(ctx.stdout).to.contains(`${heading}${line}: \t${severity} \t${description}`)
})
})
})

describe('when no standardization errors present', () => {
test.stub(config, 'getConfig', () => ({ SWAGGERHUB_URL: 'https://api.swaggerhub.com' }))
.nock('https://api.swaggerhub.com/apis', { reqheaders: { Accept: 'application/json' } }, api => api
.get(`/${apiPath}/standardization`)
.reply(200, {
validation: []
})
)
.stdout()
.command(['api:validate', apiPath])
.exit(0)
.it('should return empty result as there is no error', ctx => {
expect(ctx.stdout).to.contains('')
})

test.stub(config, 'getConfig', () => ({ SWAGGERHUB_URL: 'https://api.swaggerhub.com' }))
.nock('https://api.swaggerhub.com/apis', api => api
.get(`/${apiPath.substring(0, apiPath.lastIndexOf('/'))}/settings/default`)
.reply(200, { version: apiPath.substring(apiPath.lastIndexOf('/')+1) })
)
.nock('https://api.swaggerhub.com/apis', { reqheaders: { Accept: 'application/json' } }, api => api
.get(`/${apiPath}/standardization`)
.reply(200, {
validation: []
})
)
.stdout()
.command(['api:validate', apiPath.substring(0, apiPath.lastIndexOf('/'))])
.exit(0)
.it('should resolve version and return empty result as there is no error', ctx => {
expect(ctx.stdout).to.contains('')
})
)
.stdout()
.command(['api:validate', apiPath.substring(0, apiPath.lastIndexOf('/'))])
.exit(0)
.it('should resolve version and return empty result as there is no error', ctx => {
expect(ctx.stdout).to.contains('')
})
})
118 changes: 118 additions & 0 deletions test/utils/definitions.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
const { expect, test } = require('@oclif/test')
const { getSpecification } = require('../../src/utils/definitions')

describe('getSpecification', () => {
describe('should return `openapi-2.0`', () => {
test.it('for `swagger: 2.0`', () => {
const definition = { swagger: '2.0' }

const specification = getSpecification(definition)

expect(specification).to.equal('openapi-2.0')
})
})

describe('should return `openapi-3.1.0`', () => {
test.it('for `openapi: 3.1.0`', () => {
const definition = { openapi: '3.1.0' }

const specification = getSpecification(definition)

expect(specification).to.equal('openapi-3.1.0')
})

test.it('for `openapi: 3.1.99`', () => {
const definition = { openapi: '3.1.99' }

const specification = getSpecification(definition)

expect(specification).to.equal('openapi-3.1.0')
})
})

describe('should return `openapi-3.0.0`', () => {
test.it('for `openapi: 3.0.0`', () => {
const definition = { openapi: '3.0.0' }

const specification = getSpecification(definition)

expect(specification).to.equal('openapi-3.0.0')
})

test.it('for `openapi: 3.0.99`', () => {
const definition = { openapi: '3.0.99' }

const specification = getSpecification(definition)

expect(specification).to.equal('openapi-3.0.0')
})

test.it('for `openapi: 3.99.0`', () => {
const definition = { openapi: '3.99.0' }

const specification = getSpecification(definition)

expect(specification).to.equal('openapi-3.0.0')
})
})

describe('should return `asyncapi-2.x.x`', () => {
test.it('for `asyncapi: 2.0.0`', () => {
const definition = { asyncapi: '2.0.0' }

const specification = getSpecification(definition)

expect(specification).to.equal('asyncapi-2.x.x')
})

test.it('for `asyncapi: 2.6.99`', () => {
const definition = { asyncapi: '2.6.99' }

const specification = getSpecification(definition)

expect(specification).to.equal('asyncapi-2.x.x')
})

test.it('for `asyncapi: 2.0.99`', () => {
const definition = { asyncapi: '2.0.99' }

const specification = getSpecification(definition)

expect(specification).to.equal('asyncapi-2.x.x')
})
})

describe('should default to `openapi-3.0.0`', () => {
test.it('for `openapi: abcd`', () => {
const definition = { openapi: 'abcd' }

const specification = getSpecification(definition)

expect(specification).to.equal('openapi-3.0.0')
})

test.it('for `openapi: 4.7.9`', () => {
const definition = { openapi: '4.7.9' }

const specification = getSpecification(definition)

expect(specification).to.equal('openapi-3.0.0')
})

test.it('for `openapi: 😄`', () => {
const definition = { openapi: '😄' }

const specification = getSpecification(definition)

expect(specification).to.equal('openapi-3.0.0')
})

test.it('for `asyncapi: blah`', () => {
const definition = { asyncapi: 'blah' }

const specification = getSpecification(definition)

expect(specification).to.equal('openapi-3.0.0')
})
})
})

0 comments on commit ed74be4

Please sign in to comment.