├── .gitignore ├── gulpfile.js ├── .jshintrc ├── .about.yml ├── package.json ├── LICENSE.md ├── README.md ├── index.js ├── test └── validator-test.js ├── CONTRIBUTING.md └── lib ├── draft-04-schema.json └── schema.json /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | *.log 3 | .*.swp 4 | coverage/* 5 | node_modules/ 6 | -------------------------------------------------------------------------------- /gulpfile.js: -------------------------------------------------------------------------------- 1 | /* jshint node: true */ 2 | 3 | var gulp = require('gulp'); 4 | var mocha = require('gulp-mocha'); 5 | var jshint = require('gulp-jshint'); 6 | 7 | gulp.task('test', function() { 8 | return gulp.src('./test/*.js', {read: false}) 9 | // Reporters: 10 | // https://github.com/mochajs/mocha/blob/master/lib/reporters/index.js 11 | .pipe(mocha({reporter: 'spec'})); 12 | }); 13 | 14 | gulp.task('lint', function() { 15 | return gulp.src(['bin/*', './*.js', './lib/*.js', './test/**/*.js']) 16 | .pipe(jshint()) 17 | .pipe(jshint.reporter('default')); 18 | }); 19 | 20 | -------------------------------------------------------------------------------- /.jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | "asi": false, 3 | "bitwise": true, 4 | "browser": true, 5 | "camelcase": true, 6 | "curly": true, 7 | "forin": true, 8 | "immed": true, 9 | "latedef": "nofunc", 10 | "maxlen": 80, 11 | "newcap": true, 12 | "noarg": true, 13 | "noempty": true, 14 | "nonew": true, 15 | "predef": [ 16 | "$", 17 | "jQuery", 18 | 19 | "jasmine", 20 | "beforeEach", 21 | "describe", 22 | "it", 23 | 24 | "angular", 25 | "inject", 26 | "module", 27 | 28 | "Promise" 29 | ], 30 | "quotmark": true, 31 | "trailing": true, 32 | "undef": true, 33 | "unused": true 34 | } 35 | -------------------------------------------------------------------------------- /.about.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: about-yml-npm 3 | full_name: .about.yml npm 4 | type: app 5 | owner_type: project 6 | status: active 7 | stage: discovery 8 | testable: true 9 | description: > 10 | An npm for the .about.yml project metadata schema and tools 11 | stack: 12 | - JavaScript 13 | licenses: 14 | .about.yml: 15 | name: CC0 16 | url: "https://github.com/18F/about-yml-npm/blob/master/LICENSE.md" 17 | contact: 18 | - url: "mailto:michael.bland@gsa.gov" 19 | text: Mike Bland 20 | - url: "mailto:carlo.costino@gsa.gov" 21 | text: Carlo Costino 22 | - url: "https://github.com/18F/about-yml-npm/issues" 23 | text: about-yml-npm GitHub Issues 24 | team: 25 | - github: mbland 26 | role: lead 27 | - github: arowla 28 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "about-yml-validator", 3 | "version": "0.1.0", 4 | "description": ".about.yml project metadata schema and tools", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "gulp test", 8 | "lint": "gulp lint" 9 | }, 10 | "repository": { 11 | "type": "git", 12 | "url": "git+https://github.com/18F/about-yml-validator.git" 13 | }, 14 | "keywords": [ 15 | "18F", 16 | ".about.yml" 17 | ], 18 | "author": "Mike Bland, Carlo Costino", 19 | "license": "CC0-1.0", 20 | "bugs": { 21 | "url": "https://github.com/18F/about-yml-validator/issues" 22 | }, 23 | "homepage": "https://github.com/18F/about-yml-validator#readme", 24 | "devDependencies": { 25 | "chai": "^3.4.1", 26 | "gulp": "^3.9.0", 27 | "gulp-jshint": "^2.0.0", 28 | "gulp-mocha": "^2.2.0", 29 | "jshint": "^2.8.0", 30 | "mocha": "^2.3.4" 31 | }, 32 | "dependencies": { 33 | "github": "^0.2.4", 34 | "json-schema": "^0.2.2", 35 | "yamljs": "^0.2.4" 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | As a work of the United States Government, this project is in the 2 | public domain within the United States. 3 | 4 | Additionally, we waive copyright and related rights in the work 5 | worldwide through the CC0 1.0 Universal public domain dedication. 6 | 7 | ## CC0 1.0 Universal Summary 8 | 9 | This is a human-readable summary of the [Legal Code (read the full text)](https://creativecommons.org/publicdomain/zero/1.0/legalcode). 10 | 11 | ### No Copyright 12 | 13 | The person who associated a work with this deed has dedicated the work to 14 | the public domain by waiving all of his or her rights to the work worldwide 15 | under copyright law, including all related and neighboring rights, to the 16 | extent allowed by law. 17 | 18 | You can copy, modify, distribute and perform the work, even for commercial 19 | purposes, all without asking permission. 20 | 21 | ### Other Information 22 | 23 | In no way are the patent or trademark rights of any person affected by CC0, 24 | nor are the rights that other persons may have in the work or in how the 25 | work is used, such as publicity or privacy rights. 26 | 27 | Unless expressly stated otherwise, the person who associated a work with 28 | this deed makes no warranties about the work, and disclaims liability for 29 | all uses of the work, to the fullest extent permitted by applicable law. 30 | When using or citing the work, you should not imply endorsement by the 31 | author or the affirmer. 32 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # `.about.yml` schema and tools 2 | 3 | The `.about.yml` mechanism allows a project to publish and maintain metadata 4 | that can be easily maintained by project owners, that is visible and 5 | accessible to interested parties, and that can be harvested and processed by 6 | tools and automated systems. It is implemented using the 7 | [YAML](https://en.wikipedia.org/wiki/YAML) format. 8 | 9 | The [18F Team API](https://team-api.18f.gov/public/api/) is the original, 10 | primary consumer of this information, which in turn provides data for: 11 | 12 | - [18F Hub](https://github.com/18F/hub) 13 | - [18F Dashboard](https://github.com/18F/dashboard) 14 | - [18F.gsa.gov](https://github.com/18F/18f.gsa.gov) 15 | 16 | We hope that every active 18F project, [working 17 | group](https://pages.18f.gov/grouplet-playbook/working-groups/), and 18 | [guild](https://pages.18f.gov/grouplet-playbook/guilds/) will publish 19 | `.about.yml` files in their respective repositories. By feeding this 20 | information through the Team API server and into our Hub, Dashboard, and main 21 | web site, cultivation of `.about.yml` files will help make our activity more 22 | easily transparent to our teammates, and to anyone outside our team who wishes 23 | to discover what we're working on (and how we work). 24 | 25 | ## Public domain 26 | 27 | This project is in the worldwide [public domain](LICENSE.md). As stated in [CONTRIBUTING](CONTRIBUTING.md): 28 | 29 | > This project is in the public domain within the United States, and copyright and related rights in the work worldwide are waived through the [CC0 1.0 Universal public domain dedication](https://creativecommons.org/publicdomain/zero/1.0/). 30 | > 31 | > All contributions to this project will be released under the CC0 32 | >dedication. By submitting a pull request, you are agreeing to comply 33 | >with this waiver of copyright interest. 34 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | /* jshint node: true */ 2 | 3 | var fs = require('fs'); 4 | var jsonSchema = require('json-schema'); 5 | var yamlJs = require('yamljs'); 6 | var referenceSchema = require('./lib/draft-04-schema.json'); 7 | var aboutSchema = require('./lib/schema.json'); 8 | var packageInfo = require('./package.json'); 9 | 10 | module.exports.versionString = function() { 11 | return packageInfo.name + ' v' + packageInfo.version; 12 | }; 13 | 14 | module.exports = Validator; 15 | 16 | /** 17 | * Creates an instance of Validator. 18 | * 19 | * @constructor 20 | * @this {Validator} 21 | * @param {json} schema (optional) - Schema to validate against. 22 | */ 23 | function Validator(schema) { 24 | var result; 25 | 26 | this.schema = schema || aboutSchema; 27 | delete this.schema.$schema; 28 | 29 | result = jsonSchema.validate(this.schema, referenceSchema); 30 | 31 | if (!result.valid) { 32 | throw new Error('JSON Schema is invalid: ', result.errors); 33 | } 34 | } 35 | 36 | /** 37 | * Validate against a string. 38 | * 39 | * @param {string} yamlContents - String of YML to validate 40 | * @returns {array} errors - Validation errors, if any. Otherwise returns 41 | * nothing 42 | */ 43 | Validator.prototype.validate = function (yamlContents) { 44 | var jsonContents, 45 | result; 46 | 47 | try { 48 | jsonContents = yamlJs.parse(yamlContents); 49 | } catch (err) { 50 | return [err.toString()]; 51 | } 52 | 53 | result = jsonSchema.validate(jsonContents, this.schema); 54 | 55 | if (!result.valid) { 56 | return result.errors; 57 | } 58 | }; 59 | 60 | /** 61 | * Validate against a file. 62 | * 63 | * @param {string} filePath - Path to file to validate 64 | * @param {fn} callback - To execute after validation with results 65 | */ 66 | Validator.prototype.validateFile = function (filePath, callback) { 67 | var that = this; 68 | 69 | fs.readFile(filePath, 'utf8', function(err, data) { 70 | callback(err || that.validate(data)); 71 | }); 72 | }; 73 | -------------------------------------------------------------------------------- /test/validator-test.js: -------------------------------------------------------------------------------- 1 | /* jshint node: true */ 2 | /* jshint expr: true */ 3 | /* jshint mocha: true */ 4 | 'use strict'; 5 | 6 | var fs = require('fs'); 7 | var path = require('path'); 8 | var yamlJs = require('yamljs'); 9 | var Validator = require( 10 | path.resolve(path.dirname(__dirname), 'index.js')); 11 | var aboutYmlPath = 12 | path.resolve(path.dirname(__dirname), '.about.yml'); 13 | var schemaPath = 14 | path.resolve(path.dirname(__dirname), 'lib', 'schema.json'); 15 | var chai = require('chai'); 16 | var expect = chai.expect; 17 | chai.should(); 18 | 19 | 20 | function check(done, cb) { 21 | return function(err) { try { cb(err); done(); } catch (e) { done(e); } }; 22 | } 23 | 24 | describe('validate', function() { 25 | var aboutYmlData, 26 | validator; 27 | 28 | beforeEach(function() { 29 | var schemaFile = JSON.parse(fs.readFileSync(schemaPath, 'utf8')); 30 | validator = new Validator(schemaFile); 31 | aboutYmlData = fs.readFileSync(aboutYmlPath, 'utf8'); 32 | }); 33 | 34 | it('should return an error if the JSON schema is invalid or incomplete', 35 | function() { 36 | var jsonSchema = JSON.stringify('garbage'), 37 | testValidator; 38 | 39 | expect(function() { testValidator = new Validator(jsonSchema); }) 40 | .to.throw('JSON Schema is invalid:'); 41 | }); 42 | 43 | it('should return an array of errors if the YAML fails to parse', 44 | function() { 45 | var yamlContents = 'lyric: "watch out boy: she\'ll chew you up!', 46 | results = validator.validate(yamlContents); 47 | 48 | expect(results).to.not.be.empty; 49 | expect(results[0]).to.have.string('ParseException'); 50 | }); 51 | 52 | it('should return nothing if the YAML content is valid', function() { 53 | var results = validator.validate(aboutYmlData); 54 | 55 | expect(results).to.be.undefined; 56 | }); 57 | 58 | it('should return an array of errors if the YAML content is invalid', 59 | function() { 60 | var aboutYmlDataBogus, 61 | results; 62 | 63 | aboutYmlDataBogus = yamlJs.parse(aboutYmlData); 64 | aboutYmlDataBogus.contact = 'bogus'; 65 | results = validator.validate(yamlJs.dump(aboutYmlDataBogus)); 66 | 67 | expect(results).to.eql([{ 68 | 'property': 'contact', 69 | 'message': 'string value found, but a array is required' 70 | }]); 71 | }); 72 | }); 73 | 74 | describe('validateFile', function() { 75 | var validator; 76 | 77 | beforeEach(function() { 78 | var schemaFile = JSON.parse(fs.readFileSync(schemaPath, 'utf8')); 79 | validator = new Validator(schemaFile); 80 | }); 81 | 82 | it('should pass an error to the callback method if the file read fails', 83 | function(done) { 84 | var invalidFilePath = '/dev/null/fail'; 85 | 86 | validator.validateFile(invalidFilePath, check(done, function(err) { 87 | expect(err).to.not.be.undefined; 88 | expect(err.message).to.have.string( 89 | 'ENOTDIR: not a directory, open \'/dev/null/fail\'' 90 | ); 91 | })); 92 | }); 93 | 94 | it('should throw an error if the file contents are invalid', 95 | function(done) { 96 | validator.validateFile(__filename, check(done, function(err) { 97 | expect(err).to.not.be.empty; 98 | expect(err[0]).to.have.string('ParseException'); 99 | })); 100 | }); 101 | 102 | it('should not return anything if the file validates successfully', 103 | function(done) { 104 | validator.validateFile(aboutYmlPath, check(done, function(err) { 105 | expect(err).to.be.undefined; 106 | })); 107 | }); 108 | }); 109 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | ## Welcome! 2 | 3 | We're so glad you're thinking about contributing to an 18F open source project! 4 | If you're unsure or afraid of anything, just ask or submit the issue or pull 5 | request anyways. The worst that can happen is that you'll be politely asked to 6 | change something. We appreciate any sort of contribution, and don't want a wall 7 | of rules to get in the way of that. 8 | 9 | Before contributing, we encourage you to read our CONTRIBUTING policy (you are 10 | here), our LICENSE, and our README, all of which should be in this repository. 11 | If you have any questions, or want to read more about our underlying policies, 12 | you can consult the 18F Open Source Policy GitHub repository at 13 | https://github.com/18f/open-source-policy, or just shoot us an email/official 14 | government letterhead note to [18f@gsa.gov](mailto:18f@gsa.gov). 15 | 16 | ## Public domain 17 | 18 | This project is in the public domain within the United States, and 19 | copyright and related rights in the work worldwide are waived through 20 | the [CC0 1.0 Universal public domain dedication](https://creativecommons.org/publicdomain/zero/1.0/). 21 | 22 | All contributions to this project will be released under the CC0 23 | dedication. By submitting a pull request, you are agreeing to comply 24 | with this waiver of copyright interest. 25 | 26 | ## Starting work on an issue 27 | 28 | Issues that are marked with the `ready` label are ripe for the picking! Simply 29 | assign yourself to the issue to and change its label to `in progress` to 30 | indicate that you are working on it. 31 | 32 | If the issue involves writing code or producing some other change that will 33 | result in a pull request, begin by creating yourself a branch with a short 34 | descriptive name of the work that includes the issue number at the end, e.g., 35 | `document-pr-process-#36`. 36 | 37 | **Note:** If you are not a part of the 18F Team, please fork the repository 38 | first and then create a branch for yourself with the same convention. 39 | 40 | Once your local branch is created, simply push it remotely and this will 41 | assign the issue to you and move it to be `in progress` automatically. 42 | 43 | ## Submitting a pull request and completing work 44 | 45 | When you are satisfied with your work and ready to submit it to be completed, 46 | please submit a pull request for review. If you haven't already, please 47 | follow the instructions above and create a branch for yourself first. Prior 48 | to submitting the pull request, please make note of the following: 49 | 50 | 1. Code changes should be accompanied by tests. 51 | 2. Please run the tests (`$ npm test`) to make sure there are no regressions. 52 | 53 | Once everything is ready to go, [submit your pull request](https://help.github.com/articles/using-pull-requests/)! 54 | When creating a pull request please be sure to reference the issue number it 55 | is associated with, preferably in the title. 56 | 57 | If you are working in a branch off of the 18F/about-yml-npm repo directly, you can 58 | reference the issue like this: 59 | `Closes #1: Short sentence describing the pull request` 60 | 61 | If you are working in a forked copy of the repo, please reference the issue 62 | like this: 63 | `Closes 18F/about-yml-npm#1: Short sentence describing the pull request` 64 | 65 | In both cases, please include a descriptive summary of the change in the body 66 | of the pull request as that will help greatly in reviewing the change and 67 | understanding what should be taking place inside of it. 68 | 69 | By referencing the issue in the pull request as noted above, this will 70 | automatically update the issue with a `needs review` label and notify the 71 | collaborators on the project that something is ready for a review. One of us 72 | will take a look as soon as we can and initiate the review process, provide 73 | feedback as necessary, and ultimately merge the change. 74 | 75 | Once the code is merged, the branch will be deleted and the `in review` 76 | label will be removed. The issue will be automatically updated again to be 77 | marked as Done and Closed. 78 | 79 | ## Performing a review of a pull request 80 | 81 | If you are performing a review of a pull request please add the `in review` 82 | label to the pull request and be sure keep the `needs review` label 83 | associated with it. This will help keep our Waffle board up-to-date and 84 | reflect that the pull request is being actively reviewed. Also, please 85 | assign yourself so others know who the primary reviewer is. 86 | -------------------------------------------------------------------------------- /lib/draft-04-schema.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-04/hyper-schema#", 3 | "id": "http://json-schema.org/draft-04/hyper-schema#", 4 | "title": "JSON Hyper-Schema", 5 | "allOf": [ 6 | { 7 | "$ref": "http://json-schema.org/draft-04/schema#" 8 | } 9 | ], 10 | "properties": { 11 | "additionalItems": { 12 | "anyOf": [ 13 | { 14 | "type": "boolean" 15 | }, 16 | { 17 | "$ref": "#" 18 | } 19 | ] 20 | }, 21 | "additionalProperties": { 22 | "anyOf": [ 23 | { 24 | "type": "boolean" 25 | }, 26 | { 27 | "$ref": "#" 28 | } 29 | ] 30 | }, 31 | "dependencies": { 32 | "additionalProperties": { 33 | "anyOf": [ 34 | { 35 | "$ref": "#" 36 | }, 37 | { 38 | "type": "array" 39 | } 40 | ] 41 | } 42 | }, 43 | "items": { 44 | "anyOf": [ 45 | { 46 | "$ref": "#" 47 | }, 48 | { 49 | "$ref": "#/definitions/schemaArray" 50 | } 51 | ] 52 | }, 53 | "definitions": { 54 | "additionalProperties": { 55 | "$ref": "#" 56 | } 57 | }, 58 | "patternProperties": { 59 | "additionalProperties": { 60 | "$ref": "#" 61 | } 62 | }, 63 | "properties": { 64 | "additionalProperties": { 65 | "$ref": "#" 66 | } 67 | }, 68 | "allOf": { 69 | "$ref": "#/definitions/schemaArray" 70 | }, 71 | "anyOf": { 72 | "$ref": "#/definitions/schemaArray" 73 | }, 74 | "oneOf": { 75 | "$ref": "#/definitions/schemaArray" 76 | }, 77 | "not": { 78 | "$ref": "#" 79 | }, 80 | 81 | "links": { 82 | "type": "array", 83 | "items": { 84 | "$ref": "#/definitions/linkDescription" 85 | } 86 | }, 87 | "fragmentResolution": { 88 | "type": "string" 89 | }, 90 | "media": { 91 | "type": "object", 92 | "properties": { 93 | "type": { 94 | "description": "A media type, as described in RFC 2046", 95 | "type": "string" 96 | }, 97 | "binaryEncoding": { 98 | "description": "A content encoding scheme, as described in RFC 2045", 99 | "type": "string" 100 | } 101 | } 102 | }, 103 | "pathStart": { 104 | "description": "Instances' URIs must start with this value for this schema to apply to them", 105 | "type": "string", 106 | "format": "uri" 107 | } 108 | }, 109 | "definitions": { 110 | "schemaArray": { 111 | "type": "array", 112 | "items": { 113 | "$ref": "#" 114 | } 115 | }, 116 | "linkDescription": { 117 | "title": "Link Description Object", 118 | "type": "object", 119 | "required": [ "href", "rel" ], 120 | "properties": { 121 | "href": { 122 | "description": "a URI template, as defined by RFC 6570, with the addition of the $, ( and ) characters for pre-processing", 123 | "type": "string" 124 | }, 125 | "rel": { 126 | "description": "relation to the target resource of the link", 127 | "type": "string" 128 | }, 129 | "title": { 130 | "description": "a title for the link", 131 | "type": "string" 132 | }, 133 | "targetSchema": { 134 | "description": "JSON Schema describing the link target", 135 | "$ref": "#" 136 | }, 137 | "mediaType": { 138 | "description": "media type (as defined by RFC 2046) describing the link target", 139 | "type": "string" 140 | }, 141 | "method": { 142 | "description": "method for requesting the target of the link (e.g. for HTTP this might be \"GET\" or \"DELETE\")", 143 | "type": "string" 144 | }, 145 | "encType": { 146 | "description": "The media type in which to submit data along with the request", 147 | "type": "string", 148 | "default": "application/json" 149 | }, 150 | "schema": { 151 | "description": "Schema describing the data to submit along with the request", 152 | "$ref": "#" 153 | } 154 | } 155 | } 156 | } 157 | } 158 | 159 | -------------------------------------------------------------------------------- /lib/schema.json: -------------------------------------------------------------------------------- 1 | { 2 | "title": ".about.yml - .about.yml files", 3 | "description": ".about.yml project metadata", 4 | "$schema": "http://json-schema.org/draft-04/hyper-schema#", 5 | "type": "object", 6 | "properties": { 7 | "name": { 8 | "type": "string", 9 | "description": "Short name that acts as the project identifier" 10 | }, 11 | "full_name": { 12 | "type": "string", 13 | "description": "Full proper name of the project" 14 | }, 15 | "type": { 16 | "type": "string", 17 | "description": "The type of content in the repo", 18 | "enum": ["app", "docs", "policy"] 19 | }, 20 | "owner_type": { 21 | "type": "string", 22 | "description": "Describes whether a project team, working group/guild, etc. owns the repo", 23 | "enum": ["guild", "working-group", "project"] 24 | }, 25 | "parent": { 26 | "type": "string", 27 | "description": "Name of the main project repo if this is a sub-repo; name of the working group/guild repo if this is a working group/guild subproject" 28 | }, 29 | "stage": { 30 | "type": "string", 31 | "enum": ["discovery", "alpha", "beta", "live", "sunset", "transfer", "end"], 32 | "description": "Maturity stage of the project" 33 | }, 34 | "description": { 35 | "type": "string", 36 | "description": "Description of the project" 37 | }, 38 | "tags": { 39 | "type": "array", 40 | "description": "Tags that describe the project or aspects of the project", 41 | "items": {"type": "string"}, 42 | "uniqueItems": true 43 | }, 44 | "testable": { 45 | "type": "boolean", 46 | "default": false, 47 | "description": "Should this repo have automated tests? If so, set to `true`." 48 | }, 49 | "team": { 50 | "type": "array", 51 | "description": "Team members contributing to the project", 52 | "items": { 53 | "$ref": "#/definitions/person" 54 | }, 55 | "uniqueItems": true 56 | }, 57 | "partners": { 58 | "type": "array", 59 | "description": "Partners for whom the project is developed", 60 | "items": {"type": "string"}, 61 | "uniqueItems": true 62 | }, 63 | "users": { 64 | "type": "array", 65 | "description": "Organizations or individuals who have adopted the project for their own use", 66 | "items": { 67 | "$ref": "#/definitions/user" 68 | }, 69 | "uniqueItems": true 70 | }, 71 | "milestones": { 72 | "type": "array", 73 | "description": "Brief descriptions of significant project developments", 74 | "items": {"type": "string"}, 75 | "uniqueItems": true 76 | }, 77 | "stack": { 78 | "type": "array", 79 | "description": "Technologies used to build the project", 80 | "items": {"type": "string"}, 81 | "uniqueItems": true 82 | }, 83 | "impact": { 84 | "type": "string", 85 | "description": "Brief description of the project's outcomes" 86 | }, 87 | "services": { 88 | "type": "array", 89 | "description": "Services used to supply project status information", 90 | "items": { 91 | "$ref": "#/definitions/service" 92 | }, 93 | "uniqueItems": true 94 | }, 95 | "licenses": { 96 | "type": "object", 97 | "description": "Licenses that apply to the project and/or its components", 98 | "patternProperties": { 99 | ".*": {"$ref": "#/definitions/license"} 100 | } 101 | }, 102 | "blogTag": { 103 | "type": "array", 104 | "description": "Tag to use when blogging about this project", 105 | "items": { 106 | "type": "string" 107 | }, 108 | "format": "uri", 109 | "uniqueItems": true 110 | }, 111 | "links": { 112 | "type": "array", 113 | "description": "Links to project artifacts", 114 | "items": { 115 | "$ref": "#/definitions/link" 116 | }, 117 | "format": "uri", 118 | "uniqueItems": true 119 | }, 120 | "contact": { 121 | "type": "array", 122 | "description": "URIs for points-of-contact", 123 | "items": { 124 | "$ref": "#/definitions/contact" 125 | }, 126 | "uniqueItems": true 127 | } 128 | }, 129 | "required": [ 130 | "name", "full_name", "stage", "team", "licenses", "owner_type", "testable" 131 | ], 132 | "definitions": { 133 | "person": { 134 | "type": "object", 135 | "description": "Individual contributor to the project", 136 | "properties": { 137 | "github": { 138 | "type": "string", 139 | "description": "GitHub user name" 140 | }, 141 | "id": { 142 | "type": "string", 143 | "description": "Internal team identifier/user name" 144 | }, 145 | "role": { 146 | "type": "string", 147 | "description": "Team member's role; leads should be designated as 'lead'" 148 | } 149 | } 150 | }, 151 | "user": { 152 | "type": "object", 153 | "description": "Organizations or individuals who have adopted the project for their own use", 154 | "properties": { 155 | "id": { 156 | "type": "string", 157 | "description": "The name of the organization or individual" 158 | }, 159 | "url": { 160 | "type": "string", 161 | "description": "A URL to the user's version of the project" 162 | } 163 | } 164 | }, 165 | "service": { 166 | "type": "object", 167 | "description": "Service used to provide project status", 168 | "properties": { 169 | "name": { 170 | "type": "string", 171 | "description": "Name of the service" 172 | }, 173 | "category": { 174 | "type": "string", 175 | "description": "Type of the service" 176 | }, 177 | "url": { 178 | "type": "string", 179 | "description": "URL for detailed information", 180 | "format": "uri" 181 | }, 182 | "badge": { 183 | "type": "string", 184 | "description": "URL for the status badge", 185 | "format": "uri" 186 | } 187 | } 188 | }, 189 | "license": { 190 | "type": "object", 191 | "description": "License under which the project (or a component of the project) is offered", 192 | "properties": { 193 | "name": { 194 | "type": "string", 195 | "description": "Name of the license from the Software Package Data Exchange (SPDX): https://spdx.org/licenses/" 196 | }, 197 | "url": { 198 | "type": "string", 199 | "description": "URL for the text of the license", 200 | "format": "uri" 201 | } 202 | } 203 | }, 204 | "link": { 205 | "type": "object", 206 | "description": "Link to a project artifact", 207 | "properties": { 208 | "url": { 209 | "type": "string", 210 | "description": "URL for the link", 211 | "format": "uri" 212 | }, 213 | "text": { 214 | "type": "string", 215 | "description": "Anchor text for the link" 216 | }, 217 | "category": { 218 | "type": "string", 219 | "description": "Type of the link", 220 | "enum": ["api", "process", "related"] 221 | } 222 | }, 223 | "required": [ 224 | "url" 225 | ] 226 | }, 227 | "contact": { 228 | "type": "object", 229 | "description": "Link to a project contact", 230 | "properties": { 231 | "url": { 232 | "type": "string", 233 | "description": "URL for the link", 234 | "format": "uri" 235 | }, 236 | "text": { 237 | "type": "string", 238 | "description": "Anchor text for the link" 239 | } 240 | } 241 | } 242 | } 243 | } 244 | --------------------------------------------------------------------------------