codeinventory-github 0.1.0 → 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (4) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +41 -4
  3. data/lib/codeinventory/github.rb +130 -21
  4. metadata +2 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 14db941ce2b924355eaffb6c538731d1da65990b
4
- data.tar.gz: 51069e1abc8f558d31839501a933c9ce3850928a
3
+ metadata.gz: 19dae8a55610afeed89a5575c736660b2a21345f
4
+ data.tar.gz: 29bba4eaaf69703b92a7d013e8b54de7907f9980
5
5
  SHA512:
6
- metadata.gz: b490bf919711a73cf0c4a3c6c7f014efe96f6c6628a158138e5dd8e3e55ee6a17e0e114afb1e67ba16bae604bda35c488606c0cfe146c5ebfec59a13f4fa4cc4
7
- data.tar.gz: 043d08d40d9d9eed3a5382bc5ae354f10541a25231a3b72dd8f0e799659215c3e5f988a654434c2edeb55a9d179a09dae2cad83d25861c32624800cd9ef3bfa8
6
+ metadata.gz: cc84d36b7e0b11382a27a6543ba801823ae22de8484f0946604e4ce95f4deafffdccc8f53b50eac3672e8d5a1e8ebcb5a13200b76dc0351a7f1d9aba3cc20ce9
7
+ data.tar.gz: 6c7dabbc11ec19c81c6394f2ea2d7d37163180f4164c8b9871364e5b11aff04344b58cc871cc57e16cb4e1006d6a0ee3c11ee1904faba93f9f8d5364c19a14ed
data/README.md CHANGED
@@ -2,7 +2,11 @@
2
2
 
3
3
  *_This is an experimental gem that is currently in an alpha stage. The features and interface are unstable and may change at any time._*
4
4
 
5
- The `codeinventory-github` gem is a [CodeInventory](https://github.com/GSA/codeinventory) plugin. This plugin allows CodeInventory to gather metadata from `.codeinventory.yml` or `.codeinventory.json` files in GitHub repositories.
5
+ The `codeinventory-github` gem is a [CodeInventory](https://github.com/GSA/codeinventory) plugin. This plugin allows CodeInventory to gather metadata from GitHub repositories. It builds a list of projects based on a combination of:
6
+
7
+ * `.codeinventory.yml` and `.codeinventory.json` files in GitHub repositories
8
+ * GitHub metadata
9
+ * Manually specified overrides
6
10
 
7
11
  ## Installation
8
12
 
@@ -26,15 +30,21 @@ Basically:
26
30
 
27
31
  ```ruby
28
32
  require "codeinventory"
29
- require "codeinventory-github"
33
+ require "codeinventory/github"
30
34
 
31
35
  github_source = CodeInventory::GitHub.new(access_token: "GITHUB_ACCESS_TOKEN", org: "github_org_name")
32
36
 
33
37
  inventory = CodeInventory::Inventory.new(github_source)
34
- inventory.projects # Returns an array of all projects in the GitHub org that have metadata
38
+ inventory.projects # Returns an array of projects in the GitHub org
35
39
  ```
36
40
 
37
- When using `CodeInventory::GitHub`, provide a [GitHub access token](https://developer.github.com/v3/oauth/) and the GitHub organization name (e.g., "[GSA](https://github.com/GSA/)"). Each repository within the organization that needs to be included in the project listing should have a `.codeinventory.yml` or `.codeinventory.json` file in the repository's root directory.
41
+ When using `CodeInventory::GitHub`, provide a [GitHub access token](https://developer.github.com/v3/oauth/) and the GitHub organization name (e.g., "[GSA](https://github.com/GSA/)").
42
+
43
+ The `codeinventory-github` plugin will then automatically harvest your project metadata from GitHub metadata.
44
+
45
+ ### Using inventory files
46
+
47
+ If you want more fine-grained control over project metadata beyond what is in the GitHub metadata, you can optionally include a `.codeinventory.yml` or `.codeinventory.json` file in the root directories of your GitHub project repositories. For each repository that has such a file, `codeinventory-github` will automatically use the metadata from it.
38
48
 
39
49
  #### YAML Format (.codeinventory.yml)
40
50
 
@@ -68,6 +78,33 @@ contact:
68
78
  }
69
79
  ```
70
80
 
81
+ ### Using overrides
82
+
83
+ You can override any of the inventory fields by passing an override hash.
84
+
85
+ ```ruby
86
+ overrides = {
87
+ tags: ["my-tag-1", "my-tag-2"],
88
+ contact: {
89
+ email: "me@example.com"
90
+ }
91
+ }
92
+ github_source = CodeInventory::GitHub.new(access_token: "GITHUB_ACCESS_TOKEN", org: "github_org_name", overrides: overrides)
93
+ ```
94
+
95
+ In this example, `codeinventory-github` will set the tags on all your projects to `my-tag-1` and `my-tag-2` also use the contact email you specified on all projects.
96
+
97
+ ### Excluding repositories
98
+
99
+ You can exclude any repository from scanning.
100
+
101
+ ```ruby
102
+ exclusions = ["not-a-real-product", "DontScanMe"]
103
+ github_source = CodeInventory::GitHub.new(access_token: "GITHUB_ACCESS_TOKEN", org: "github_org_name", exclude: exclusions)
104
+ ```
105
+
106
+ In this example, `codeinventory-github` will ignore the repositories named `not-a-real-product` or `DontScanMe`.
107
+
71
108
  ## Development
72
109
 
73
110
  After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake test` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
@@ -4,41 +4,150 @@ require "base64"
4
4
 
5
5
  module CodeInventory
6
6
  class GitHub
7
- VERSION = "0.1.0"
8
- attr_accessor :org
7
+ VERSION = "0.1.1"
8
+ attr_accessor :org, :overrides, :exclude
9
9
 
10
- def initialize(access_token:, org:)
10
+ def initialize(access_token:, org:, overrides: {}, exclude: [])
11
11
  Octokit.auto_paginate = true
12
12
  @access_token = access_token
13
13
  @org = org
14
+ @overrides = overrides
15
+ @exclude = exclude
14
16
  end
15
17
 
16
18
  def projects
17
19
  repos = client.organization_repositories(@org)
20
+ repos.delete_if { |repo| exclude.include? repo[:name] }
18
21
  projects = []
19
22
  repos.each do |repo|
20
- begin
21
- contents_metadata = client.contents(repo[:full_name], path: ".codeinventory.yml")
22
- type = :yaml
23
- raw_content = Base64.decode64(contents_metadata[:content])
24
- rescue Octokit::NotFound
25
- begin
26
- contents_metadata = client.contents(repo[:full_name], path: ".codeinventory.json")
27
- type = :json
28
- raw_content = Base64.decode64(contents_metadata[:content])
29
- rescue Octokit::NotFound
30
- # Ignore repositories that don't have a CodeInventory metadata file
31
- end
32
- end
33
- if type == :yaml
34
- projects << YAML.load(raw_content).to_hash
35
- elsif type == :json
36
- projects << JSON.parse(raw_content)
37
- end
23
+ inventory_file_metadata = inventory_file(repo)
24
+ repo_metadata = {}
25
+ repo_metadata["name"] = name(repo, inventory_file_metadata)
26
+ repo_metadata["description"] = description(repo, inventory_file_metadata)
27
+ repo_metadata["license"] = license(repo, inventory_file_metadata)
28
+ repo_metadata["openSourceProject"] = open_source_project(repo, inventory_file_metadata)
29
+ repo_metadata["governmentWideReuseProject"] = government_wide_reuse_project(repo, inventory_file_metadata)
30
+ repo_metadata["tags"] = tags(repo, inventory_file_metadata)
31
+ repo_metadata["contact"] = { "email" => contact_email(repo, inventory_file_metadata) }
32
+ repo_metadata["repository"] = repository(repo, inventory_file_metadata)
33
+ projects << repo_metadata
38
34
  end
39
35
  projects
40
36
  end
41
37
 
38
+ # Checks if the repo has an inventory file. If so, loads its metadata.
39
+ def inventory_file(repo)
40
+ filenames = [ ".codeinventory.yml", "codeinventory.yml", ".codeinventory.json", "codeinventory.json"]
41
+ repo_contents = client.contents(repo[:full_name], path: "/")
42
+ inventory_file = repo_contents.select { |file| filenames.include? file[:name] }.first
43
+ unless inventory_file.nil?
44
+ file_content = client.contents(repo[:full_name], path: inventory_file[:path])
45
+ raw_content = Base64.decode64(file_content[:content])
46
+ if inventory_file[:name].end_with? ".yml"
47
+ metadata = YAML.load(raw_content).to_hash
48
+ elsif inventory_file[:name].end_with? ".json"
49
+ metadata = JSON.parse(raw_content)
50
+ end
51
+ end
52
+ metadata || {}
53
+ end
54
+
55
+ # Provides a value for the name field.
56
+ # Order of precedence:
57
+ # 1. CodeInventory metadata file
58
+ # 2. GitHub repository name
59
+ def name(repo, inventory_file_metadata)
60
+ return inventory_file_metadata["name"] if inventory_file_metadata["name"]
61
+ repo[:name]
62
+ end
63
+
64
+ # Provides a value for the description field.
65
+ # Order of precedence:
66
+ # 1. List of overrides
67
+ # 2. CodeInventory metadata file
68
+ # 3. GitHub repository description
69
+ # 4. GitHub repository name
70
+ def description(repo, inventory_file_metadata)
71
+ return @overrides[:description] if @overrides[:description]
72
+ return inventory_file_metadata["description"] if inventory_file_metadata["description"]
73
+ return repo[:description] if repo[:description]
74
+ repo[:name]
75
+ end
76
+
77
+ # Provides a value for the license field.
78
+ # Order of precedence:
79
+ # 1. List of overrides
80
+ # 2. CodeInventory metadata file
81
+ # 3. LICENSE.md or LICENSE file in the repository
82
+ # 4. nil
83
+ def license(repo, inventory_file_metadata)
84
+ return @overrides[:license] if @overrides[:license]
85
+ return inventory_file_metadata["license"] if inventory_file_metadata["license"]
86
+ # Need to set header to quiet warning about using a GitHub preview feature
87
+ headers = { accept: "application/vnd.github.drax-preview+json" }
88
+ begin
89
+ license_meta = client.repository_license_contents(repo[:full_name], headers)
90
+ license = license_meta[:html_url]
91
+ rescue Octokit::NotFound ; end
92
+ license
93
+ end
94
+
95
+ # Provides a value for the openSourceProject field.
96
+ # Order of precedence:
97
+ # 1. List of overrides
98
+ # 2. CodeInventory metadata file
99
+ # 3. GitHub repository public/private status (public=1; private=0)
100
+ def open_source_project(repo, inventory_file_metadata)
101
+ return @overrides[:openSourceProject] if @overrides[:openSourceProject]
102
+ return inventory_file_metadata["openSourceProject"] if inventory_file_metadata["openSourceProject"]
103
+ repo[:private] ? 0 : 1
104
+ end
105
+
106
+ # Provides a value for the governmentWideReuseProject field.
107
+ # Order of precedence:
108
+ # 1. List of overrides
109
+ # 2. CodeInventory metadata file
110
+ # 3. 1 (assume government-wide reuse)
111
+ def government_wide_reuse_project(repo, inventory_file_metadata)
112
+ return @overrides[:governmentWideReuseProject] if @overrides[:governmentWideReuseProject]
113
+ return inventory_file_metadata["governmentWideReuseProject"] if inventory_file_metadata["governmentWideReuseProject"]
114
+ 1
115
+ end
116
+
117
+ # Provides a value for the tags field.
118
+ # Order of precedence:
119
+ # 1. List of overrides
120
+ # 2. CodeInventory metadata file
121
+ # 3. A single tag consisting of the org name.
122
+ def tags(repo, inventory_file_metadata)
123
+ return @overrides[:tags] if @overrides[:tags]
124
+ return inventory_file_metadata["tags"] if inventory_file_metadata["tags"]
125
+ [repo[:owner][:login]]
126
+ end
127
+
128
+ # Provides a value for the contact.email field.
129
+ # Order of precedence:
130
+ # 1. List of overrides
131
+ # 2. CodeInventory metadata file
132
+ # 3. GitHub organization email
133
+ def contact_email(repo, inventory_file_metadata)
134
+ return @overrides[:contact][:email] if @overrides.dig(:contact, :email)
135
+ return inventory_file_metadata["contact"]["email"] if inventory_file_metadata.dig("contact", "email")
136
+ org = client.organization(@org)
137
+ org[:email]
138
+ end
139
+
140
+ # Provies a value for the repository field.
141
+ # Order of precedence:
142
+ # 1. List of overrides
143
+ # 2. CodeInventory metadata file
144
+ # 3. GitHub repository URL
145
+ def repository(repo, inventory_file_metadata)
146
+ return @overrides[:repository] if @overrides[:repository]
147
+ return inventory_file_metadata["repository"] if inventory_file_metadata["repository"]
148
+ repo[:html_url]
149
+ end
150
+
42
151
  def client
43
152
  @client ||= Octokit::Client.new(access_token: @access_token)
44
153
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: codeinventory-github
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.1.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jeff Fredrickson
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2016-12-06 00:00:00.000000000 Z
11
+ date: 2016-12-29 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler