codeinventory-github 0.1.9 → 0.2.0

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: fcdbf327550dd781c0433fc01596d9199a56707b
4
- data.tar.gz: 0f01483ec0a4d89d0558b6476b6111bff2b926f0
3
+ metadata.gz: 9294afff7d3f67ca26ad6f34910f2acf07385d10
4
+ data.tar.gz: 9d1383ba2fde285619fb8c466d3db5f96b87f7bd
5
5
  SHA512:
6
- metadata.gz: 98cd2c92bd4b0ec24a6b3dc6c9a9d1e03d6ad4b8e592355542978cdd0512f25864bfa20de097825fee91287faf88de585efbdb8a69bb35f34ee127f9fcb709f0
7
- data.tar.gz: 704f4e213ef25761a7f9fab7e098f3111b05315b8702d9dba7fccfa861360151b5a338aaffb4fd712c652a0cfb75ddf77a743be4256352f3920f20ca00dc62a2
6
+ metadata.gz: 784525c02eaebe5ccd88b865f9a46971835e4766e8e8c4a224db5b1957456c89bb50bf43fd700695123ba546d29af67c29ae705de438216655557245852dda0e
7
+ data.tar.gz: 6d87d54b5be798fa92765d4b9ecfa2f4800106a8faeb37ddb530331d3cbc4c0e3edcb519f87cea0d7d0d2b588c92a7bde1d1a3c14a51fa8298eb6b5647c8b9ed
data/README.md CHANGED
@@ -47,7 +47,7 @@ require "codeinventory"
47
47
  require "codeinventory/github"
48
48
 
49
49
  auth = { access_token: "GITHUB_ACCESS_TOKEN" }
50
- github_source = CodeInventory::GitHub.new(auth, "GITHUB_ORG_NAME")
50
+ github_source = CodeInventory::GitHub::Source.new(auth, "GITHUB_ORG_NAME")
51
51
 
52
52
  inventory = CodeInventory::Inventory.new(github_source)
53
53
  inventory.projects # Returns an array of projects in the GitHub org
@@ -59,7 +59,7 @@ The `codeinventory-github` plugin will then automatically harvest the given orga
59
59
 
60
60
  This gem uses the [Octokit](https://github.com/octokit/octokit.rb) GitHub client to interface with the GitHub API.
61
61
 
62
- For the `auth` parameter when instantiating `CodeInventory::GitHub`, provide any type of [authentication information that Octokit supports](https://github.com/octokit/octokit.rb#authentication). Examples: a basic login/password, [OAuth access token](https://developer.github.com/v3/oauth/), or application authentication.
62
+ For the `auth` parameter when instantiating `CodeInventory::GitHub::Source`, provide any type of [authentication information that Octokit supports](https://github.com/octokit/octokit.rb#authentication). Examples: a basic login/password, [OAuth access token](https://developer.github.com/v3/oauth/), or application authentication.
63
63
 
64
64
  ### Using inventory files
65
65
 
@@ -133,7 +133,7 @@ overrides = {
133
133
  email: "me@example.com"
134
134
  }
135
135
  }
136
- github_source = CodeInventory::GitHub.new({ access_token: "GITHUB_ACCESS_TOKEN" }, "GITHUB_ORG_NAME", overrides: overrides)
136
+ github_source = CodeInventory::GitHub::Source.new({ access_token: "GITHUB_ACCESS_TOKEN" }, "GITHUB_ORG_NAME", overrides: overrides)
137
137
  ```
138
138
 
139
139
  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.
@@ -144,7 +144,7 @@ You can exclude any repository from scanning.
144
144
 
145
145
  ```ruby
146
146
  exclusions = ["not-a-real-product", "DontScanMe"]
147
- github_source = CodeInventory::GitHub.new({ access_token: "GITHUB_ACCESS_TOKEN" }, "GITHUB_ORG_NAME", exclude: exclusions)
147
+ github_source = CodeInventory::GitHub::Source.new({ access_token: "GITHUB_ACCESS_TOKEN" }, "GITHUB_ORG_NAME", exclude: exclusions)
148
148
  ```
149
149
 
150
150
  In this example, `codeinventory-github` will ignore the repositories named `not-a-real-product` or `DontScanMe`.
@@ -1,175 +1,2 @@
1
- require "octokit"
2
- require "yaml"
3
- require "base64"
4
-
5
- module CodeInventory
6
- class GitHub
7
- VERSION = "0.1.9"
8
- attr_accessor :org, :overrides, :exclude
9
-
10
- def initialize(auth, org, overrides: {}, exclude: [])
11
- Octokit.auto_paginate = true
12
- @auth = auth
13
- @org = org
14
- @overrides = overrides
15
- @exclude = exclude
16
- end
17
-
18
- def projects
19
- repos = client.organization_repositories(@org)
20
- repos.delete_if { |repo| exclude.include? repo[:name] }
21
- projects = []
22
- repos.each do |repo|
23
- inventory_file_metadata = inventory_file(repo)
24
- unless inventory_file_metadata.dig("codeinventory", "exclude")
25
- repo_metadata = {}
26
- repo_metadata["name"] = name(repo, inventory_file_metadata)
27
- repo_metadata["description"] = description(repo, inventory_file_metadata)
28
- repo_metadata["license"] = license(repo, inventory_file_metadata)
29
- repo_metadata["openSourceProject"] = open_source_project(repo, inventory_file_metadata)
30
- repo_metadata["governmentWideReuseProject"] = government_wide_reuse_project(repo, inventory_file_metadata)
31
- repo_metadata["tags"] = tags(repo, inventory_file_metadata)
32
- repo_metadata["contact"] = { "email" => contact_email(repo, inventory_file_metadata) }
33
- repo_metadata["repository"] = repository(repo, inventory_file_metadata)
34
- organization = organization(repo, inventory_file_metadata)
35
- repo_metadata["organization"] = organization(repo, inventory_file_metadata) unless organization.nil?
36
- projects << repo_metadata
37
- yield repo_metadata if block_given?
38
- end
39
- end
40
- projects
41
- end
42
-
43
- # Checks if the repo has an inventory file. If so, loads its metadata.
44
- def inventory_file(repo)
45
- metadata = {}
46
- return metadata if repo[:size] == 0 # Empty repo
47
- filenames = [ ".codeinventory.yml", "codeinventory.yml", ".codeinventory.json", "codeinventory.json"]
48
- repo_contents = client.contents(repo[:full_name], path: "/")
49
- inventory_file = repo_contents.select { |file| filenames.include? file[:name] }.first
50
- unless inventory_file.nil?
51
- file_content = client.contents(repo[:full_name], path: inventory_file[:path])
52
- raw_content = Base64.decode64(file_content[:content])
53
- # Remove UTF-8 BOM if there is one; it throws off JSON.parse
54
- raw_content.sub!("\xEF\xBB\xBF".force_encoding("ASCII-8BIT"), "")
55
- if inventory_file[:name].end_with? ".yml"
56
- metadata = YAML.load(raw_content).to_hash
57
- elsif inventory_file[:name].end_with? ".json"
58
- metadata = JSON.parse(raw_content)
59
- end
60
- end
61
- metadata
62
- end
63
-
64
- # Provides a value for the name field.
65
- # Order of precedence:
66
- # 1. CodeInventory metadata file
67
- # 2. GitHub repository name
68
- def name(repo, inventory_file_metadata)
69
- return inventory_file_metadata["name"] if inventory_file_metadata["name"]
70
- repo[:name]
71
- end
72
-
73
- # Provides a value for the description field.
74
- # Order of precedence:
75
- # 1. List of overrides
76
- # 2. CodeInventory metadata file
77
- # 3. GitHub repository description
78
- # 4. GitHub repository name
79
- def description(repo, inventory_file_metadata)
80
- return @overrides[:description] if @overrides[:description]
81
- return inventory_file_metadata["description"] if inventory_file_metadata["description"]
82
- return repo[:description] if repo[:description]
83
- repo[:name]
84
- end
85
-
86
- # Provides a value for the license field.
87
- # Order of precedence:
88
- # 1. List of overrides
89
- # 2. CodeInventory metadata file
90
- # 3. LICENSE.md or LICENSE file in the repository
91
- # 4. nil
92
- def license(repo, inventory_file_metadata)
93
- return @overrides[:license] if @overrides[:license]
94
- return inventory_file_metadata["license"] if inventory_file_metadata["license"]
95
- # Need to set header to quiet warning about using a GitHub preview feature
96
- headers = { accept: "application/vnd.github.drax-preview+json" }
97
- begin
98
- license_meta = client.repository_license_contents(repo[:full_name], headers)
99
- license = license_meta[:html_url]
100
- rescue Octokit::NotFound ; end
101
- license
102
- end
103
-
104
- # Provides a value for the openSourceProject field.
105
- # Order of precedence:
106
- # 1. List of overrides
107
- # 2. CodeInventory metadata file
108
- # 3. GitHub repository public/private status (public=1; private=0)
109
- def open_source_project(repo, inventory_file_metadata)
110
- return @overrides[:openSourceProject] if @overrides[:openSourceProject]
111
- return inventory_file_metadata["openSourceProject"] if inventory_file_metadata["openSourceProject"]
112
- repo[:private] ? 0 : 1
113
- end
114
-
115
- # Provides a value for the governmentWideReuseProject field.
116
- # Order of precedence:
117
- # 1. List of overrides
118
- # 2. CodeInventory metadata file
119
- # 3. 1 (assume government-wide reuse)
120
- def government_wide_reuse_project(repo, inventory_file_metadata)
121
- return @overrides[:governmentWideReuseProject] if @overrides[:governmentWideReuseProject]
122
- return inventory_file_metadata["governmentWideReuseProject"] if inventory_file_metadata["governmentWideReuseProject"]
123
- 1
124
- end
125
-
126
- # Provides a value for the tags field.
127
- # Order of precedence:
128
- # 1. List of overrides
129
- # 2. CodeInventory metadata file
130
- # 3. A single tag consisting of the org name.
131
- def tags(repo, inventory_file_metadata)
132
- return @overrides[:tags] if @overrides[:tags]
133
- return inventory_file_metadata["tags"] if inventory_file_metadata["tags"]
134
- [repo[:owner][:login]]
135
- end
136
-
137
- # Provides a value for the contact.email field.
138
- # Order of precedence:
139
- # 1. List of overrides
140
- # 2. CodeInventory metadata file
141
- # 3. GitHub organization email
142
- def contact_email(repo, inventory_file_metadata)
143
- return @overrides[:contact][:email] if @overrides.dig(:contact, :email)
144
- return inventory_file_metadata["contact"]["email"] if inventory_file_metadata.dig("contact", "email")
145
- org = client.organization(@org)
146
- org[:email]
147
- end
148
-
149
- # Provies a value for the repository field.
150
- # Order of precedence:
151
- # 1. List of overrides
152
- # 2. CodeInventory metadata file
153
- # 3. If repo is public, GitHub repository URL, otherwise nil
154
- def repository(repo, inventory_file_metadata)
155
- return @overrides[:repository] if @overrides[:repository]
156
- return inventory_file_metadata["repository"] if inventory_file_metadata["repository"]
157
- repo[:private] ? nil : repo[:html_url]
158
- end
159
-
160
- # Provies a value for the organization field (optional).
161
- # Order of precedence:
162
- # 1. List of overrides
163
- # 2. CodeInventory metadata file
164
- # 3. No organization field
165
- def organization(repo, inventory_file_metadata)
166
- return @overrides[:organization] if @overrides[:organization]
167
- return inventory_file_metadata["organization"] if inventory_file_metadata["organization"]
168
- nil
169
- end
170
-
171
- def client
172
- @client ||= Octokit::Client.new(@auth)
173
- end
174
- end
175
- end
1
+ require "codeinventory/github/source"
2
+ require "codeinventory/github/version"
@@ -0,0 +1,176 @@
1
+ require "octokit"
2
+ require "yaml"
3
+ require "base64"
4
+
5
+ module CodeInventory
6
+ module GitHub
7
+ class Source
8
+ attr_accessor :org, :overrides, :exclude
9
+
10
+ def initialize(auth, org, overrides: {}, exclude: [])
11
+ Octokit.auto_paginate = true
12
+ @auth = auth
13
+ @org = org
14
+ @overrides = overrides
15
+ @exclude = exclude
16
+ end
17
+
18
+ def projects
19
+ repos = client.organization_repositories(@org)
20
+ repos.delete_if { |repo| exclude.include? repo[:name] }
21
+ projects = []
22
+ repos.each do |repo|
23
+ inventory_file_metadata = inventory_file(repo)
24
+ unless inventory_file_metadata.dig("codeinventory", "exclude")
25
+ repo_metadata = {}
26
+ repo_metadata["name"] = name(repo, inventory_file_metadata)
27
+ repo_metadata["description"] = description(repo, inventory_file_metadata)
28
+ repo_metadata["license"] = license(repo, inventory_file_metadata)
29
+ repo_metadata["openSourceProject"] = open_source_project(repo, inventory_file_metadata)
30
+ repo_metadata["governmentWideReuseProject"] = government_wide_reuse_project(repo, inventory_file_metadata)
31
+ repo_metadata["tags"] = tags(repo, inventory_file_metadata)
32
+ repo_metadata["contact"] = { "email" => contact_email(repo, inventory_file_metadata) }
33
+ repo_metadata["repository"] = repository(repo, inventory_file_metadata)
34
+ organization = organization(repo, inventory_file_metadata)
35
+ repo_metadata["organization"] = organization(repo, inventory_file_metadata) unless organization.nil?
36
+ projects << repo_metadata
37
+ yield repo_metadata if block_given?
38
+ end
39
+ end
40
+ projects
41
+ end
42
+
43
+ # Checks if the repo has an inventory file. If so, loads its metadata.
44
+ def inventory_file(repo)
45
+ metadata = {}
46
+ return metadata if repo[:size] == 0 # Empty repo
47
+ filenames = [ ".codeinventory.yml", "codeinventory.yml", ".codeinventory.json", "codeinventory.json"]
48
+ repo_contents = client.contents(repo[:full_name], path: "/")
49
+ inventory_file = repo_contents.select { |file| filenames.include? file[:name] }.first
50
+ unless inventory_file.nil?
51
+ file_content = client.contents(repo[:full_name], path: inventory_file[:path])
52
+ raw_content = Base64.decode64(file_content[:content])
53
+ # Remove UTF-8 BOM if there is one; it throws off JSON.parse
54
+ raw_content.sub!("\xEF\xBB\xBF".force_encoding("ASCII-8BIT"), "")
55
+ if inventory_file[:name].end_with? ".yml"
56
+ metadata = YAML.load(raw_content).to_hash
57
+ elsif inventory_file[:name].end_with? ".json"
58
+ metadata = JSON.parse(raw_content)
59
+ end
60
+ end
61
+ metadata
62
+ end
63
+
64
+ # Provides a value for the name field.
65
+ # Order of precedence:
66
+ # 1. CodeInventory metadata file
67
+ # 2. GitHub repository name
68
+ def name(repo, inventory_file_metadata)
69
+ return inventory_file_metadata["name"] if inventory_file_metadata["name"]
70
+ repo[:name]
71
+ end
72
+
73
+ # Provides a value for the description field.
74
+ # Order of precedence:
75
+ # 1. List of overrides
76
+ # 2. CodeInventory metadata file
77
+ # 3. GitHub repository description
78
+ # 4. GitHub repository name
79
+ def description(repo, inventory_file_metadata)
80
+ return @overrides[:description] if @overrides[:description]
81
+ return inventory_file_metadata["description"] if inventory_file_metadata["description"]
82
+ return repo[:description] if repo[:description]
83
+ repo[:name]
84
+ end
85
+
86
+ # Provides a value for the license field.
87
+ # Order of precedence:
88
+ # 1. List of overrides
89
+ # 2. CodeInventory metadata file
90
+ # 3. LICENSE.md or LICENSE file in the repository
91
+ # 4. nil
92
+ def license(repo, inventory_file_metadata)
93
+ return @overrides[:license] if @overrides[:license]
94
+ return inventory_file_metadata["license"] if inventory_file_metadata["license"]
95
+ # Need to set header to quiet warning about using a GitHub preview feature
96
+ headers = { accept: "application/vnd.github.drax-preview+json" }
97
+ begin
98
+ license_meta = client.repository_license_contents(repo[:full_name], headers)
99
+ license = license_meta[:html_url]
100
+ rescue Octokit::NotFound ; end
101
+ license
102
+ end
103
+
104
+ # Provides a value for the openSourceProject field.
105
+ # Order of precedence:
106
+ # 1. List of overrides
107
+ # 2. CodeInventory metadata file
108
+ # 3. GitHub repository public/private status (public=1; private=0)
109
+ def open_source_project(repo, inventory_file_metadata)
110
+ return @overrides[:openSourceProject] if @overrides[:openSourceProject]
111
+ return inventory_file_metadata["openSourceProject"] if inventory_file_metadata["openSourceProject"]
112
+ repo[:private] ? 0 : 1
113
+ end
114
+
115
+ # Provides a value for the governmentWideReuseProject field.
116
+ # Order of precedence:
117
+ # 1. List of overrides
118
+ # 2. CodeInventory metadata file
119
+ # 3. 1 (assume government-wide reuse)
120
+ def government_wide_reuse_project(repo, inventory_file_metadata)
121
+ return @overrides[:governmentWideReuseProject] if @overrides[:governmentWideReuseProject]
122
+ return inventory_file_metadata["governmentWideReuseProject"] if inventory_file_metadata["governmentWideReuseProject"]
123
+ 1
124
+ end
125
+
126
+ # Provides a value for the tags field.
127
+ # Order of precedence:
128
+ # 1. List of overrides
129
+ # 2. CodeInventory metadata file
130
+ # 3. A single tag consisting of the org name.
131
+ def tags(repo, inventory_file_metadata)
132
+ return @overrides[:tags] if @overrides[:tags]
133
+ return inventory_file_metadata["tags"] if inventory_file_metadata["tags"]
134
+ [repo[:owner][:login]]
135
+ end
136
+
137
+ # Provides a value for the contact.email field.
138
+ # Order of precedence:
139
+ # 1. List of overrides
140
+ # 2. CodeInventory metadata file
141
+ # 3. GitHub organization email
142
+ def contact_email(repo, inventory_file_metadata)
143
+ return @overrides[:contact][:email] if @overrides.dig(:contact, :email)
144
+ return inventory_file_metadata["contact"]["email"] if inventory_file_metadata.dig("contact", "email")
145
+ org = client.organization(@org)
146
+ org[:email]
147
+ end
148
+
149
+ # Provies a value for the repository field.
150
+ # Order of precedence:
151
+ # 1. List of overrides
152
+ # 2. CodeInventory metadata file
153
+ # 3. If repo is public, GitHub repository URL, otherwise nil
154
+ def repository(repo, inventory_file_metadata)
155
+ return @overrides[:repository] if @overrides[:repository]
156
+ return inventory_file_metadata["repository"] if inventory_file_metadata["repository"]
157
+ repo[:private] ? nil : repo[:html_url]
158
+ end
159
+
160
+ # Provies a value for the organization field (optional).
161
+ # Order of precedence:
162
+ # 1. List of overrides
163
+ # 2. CodeInventory metadata file
164
+ # 3. No organization field
165
+ def organization(repo, inventory_file_metadata)
166
+ return @overrides[:organization] if @overrides[:organization]
167
+ return inventory_file_metadata["organization"] if inventory_file_metadata["organization"]
168
+ nil
169
+ end
170
+
171
+ def client
172
+ @client ||= Octokit::Client.new(@auth)
173
+ end
174
+ end
175
+ end
176
+ end
@@ -0,0 +1,5 @@
1
+ module CodeInventory
2
+ module GitHub
3
+ VERSION = "0.2.0"
4
+ end
5
+ end
@@ -5,11 +5,36 @@ require "codeinventory/github"
5
5
  module CodeInventory
6
6
  module CLI
7
7
  class App < Thor
8
- desc "github GITHUB_ACCESS_TOKEN GITHUB_ORG [OPTIONS]", "Build an inventory from GitHub"
9
- option :overrides, aliases: "-o", type: :hash, default: {}
10
- option :exclude, aliases: "-e", type: :array, default: []
11
- def github(access_token, org)
12
- source = CodeInventory::GitHub.new({ access_token: access_token }, org, overrides: options[:overrides], exclude: options[:exclude])
8
+ desc "github GITHUB_ORG [OPTIONS]", "Build an inventory from GitHub"
9
+ option "access-token", aliases: "-a", type: :string, banner: "ACCESS_TOKEN"
10
+ option "client-credentials", aliases: "-c", type: :string, banner: "CLIENT_ID:CLIENT_SECRET"
11
+ option "login", aliases: "-l", type: :string, banner: "USERNAME:PASSWORD"
12
+ option "overrides", aliases: "-o", type: :hash, default: {}
13
+ option "exclude", aliases: "-e", type: :array, default: []
14
+ def github(org)
15
+ unless !options["access-token"].nil? ^ !options["client-credentials"].nil? ^ !options["login"].nil?
16
+ puts "One authentication method is required (-a, -c, or -l)"
17
+ exit 1
18
+ end
19
+ auth = {}
20
+ if !options["access-token"].nil?
21
+ auth = { access_token: options["access-token"] }
22
+ elsif !options["client-credentials"].nil?
23
+ values = options["client-credentials"].split(":")
24
+ unless values.count == 2
25
+ puts "You must provide client credentials in the format CLIENT_ID:CLIENT_SECRET"
26
+ exit 1
27
+ end
28
+ auth = { client_id: values[0], client_secret: values[1] }
29
+ elsif !options["login"].nil?
30
+ values = options["login"].split(":")
31
+ unless values.count == 2
32
+ puts "You must provide a login in the format USERNAME:PASSWORD"
33
+ exit 1
34
+ end
35
+ auth = { login: values[0], password: values[1] }
36
+ end
37
+ source = CodeInventory::GitHub::Source.new(auth, org, overrides: options[:overrides], exclude: options[:exclude])
13
38
  inventory = CodeInventory::Inventory.new(source)
14
39
  puts JSON.pretty_generate(inventory.projects)
15
40
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: codeinventory-github
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.9
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jeff Fredrickson
@@ -127,6 +127,8 @@ files:
127
127
  - bin/setup
128
128
  - codeinventory-github.gemspec
129
129
  - lib/codeinventory/github.rb
130
+ - lib/codeinventory/github/source.rb
131
+ - lib/codeinventory/github/version.rb
130
132
  - lib/codeinventory_plugin.rb
131
133
  homepage: https://github.com/GSA/codeinventory-github
132
134
  licenses: