├── .hound.yml ├── spec ├── README.md ├── integration_spec.rb └── about_yml_file_spec.rb ├── .travis.yml ├── Gemfile ├── lib ├── about_yml │ ├── version.rb │ ├── tasks │ │ └── check_about_yml.rake │ ├── template_generator.rb │ ├── data_faker.rb │ ├── about.rb │ └── schema.json └── about_yml.rb ├── bin ├── about_yml_generate ├── about_yml_validate ├── github_org_descriptions └── about_yml_scrape ├── Rakefile ├── .gitignore ├── .about.yml ├── LICENSE.md ├── go ├── about_yml.gemspec ├── .rubocop.yml ├── template.yml ├── CONTRIBUTING.md └── README.md /.hound.yml: -------------------------------------------------------------------------------- 1 | ruby: 2 | config_file: .rubocop.yml 3 | -------------------------------------------------------------------------------- /spec/README.md: -------------------------------------------------------------------------------- 1 | # .about.yml tests 2 | 3 | To run, invoke `./go test`. 4 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: ruby 2 | sudo: false 3 | script: ./go ci_build 4 | rvm: 5 | - 2.2.3 6 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | 3 | gemspec 4 | gem 'rspec' 5 | gem 'random_data' 6 | -------------------------------------------------------------------------------- /lib/about_yml/version.rb: -------------------------------------------------------------------------------- 1 | # @author Mike Bland (michael.bland@gsa.gov) 2 | 3 | module AboutYml 4 | VERSION = '0.0.10' 5 | end 6 | -------------------------------------------------------------------------------- /bin/about_yml_generate: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env ruby 2 | # @author Mike Bland (michael.bland@gsa.gov) 3 | 4 | require_relative '../lib/about_yml' 5 | 6 | puts AboutYml::TemplateGenerator.new.generate 7 | -------------------------------------------------------------------------------- /lib/about_yml.rb: -------------------------------------------------------------------------------- 1 | # @author Mike Bland (michael.bland@gsa.gov) 2 | 3 | require_relative 'about_yml/about' 4 | require_relative 'about_yml/template_generator' 5 | require_relative 'about_yml/version' 6 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | require 'bundler/gem_tasks' 2 | require 'rake/testtask' 3 | import './lib/about_yml/tasks/check_about_yml.rake' 4 | 5 | Rake::TestTask.new do |t| 6 | t.libs << 'test' 7 | t.test_files = FileList['test/*test.rb'] 8 | end 9 | 10 | desc 'Run .about.yml tests' 11 | task default: :test 12 | task test: :run_about_yml_check 13 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .*.swp 2 | *.gem 3 | /coverage/ 4 | /pkg/ 5 | 6 | # for a library or gem, you might want to ignore these files since the code is 7 | # intended to run in multiple environments; otherwise, check them in: 8 | Gemfile.lock 9 | .ruby-version 10 | .ruby-gemset 11 | 12 | # unless supporting rvm < 1.11.0 or doing something fancy, ignore this: 13 | .rvmrc 14 | -------------------------------------------------------------------------------- /spec/integration_spec.rb: -------------------------------------------------------------------------------- 1 | require_relative '../lib/about_yml' 2 | require_relative '../lib/about_yml/data_faker' 3 | 4 | require 'rspec' 5 | require 'safe_yaml' 6 | 7 | RSpec.describe AboutYml::TemplateGenerator do 8 | it 'generates a valid template' do 9 | faker = AboutYml::DataFaker.new 10 | errors = ::AboutYml::AboutFile.validate_single_file faker.template_data 11 | expect(errors).to be_empty 12 | end 13 | end 14 | -------------------------------------------------------------------------------- /spec/about_yml_file_spec.rb: -------------------------------------------------------------------------------- 1 | require_relative '../lib/about_yml' 2 | 3 | require 'rspec' 4 | require 'safe_yaml' 5 | 6 | RSpec.describe AboutYml::AboutFile do 7 | it 'validates the .about.yml file against the schema' do 8 | filepath = File.expand_path('../../.about.yml', __FILE__) 9 | about_file = File.join filepath 10 | about_data = SafeYAML.load_file about_file, safe: true 11 | errors = ::AboutYml::AboutFile.validate_single_file about_data 12 | expect(errors).to be_empty 13 | end 14 | end 15 | -------------------------------------------------------------------------------- /lib/about_yml/tasks/check_about_yml.rake: -------------------------------------------------------------------------------- 1 | require 'about_yml' 2 | require 'safe_yaml' 3 | 4 | desc 'Check your .about.yml file' 5 | task :run_about_yml_check do 6 | project_dir = Rake.original_dir 7 | about_file = File.join project_dir, '.about.yml' 8 | unless File.exist? about_file 9 | $stderr.puts "No .about.yml file found in #{project_dir}" 10 | exit 1 11 | end 12 | 13 | about_data = SafeYAML.load_file about_file, safe: true 14 | errors = ::AboutYml::AboutFile.validate_single_file about_data 15 | unless errors.empty? 16 | $stderr.puts(".about.yml contains the following validation errors:\n " + 17 | "#{errors.join("\n ")}") 18 | exit 1 19 | end 20 | end 21 | -------------------------------------------------------------------------------- /.about.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: about_yml 3 | full_name: .about.yml gem 4 | type: app 5 | owner_type: project 6 | status: active 7 | stage: alpha 8 | testable: true 9 | description: > 10 | A gem for the .about.yml project metadata schema and tools 11 | impact: > 12 | Making it easy for project leads to communicate details of their project to any audience by simply updating a file in the project repo. 13 | stack: 14 | - Ruby 15 | licenses: 16 | .about.yml: 17 | name: CC0 18 | url: https://github.com/18F/about_yml/blob/master/LICENSE.md 19 | tasks: https://github.com/18F/about_yml/issues 20 | contact: 21 | - url: mailto:michael.bland@gsa.gov 22 | text: Michael Bland 23 | team: 24 | - github: mtorres253 25 | role: lead 26 | - github: mbland 27 | role: author 28 | - github: arowla 29 | - github: ertzeid 30 | -------------------------------------------------------------------------------- /bin/about_yml_validate: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env ruby 2 | 3 | require_relative '../lib/about_yml' 4 | require 'English' 5 | require 'safe_yaml' 6 | 7 | def usage(exitstatus = 0) 8 | (exitstatus == 0 ? $stdout : $stderr).puts < repo.name, 'description' => repo.description } 33 | end.to_yaml) 34 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /go: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env ruby 2 | 3 | require 'English' 4 | 5 | Dir.chdir File.dirname(__FILE__) 6 | 7 | def try_command_and_restart(command) 8 | exit $CHILD_STATUS.exitstatus unless system command 9 | exec RbConfig.ruby, *[$PROGRAM_NAME].concat(ARGV) 10 | end 11 | 12 | begin 13 | require 'bundler/setup' if File.exist? 'Gemfile' 14 | rescue LoadError 15 | try_command_and_restart 'gem install bundler' 16 | rescue SystemExit 17 | try_command_and_restart 'bundle install' 18 | end 19 | 20 | begin 21 | require 'go_script' 22 | rescue LoadError 23 | try_command_and_restart 'gem install go_script' unless File.exist? 'Gemfile' 24 | abort "Please add \"gem 'go_script'\" to your Gemfile" 25 | end 26 | 27 | extend GoScript 28 | check_ruby_version '2.2.3' 29 | 30 | command_group :dev, 'Development commands' 31 | 32 | def_command :update_gems, 'Update Ruby gems' do |gems = []| 33 | update_gems gems 34 | end 35 | 36 | def_command :test, 'Execute automated tests' do |args = []| 37 | exec_cmd 'bundle exec rake test' 38 | exec_cmd "bundle exec rspec #{args.join ' '}" 39 | end 40 | 41 | def_command :lint, 'Run style-checking tools' do |files = []| 42 | lint_ruby files 43 | end 44 | 45 | def_command :ci_build, 'Execute continuous integration build' do 46 | test 47 | exec_cmd 'bundle exec rake build' 48 | end 49 | 50 | def_command :release, 'Test, build, and release a new gem' do 51 | test 52 | exec_cmd 'bundle exec rake release' 53 | end 54 | 55 | execute_command ARGV 56 | -------------------------------------------------------------------------------- /about_yml.gemspec: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | lib = File.expand_path('../lib', __FILE__) 3 | $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib) 4 | require 'about_yml/version' 5 | 6 | Gem::Specification.new do |s| 7 | s.name = 'about_yml' 8 | s.version = AboutYml::VERSION 9 | s.authors = ['Mike Bland', 'Alison Rowland'] 10 | s.email = ['michael.bland@gsa.gov', 'alisonrowland@gmail.com'] 11 | s.summary = '.about.yml project metadata schema and tools' 12 | s.description = ( 13 | 'The .about.yml mechanism allows an project to publish and maintain ' \ 14 | 'metadata that can be easily maintained by project owners, that is ' \ 15 | 'visible and accessible to interested parties, and that can be ' \ 16 | 'harvested and processed by tools and automated systems.' 17 | ) 18 | s.homepage = 'https://github.com/18F/about_yml' 19 | s.license = 'CC0' 20 | 21 | s.files = `git ls-files -z *.md bin lib`.split("\x0") + [ 22 | ] 23 | s.executables = s.files.grep(%r{^bin/}) { |f| File.basename(f) } 24 | 25 | s.add_runtime_dependency 'safe_yaml', '~> 1.0' 26 | s.add_runtime_dependency 'octokit', '~> 3.0' 27 | s.add_runtime_dependency 'json-schema' 28 | s.add_development_dependency 'go_script', '~> 0.1' 29 | s.add_development_dependency 'rake', '~> 10.4' 30 | s.add_development_dependency 'minitest' 31 | s.add_development_dependency 'codeclimate-test-reporter' 32 | s.add_development_dependency 'coveralls' 33 | s.add_development_dependency 'rubocop' 34 | end 35 | -------------------------------------------------------------------------------- /lib/about_yml/template_generator.rb: -------------------------------------------------------------------------------- 1 | # @author Mike Bland (michael.bland@gsa.gov) 2 | 3 | require_relative 'about' 4 | require 'json-schema' 5 | require 'safe_yaml' 6 | 7 | module AboutYml 8 | class TemplateGenerator 9 | attr_reader :schema, :properties, :required 10 | def initialize 11 | @schema = ::AboutYml::AboutFile.schema 12 | @properties = schema['properties'] 13 | @required = schema['required'] 14 | end 15 | 16 | def generate 17 | props = properties.map { |name, defn| generate_item name, defn } 18 | "---\n# #{schema['description']}\n#\n#{props.join "\n\n"}" 19 | end 20 | 21 | def definition_properties(item_ref) 22 | schema['definitions'][item_ref.split('/').last]['properties'] 23 | end 24 | 25 | private 26 | 27 | def generate_item(name, definition) 28 | "#{property_description name, definition}\n#{name}:" \ 29 | "#{"\n- " if definition['type'] == 'array'}" \ 30 | "#{"\n placeholder_label:" if definition['patternProperties']}" 31 | end 32 | 33 | def property_description(name, definition) 34 | description = "# #{definition['description']}" 35 | description += ' (required)' if required.include? name 36 | description + value_description(definition) 37 | end 38 | 39 | def value_description(definition) 40 | values = definition['enum'] 41 | return "\n# values: #{values.join ', '}" if values 42 | type = definition['type'] 43 | return "\n# values: true, false" if type == 'boolean' 44 | return item_description definition if type == 'array' 45 | return pattern_desc definition if definition['patternProperties'] 46 | '' 47 | end 48 | 49 | def item_description(definition) 50 | item_ref = definition['items']['$ref'] 51 | return '' unless item_ref 52 | properties = definition_properties item_ref 53 | descs = properties.map { |name, defn| "#{name}: #{defn['description']}" } 54 | "\n# Items:\n# - #{descs.shift}\n# #{descs.join "\n# "}" 55 | end 56 | 57 | def pattern_desc(definition) 58 | property_descs = definition['patternProperties'].map do |prop_name, ref| 59 | descs = definition_properties(ref['$ref']).map do |defn_name, defn| 60 | "#{defn_name}: #{defn['description']}" 61 | end 62 | "\n# #{prop_name}:\n# #{descs.join "\n# "}" 63 | end.join "\n" 64 | "\n# Items by property name pattern:#{property_descs}" 65 | end 66 | 67 | end 68 | end 69 | -------------------------------------------------------------------------------- /lib/about_yml/data_faker.rb: -------------------------------------------------------------------------------- 1 | # @author Alison Rowland (alison.rowland@gsa.gov) 2 | 3 | require_relative 'about' 4 | require 'safe_yaml' 5 | require 'random_data' 6 | 7 | module AboutYml 8 | class DataFaker 9 | attr_reader :template_data 10 | 11 | TYPE_MAP = { 12 | 'string' => lambda { Random.alphanumeric }, 13 | 'boolean' => lambda { Random.boolean }, 14 | } 15 | 16 | def initialize 17 | @generator = AboutYml::TemplateGenerator.new 18 | template = @generator.generate 19 | @template_data = YAML.load template 20 | 21 | # load up the JSON schema to fill in appropriate values 22 | schema = AboutYml::AboutFile.schema 23 | 24 | @template_data.collect do |k, _| 25 | @template_data[k] = fill_data schema['properties'][k] 26 | end 27 | end 28 | 29 | # populate the template with random values according to their type 30 | # in the schema 31 | def fill_data(props) 32 | return unless props.key? 'type' 33 | type = props['type'] 34 | 35 | return props['enum'].rand if props.key? 'enum' 36 | return fill_array props if type == 'array' 37 | return fill_object props if type == 'object' 38 | 39 | TYPE_MAP[type].call if TYPE_MAP[type] 40 | end 41 | 42 | def fill_array(props) 43 | subtype = props['items']['type'] 44 | 45 | 3.times.collect do 46 | if TYPE_MAP[subtype] 47 | TYPE_MAP[subtype].call 48 | else 49 | subprops = @generator.definition_properties props['items']['$ref'] 50 | fill_new_object subprops 51 | end 52 | end 53 | end 54 | 55 | def fill_object(props) 56 | if props.key? 'items' 57 | return fill_data @generator.definition_properties props['items']['$ref'] 58 | elsif props.key? 'patternProperties' 59 | # this is hacky, but will work unless the "licenses" patternProperties 60 | # are changed to include more than one pattern 61 | _, v = props['patternProperties'].shift 62 | subprops = @generator.definition_properties v['$ref'] 63 | 64 | # the patternProperties works by regex matching on the keys of the 65 | # sub-object, # so we need to create another level of nesting with 66 | # a random key 67 | return { Random.alphanumeric => fill_new_object(subprops) } 68 | end 69 | end 70 | 71 | def fill_new_object(props) 72 | new_obj = {} 73 | props.map { |k, _| new_obj[k] = fill_data props[k] } 74 | new_obj 75 | end 76 | end 77 | end 78 | -------------------------------------------------------------------------------- /bin/about_yml_scrape: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env ruby 2 | 3 | require_relative '../lib/about_yml/about' 4 | require 'English' 5 | require 'safe_yaml' 6 | 7 | USAGE = < {}, 26 | 'private' => {}, 27 | 'missing' => [], 28 | 'errors' => {}, 29 | } 30 | repos.each { |repo| collect_repository_data repo, client, result } 31 | result 32 | end 33 | 34 | def self.fetch_file_contents(client, repo_full_name) 35 | about = client.contents repo_full_name, path: '.about.yml' 36 | SafeYAML.load Base64.decode64(about['content']) 37 | end 38 | 39 | def self.write_error(err, repo, result) 40 | $stderr.puts('Error while parsing .about.yml for ' \ 41 | "#{repo.full_name}:\n #{err}") 42 | result['errors'][repo.full_name] = err.message 43 | end 44 | 45 | def self.add_github_metadata(result, repo) 46 | result['github'] = { 47 | 'name' => repo.full_name, 48 | 'description' => repo.description, 49 | } 50 | end 51 | 52 | def self.collect_repository_data(repo, client, result) 53 | collection = (repo.private == true) ? 'private' : 'public' 54 | repo_name = repo.full_name 55 | result[collection][repo_name] = fetch_file_contents client, repo_name 56 | add_github_metadata result[collection][repo_name], repo 57 | rescue Octokit::NotFound 58 | result['missing'] << repo.full_name 59 | rescue StandardError => err 60 | write_error err, repo, result 61 | end 62 | private_class_method :collect_repository_data 63 | 64 | def self.validate_single_file(about_data) 65 | ::JSON::Validator.fully_validate schema, about_data 66 | end 67 | 68 | def self.validate_about_files(repo_name_to_about_data) 69 | r = { 'valid' => {}, 'invalid' => {} } 70 | repo_name_to_about_data.each_with_object(r) do |data, results| 71 | repo, contents = data 72 | errors = validate_single_file contents 73 | if errors.empty? 74 | results['valid'][repo] = contents 75 | else 76 | results['invalid'][repo] = { errors: errors, contents: contents } 77 | end 78 | end 79 | end 80 | 81 | def self.organize_by_owner_type_and_name(abouts) 82 | abouts.values.each_with_object({}) do |about, result| 83 | owner_type = about['owner_type'] 84 | name = about['name'] 85 | if owner_type && name 86 | (result[owner_type] ||= {})[name] = about 87 | else 88 | alt_id = about['full_name'] ? about['full_name'] : about['name'] 89 | result[alt_id + '/' + about['type']] = about 90 | end 91 | end 92 | end 93 | end 94 | end 95 | -------------------------------------------------------------------------------- /.rubocop.yml: -------------------------------------------------------------------------------- 1 | AllCops: 2 | Include: 3 | - 'Gemfile' 4 | - 'Rakefile' 5 | - 'go' 6 | - 'bin/*' 7 | 8 | Lint/ParenthesesAsGroupedExpression: 9 | Description: Checks for method calls with a space before the opening parenthesis. 10 | StyleGuide: https://github.com/bbatsov/ruby-style-guide#parens-no-spaces 11 | Enabled: true 12 | 13 | Metrics/ClassLength: 14 | Description: Avoid classes longer than 100 lines of code. 15 | Enabled: true 16 | CountComments: false 17 | Max: 100 18 | 19 | Metrics/LineLength: 20 | Description: Limit lines to 80 characters. 21 | StyleGuide: https://github.com/bbatsov/ruby-style-guide#80-character-limits 22 | Enabled: true 23 | Max: 80 24 | AllowURI: true 25 | URISchemes: 26 | - http 27 | - https 28 | 29 | Metrics/MethodLength: 30 | Description: Avoid methods longer than 10 lines of code. 31 | StyleGuide: https://github.com/bbatsov/ruby-style-guide#short-methods 32 | Enabled: true 33 | CountComments: false 34 | Max: 10 35 | 36 | Metrics/ModuleLength: 37 | Description: Avoid modules longer than 100 lines of code. 38 | Enabled: true 39 | CountComments: false 40 | Max: 100 41 | 42 | Style/AndOr: 43 | Description: Use &&/|| instead of and/or. 44 | StyleGuide: https://github.com/bbatsov/ruby-style-guide#no-and-or-or 45 | Enabled: true 46 | EnforcedStyle: always 47 | SupportedStyles: 48 | - always 49 | - conditionals 50 | 51 | Style/Documentation: 52 | Description: Document classes and non-namespace modules. 53 | Enabled: false 54 | 55 | Style/DotPosition: 56 | Description: Checks the position of the dot in multi-line method calls. 57 | StyleGuide: https://github.com/bbatsov/ruby-style-guide#consistent-multi-line-chains 58 | Enabled: true 59 | EnforcedStyle: leading 60 | SupportedStyles: 61 | - leading 62 | - trailing 63 | 64 | Style/ExtraSpacing: 65 | Description: Do not use unnecessary spacing. 66 | Enabled: false 67 | 68 | Style/GuardClause: 69 | Description: Check for conditionals that can be replaced with guard clauses 70 | StyleGuide: https://github.com/bbatsov/ruby-style-guide#no-nested-conditionals 71 | Enabled: true 72 | MinBodyLength: 1 73 | 74 | Style/StringLiterals: 75 | Description: Checks if uses of quotes match the configured preference. 76 | StyleGuide: https://github.com/bbatsov/ruby-style-guide#consistent-string-literals 77 | Enabled: true 78 | EnforcedStyle: single_quotes 79 | SupportedStyles: 80 | - single_quotes 81 | - double_quotes 82 | 83 | Style/TrailingComma: 84 | Description: 85 | Not allowing a comma after the last item in a list or hash when each item 86 | is on a single line is a bug, not a feature. 87 | EnforcedStyleForMultiline: comma 88 | 89 | Style/AlignParameters: 90 | Description: 91 | When aligning parameters is not appropriate due to line-length 92 | constraints, single indent for the lines after the first is also 93 | acceptable. 94 | StyleGuide: https://github.com/bbatsov/ruby-style-guide#no-double-indent 95 | EnforcedStyle: with_fixed_indentation 96 | 97 | Style/MultilineOperationIndentation: 98 | Description: 99 | Allow indented multiline operations, rather than strict alignment. 100 | EnforcedStyle: indented 101 | -------------------------------------------------------------------------------- /template.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # .about.yml project metadata 3 | # 4 | # Copy this template into your project repository's root directory as 5 | # .about.yml and fill in the fields as described below. 6 | 7 | # This is a short name of your project that can be used as a URL slug. 8 | # (required) 9 | name: 10 | 11 | # This is the display name of your project. (required) 12 | full_name: 13 | 14 | # What is the problem your project solves? What is the solution? Use the 15 | # format shown below. The #dashboard team will gladly help you put this 16 | # together for your project. (required) 17 | description: 18 | 19 | # What is the measurable impact of your project? Use the format shown below. 20 | # The #dashboard team will gladly help you put this together for your project. 21 | # (required) 22 | impact: 23 | 24 | # What kind of team owns the repository? (required) 25 | # values: guild, working-group, project 26 | owner_type: 27 | 28 | # What is your project's current status? (required) 29 | # values: discovery, alpha, beta, live 30 | stage: 31 | 32 | # Should this repo have automated tests? If so, set to `true`. (required) 33 | # values: true, false 34 | testable: 35 | 36 | # What are the licenses that apply to the project and/or its components? 37 | # (required) 38 | # Items by property name pattern: 39 | # .*: 40 | # name: Name of the license from the Software Package Data Exchange (SPDX): https://spdx.org/licenses/ 41 | # url: URL for the text of the license 42 | licenses: 43 | placeholder_label: 44 | 45 | # Who is the partner for your project? (Use the full name of the partner 46 | # documented here: 47 | # https://github.com/18F/dashboard/blob/staging/_data/partners.yml) 48 | partners: 49 | - 50 | 51 | # The main point of contact(s) and/or the issue reporting system for your 52 | # project, and either a `mailto:` link or URL for each contact. 53 | # Items: 54 | # - url: URL for the link 55 | # text: Anchor text for the link 56 | contact: 57 | - 58 | 59 | # Who are the team members on your project? You can specify GitHub usernames, 60 | # email addresses, or other organizational usernames. (required) 61 | # Items: 62 | # - github: GitHub user name 63 | # id: Internal team identifier/user name 64 | # role: Team member's role; leads should be designated as 'lead' 65 | team: 66 | - 67 | 68 | # What kind of content is contained in the project repository? 69 | # values: app, docs, policy 70 | type: 71 | 72 | # What are the key milestones you've achieved recently? 73 | milestones: 74 | - 75 | 76 | # Name of the main project repo if this is a sub-repo; name of the grouplet 77 | # repo if this is a working group/guild subproject 78 | parent: 79 | 80 | # What are the links to key artifacts associated with your project? e.g. the 81 | # production site, documentation. 82 | # Items: 83 | # - url: URL for the link 84 | # text: Anchor text for the link 85 | # category: Type of the link 86 | links: 87 | - 88 | 89 | # What tags does your organization's blog associate with your project? You can 90 | # find a list of 18F blog tags here: https://18f.gsa.gov/tags/ 91 | blogTag: 92 | - 93 | 94 | # What technologies are used in this project? 95 | stack: 96 | - 97 | 98 | # What are the services used to supply project status information? 99 | # Items: 100 | # - name: Name of the service 101 | # category: Type of the service 102 | # url: URL for detailed information 103 | # badge: URL for the status badge 104 | services: 105 | - 106 | 107 | # Organizations or individuals who have adopted the project for their own use 108 | # Items: 109 | # - id: The name of the organization or individual 110 | # url: A URL to the user's version of the project 111 | users: 112 | - 113 | 114 | # Tags that describe the project or aspects of the project 115 | tags: 116 | - 117 | -------------------------------------------------------------------------------- /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 (`$ ./go 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 repo directly, you can 58 | reference the issue like this: 59 | `Closes #36: 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#36: 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/about_yml/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": "This is a short name of your project that can be used as a URL slug." 10 | }, 11 | "full_name": { 12 | "type": "string", 13 | "description": "This is the display name of your project." 14 | }, 15 | "description": { 16 | "type": "string", 17 | "description": "What is the problem your project solves? What is the solution? Use the format shown below. The #dashboard team will gladly help you put this together for your project." 18 | }, 19 | "impact": { 20 | "type": "string", 21 | "description": "What is the measurable impact of your project? Use the format shown below. The #dashboard team will gladly help you put this together for your project." 22 | }, 23 | "owner_type": { 24 | "type": "string", 25 | "description": "What kind of team owns the repository?", 26 | "enum": ["guild", "working-group", "project"] 27 | }, 28 | "stage": { 29 | "type": "string", 30 | "description": "What is your project's current status?", 31 | "enum": ["discovery", "alpha", "beta", "live"] 32 | }, 33 | "testable": { 34 | "type": "boolean", 35 | "default": false, 36 | "description": "Should this repo have automated tests? If so, set to `true`." 37 | }, 38 | "licenses": { 39 | "type": "object", 40 | "description": "What are the licenses that apply to the project and/or its components?", 41 | "patternProperties": { 42 | ".*": {"$ref": "#/definitions/license"} 43 | } 44 | }, 45 | "partners": { 46 | "type": "array", 47 | "description": "Who is the partner for your project? (Use the full name of the partner documented here: https://github.com/18F/dashboard/blob/staging/_data/partners.yml)", 48 | "items": {"type": "string"}, 49 | "uniqueItems": true 50 | }, 51 | "contact": { 52 | "type": "array", 53 | "description": "The main point of contact(s) and/or the issue reporting system for your project, and either a `mailto:` link or URL for each contact.", 54 | "items": { 55 | "$ref": "#/definitions/contact" 56 | }, 57 | "uniqueItems": true 58 | }, 59 | "team": { 60 | "type": "array", 61 | "description": "Who are the team members on your project? You can specify GitHub usernames, email addresses, or other organizational usernames.", 62 | "items": { 63 | "$ref": "#/definitions/person" 64 | }, 65 | "uniqueItems": true 66 | }, 67 | "type": { 68 | "type": "string", 69 | "description": "What kind of content is contained in the project repository?", 70 | "enum": ["app", "docs", "policy"] 71 | }, 72 | "milestones": { 73 | "type": "array", 74 | "description": "What are the key milestones you've achieved recently?", 75 | "items": {"type": "string"}, 76 | "uniqueItems": true 77 | }, 78 | "parent": { 79 | "type": "string", 80 | "description": "Name of the main project repo if this is a sub-repo; name of the grouplet repo if this is a working group/guild subproject" 81 | }, 82 | "links": { 83 | "type": "array", 84 | "description": "What are the links to key artifacts associated with your project? e.g. the production site, documentation.", 85 | "items": { 86 | "$ref": "#/definitions/link" 87 | }, 88 | "format": "uri", 89 | "uniqueItems": true 90 | }, 91 | "blogTag": { 92 | "type": "array", 93 | "description": "What tags does your organization's blog associate with your project? You can find a list of 18F blog tags here: https://18f.gsa.gov/tags/", 94 | "items": { 95 | "type": "string" 96 | }, 97 | "uniqueItems": true 98 | }, 99 | "stack": { 100 | "type": "array", 101 | "description": "What technologies are used in this project?", 102 | "items": {"type": "string"}, 103 | "uniqueItems": true 104 | }, 105 | "services": { 106 | "type": "array", 107 | "description": "What are the services used to supply project status information?", 108 | "items": { 109 | "$ref": "#/definitions/service" 110 | }, 111 | "uniqueItems": true 112 | }, 113 | "users": { 114 | "type": "array", 115 | "description": "Organizations or individuals who have adopted the project for their own use", 116 | "items": { 117 | "$ref": "#/definitions/user" 118 | }, 119 | "uniqueItems": true 120 | }, 121 | "tags": { 122 | "type": "array", 123 | "description": "Tags that describe the project or aspects of the project", 124 | "items": {"type": "string"}, 125 | "uniqueItems": true 126 | } 127 | }, 128 | "required": [ 129 | "name", "full_name", "description", "impact", "stage", "team", "licenses", "owner_type", "testable" 130 | ], 131 | "definitions": { 132 | "person": { 133 | "type": "object", 134 | "description": "Individual contributor to the project", 135 | "properties": { 136 | "github": { 137 | "type": "string", 138 | "description": "GitHub user name" 139 | }, 140 | "id": { 141 | "type": "string", 142 | "description": "Internal team identifier/user name" 143 | }, 144 | "role": { 145 | "type": "string", 146 | "description": "Team member's role; leads should be designated as 'lead'" 147 | } 148 | } 149 | }, 150 | "user": { 151 | "type": "object", 152 | "description": "Organizations or individuals who have adopted the project for their own use", 153 | "properties": { 154 | "id": { 155 | "type": "string", 156 | "description": "The name of the organization or individual" 157 | }, 158 | "url": { 159 | "type": "string", 160 | "description": "A URL to the user's version of the project" 161 | } 162 | } 163 | }, 164 | "service": { 165 | "type": "object", 166 | "description": "Service used to provide project status", 167 | "properties": { 168 | "name": { 169 | "type": "string", 170 | "description": "Name of the service" 171 | }, 172 | "category": { 173 | "type": "string", 174 | "description": "Type of the service" 175 | }, 176 | "url": { 177 | "type": "string", 178 | "description": "URL for detailed information", 179 | "format": "uri" 180 | }, 181 | "badge": { 182 | "type": "string", 183 | "description": "URL for the status badge", 184 | "format": "uri" 185 | } 186 | } 187 | }, 188 | "license": { 189 | "type": "object", 190 | "description": "License under which the project (or a component of the project) is offered", 191 | "properties": { 192 | "name": { 193 | "type": "string", 194 | "description": "Name of the license from the Software Package Data Exchange (SPDX): https://spdx.org/licenses/" 195 | }, 196 | "url": { 197 | "type": "string", 198 | "description": "URL for the text of the license", 199 | "format": "uri" 200 | } 201 | } 202 | }, 203 | "link": { 204 | "type": "object", 205 | "description": "Link to a project artifact", 206 | "properties": { 207 | "url": { 208 | "type": "string", 209 | "description": "URL for the link", 210 | "format": "uri" 211 | }, 212 | "text": { 213 | "type": "string", 214 | "description": "Anchor text for the link" 215 | }, 216 | "category": { 217 | "type": "string", 218 | "description": "Type of the link", 219 | "enum": ["api", "process", "related"] 220 | } 221 | }, 222 | "required": [ 223 | "url" 224 | ] 225 | }, 226 | "contact": { 227 | "type": "object", 228 | "description": "Link to a project contact", 229 | "properties": { 230 | "url": { 231 | "type": "string", 232 | "description": "URL for the link", 233 | "format": "uri" 234 | }, 235 | "text": { 236 | "type": "string", 237 | "description": "Anchor text for the link" 238 | } 239 | } 240 | } 241 | } 242 | } 243 | -------------------------------------------------------------------------------- /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 | ## Quick start 26 | 27 | Copy the [`template.yml`](./template.yml) file from this repository into the 28 | root directory of your project's repository as `.about.yml`. Then refer to the 29 | [cheat sheet](#cheat-sheet) for instructions regarding how to fill in the 30 | data. 31 | 32 | ## Installation 33 | 34 | Run `gem install about_yml` on the command line. You can also add `gem 35 | 'about_yml'` to your project's `Gemfile` if you use 36 | [Bundler](http://bundler.io/) and wish to configure the `about_yml_validate` 37 | program as a pre-commit check. 38 | 39 | ## Usage 40 | 41 | Most users will interact with the gem through one of the following 42 | command-line programs. 43 | 44 | ### `about_yml_generate` 45 | 46 | This program will generate an empty `.about.yml` template with descriptions of 47 | each field. To add a new `.about.yml` file to your project where `MY-PROJECT` 48 | is the path to your local clone of your project's repository: 49 | 50 | ```shell 51 | $ about_yml_generate > MY-PROJECT/.about.yml 52 | ``` 53 | 54 | ### `about_yml_validate` 55 | 56 | This program checks one or more `.about.yml` files against the `.about.yml` 57 | schema. To check your project's `.about.yml` file: 58 | 59 | ```shell 60 | $ about_yml_validate MY-PROJECT/.about.yml 61 | ``` 62 | 63 | Alternatively, you can add the following to your `Rakefile` to tie 64 | `.about.yml` validation into your build process (this assumes that `Rakefile` 65 | and `.about.yml` are both in the top-level project directory): 66 | 67 | ```ruby 68 | # Development-only tasks 69 | begin 70 | require 'about_yml/tasks/check_about_yml' 71 | task test: :run_about_yml_check 72 | rescue LoadError 73 | end 74 | ``` 75 | 76 | ### `about_yml_scrape` 77 | 78 | This program checks for an `.about.yml` file in every GitHub repository 79 | belonging to a specified organization, then downloads, validates, and 80 | categorizes all of the discovered files into a single YAML object. You must 81 | have a valid 82 | [GitHub API token](https://help.github.com/articles/creating-an-access-token-for-command-line-use/) 83 | to run this command. 84 | 85 | ```shell 86 | $ about_yml_scrape 18F > 18F_about_yml_data.yml 87 | ``` 88 | 89 | ### `github_org_descriptions` 90 | 91 | This program doesn't have anything to do with the `.about.yml` schema, but is 92 | a small, handy program that also uses the 93 | [`octokit`](https://rubygems.org/gems/octokit) gem to access the GitHub API. 94 | It will return a YAML list of names and descriptions for all of the 95 | repositories belonging to an organization. 96 | 97 | ## `.about.yml` file testing 98 | 99 | The `run_about_yml_check` Rake task provides a relatively simple way to check 100 | a project's `.about.yml` file for errors. 101 | 102 | ### Add the task to your Rakefile 103 | 104 | To test whether the `.about.yml` file for a repository will successfully parse 105 | based on the schema, simply include the `about_yml` gem in your dependencies and 106 | then load the task in your Rakefile: 107 | 108 | ```ruby 109 | check_yml = Gem::Specification.find_by_name 'about_yml' 110 | load "#{check_yml.gem_dir}/lib/about_yml/tasks/check_about_yml.rake" 111 | ``` 112 | 113 | If your project already include `about_yml`, make sure it is using version 0.0.8 114 | or later. 115 | 116 | ### Run the task automatically with Travis 117 | 118 | To run the `run_about_yml_check` task automatically using Travis, simply add 119 | the following to your `.travis.yml` config file (with any preferred 120 | notifications): 121 | 122 | ```yml 123 | script: bundle exec rake run_about_yml_check 124 | ``` 125 | 126 | 127 | ## `.about.yml` cheat sheet 128 | The following attributes are currently stored in the `.about.yml` file and are used in one or more of the locations referenced above. Required attributes are marked with an asterisk, and field descriptions and examples follow each attribute. Take a look at [Every Kid in a Park](https://github.com/18F/ekip-api/blob/master/.about.yml) or [Open Opportunities](https://github.com/18F/openopps-platform/blob/dev/.about.yml) for living examples of `.about.yml` in action. 129 | 130 | 131 | `name`* - This is a short name of your project that is used as a URL slug on the 18F dashboard. 132 | > 133 | ```yml 134 | name: ekip-api 135 | ``` 136 | 137 | `full_name`* - This is the display name of your project on the 18F dashboard. 138 | > 139 | ```yml 140 | full_name: Every Kid in a Park 141 | ``` 142 | 143 | `description`* - What is the problem your project solves? What is the solution? Use the format shown below. The #dashboard team will gladly help you put this together for your project. 144 | > 145 | ```yml 146 | description: | 147 | In 2015, President Obama formally announced the Every Kid in a Park program, which provides 148 | fourth graders and their families with free access to more than 2,000 federally managed sites. 149 | 18F worked with the Department of the Interior to create the program’s website, which was 150 | written at a fourth grade level with the help of fourth graders. 151 | ``` 152 | 153 | `impact`* - What is the measurable impact of your project? Use the format shown below. The #dashboard team will gladly help you put this together for your project. 154 | > 155 | ```yml 156 | impact: | 157 | We designed a website that gives fourth graders and their families free access to more than 2,000 158 | federally-managed sites. 159 | ``` 160 | 161 | `owner_type`* - What kind of team owns the repository? *Accepted values: guild, working-group, project* 162 | > 163 | ```yml 164 | owner_type: project 165 | ``` 166 | 167 | `stage`* - What is your project's current status? *Accepted values: discovery, alpha, beta, live* 168 | > 169 | ```yml 170 | stage: live 171 | ``` 172 | 173 | `testable`* - Should this repo have automated tests? If so, set to `true`. *Accepted values: true, false* 174 | > 175 | ```yml 176 | testable: true 177 | ``` 178 | 179 | `licenses`* - What are the licences that apply to the project and/or its components? Get the license name from the [Software Package Data Exchange (SPDX)] (https://spdx.org/licenses/) 180 | > 181 | ```yml 182 | licenses: 183 | ekip-api: 184 | name: CC0-1.0 185 | url: https://github.com/18F/team_api/blob/master/LICENSE.md 186 | ``` 187 | 188 | `partners` - Who is the parter for your project? (Use the full name of the partner documented [here](https://github.com/18F/dashboard/blob/staging/_data/partners.yml)) 189 | > 190 | ```yml 191 | partners: 192 | - U.S. Department of the Interior 193 | ``` 194 | 195 | `contact` - The main point of contact(s) for your project, and a `mailto:` link for that contact. 196 | > 197 | ```yml 198 | contact: 199 | - url: mailto:shashank.khandelwal@gsa.gov 200 | text: Shashank Khandelwal 201 | ``` 202 | 203 | `team` - Who are the team members on your project? For each team member, list a github name, role and an internal identifier. (The project lead role should be `lead`) 204 | > 205 | ```yml 206 | team: 207 | - github: khandelwal 208 | role: lead 209 | id: khandelwal 210 | ``` 211 | 212 | `milestones` - What are the key milestones you've achieved recently? 213 | > 214 | ```yml 215 | milestones: 216 | - "December 2015: Discovery completed" 217 | ``` 218 | 219 | `type` - What kind of content is contained in the project repository? *Accepted values: app, docs, policy* 220 | > 221 | ```yml 222 | type: app 223 | ``` 224 | 225 | `parent` - 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 226 | > 227 | ```yml 228 | parent: [GitHub repo name] 229 | ``` 230 | 231 | `links` - What are the key links associated with your project? 232 | > 233 | ```yml 234 | links: 235 | - url: everykidinapark.gov 236 | text: Every Kid in a Park 237 | ``` 238 | 239 | `blogTag` - What is the 18F blog tag for your project? You can find a list of tags [here](https://18f.gsa.gov/tags/) 240 | > 241 | ```yml 242 | blogTag: [18F Blog Tag] 243 | ``` 244 | 245 | `stack` - What technologies are used in this project? 246 | > 247 | ```yml 248 | stack: 249 | - Django 250 | ``` 251 | 252 | `services` - What are the services used to supply project status information? 253 | > 254 | ```yml 255 | services: 256 | - name: Coveralls 257 | category: Build review 258 | url: https://coveralls.io/github/18F/ekip-api?branch=master 259 | badge: https://coveralls.io/repos/18F/ekip-api/badge.svg?branch=master&service=github 260 | - name: Quantified Code 261 | category: Site review 262 | url: https://www.quantifiedcode.com/app/project/ecb305ac0bfa4e968192621402faface 263 | badge: https://www.quantifiedcode.com/api/v1/project/ecb305ac0bfa4e968192621402faface/badge.svg 264 | ``` 265 | 266 | ## Public domain 267 | 268 | This project is in the worldwide [public domain](LICENSE.md). As stated in [CONTRIBUTING](CONTRIBUTING.md): 269 | 270 | > 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/). 271 | > 272 | > All contributions to this project will be released under the CC0 273 | >dedication. By submitting a pull request, you are agreeing to comply 274 | >with this waiver of copyright interest. 275 | --------------------------------------------------------------------------------