codeinventory 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.
- checksums.yaml +4 -4
- data/README.md +59 -8
- data/codeinventory.gemspec +1 -0
- data/exe/codeinv +5 -0
- data/lib/codeinventory/cli/app.rb +35 -0
- data/lib/codeinventory/cli.rb +1 -0
- data/lib/codeinventory/csv_file.rb +51 -0
- data/lib/codeinventory/json_file.rb +11 -0
- data/lib/codeinventory/version.rb +1 -1
- data/lib/codeinventory.rb +3 -6
- metadata +23 -6
- data/lib/codeinventory/source/csv_file.rb +0 -50
- data/lib/codeinventory/source/github.rb +0 -47
- data/lib/codeinventory/source/json_file.rb +0 -13
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 992cc66fc416b27e661d1aa3519a5bb2530bb06a
|
4
|
+
data.tar.gz: 500dbda2306c83785d09b89ce7ad63ef07eba0f1
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a1ee75116c0d295503b0b7db4411b9e3c2e3796ea7d188b19ff5c2f01771898a2989f0c924446f464afe1641aa160523a9b2d75ece4a6e1360bdb09523f7136f
|
7
|
+
data.tar.gz: f88d4b3e63b10e470fdef237521fbb186e35768369e10794268de2b514177a638198bde82bf894906913d8621dc90b7fe40285140d5b9794c83b9799a3b43809
|
data/README.md
CHANGED
@@ -6,9 +6,8 @@ The `codeinventory` gem is a tool to harvest project metadata from an agency's r
|
|
6
6
|
|
7
7
|
* JSON files
|
8
8
|
* CSV files
|
9
|
-
* GitHub
|
10
9
|
|
11
|
-
More sources can be added.
|
10
|
+
More sources can be added via plugins.
|
12
11
|
|
13
12
|
## Installation
|
14
13
|
|
@@ -28,20 +27,72 @@ Or install it yourself as:
|
|
28
27
|
|
29
28
|
## Usage
|
30
29
|
|
30
|
+
Basically:
|
31
|
+
|
31
32
|
```ruby
|
32
|
-
json_source = CodeInventory::
|
33
|
-
csv_source = CodeInventory::
|
34
|
-
|
33
|
+
json_source = CodeInventory::JSONFile.new(File.new("some_projects.json"))
|
34
|
+
csv_source = CodeInventory::CSVFile.new(File.new("more_projects.csv"))
|
35
|
+
|
36
|
+
inventory = CodeInventory::Inventory.new(json_source, csv_source)
|
37
|
+
inventory.projects # Returns an array of all projects in the JSON and CSV files
|
38
|
+
```
|
39
|
+
|
40
|
+
### JSON Source
|
41
|
+
|
42
|
+
When using `CodeInventory::JSONFile`, the source file is expected to be a JSON file in the following format:
|
43
|
+
|
44
|
+
```json
|
45
|
+
[
|
46
|
+
{
|
47
|
+
"name": "Product One",
|
48
|
+
"description": "An awesome product.",
|
49
|
+
"license": "http://www.usa.gov/publicdomain/label/1.0/",
|
50
|
+
"openSourceProject": 1,
|
51
|
+
"governmentWideReuseProject": 1,
|
52
|
+
"tags": [
|
53
|
+
"usa"
|
54
|
+
],
|
55
|
+
"contact": {
|
56
|
+
"email": "example@example.com"
|
57
|
+
}
|
58
|
+
},
|
59
|
+
{
|
60
|
+
"name": "Product Two",
|
61
|
+
"description": "Another awesome product.",
|
62
|
+
"license": "http://www.usa.gov/publicdomain/label/1.0/",
|
63
|
+
"openSourceProject": 0,
|
64
|
+
"governmentWideReuseProject": 0,
|
65
|
+
"tags": [
|
66
|
+
"national-security",
|
67
|
+
"top-secret"
|
68
|
+
],
|
69
|
+
"contact": {
|
70
|
+
"email": "example@example.com"
|
71
|
+
}
|
72
|
+
}
|
73
|
+
]
|
74
|
+
|
75
|
+
```
|
76
|
+
|
77
|
+
See the [Code.gov documentation](https://code.gov/#/policy-guide/docs/compliance/inventory-code) for specifics on required fields and value types.
|
78
|
+
|
79
|
+
### CSV Source
|
35
80
|
|
36
|
-
|
37
|
-
|
81
|
+
When using `CodeInventory::CSVFile`, the source file is expected to be a CSV file in the following format:
|
82
|
+
|
83
|
+
```csv
|
84
|
+
name,description,license,openSourceProject,governmentWideReuseProject,tags,contact.email
|
85
|
+
Product One,An awesome product.,http://www.usa.gov/publicdomain/label/1.0/,1,1,usa,example@example.com
|
86
|
+
Product Two,Another awesome product.,http://www.usa.gov/publicdomain/label/1.0/,0,0,"national-security,top-secret",example@example.com
|
38
87
|
```
|
39
88
|
|
89
|
+
See the [Code.gov documentation](https://code.gov/#/policy-guide/docs/compliance/inventory-code) for specifics on required fields and value types.
|
90
|
+
|
40
91
|
## Development
|
41
92
|
|
42
93
|
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.
|
43
94
|
|
44
|
-
To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb
|
95
|
+
To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in [`version.rb`](/lib/codeinventory/version.rb), and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
|
45
96
|
|
46
97
|
## Contributing
|
47
98
|
|
data/codeinventory.gemspec
CHANGED
data/exe/codeinv
ADDED
@@ -0,0 +1,35 @@
|
|
1
|
+
require "codeinventory"
|
2
|
+
require "thor"
|
3
|
+
require "pathname"
|
4
|
+
|
5
|
+
module CodeInventory
|
6
|
+
module CLI
|
7
|
+
class App < Thor
|
8
|
+
desc "csv FILENAME", "Build an inventory from a CSV file"
|
9
|
+
def csv(filename)
|
10
|
+
file = Pathname.new(filename)
|
11
|
+
unless File.exist? file
|
12
|
+
puts "No such file: #{file}"
|
13
|
+
exit 1
|
14
|
+
end
|
15
|
+
source = CodeInventory::CSVFile.new(file)
|
16
|
+
inventory = CodeInventory::Inventory.new(source)
|
17
|
+
projects = inventory.projects
|
18
|
+
puts JSON.pretty_generate(projects)
|
19
|
+
end
|
20
|
+
|
21
|
+
desc "json FILENAME", "Build an inventory from a JSON file"
|
22
|
+
def json(filename)
|
23
|
+
file = Pathname.new(filename)
|
24
|
+
unless File.exist? file
|
25
|
+
puts "No such file: #{file}"
|
26
|
+
exit 1
|
27
|
+
end
|
28
|
+
source = CodeInventory::JSONFile.new(file)
|
29
|
+
inventory = CodeInventory::Inventory.new(source)
|
30
|
+
projects = inventory.projects
|
31
|
+
puts JSON.pretty_generate(projects)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
require "codeinventory/cli/app"
|
@@ -0,0 +1,51 @@
|
|
1
|
+
require "csv"
|
2
|
+
|
3
|
+
module CodeInventory
|
4
|
+
class CSVFile
|
5
|
+
attr_reader :csv
|
6
|
+
|
7
|
+
def initialize(csv_file)
|
8
|
+
@csv = CSV.read(csv_file, { headers: true, converters: [ :integer ] })
|
9
|
+
validate_headers
|
10
|
+
end
|
11
|
+
|
12
|
+
def projects
|
13
|
+
@csv.collect do |row|
|
14
|
+
csv_data = row.to_hash
|
15
|
+
csv_data.inject({}) do |memo, pair|
|
16
|
+
csv_header, csv_value = pair
|
17
|
+
case
|
18
|
+
when csv_header == "tags"
|
19
|
+
new_pair = { "tags" => csv_value.split(",").collect { |tag| tag.strip } }
|
20
|
+
when csv_header.include?(".")
|
21
|
+
new_pair = dotted_to_nested(csv_header, csv_value)
|
22
|
+
else
|
23
|
+
new_pair = { csv_header => csv_value }
|
24
|
+
end
|
25
|
+
memo.merge(new_pair)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
private
|
31
|
+
|
32
|
+
# Convert a dotted notation header and a value to a nested hash
|
33
|
+
# e.g., "contact.email" header with value "me@example.com" becomes
|
34
|
+
# { "contact" => { "email" => "me@example.com" } }
|
35
|
+
def dotted_to_nested(path, value)
|
36
|
+
path.split(".").reverse.inject(value) do |hash, element|
|
37
|
+
{ element => hash }
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def validate_headers
|
42
|
+
required_headers = [ "name", "description", "license", "openSourceProject", "governmentWideReuseProject", "tags", "contact.email" ]
|
43
|
+
required_headers.each do |required|
|
44
|
+
raise FileFormatError unless @csv.headers.include? required
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
class FileFormatError < StandardError
|
50
|
+
end
|
51
|
+
end
|
data/lib/codeinventory.rb
CHANGED
@@ -1,8 +1,5 @@
|
|
1
1
|
require "codeinventory/version"
|
2
2
|
require "codeinventory/inventory"
|
3
|
-
require "codeinventory/
|
4
|
-
require "codeinventory/
|
5
|
-
require "codeinventory/
|
6
|
-
|
7
|
-
module CodeInventory
|
8
|
-
end
|
3
|
+
require "codeinventory/cli"
|
4
|
+
require "codeinventory/json_file"
|
5
|
+
require "codeinventory/csv_file"
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: codeinventory
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
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:
|
11
|
+
date: 2017-01-05 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -94,11 +94,26 @@ dependencies:
|
|
94
94
|
- - "~>"
|
95
95
|
- !ruby/object:Gem::Version
|
96
96
|
version: '4.6'
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: thor
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - "~>"
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '0.19'
|
104
|
+
type: :runtime
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - "~>"
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '0.19'
|
97
111
|
description: Harvests project metadata from an agency's repositories to build a code
|
98
112
|
inventory. This helps agencies comply with the Federal Source Code Policy.
|
99
113
|
email:
|
100
114
|
- jeffrey.fredrickson@gsa.gov
|
101
|
-
executables:
|
115
|
+
executables:
|
116
|
+
- codeinv
|
102
117
|
extensions: []
|
103
118
|
extra_rdoc_files: []
|
104
119
|
files:
|
@@ -112,11 +127,13 @@ files:
|
|
112
127
|
- bin/console
|
113
128
|
- bin/setup
|
114
129
|
- codeinventory.gemspec
|
130
|
+
- exe/codeinv
|
115
131
|
- lib/codeinventory.rb
|
132
|
+
- lib/codeinventory/cli.rb
|
133
|
+
- lib/codeinventory/cli/app.rb
|
134
|
+
- lib/codeinventory/csv_file.rb
|
116
135
|
- lib/codeinventory/inventory.rb
|
117
|
-
- lib/codeinventory/
|
118
|
-
- lib/codeinventory/source/github.rb
|
119
|
-
- lib/codeinventory/source/json_file.rb
|
136
|
+
- lib/codeinventory/json_file.rb
|
120
137
|
- lib/codeinventory/version.rb
|
121
138
|
homepage: https://github.com/GSA/codeinventory
|
122
139
|
licenses:
|
@@ -1,50 +0,0 @@
|
|
1
|
-
require "csv"
|
2
|
-
|
3
|
-
module CodeInventory
|
4
|
-
module Source
|
5
|
-
class CSVFile
|
6
|
-
attr_reader :csv
|
7
|
-
|
8
|
-
def initialize(csv_file)
|
9
|
-
@csv = CSV.read(csv_file, { headers: true, converters: [ :integer ] })
|
10
|
-
validate_headers
|
11
|
-
end
|
12
|
-
|
13
|
-
def projects
|
14
|
-
@csv.collect do |row|
|
15
|
-
csv_data = row.to_hash
|
16
|
-
csv_data.inject({}) do |memo, pair|
|
17
|
-
csv_header, csv_value = pair
|
18
|
-
case
|
19
|
-
when csv_header == "tags"
|
20
|
-
new_pair = { "tags" => csv_value.split(",").collect { |tag| tag.strip } }
|
21
|
-
when csv_header.include?(".")
|
22
|
-
new_pair = dotted_to_nested(csv_header, csv_value)
|
23
|
-
else
|
24
|
-
new_pair = { csv_header => csv_value }
|
25
|
-
end
|
26
|
-
memo.merge(new_pair)
|
27
|
-
end
|
28
|
-
end
|
29
|
-
end
|
30
|
-
|
31
|
-
private
|
32
|
-
|
33
|
-
def dotted_to_nested(path, value)
|
34
|
-
path.split(".").reverse.inject(value) do |hash, element|
|
35
|
-
{ element => hash }
|
36
|
-
end
|
37
|
-
end
|
38
|
-
|
39
|
-
def validate_headers
|
40
|
-
required_headers = [ "name", "description", "license", "openSourceProject", "governmentWideReuseProject", "tags", "contact.email" ]
|
41
|
-
required_headers.each do |required|
|
42
|
-
raise FileFormatError unless @csv.headers.include? required
|
43
|
-
end
|
44
|
-
end
|
45
|
-
end
|
46
|
-
|
47
|
-
class FileFormatError < StandardError
|
48
|
-
end
|
49
|
-
end
|
50
|
-
end
|
@@ -1,47 +0,0 @@
|
|
1
|
-
require "octokit"
|
2
|
-
require "yaml"
|
3
|
-
require "base64"
|
4
|
-
|
5
|
-
module CodeInventory
|
6
|
-
module Source
|
7
|
-
class GitHub
|
8
|
-
attr_accessor :org
|
9
|
-
|
10
|
-
def initialize(access_token:, org:)
|
11
|
-
Octokit.auto_paginate = true
|
12
|
-
@access_token = access_token
|
13
|
-
@org = org
|
14
|
-
end
|
15
|
-
|
16
|
-
def projects
|
17
|
-
repos = client.organization_repositories(@org)
|
18
|
-
projects = []
|
19
|
-
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
|
38
|
-
end
|
39
|
-
projects
|
40
|
-
end
|
41
|
-
|
42
|
-
def client
|
43
|
-
@client ||= Octokit::Client.new(access_token: @access_token)
|
44
|
-
end
|
45
|
-
end
|
46
|
-
end
|
47
|
-
end
|