magnum-payload 0.3.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.
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