cid 0.0.2 → 0.1.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 +7 -0
- data/.gitignore +2 -0
- data/.travis.yml +13 -0
- data/Gemfile +3 -0
- data/Rakefile +16 -0
- data/bin/cid +18 -0
- data/cid.gemspec +11 -0
- data/features/publish.feature +29 -0
- data/features/step_definitions/cid.rb +7 -0
- data/features/support/env.rb +28 -0
- data/features/validate.feature +30 -0
- data/lib/cid/datapackage.rb +57 -0
- data/lib/cid/helpers/github.rb +91 -0
- data/lib/cid/publish.rb +28 -0
- data/lib/cid/validation.rb +1 -1
- data/lib/cid/version.rb +1 -1
- data/lib/cid.rb +11 -0
- data/spec/cassettes/Cid_Publish/should_be_able_to_create_a_new_blob.yml +81 -0
- data/spec/cassettes/Cid_Publish/should_be_able_to_create_a_new_commit_from_a_tree.yml +244 -0
- data/spec/cassettes/Cid_Publish/should_be_able_to_create_a_tree_with_the_new_blob_in_it_given_a_filename.yml +240 -0
- data/spec/cassettes/Cid_Publish/should_be_able_to_fetch_the_default_branch_for_a_repo.yml +83 -0
- data/spec/cassettes/Cid_Publish/should_be_able_to_get_a_blob_sha_for_a_file_on_a_branch.yml +82 -0
- data/spec/cassettes/Cid_Publish/should_be_able_to_get_latest_commit_SHA_on_a_branch.yml +83 -0
- data/spec/cassettes/Cid_Publish/should_push_to_the_default_branch.yml +583 -0
- data/spec/datapackage_spec.rb +27 -0
- data/spec/fixtures/multiple_files/datapackage.json +71 -0
- data/spec/fixtures/no_schema/votes/votes-1.csv +13 -0
- data/spec/fixtures/valid/datapackage.json +71 -0
- data/spec/publish_spec.rb +45 -0
- data/spec/spec_helper.rb +10 -0
- data/spec/validate_spec.rb +9 -0
- metadata +209 -35
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 08cc9c8917f69e177896bea64e370d42af222bf7
|
4
|
+
data.tar.gz: 2a54b94ce968d84233d8f8de41883b214ca797a8
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: a6ad26c203b9c356578ed153e8cf04182e4d230182e2d07158e8ab41d24a820e4da6409bdac389935a32ace32b31ff28bd6d29a85a0fe0a06c372a6bea0355ab
|
7
|
+
data.tar.gz: 3da71f338651e9086f3c7d6a2f2f9219b6f7a867a5c3859a4f2902072175355b479e21380e830a2a224dff9981099e27c808ac83b447cb54ad6ce35ab74d7a0d
|
data/.gitignore
CHANGED
data/.travis.yml
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
rvm:
|
2
|
+
- 2.0.0
|
3
|
+
notifications:
|
4
|
+
irc:
|
5
|
+
channels:
|
6
|
+
- irc.freenode.net#theodi
|
7
|
+
template:
|
8
|
+
- '%{repository} %{branch} - %{message} %{build_url}'
|
9
|
+
on_success: change
|
10
|
+
on_failure: always
|
11
|
+
env:
|
12
|
+
global:
|
13
|
+
secure: HZhBJjfU3C6ub01Ioong30m3NMAoT5re8XwDg3VQ86L2Z/lz/Zz7FU+cJvLcJJaO7Jj7UmZK0ov0kFxIesIJMV/KsMfmMOlJjTMz0K5g/C/NaTIKlZTY4Mg53oS4fh0ZNogtfkttOfL/JLyNS2buuSEuMtFtC0+DXlqklQ/JT3w=
|
data/Gemfile
CHANGED
data/Rakefile
CHANGED
@@ -1 +1,17 @@
|
|
1
1
|
require "bundler/gem_tasks"
|
2
|
+
|
3
|
+
$:.unshift File.join( File.dirname(__FILE__), "lib")
|
4
|
+
|
5
|
+
require 'rubygems'
|
6
|
+
require 'cucumber'
|
7
|
+
require 'cucumber/rake/task'
|
8
|
+
require 'coveralls/rake/task'
|
9
|
+
require 'rspec/core/rake_task'
|
10
|
+
|
11
|
+
RSpec::Core::RakeTask.new(:spec)
|
12
|
+
Coveralls::RakeTask.new
|
13
|
+
Cucumber::Rake::Task.new(:features) do |t|
|
14
|
+
t.cucumber_opts = "features --format pretty"
|
15
|
+
end
|
16
|
+
|
17
|
+
task :default => [:spec, :features, 'coveralls:push']
|
data/bin/cid
CHANGED
@@ -48,4 +48,22 @@ if ARGV[0] == "validate"
|
|
48
48
|
|
49
49
|
exit code
|
50
50
|
|
51
|
+
elsif ARGV[0] == "publish"
|
52
|
+
|
53
|
+
if ARGV[1]
|
54
|
+
source = ARGV[1]
|
55
|
+
else
|
56
|
+
source = "."
|
57
|
+
end
|
58
|
+
|
59
|
+
datapackage = Cid::Datapackage.new(source)
|
60
|
+
datapackage.create
|
61
|
+
datapackage.write
|
62
|
+
if File.exist?("#{source}/.git")
|
63
|
+
datapackage.publish
|
64
|
+
puts "Changes pushed successfully".colorize(:green)
|
65
|
+
else
|
66
|
+
puts "Git repo not found".colorize(:red)
|
67
|
+
exit 1
|
68
|
+
end
|
51
69
|
end
|
data/cid.gemspec
CHANGED
@@ -19,11 +19,22 @@ Gem::Specification.new do |spec|
|
|
19
19
|
|
20
20
|
spec.add_dependency "csvlint"
|
21
21
|
spec.add_dependency "colorize"
|
22
|
+
spec.add_dependency "json"
|
23
|
+
spec.add_dependency "git"
|
24
|
+
spec.add_dependency "github_api"
|
25
|
+
spec.add_dependency "dotenv"
|
26
|
+
spec.add_dependency "memoist"
|
22
27
|
|
23
28
|
spec.add_development_dependency "bundler", "~> 1.3"
|
24
29
|
spec.add_development_dependency "rake"
|
25
30
|
spec.add_development_dependency "rspec"
|
26
31
|
spec.add_development_dependency "pry"
|
32
|
+
spec.add_development_dependency "pry-remote"
|
27
33
|
spec.add_development_dependency "coveralls"
|
34
|
+
spec.add_development_dependency "cucumber"
|
35
|
+
spec.add_development_dependency "aruba"
|
36
|
+
spec.add_development_dependency "spork"
|
37
|
+
spec.add_development_dependency "vcr"
|
38
|
+
spec.add_development_dependency "webmock"
|
28
39
|
|
29
40
|
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
@publish
|
2
|
+
Feature: Publish a datapackage
|
3
|
+
|
4
|
+
Scenario: Create datapackage
|
5
|
+
Given I run `cp -r ../../spec/fixtures/valid valid`
|
6
|
+
And I cd to "valid"
|
7
|
+
When I run `cid publish`
|
8
|
+
And I run `cat datapackage.json`
|
9
|
+
Then the output should contain "votes/votes-1.csv"
|
10
|
+
|
11
|
+
Scenario: Create datapackage with new files
|
12
|
+
Given I run `cp -r ../../spec/fixtures/multiple_files multiple_files`
|
13
|
+
And I cd to "multiple_files"
|
14
|
+
When I run `cid publish`
|
15
|
+
And I run `cat datapackage.json`
|
16
|
+
Then the output should contain "votes/votes-1.csv"
|
17
|
+
And the output should contain "votes/votes-2.csv"
|
18
|
+
|
19
|
+
Scenario: Return error if not in a git repo
|
20
|
+
Given I run `cp -r ../../spec/fixtures/multiple_files multiple_files`
|
21
|
+
And I cd to "multiple_files"
|
22
|
+
When I run `cid publish`
|
23
|
+
Then the output should contain "Git repo not found"
|
24
|
+
|
25
|
+
Scenario: Sucessfully push to Github
|
26
|
+
Given I run `git clone https://github.com/theodi/cid-test.git`
|
27
|
+
And I cd to "cid-test"
|
28
|
+
When I successfully run `cid publish`
|
29
|
+
Then the output should contain "Changes pushed successfully"
|
@@ -0,0 +1,28 @@
|
|
1
|
+
$:.unshift File.join( File.dirname(__FILE__), "..", "..", "lib")
|
2
|
+
|
3
|
+
require 'rspec/expectations'
|
4
|
+
require 'pry'
|
5
|
+
require 'pry-remote'
|
6
|
+
require 'spork'
|
7
|
+
require 'aruba/cucumber'
|
8
|
+
require 'dotenv'
|
9
|
+
|
10
|
+
Dotenv.load
|
11
|
+
|
12
|
+
World(RSpec::Matchers)
|
13
|
+
|
14
|
+
Before do
|
15
|
+
@aruba_timeout_seconds = 10
|
16
|
+
end
|
17
|
+
|
18
|
+
Before('@validate') do
|
19
|
+
@dirs = ["#{File.dirname(__FILE__)}/../.."]
|
20
|
+
end
|
21
|
+
|
22
|
+
After('@publish') do
|
23
|
+
`rm -rf tmp/aruba/`
|
24
|
+
end
|
25
|
+
|
26
|
+
Spork.each_run do
|
27
|
+
require 'cid'
|
28
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
@validate
|
2
|
+
Feature: Validate a datapackage
|
3
|
+
|
4
|
+
Scenario: Package with a single CSV
|
5
|
+
When I cd to "spec/fixtures/valid"
|
6
|
+
And I run `cid validate`
|
7
|
+
Then the output should contain "votes/votes-1.csv is VALID"
|
8
|
+
|
9
|
+
Scenario: Package with multiple CSVs
|
10
|
+
When I cd to "spec/fixtures/multiple_files"
|
11
|
+
And I run `cid validate`
|
12
|
+
Then the output should contain "votes/votes-1.csv is VALID"
|
13
|
+
And the output should contain "votes/votes-2.csv is VALID"
|
14
|
+
|
15
|
+
Scenario: Package with multiple folders
|
16
|
+
When I cd to "spec/fixtures/multiple_folders"
|
17
|
+
And I run `cid validate`
|
18
|
+
Then the output should contain "seats/seats-1.csv is VALID"
|
19
|
+
And the output should contain "seats/seats-2.csv is VALID"
|
20
|
+
And the output should contain "votes/votes-1.csv is VALID"
|
21
|
+
And the output should contain "votes/votes-2.csv is VALID"
|
22
|
+
|
23
|
+
Scenario: Package with invalid CSV
|
24
|
+
When I cd to "spec/fixtures/invalid"
|
25
|
+
And I run `cid validate`
|
26
|
+
Then the output should contain "votes/votes-1.csv is INVALID"
|
27
|
+
|
28
|
+
Scenario: Specify directory
|
29
|
+
When I run `cid validate spec/fixtures/valid`
|
30
|
+
Then the output should contain "votes/votes-1.csv is VALID"
|
@@ -0,0 +1,57 @@
|
|
1
|
+
require 'csvlint'
|
2
|
+
require 'json'
|
3
|
+
|
4
|
+
module Cid
|
5
|
+
|
6
|
+
class Datapackage
|
7
|
+
|
8
|
+
attr_accessor :json
|
9
|
+
|
10
|
+
def initialize(path)
|
11
|
+
@path = path
|
12
|
+
begin
|
13
|
+
@datapackage = JSON.parse(File.new("#{@path}/datapackage.json").read)
|
14
|
+
rescue
|
15
|
+
return "No datapackage present!"
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def create
|
20
|
+
# Clear out all the resources
|
21
|
+
@datapackage["resources"] = []
|
22
|
+
|
23
|
+
paths = Dir.glob("#{@path}/*/")
|
24
|
+
|
25
|
+
paths.each do |path|
|
26
|
+
schema = JSON.parse(File.new(Dir["#{path}/schema.json"][0]).read)
|
27
|
+
|
28
|
+
Dir["#{path}*.csv"].each do |csv|
|
29
|
+
@datapackage["resources"] << {
|
30
|
+
name: File.basename(csv, ".csv"),
|
31
|
+
path: csv.split("/").last(2).join("/"),
|
32
|
+
format: "csv",
|
33
|
+
mediatype: "text/csv",
|
34
|
+
bytes: File.size(csv),
|
35
|
+
schema: {
|
36
|
+
fields: schema["fields"]
|
37
|
+
}
|
38
|
+
}
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
@json = @datapackage.to_json
|
43
|
+
end
|
44
|
+
|
45
|
+
def write
|
46
|
+
self.create if @json.nil?
|
47
|
+
File.open("#{@path}/datapackage.json", 'w') { |f| f.write(@json) }
|
48
|
+
end
|
49
|
+
|
50
|
+
def publish
|
51
|
+
git = Cid::Publish.new(@path, ENV['GITHUB_OAUTH_TOKEN'])
|
52
|
+
git.publish
|
53
|
+
end
|
54
|
+
|
55
|
+
end
|
56
|
+
|
57
|
+
end
|
@@ -0,0 +1,91 @@
|
|
1
|
+
require 'base64'
|
2
|
+
require 'github_api'
|
3
|
+
require 'memoist'
|
4
|
+
|
5
|
+
module Cid::Helpers::Github
|
6
|
+
|
7
|
+
extend Memoist
|
8
|
+
|
9
|
+
GITHUB_REPO_REGEX = /github.com[:\/]([^\/]*)\/([^\.]*)/
|
10
|
+
|
11
|
+
def github
|
12
|
+
Github.new oauth_token: @oauth_token
|
13
|
+
end
|
14
|
+
memoize :github
|
15
|
+
|
16
|
+
def user
|
17
|
+
match = @git_url.match GITHUB_REPO_REGEX
|
18
|
+
match ? match[1] : nil
|
19
|
+
end
|
20
|
+
memoize :user
|
21
|
+
|
22
|
+
def repo
|
23
|
+
match = @git_url.match GITHUB_REPO_REGEX
|
24
|
+
match ? match[2] : nil
|
25
|
+
end
|
26
|
+
memoize :repo
|
27
|
+
|
28
|
+
def default_branch
|
29
|
+
repository = github.repos.get user, repo
|
30
|
+
repository.default_branch
|
31
|
+
end
|
32
|
+
memoize :default_branch
|
33
|
+
|
34
|
+
def latest_commit(branch_name)
|
35
|
+
branch_data = github.repos.branch user, repo, branch_name
|
36
|
+
branch_data['commit']['sha']
|
37
|
+
end
|
38
|
+
memoize :latest_commit
|
39
|
+
|
40
|
+
def tree(branch)
|
41
|
+
github.git_data.trees.get user, repo, branch
|
42
|
+
end
|
43
|
+
memoize :tree
|
44
|
+
|
45
|
+
def blob_shas(branch, path)
|
46
|
+
tree = tree branch
|
47
|
+
Hash[tree['tree'].select{|x| x['path'] =~ /^#{path}$/ && x['type'] == 'blob'}.map{|x| [x.path, x.sha]}]
|
48
|
+
end
|
49
|
+
memoize :blob_shas
|
50
|
+
|
51
|
+
def blob_content(sha)
|
52
|
+
blob = github.git_data.blobs.get user, repo, sha
|
53
|
+
if blob['encoding'] == 'base64'
|
54
|
+
Base64.decode64(blob['content'])
|
55
|
+
else
|
56
|
+
blob['content']
|
57
|
+
end
|
58
|
+
end
|
59
|
+
memoize :blob_content
|
60
|
+
|
61
|
+
|
62
|
+
def create_blob(content)
|
63
|
+
blob = github.git_data.blobs.create user, repo, "content" => content, "encoding" => "utf-8"
|
64
|
+
blob['sha']
|
65
|
+
end
|
66
|
+
|
67
|
+
def add_blob_to_tree(sha, filename)
|
68
|
+
tree = tree default_branch
|
69
|
+
new_tree = github.git_data.trees.create user, repo, "base_tree" => tree['sha'], "tree" => [
|
70
|
+
"path" => filename,
|
71
|
+
"mode" => "100644",
|
72
|
+
"type" => "blob",
|
73
|
+
"sha" => sha
|
74
|
+
]
|
75
|
+
new_tree['sha']
|
76
|
+
end
|
77
|
+
|
78
|
+
def commit(sha)
|
79
|
+
parent = latest_commit(default_branch)
|
80
|
+
commit = github.git_data.commits.create user, repo, "message" => "Updated datapackage.json",
|
81
|
+
"parents" => [parent],
|
82
|
+
"tree" => sha
|
83
|
+
commit['sha']
|
84
|
+
end
|
85
|
+
|
86
|
+
def push(sha)
|
87
|
+
branch = github.git_data.references.update user, repo, "heads/#{default_branch}", "sha" => sha
|
88
|
+
branch['ref']
|
89
|
+
end
|
90
|
+
|
91
|
+
end
|
data/lib/cid/publish.rb
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
require 'git'
|
2
|
+
|
3
|
+
module Cid
|
4
|
+
|
5
|
+
class Publish
|
6
|
+
|
7
|
+
include Cid::Helpers::Github
|
8
|
+
|
9
|
+
GITHUB_REPO_REGEX = /github.com[:\/]([^\/]*)\/([^\.]*)/
|
10
|
+
|
11
|
+
def initialize(path, oauth_token)
|
12
|
+
g = Git.open(path)
|
13
|
+
@path = path
|
14
|
+
@git_url = g.config["remote.origin.url"]
|
15
|
+
@oauth_token = oauth_token
|
16
|
+
end
|
17
|
+
|
18
|
+
def publish
|
19
|
+
name, content = "datapackage.json", File.read("#{@path}/datapackage.json")
|
20
|
+
blob_sha = create_blob(content)
|
21
|
+
tree_sha = add_blob_to_tree(blob_sha, name)
|
22
|
+
commit_sha = commit(tree_sha)
|
23
|
+
push(commit_sha)
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
data/lib/cid/validation.rb
CHANGED
data/lib/cid/version.rb
CHANGED
data/lib/cid.rb
CHANGED
@@ -0,0 +1,81 @@
|
|
1
|
+
---
|
2
|
+
http_interactions:
|
3
|
+
- request:
|
4
|
+
method: post
|
5
|
+
uri: https://api.github.com/repos/theodi/cid-test/git/blobs?access_token=<GITHUB_OAUTH_TOKEN>
|
6
|
+
body:
|
7
|
+
encoding: UTF-8
|
8
|
+
string: '{"content":"new blob content","encoding":"utf-8"}'
|
9
|
+
headers:
|
10
|
+
Accept:
|
11
|
+
- application/vnd.github.v3+json,application/vnd.github.beta+json;q=0.5,application/json;q=0.1
|
12
|
+
Accept-Charset:
|
13
|
+
- utf-8
|
14
|
+
User-Agent:
|
15
|
+
- Github Ruby Gem 0.11.3
|
16
|
+
Content-Type:
|
17
|
+
- application/json
|
18
|
+
Authorization:
|
19
|
+
- Token token="<GITHUB_OAUTH_TOKEN>"
|
20
|
+
Accept-Encoding:
|
21
|
+
- gzip;q=1.0,deflate;q=0.6,identity;q=0.3
|
22
|
+
response:
|
23
|
+
status:
|
24
|
+
code: 201
|
25
|
+
message: Created
|
26
|
+
headers:
|
27
|
+
Server:
|
28
|
+
- GitHub.com
|
29
|
+
Date:
|
30
|
+
- Thu, 22 May 2014 14:09:04 GMT
|
31
|
+
Content-Type:
|
32
|
+
- application/json; charset=utf-8
|
33
|
+
Status:
|
34
|
+
- 201 Created
|
35
|
+
X-Ratelimit-Limit:
|
36
|
+
- '5000'
|
37
|
+
X-Ratelimit-Remaining:
|
38
|
+
- '4998'
|
39
|
+
X-Ratelimit-Reset:
|
40
|
+
- '1400771341'
|
41
|
+
Cache-Control:
|
42
|
+
- private, max-age=60, s-maxage=60
|
43
|
+
Etag:
|
44
|
+
- '"3cb71254860221b3fe02e4d6afd3b069"'
|
45
|
+
X-Oauth-Scopes:
|
46
|
+
- gist, repo, user
|
47
|
+
X-Accepted-Oauth-Scopes:
|
48
|
+
- ''
|
49
|
+
Location:
|
50
|
+
- https://api.github.com/repos/theodi/cid-test/git/blobs/28b552e7359c5c3bbe947749aab70d18e3ea554b
|
51
|
+
Vary:
|
52
|
+
- Accept, Authorization, Cookie, X-GitHub-OTP
|
53
|
+
X-Github-Media-Type:
|
54
|
+
- github.v3; format=json
|
55
|
+
X-Xss-Protection:
|
56
|
+
- 1; mode=block
|
57
|
+
X-Frame-Options:
|
58
|
+
- deny
|
59
|
+
Content-Security-Policy:
|
60
|
+
- default-src 'none'
|
61
|
+
Content-Length:
|
62
|
+
- '154'
|
63
|
+
Access-Control-Allow-Credentials:
|
64
|
+
- 'true'
|
65
|
+
Access-Control-Expose-Headers:
|
66
|
+
- ETag, Link, X-GitHub-OTP, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset,
|
67
|
+
X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Poll-Interval
|
68
|
+
Access-Control-Allow-Origin:
|
69
|
+
- '*'
|
70
|
+
X-Github-Request-Id:
|
71
|
+
- 4F4C59B3:0FE8:383DBFF:537E0500
|
72
|
+
Strict-Transport-Security:
|
73
|
+
- max-age=31536000
|
74
|
+
X-Content-Type-Options:
|
75
|
+
- nosniff
|
76
|
+
body:
|
77
|
+
encoding: UTF-8
|
78
|
+
string: '{"sha":"28b552e7359c5c3bbe947749aab70d18e3ea554b","url":"https://api.github.com/repos/theodi/cid-test/git/blobs/28b552e7359c5c3bbe947749aab70d18e3ea554b"}'
|
79
|
+
http_version:
|
80
|
+
recorded_at: Thu, 22 May 2014 14:09:09 GMT
|
81
|
+
recorded_with: VCR 2.4.0
|