jmgarnier_travis_dedup 0.5.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: 464ee010aaf415a819f821dce1ec7b2ab3345f3d
4
+ data.tar.gz: 6d7d7458af673bbcd3cd3986f2688aa632569dee
5
+ SHA512:
6
+ metadata.gz: 6b2197268038ab24b6a83fcf63ce02db45e39e4c077b970816719d6e617980dde323c932eecf95087ea9652099ca0cc35f46cdb20f8601a002d3c1ce54e4a0bd
7
+ data.tar.gz: eca992c5a94ee3207fe3df8d263973f3d39fbd0f7d8f8c2e149d8274d325132a2d47e003b997553a0605199c65cff7f0cbd2ac691d71cc88221c6b2045b245eb
data/MIT-LICENSE.txt ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (C) 2013 Michael Grosser <michael@grosser.it>
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/bin/travis-dedup ADDED
@@ -0,0 +1,9 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ # enable local usage from cloned repo
4
+ root = File.expand_path("../..", __FILE__)
5
+ $LOAD_PATH << "#{root}/lib" if File.exist?("#{root}/Gemfile")
6
+
7
+ require "travis_dedup"
8
+
9
+ exit TravisDedup.cli(ARGV)
@@ -0,0 +1,3 @@
1
+ module TravisDedup
2
+ VERSION = "0.5.0"
3
+ end
@@ -0,0 +1,136 @@
1
+ require 'faraday'
2
+ require 'json'
3
+ require 'optparse'
4
+
5
+ module TravisDedup
6
+ ACTIVE = %w[created started queued]
7
+
8
+ DEFAULT_MAX_ATTEMPTS_WHEN_TRAVIS_DOES_NOT_RESPOND = 3
9
+
10
+ class << self
11
+ attr_accessor :pro, :verbose, :branches
12
+
13
+ def cli(argv)
14
+ parser = OptionParser.new do |opts|
15
+ opts.banner = <<-BANNER.gsub(/^ /, "")
16
+ Stop all builds on the same PR when a new job starts.
17
+
18
+ Usage:
19
+ travis-dedup your_org/your_repo $TRAVIS_ACCESS_TOKEN --pro
20
+
21
+ Options:
22
+ BANNER
23
+ opts.on("--pro", "travis pro") { self.pro = true }
24
+ opts.on("--branches", "dedup builds on branches too") { self.branches = true }
25
+ opts.on("-h", "--help","Show this") { puts opts; exit }
26
+ opts.on('-v', '--version','Show Version'){ require 'travis_dedup/version'; puts TravisDedup::VERSION; exit}
27
+ end
28
+ parser.parse!(argv)
29
+
30
+ unless argv.size == 2
31
+ puts parser
32
+ return 1
33
+ end
34
+
35
+ puts dedup_message(*argv)
36
+ 0
37
+ end
38
+
39
+ def dedup(repo, access_token)
40
+ dedup_builds(repo, access_token).last
41
+ end
42
+
43
+ def dedup_message(repo, access_token)
44
+ all, canceled = dedup_builds(repo, access_token)
45
+ canceled = (canceled.any? ? canceled.map { |b| b.fetch("id") }.join(", ") : "None")
46
+ "Found #{all.size} builds, canceled: #{canceled}"
47
+ end
48
+
49
+ def access_token(github_token)
50
+ request(:post, "auth/github", {github_token: github_token}, 'User-Agent' => 'Travis/1.0').fetch("access_token")
51
+ end
52
+
53
+ private
54
+
55
+ def dedup_builds(repo, access_token)
56
+ builds = active_builds(repo, access_token)
57
+ cancel = duplicate_builds(builds)
58
+ cancel(cancel, access_token)
59
+ return builds, cancel
60
+ end
61
+
62
+ def cancel(builds, access_token)
63
+ builds.each { |build| request :post, "builds/#{build.fetch("id")}/cancel", {}, headers(access_token) }
64
+ end
65
+
66
+ def duplicate_builds(builds)
67
+ seen = []
68
+ builds.select do |build|
69
+ pr = build.fetch "pull_request_number"
70
+ branch = build.fetch "branch"
71
+
72
+ next if !pr && !branches
73
+
74
+ id = pr || branch
75
+ if seen.include?(id)
76
+ true
77
+ else
78
+ seen << id
79
+ false
80
+ end
81
+ end
82
+ end
83
+
84
+ # see http://docs.travis-ci.com/api/#builds
85
+ def active_builds(repo, access_token)
86
+ response = request(:get, "repos/#{repo}/builds", {}, headers(access_token))
87
+ builds = response.fetch("builds").select { |b| ACTIVE.include?(b.fetch("state")) }
88
+ builds.each { |build| build["branch"] = response.fetch("commits").detect { |c| c["id"] == build["commit_id"] }.fetch("branch") }
89
+ end
90
+
91
+ def headers(access_token)
92
+ {
93
+ "Authorization" => %{token "#{access_token}"},
94
+ 'Accept' => 'application/vnd.travis-ci.2+json' # otherwise we only get half the build data
95
+ }
96
+ end
97
+
98
+ def host
99
+ pro ? "https://api.travis-ci.com" : "https://api.travis-ci.org"
100
+ end
101
+
102
+ def request(method, path, params, headers={})
103
+ attempts = 0
104
+ begin
105
+ faraday_send(method, path, params, headers)
106
+ rescue TravisError500 => error
107
+ raise error if (attempts += 1) > max_attempts
108
+ retry
109
+ end
110
+ end
111
+
112
+ def max_attempts
113
+ DEFAULT_MAX_ATTEMPTS_WHEN_TRAVIS_DOES_NOT_RESPOND
114
+ end
115
+
116
+ class TravisError500 < Faraday::Error; end
117
+
118
+ def faraday_send(method, path, params, headers={})
119
+ response = Faraday.send(method, "#{host}/#{path}", params, headers)
120
+ case response.status
121
+ when 200 then JSON.parse(response.body)
122
+ when 204 then nil
123
+ when 500
124
+ 256.times { puts "500 on Travis, retrying! ⏰" }
125
+ raise(TravisError500, error_message(method, path, response))
126
+ else
127
+ raise(Faraday::Error, error_message(method, path, response))
128
+ end
129
+ end
130
+
131
+ def error_message(method, path, response)
132
+ "Communication with travis failed when trying to #{method} #{path}\n" \
133
+ "Response: #{response.status} - #{response.body}"
134
+ end
135
+ end
136
+ end
metadata ADDED
@@ -0,0 +1,76 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: jmgarnier_travis_dedup
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.5.0
5
+ platform: ruby
6
+ authors:
7
+ - Michael Grosser
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2016-11-18 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: faraday
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: json
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ description:
42
+ email: michael@grosser.it
43
+ executables:
44
+ - travis-dedup
45
+ extensions: []
46
+ extra_rdoc_files: []
47
+ files:
48
+ - MIT-LICENSE.txt
49
+ - bin/travis-dedup
50
+ - lib/travis_dedup.rb
51
+ - lib/travis_dedup/version.rb
52
+ homepage: https://github.com/grosser/travis_dedup
53
+ licenses:
54
+ - MIT
55
+ metadata: {}
56
+ post_install_message:
57
+ rdoc_options: []
58
+ require_paths:
59
+ - lib
60
+ required_ruby_version: !ruby/object:Gem::Requirement
61
+ requirements:
62
+ - - ">="
63
+ - !ruby/object:Gem::Version
64
+ version: 1.9.3
65
+ required_rubygems_version: !ruby/object:Gem::Requirement
66
+ requirements:
67
+ - - ">="
68
+ - !ruby/object:Gem::Version
69
+ version: '0'
70
+ requirements: []
71
+ rubyforge_project:
72
+ rubygems_version: 2.6.6
73
+ signing_key:
74
+ specification_version: 4
75
+ summary: Stop all builds on the same PR when a new job starts.
76
+ test_files: []