magnum-payload 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (42) hide show
  1. checksums.yaml +15 -0
  2. data/.gitignore +24 -0
  3. data/.rspec +2 -0
  4. data/Gemfile +6 -0
  5. data/LICENSE +18 -0
  6. data/README.md +107 -0
  7. data/Rakefile +10 -0
  8. data/lib/magnum/payload/base.rb +62 -0
  9. data/lib/magnum/payload/beanstalk.rb +43 -0
  10. data/lib/magnum/payload/bitbucket.rb +53 -0
  11. data/lib/magnum/payload/custom.rb +19 -0
  12. data/lib/magnum/payload/github.rb +50 -0
  13. data/lib/magnum/payload/gitlab.rb +38 -0
  14. data/lib/magnum/payload/gitslice.rb +21 -0
  15. data/lib/magnum/payload/message_parser.rb +11 -0
  16. data/lib/magnum/payload/version.rb +5 -0
  17. data/lib/magnum/payload.rb +24 -0
  18. data/magnum-payload.gemspec +23 -0
  19. data/spec/fixtures/beanstalk/git.json +28 -0
  20. data/spec/fixtures/beanstalk/hg.json +27 -0
  21. data/spec/fixtures/beanstalk/svn.json +15 -0
  22. data/spec/fixtures/bitbucket/git.json +48 -0
  23. data/spec/fixtures/bitbucket/hg.json +48 -0
  24. data/spec/fixtures/github/deleted.json +39 -0
  25. data/spec/fixtures/github/forced.json +58 -0
  26. data/spec/fixtures/github/new_branch.json +77 -0
  27. data/spec/fixtures/github/new_tag.json +58 -0
  28. data/spec/fixtures/github.json +113 -0
  29. data/spec/fixtures/gitlab/commits.json +34 -0
  30. data/spec/fixtures/gitlab/create_branch.json +15 -0
  31. data/spec/fixtures/gitlab/delete_branch.json +15 -0
  32. data/spec/fixtures/gitslice.json +9 -0
  33. data/spec/payload/base_spec.rb +52 -0
  34. data/spec/payload/beanstalk_spec.rb +114 -0
  35. data/spec/payload/bitbucket_spec.rb +94 -0
  36. data/spec/payload/github_spec.rb +74 -0
  37. data/spec/payload/gitlab_spec.rb +53 -0
  38. data/spec/payload/gitslice_spec.rb +33 -0
  39. data/spec/payload/message_parser_spec.rb +45 -0
  40. data/spec/payload_spec.rb +35 -0
  41. data/spec/spec_helper.rb +17 -0
  42. metadata +177 -0
checksums.yaml ADDED
@@ -0,0 +1,15 @@
1
+ ---
2
+ !binary "U0hBMQ==":
3
+ metadata.gz: !binary |-
4
+ NWM5YzVmNTc0ZTJhZTIwNDA4OGExODViN2E2NDdkOWViMjI4MWQxNw==
5
+ data.tar.gz: !binary |-
6
+ NWQzZjM0NmZiYWNiMzhhYzgwM2MxZWVhY2RkNzdmMjVjODMyOTIyYQ==
7
+ !binary "U0hBNTEy":
8
+ metadata.gz: !binary |-
9
+ MDM2MWEyNzhiNjkxYTI3OTZiMDI3M2VmYjBjYTgwYWQzOGRjNmFjNmE2Zjg4
10
+ MWFmOTFjZThjNTBlOWEwYmI2NzgxMTUzY2I4N2I5Y2NjYmY4M2I0MDg5NmNj
11
+ NDE0NTliNjlmMzEzOWRiYTBmZmRlM2MyNTNjZDBkYjFhNmU4MDk=
12
+ data.tar.gz: !binary |-
13
+ OGVmMGM2ZTU5MjFmNmFmZDQwOWVkOTE3M2UzZTMxYTNmYTI1N2E1ZWQzNTVk
14
+ NTc3MWFmNWUyZGIxOTAzMTZhZmIyNjE1ODgxYjQ1NGFlYmM1MWFkZmIyNGNj
15
+ MTA2Y2YzYjJjNWM5ODRlYTAwMjAwMzA5MzFiMzIwODEyZTc1OWY=
data/.gitignore ADDED
@@ -0,0 +1,24 @@
1
+ *.gem
2
+ *.rbc
3
+ *.swp
4
+ *.tmproj
5
+ *~
6
+ .DS_Store
7
+ .\#*
8
+ .bundle
9
+ .config
10
+ .yardoc
11
+ Gemfile.lock
12
+ InstalledFiles
13
+ \#*
14
+ _yardoc
15
+ coverage
16
+ doc/
17
+ lib/bundler/man
18
+ pkg
19
+ rdoc
20
+ spec/reports
21
+ test/tmp
22
+ test/version_tmp
23
+ tmp
24
+ tmtags
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --color
2
+ --format=documentation
data/Gemfile ADDED
@@ -0,0 +1,6 @@
1
+ source 'https://rubygems.org'
2
+ gemspec
3
+
4
+ group :test do
5
+ gem 'simplecov', :require => false
6
+ end
data/LICENSE ADDED
@@ -0,0 +1,18 @@
1
+ Copyright (c) 2013 Magnum CI, Dan Sosedoff <dan.sosedoff@gmail.com>
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy of
4
+ this software and associated documentation files (the "Software"), to deal in
5
+ the Software without restriction, including without limitation the rights to
6
+ use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
7
+ the Software, and to permit persons to whom the Software is furnished to do so,
8
+ subject to the following conditions
9
+
10
+ The above copyright notice and this permission notice shall be included in all
11
+ copies or substantial portions of the Software
12
+
13
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
15
+ FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
16
+ COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
17
+ IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
18
+ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE
data/README.md ADDED
@@ -0,0 +1,107 @@
1
+ # magnum-payload
2
+
3
+ Ruby library to parse and process JSON-formatted payloads from code hosting providers.
4
+ It accepts any commits payloads and transforms them into identical data structures.
5
+
6
+ If you need to integrate web-hooks from Github, Bitbucket or Gitlab this is definitely
7
+ worth checking out. Check examples for details.
8
+
9
+ ## Supported platforms
10
+
11
+ You can integrate with the following providers:
12
+
13
+ - [Github](https://github.com) - git
14
+ - [Bitbucket](https://bitbucket.org) - git, mercurial
15
+ - [Gitlab](http://gitlab.org/) - git
16
+ - [Beanstalkapp](http://beanstalkapp.com/) - git, mercurial, subversion
17
+ - Your own server - git
18
+
19
+ ## Installation
20
+
21
+ Add dependency to Gemfile:
22
+
23
+ ```
24
+ gem 'magnum-payload',
25
+ github: 'magnumci/magnum-payload',
26
+ require: 'magnum/payload'
27
+ ```
28
+
29
+ NOTE: Library is not distributed via Rubygems.
30
+
31
+ ## Usage
32
+
33
+ Example:
34
+
35
+ ```ruby
36
+ require 'magnum/payload'
37
+
38
+ # Shorthand method to parse payload
39
+ Magnum::Payload.parse('github', 'JSON data') # => Magnum::Payload::Github
40
+ Magnum::Payload.parse('bitbucket', 'JSON data') # => Magnum::Payload::Bitbucket
41
+ Magnum::Payload.parse('gitlab', 'JSON data') # => Magnum::Payload::Bitbucket
42
+
43
+ # Or directly initialize a class
44
+ payload = Magnum::Payload::Github.new('JSON data')
45
+
46
+ # Detect skip
47
+ payload.skip?
48
+ payload.skip_message?
49
+ ```
50
+
51
+ See `Payload Attributes` section for payload instance details.
52
+
53
+ ## Payload Classes
54
+
55
+ All payload classes are inherited from `Magnum::Payload::Base`:
56
+
57
+ - Magnum::Payload::Github
58
+ - Magnum::Payload::Gitlab
59
+ - Magnum::Payload::Beanstalk
60
+ - Magnum::Payload::Bitbucket
61
+ - Magnum::Payload::Custom
62
+
63
+ ## Payload Attributes
64
+
65
+ Attributes are depending on payload class.
66
+
67
+ - `raw_data` - Original payload string or hash
68
+ - `data` - Formatted hash instance
69
+ - `skip` - Skip flag that indicated full payload skip (deleted head, etc)
70
+ - `commit` - Code revision (SHA1, number)
71
+ - `branch` - Code branch name (git, hg, svn)
72
+ - `author` - Commit author name
73
+ - `committer` - Commit committer name (git)
74
+ - `message` - Commit message text
75
+ - `committer_email` - Committer email (git)
76
+ - `author_email` - Author email (git)
77
+ - `commit_url` - Direct URL to view commit diff
78
+ - `compare_url` - Direct URL to view commits diff
79
+
80
+ ## Test Suite
81
+
82
+ To execute test suite run:
83
+
84
+ ```
85
+ rake test
86
+ ```
87
+
88
+ ## License
89
+
90
+ Copyright (c) 2013 Magnum CI, Dan Sosedoff <dan.sosedoff@gmail.com>
91
+
92
+ Permission is hereby granted, free of charge, to any person obtaining a copy of
93
+ this software and associated documentation files (the "Software"), to deal in
94
+ the Software without restriction, including without limitation the rights to
95
+ use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
96
+ the Software, and to permit persons to whom the Software is furnished to do so,
97
+ subject to the following conditions
98
+
99
+ The above copyright notice and this permission notice shall be included in all
100
+ copies or substantial portions of the Software
101
+
102
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
103
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
104
+ FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
105
+ COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
106
+ IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
107
+ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE
data/Rakefile ADDED
@@ -0,0 +1,10 @@
1
+ require 'bundler'
2
+ require 'bundler/gem_tasks'
3
+ require "rspec/core/rake_task"
4
+
5
+ RSpec::Core::RakeTask.new(:test) do |t|
6
+ t.pattern = 'spec/**/*_spec.rb'
7
+ t.verbose = false
8
+ end
9
+
10
+ task :default => :test
@@ -0,0 +1,62 @@
1
+ require 'json'
2
+ require 'hashr'
3
+
4
+ module Magnum
5
+ module Payload
6
+ class Base
7
+ include Magnum::Payload::MessageParser
8
+
9
+ attr_reader :raw_data, :data
10
+ attr_reader :skip, :test
11
+
12
+ attr_reader :commit, :branch, :author, :committer, :message
13
+ attr_reader :committer_email, :author_email
14
+ attr_reader :commit_url, :compare_url
15
+
16
+ def initialize(payload)
17
+ @skip = false # Do not skip by default
18
+ @test = false # Do not treat as test payload
19
+ @raw_data = payload
20
+ @data = parse_payload(payload)
21
+
22
+ parse!
23
+
24
+ @skip = skip_message? unless @skip
25
+ end
26
+
27
+ def attributes_hash
28
+ {
29
+ 'commit' => commit,
30
+ 'branch' => branch,
31
+ 'author' => author,
32
+ 'committer' => committer,
33
+ 'message' => message,
34
+ 'commit_url' => commit_url,
35
+ 'compare_url' => compare_url
36
+ }
37
+ end
38
+
39
+ def parse!
40
+ raise "Not implemented in base class"
41
+ end
42
+
43
+ def skip?
44
+ skip == true
45
+ end
46
+
47
+ private
48
+
49
+ def parse_payload(payload)
50
+ if payload.kind_of?(String)
51
+ Hashr.new(JSON.parse(payload))
52
+ elsif payload.kind_of?(Hash)
53
+ Hashr.new(payload)
54
+ else
55
+ raise ArgumentError, "String or Hash required"
56
+ end
57
+ rescue JSON::ParserError
58
+ raise Magnum::Payload::ParseError, "Valid JSON required"
59
+ end
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,43 @@
1
+ module Magnum
2
+ class Payload::Beanstalk < Payload::Base
3
+ def parse!
4
+ data.revision ? parse_svn! : parse_git!
5
+ detect_fake_payload!
6
+ end
7
+
8
+ def last_commit
9
+ @last_commit ||= Hashr.new(data.commits.last)
10
+ end
11
+
12
+ private
13
+
14
+ def parse_git!
15
+ @commit = last_commit.id
16
+ @branch = data.branch
17
+ @message = last_commit.message
18
+ @author = last_commit.author.name
19
+ @author_email = last_commit.author.email
20
+ @commit_url = last_commit.url
21
+ end
22
+
23
+ def parse_svn!
24
+ @commit = data.revision
25
+ @branch = 'master'
26
+ @author = data.author_full_name || data.author
27
+ @author_email = data.author_email
28
+ @committer = @author
29
+ @committer_email = @author_email
30
+ @commit_url = data.changeset_url
31
+ @message = data.message
32
+ end
33
+
34
+ def detect_fake_payload!
35
+ if data.before && data.after
36
+ if data.before =~ /^[0]+$/ && data.after =~ /^[1]+$/
37
+ @skip = true
38
+ @test = true
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,53 @@
1
+ module Magnum
2
+ class Payload::Bitbucket < Payload::Base
3
+ def parse!
4
+ commit = Hashr.new(data.commits.last)
5
+
6
+ branch = commit.branch || commit.branches.first || 'none'
7
+ revision = commit.revision || commit.raw_node
8
+ author = parse_author(commit.raw_author)
9
+
10
+ @commit = revision
11
+ @author = author.name
12
+ @author_email = author.email
13
+ @message = commit.message.strip
14
+ @branch = branch
15
+ @commit_url = make_url("commits/#{revision}")
16
+
17
+ if data.commits.size > 1
18
+ parse_compare_url(revision)
19
+ end
20
+ end
21
+
22
+ def make_url(path=nil)
23
+ [site_url, repo_url, path].compact.join
24
+ end
25
+
26
+ def site_url
27
+ data.canon_url
28
+ end
29
+
30
+ def repo_url
31
+ data.repository.absolute_url
32
+ end
33
+
34
+ def parse_author(str)
35
+ case str
36
+ when /<.+>/
37
+ m, name, email = *str.match(/(.*) <(.+?)>/)
38
+ Hashr.new(:name => name, :email => email)
39
+ else
40
+ Hashr.new(:name => str)
41
+ end
42
+ end
43
+
44
+ private
45
+
46
+ def parse_compare_url(revision)
47
+ first_commit = Hashr.new(data.commits.first)
48
+ rev_start = first_commit.revision || first_commit.raw_node
49
+ rev_end = revision
50
+ @compare_url = make_url("compare/#{rev_start}..#{rev_end}")
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,19 @@
1
+ module Magnum
2
+ class Payload::Custom < Payload::Base
3
+ def parse!
4
+ assign_payload
5
+ end
6
+
7
+ private
8
+
9
+ def assign_payload
10
+ @commit = data.commit
11
+ @author = data.author
12
+ @committer = data.committer
13
+ @message = data.message
14
+ @branch = data.branch
15
+ @commit_url = data.commit_url
16
+ @compare_url = data.compare_url
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,50 @@
1
+ module Magnum
2
+ class Payload::Github < Payload::Base
3
+ def parse!
4
+ assign_payload unless skip_payload?
5
+ end
6
+
7
+ private
8
+
9
+ def assign_payload
10
+ @commit = last_commit.id
11
+ @author = last_commit.author.name
12
+ @author_email = last_commit.author.email
13
+ @committer = last_commit.committer.name
14
+ @committer_email = last_commit.committer.email
15
+ @message = last_commit.message
16
+ @branch = data.ref.split('/').last
17
+ @commit_url = last_commit.url
18
+ @compare_url = data.compare
19
+ end
20
+
21
+ def skip_payload?
22
+ @skip = true if deleted? || last_commit.nil?
23
+ @skip = true if data.ref =~ /tags/
24
+
25
+ @skip
26
+ end
27
+
28
+ # Check if push is forced
29
+ # @return [Boolean]
30
+ def forced?
31
+ data.forced == true
32
+ end
33
+
34
+ # Check if head is deleted
35
+ # @return [Boolean]
36
+ def deleted?
37
+ data.deleted == true
38
+ end
39
+
40
+ # Get last commit in the push
41
+ # @return [Hashr]
42
+ def last_commit
43
+ if forced?
44
+ data.head_commit
45
+ else
46
+ Hashr.new(data.commits.last)
47
+ end
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,38 @@
1
+ module Magnum
2
+ class Payload::Gitlab < Payload::Base
3
+ ZERO_SHA = /\A[0]{40}\z/
4
+
5
+ def parse!
6
+ assign_payload unless skip_payload?
7
+ end
8
+
9
+ def last_commit
10
+ @last_commit ||= Hashr.new(data.commits.last)
11
+ end
12
+
13
+ private
14
+
15
+ def assign_payload
16
+ @commit = data.after
17
+ @branch = data.ref.split('/').last
18
+
19
+ if data.commits.any?
20
+ @author = last_commit.author.name
21
+ @author_email = last_commit.author.email
22
+ @committer = @author
23
+ @committer_email = @author_email
24
+ @message = last_commit.message
25
+ @commit_url = last_commit.url
26
+ end
27
+ end
28
+
29
+ def skip_payload?
30
+ @skip = true if deleted?
31
+ @skip
32
+ end
33
+
34
+ def deleted?
35
+ data.before !~ ZERO_SHA && data.after =~ ZERO_SHA
36
+ end
37
+ end
38
+ end