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 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
@@ -15,3 +15,5 @@ spec/reports
15
15
  test/tmp
16
16
  test/version_tmp
17
17
  tmp
18
+
19
+ /.env
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
@@ -1,3 +1,6 @@
1
+ #ruby=ruby-2.0.0
2
+ #ruby-gemset=cid
3
+
1
4
  source 'https://rubygems.org'
2
5
 
3
6
  # Specify your gem's dependencies in cid.gemspec
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,7 @@
1
+ Given(/^I set up a new git repo$/) do
2
+ steps %{
3
+ And I run `git init`
4
+ And I run `git add .`
5
+ And I run `git commit -am 'New git repo'`
6
+ }
7
+ end
@@ -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
@@ -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
@@ -13,7 +13,7 @@ module Cid
13
13
  begin
14
14
  schema = Csvlint::Schema.load_from_json_table(File.new(Dir["#{path}/schema.json"][0]))
15
15
  rescue
16
- # Error! No schema in place!
16
+ schema = nil
17
17
  end
18
18
 
19
19
  Dir["#{path}/*.csv"].each do |csv|
data/lib/cid/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Cid
2
- VERSION = "0.0.2"
2
+ VERSION = "0.1.0"
3
3
  end
data/lib/cid.rb CHANGED
@@ -1,2 +1,13 @@
1
+ module Cid
2
+
3
+ module Helpers
4
+ end
5
+
6
+ end
7
+
8
+ require "cid/helpers/github"
9
+
1
10
  require "cid/version"
2
11
  require "cid/validation"
12
+ require "cid/datapackage"
13
+ require "cid/publish"
@@ -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