Skip to content

Commit 39778c0

Browse files
committed
Switch to Node and add Readme
1 parent 9938bbc commit 39778c0

8 files changed

+444
-26
lines changed

Diff for: .gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
/node_modules

Diff for: Dockerfile

+5-4
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
1-
FROM ruby:2.5.1-alpine
2-
RUN gem install json-schema
1+
FROM node:9-alpine
32
WORKDIR /src
4-
ADD example-validator.rb .
5-
ENTRYPOINT ["ruby", "example-validator.rb"]
3+
ADD index.js package.json package-lock.json /src/
4+
ENV NODE_ENV=production
5+
RUN npm -s install
6+
ENTRYPOINT ["node", "index.js"]

Diff for: LICENSE

+22
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
The MIT License (MIT)
2+
3+
Copyright (c) 2018 Buildkite
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
SOFTWARE.
22+

Diff for: README.md

+26
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
# Buildkite Plugin Example Validator
2+
3+
A tool for validating a [Buildkite plugin](https://buildkite.com/docs/agent/v3/plugin)’s readme examples against its JSON schema file.
4+
5+
## Usage
6+
7+
In a plugin’s pipeline.yml test suite:
8+
9+
```yaml
10+
- label: ":json:"
11+
command: /plugin/schema.yml /plugin/README.md
12+
plugins:
13+
docker#x.x.x:
14+
image: buildkite/plugin-example-validator
15+
workdir: /plugin
16+
```
17+
18+
On the command line:
19+
20+
```bash
21+
docker run -it --rm -v "$(pwd):/plugin" buildkite/plugin-example-validator /plugin/schema.yml /plugin/README.md
22+
```
23+
24+
## License
25+
26+
MIT (see [LICENSE](LICENSE))

Diff for: example-validator.rb

-22
This file was deleted.

Diff for: index.js

+68
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
const fs = require('fs')
2+
const Ajv = require('ajv')
3+
const yaml = require('js-yaml')
4+
5+
const pluginName = process.argv[2]
6+
const schemaPath = process.argv[3]
7+
const readmePath = process.argv[4]
8+
9+
if (!pluginName || !schemaPath || !readmePath) {
10+
throw "Usage: <plugin-name> <schema-path> <readme-path>"
11+
}
12+
13+
const readme = fs.readFileSync(readmePath, 'utf8')
14+
const schema = yaml.safeLoad(fs.readFileSync(schemaPath, 'utf8'))
15+
const ajv = new Ajv({ allErrors: true, jsonPointers: true })
16+
const validator = ajv.compile(schema)
17+
18+
const pluginConfigKeyPattern = new RegExp(`^${pluginName}#v.*$`)
19+
20+
const pluginConfigs = []
21+
22+
extractPipelineExamples()
23+
.forEach((example) => {
24+
extractPluginConfigs(example)
25+
.forEach((config) => {
26+
pluginConfigs.push(config)
27+
validateConfig(example, config)
28+
})
29+
})
30+
31+
function extractPipelineExamples() {
32+
const examples = []
33+
const yamlPattern = /```yml\n+(.*?)\n+```/gs
34+
while (yamlMatch = yamlPattern.exec(readme)) {
35+
examples.push(yamlMatch[1])
36+
}
37+
return examples
38+
}
39+
40+
function extractPluginConfigs(exampleYaml) {
41+
const configs = []
42+
const example = yaml.safeLoad(exampleYaml)
43+
if (example.steps) {
44+
example.steps.forEach((step) => {
45+
if (step.plugins) {
46+
Object.entries(step.plugins).forEach(([ name, config ]) => {
47+
if (pluginConfigKeyPattern.exec(name)) {
48+
configs.push(config)
49+
}
50+
})
51+
}
52+
})
53+
}
54+
return configs
55+
}
56+
57+
function validateConfig(fullExample, pluginConfig) {
58+
if (!validator(pluginConfig)) {
59+
console.log("🚨 Example is invalid:")
60+
console.log(fullExample)
61+
console.log(validator.errors)
62+
process.exitCode = 1
63+
}
64+
}
65+
66+
if (process.exitCode != 1) {
67+
console.log(`🙌 All ${pluginConfigs.length} plugin examples are valid`)
68+
}

0 commit comments

Comments
 (0)