buildkite-builder 2.4.1 → 3.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +9 -0
- data/README.md +34 -4
- data/VERSION +1 -1
- data/lib/buildkite/builder/commands.rb +0 -1
- data/lib/buildkite/builder/data.rb +1 -1
- data/lib/buildkite/builder/extensions/sub_pipelines.rb +106 -0
- data/lib/buildkite/builder/extensions.rb +1 -0
- data/lib/buildkite/builder/loaders.rb +0 -1
- data/lib/buildkite/builder/pipeline.rb +1 -7
- data/lib/buildkite/builder/pipeline_collection.rb +39 -0
- data/lib/buildkite/builder.rb +1 -3
- metadata +4 -8
- data/lib/buildkite/builder/commands/files.rb +0 -24
- data/lib/buildkite/builder/file_resolver.rb +0 -59
- data/lib/buildkite/builder/github.rb +0 -71
- data/lib/buildkite/builder/loaders/manifests.rb +0 -23
- data/lib/buildkite/builder/manifest/rule.rb +0 -51
- data/lib/buildkite/builder/manifest.rb +0 -88
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d50f76bdcfda9a7561fce2b86dbae5b0ea99d37c0dbd6c763b35541a39e904c8
|
4
|
+
data.tar.gz: 2fbd91625db37b0bf88546931254b4f4024de25d3d20d09267318eafae2e3646
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5902b46da66c6ec7828d1bdf4f148f5445f2c7820e9f209e4a7ea22dae1ac8e62ea397660cca1f512737681c4c9397b97d5361f0fd64dba95066cb32751489ad
|
7
|
+
data.tar.gz: f67169e9bbdb7b84ccc1a6a8fec9593e878b70759e74f7236f595a3772649ce140d3ae99a329e090fb514c9bbbb450d70e58ea6362459404bced23f4a575cab1
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,12 @@
|
|
1
|
+
## 3.2.0
|
2
|
+
* Remove `template` from sub-pipeline trigger step setup and use arguments instead.
|
3
|
+
|
4
|
+
## 3.1.0
|
5
|
+
* Add subpipeline support to save triggered pipeline's YML definition beforehand to artifacts and pass down the file to an ENV for pipeline setup.
|
6
|
+
|
7
|
+
## 3.0.0
|
8
|
+
* Remove manifest features to prevent Github API dependency and simplify the gem to focus on Buildkite features.
|
9
|
+
|
1
10
|
## 2.4.1
|
2
11
|
* Fix pipeline upload as artifact logic.
|
3
12
|
|
data/README.md
CHANGED
@@ -48,7 +48,7 @@ At its core, BKB is really just a YAML builder. This tool allows you to scale yo
|
|
48
48
|
- Perform pre-build code/diff analysis to determine whether or not to to add a step to the pipeline.
|
49
49
|
- Reorder pipeline steps dynamically.
|
50
50
|
- Augment your pipeline steps with BKB processors.
|
51
|
-
|
51
|
+
|
52
52
|
### Pipeline Files
|
53
53
|
|
54
54
|
Your repo can contain as many pipeline definitions as you'd like. By convention, pipeline file structure are as such:
|
@@ -74,9 +74,9 @@ Buildkite::Builder.pipeline do
|
|
74
74
|
label "Rspec", emoji: :rspec
|
75
75
|
command "bundle exec rspec"
|
76
76
|
end
|
77
|
-
|
77
|
+
|
78
78
|
wait
|
79
|
-
|
79
|
+
|
80
80
|
trigger do
|
81
81
|
trigger "deploy-pipeline"
|
82
82
|
end
|
@@ -127,7 +127,7 @@ You can then include the template into the the pipeline once or as many time as
|
|
127
127
|
```ruby
|
128
128
|
Buildkite::Builder.pipeline do
|
129
129
|
command(:rspec)
|
130
|
-
|
130
|
+
|
131
131
|
# Reuse and agument templates on the fly.
|
132
132
|
command(:rspec) do
|
133
133
|
label "Run RSpec again!"
|
@@ -135,6 +135,36 @@ Buildkite::Builder.pipeline do
|
|
135
135
|
end
|
136
136
|
```
|
137
137
|
|
138
|
+
### Subpipeline
|
139
|
+
|
140
|
+
While triggering another pipeline, you can predefine subpipeline's steps using `pipeline(NAME_OF_SUBPIPELINE)` in the main pipeline's `pipeline.rb` file and share with main pipeline's plugins and templates definition.
|
141
|
+
|
142
|
+
`.buildkite/pipelines/pipeline-triggerer/pipeline.rb`
|
143
|
+
|
144
|
+
```ruby
|
145
|
+
Buildkite::Builder.pipeline do
|
146
|
+
pipeline('rspec-pipeline') do
|
147
|
+
command do
|
148
|
+
label "Run RSpec in separate pipeline"
|
149
|
+
end
|
150
|
+
end
|
151
|
+
end
|
152
|
+
```
|
153
|
+
|
154
|
+
Inside your Buildkite pipeline setup, you can do the following:
|
155
|
+
|
156
|
+
In `https://buildkite.com/your-org/rspec-pipeline/steps`
|
157
|
+
|
158
|
+
```yaml
|
159
|
+
steps:
|
160
|
+
- label: ":pipeline:"
|
161
|
+
commands:
|
162
|
+
- buildkite-agent artifact download $BKB_SUBPIPELINE_FILE . --build $BUILDKITE_TRIGGERED_FROM_BUILD_ID
|
163
|
+
- buildkite-agent pipeline upload $BKB_SUBPIPELINE_FILE
|
164
|
+
```
|
165
|
+
|
166
|
+
This will upload the pregenerated `pipeline.yml` to `rspec-pipeline`.
|
167
|
+
|
138
168
|
## Development
|
139
169
|
|
140
170
|
After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
2.
|
1
|
+
3.2.0
|
@@ -0,0 +1,106 @@
|
|
1
|
+
require 'securerandom'
|
2
|
+
|
3
|
+
module Buildkite
|
4
|
+
module Builder
|
5
|
+
module Extensions
|
6
|
+
class SubPipelines < Extension
|
7
|
+
class Pipeline
|
8
|
+
include Buildkite::Pipelines::Attributes
|
9
|
+
|
10
|
+
attr_reader :data, :name, :dsl
|
11
|
+
|
12
|
+
attribute :depends_on, append: true
|
13
|
+
attribute :key
|
14
|
+
|
15
|
+
def self.to_sym
|
16
|
+
name.split('::').last.downcase.to_sym
|
17
|
+
end
|
18
|
+
|
19
|
+
def initialize(name, context, &block)
|
20
|
+
@context = context
|
21
|
+
@name = name
|
22
|
+
@data = Data.new
|
23
|
+
@data.steps = StepCollection.new(
|
24
|
+
context.data.steps.templates,
|
25
|
+
context.data.steps.plugins
|
26
|
+
)
|
27
|
+
@data.notify = []
|
28
|
+
@data.env = {}
|
29
|
+
|
30
|
+
# Use `clone` to copy over dsl's extended extensions
|
31
|
+
@dsl = context.dsl.clone
|
32
|
+
# Override dsl context to current pipeline
|
33
|
+
@dsl.instance_variable_set(:@context, self)
|
34
|
+
|
35
|
+
instance_eval(&block) if block_given?
|
36
|
+
self
|
37
|
+
end
|
38
|
+
|
39
|
+
def to_h
|
40
|
+
attributes = super
|
41
|
+
# Merge envs from main pipeline, since ruby does not have `reverse_merge` and
|
42
|
+
# `data` does not allow keys override, we have to reset the data hash per key.
|
43
|
+
@context.data.env.merge(data.env).each do |key, value|
|
44
|
+
data.env[key] = value
|
45
|
+
end
|
46
|
+
attributes.merge(data.to_definition)
|
47
|
+
end
|
48
|
+
|
49
|
+
def method_missing(method_name, *args, **kwargs, &_block)
|
50
|
+
@dsl.public_send(method_name, *args, **kwargs, &_block)
|
51
|
+
end
|
52
|
+
|
53
|
+
def pipeline_yml
|
54
|
+
@pipeline_yml ||= "tmp/buildkite-builder/#{SecureRandom.urlsafe_base64}.yml"
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def prepare
|
59
|
+
context.data.pipelines = PipelineCollection.new(context.artifacts)
|
60
|
+
end
|
61
|
+
|
62
|
+
dsl do
|
63
|
+
def pipeline(name, **options, &block)
|
64
|
+
raise "Subpipeline must have a name" if name.empty?
|
65
|
+
raise "Subpipeline does not allow nested in another Subpipeline" if context.is_a?(Buildkite::Builder::Extensions::SubPipelines::Pipeline)
|
66
|
+
|
67
|
+
sub_pipeline = Buildkite::Builder::Extensions::SubPipelines::Pipeline.new(name, context, &block)
|
68
|
+
context.data.pipelines.add(sub_pipeline)
|
69
|
+
|
70
|
+
options = options.slice(:key, :label, :async, :branches, :condition, :depends_on, :allow_dependency_failure, :skip, :emoji)
|
71
|
+
options[:key] ||= "subpipeline_#{name}_#{context.data.pipelines.count}"
|
72
|
+
options[:label] ||= name.capitalize
|
73
|
+
|
74
|
+
if options[:emoji]
|
75
|
+
emoji = Array(options.delete(:emoji)).map { |name| ":#{name}:" }.join
|
76
|
+
options[:label] = [emoji, options[:label]].compact.join(' ')
|
77
|
+
end
|
78
|
+
|
79
|
+
context.data.steps.add(Pipelines::Steps::Trigger, **options) do |context|
|
80
|
+
key context[:key]
|
81
|
+
label context[:label]
|
82
|
+
trigger name
|
83
|
+
build(
|
84
|
+
message: '${BUILDKITE_MESSAGE}',
|
85
|
+
commit: '${BUILDKITE_COMMIT}',
|
86
|
+
branch: '${BUILDKITE_BRANCH}',
|
87
|
+
env: {
|
88
|
+
BUILDKITE_PULL_REQUEST: '${BUILDKITE_PULL_REQUEST}',
|
89
|
+
BUILDKITE_PULL_REQUEST_BASE_BRANCH: '${BUILDKITE_PULL_REQUEST_BASE_BRANCH}',
|
90
|
+
BUILDKITE_PULL_REQUEST_REPO: '${BUILDKITE_PULL_REQUEST_REPO}',
|
91
|
+
BKB_SUBPIPELINE_FILE: sub_pipeline.pipeline_yml
|
92
|
+
}
|
93
|
+
)
|
94
|
+
async context[:async] || false
|
95
|
+
branches context[:branches] if context[:branches]
|
96
|
+
condition context[:condition] if context[:condition]
|
97
|
+
depends_on *context[:depends_on] if context[:depends_on]
|
98
|
+
allow_dependency_failure context[:allow_dependency_failure] || false
|
99
|
+
skip context[:skip] || false
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
@@ -6,6 +6,7 @@ module Buildkite
|
|
6
6
|
autoload :Env, File.expand_path('extensions/env', __dir__)
|
7
7
|
autoload :Lib, File.expand_path('extensions/lib', __dir__)
|
8
8
|
autoload :Notify, File.expand_path('extensions/notify', __dir__)
|
9
|
+
autoload :SubPipelines, File.expand_path('extensions/sub_pipelines', __dir__)
|
9
10
|
autoload :Steps, File.expand_path('extensions/steps', __dir__)
|
10
11
|
autoload :Use, File.expand_path('extensions/use', __dir__)
|
11
12
|
end
|
@@ -4,7 +4,6 @@ module Buildkite
|
|
4
4
|
module Builder
|
5
5
|
module Loaders
|
6
6
|
autoload :Abstract, File.expand_path('loaders/abstract', __dir__)
|
7
|
-
autoload :Manifests, File.expand_path('loaders/manifests', __dir__)
|
8
7
|
autoload :Templates, File.expand_path('loaders/templates', __dir__)
|
9
8
|
autoload :Extensions, File.expand_path('loaders/extensions', __dir__)
|
10
9
|
end
|
@@ -37,7 +37,7 @@ module Buildkite
|
|
37
37
|
use(Extensions::Env)
|
38
38
|
use(Extensions::Notify)
|
39
39
|
use(Extensions::Steps)
|
40
|
-
|
40
|
+
use(Extensions::SubPipelines)
|
41
41
|
end
|
42
42
|
|
43
43
|
def upload
|
@@ -82,12 +82,6 @@ module Buildkite
|
|
82
82
|
|
83
83
|
attr_reader :extensions
|
84
84
|
|
85
|
-
def load_manifests
|
86
|
-
Loaders::Manifests.load(root).each do |name, asset|
|
87
|
-
Manifest[name] = asset
|
88
|
-
end
|
89
|
-
end
|
90
|
-
|
91
85
|
def upload_artifacts
|
92
86
|
return if artifacts.empty?
|
93
87
|
|
@@ -0,0 +1,39 @@
|
|
1
|
+
require "forwardable"
|
2
|
+
|
3
|
+
module Buildkite
|
4
|
+
module Builder
|
5
|
+
class PipelineCollection
|
6
|
+
extend Forwardable
|
7
|
+
|
8
|
+
attr_reader :pipelines
|
9
|
+
|
10
|
+
def_delegator :@pipelines, :count
|
11
|
+
|
12
|
+
def initialize(artifacts)
|
13
|
+
@artifacts = artifacts
|
14
|
+
@pipelines = []
|
15
|
+
end
|
16
|
+
|
17
|
+
def add(pipeline)
|
18
|
+
unless pipeline.is_a?(Buildkite::Builder::Extensions::SubPipelines::Pipeline)
|
19
|
+
raise "`#{pipeline}` must be a Buildkite::Builder::Extensions::SubPipelines::Pipeline"
|
20
|
+
end
|
21
|
+
|
22
|
+
pipelines << pipeline
|
23
|
+
end
|
24
|
+
|
25
|
+
def to_definition
|
26
|
+
# Instead of generates pipeline.yml, subpipelines save generated file to artifacts
|
27
|
+
pipelines.each do |pipeline|
|
28
|
+
file = Pathname.new(pipeline.pipeline_yml)
|
29
|
+
file.dirname.mkpath
|
30
|
+
file.write(YAML.dump(Pipelines::Helpers.sanitize(pipeline.to_h)))
|
31
|
+
|
32
|
+
@artifacts << file
|
33
|
+
end
|
34
|
+
|
35
|
+
nil
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
data/lib/buildkite/builder.rb
CHANGED
@@ -13,16 +13,14 @@ module Buildkite
|
|
13
13
|
autoload :Extension, File.expand_path('builder/extension', __dir__)
|
14
14
|
autoload :ExtensionManager, File.expand_path('builder/extension_manager', __dir__)
|
15
15
|
autoload :Extensions, File.expand_path('builder/extensions', __dir__)
|
16
|
-
autoload :FileResolver, File.expand_path('builder/file_resolver', __dir__)
|
17
|
-
autoload :Github, File.expand_path('builder/github', __dir__)
|
18
16
|
autoload :Loaders, File.expand_path('builder/loaders', __dir__)
|
19
17
|
autoload :LoggingUtils, File.expand_path('builder/logging_utils', __dir__)
|
20
|
-
autoload :Manifest, File.expand_path('builder/manifest', __dir__)
|
21
18
|
autoload :Processors, File.expand_path('builder/processors', __dir__)
|
22
19
|
autoload :Rainbow, File.expand_path('builder/rainbow', __dir__)
|
23
20
|
autoload :Plugin, File.expand_path('builder/plugin', __dir__)
|
24
21
|
autoload :PluginCollection, File.expand_path('builder/plugin_collection', __dir__)
|
25
22
|
autoload :StepCollection, File.expand_path('builder/step_collection', __dir__)
|
23
|
+
autoload :PipelineCollection, File.expand_path('builder/pipeline_collection', __dir__)
|
26
24
|
autoload :TemplateManager, File.expand_path('builder/template_manager', __dir__)
|
27
25
|
autoload :PluginManager, File.expand_path('builder/plugin_manager', __dir__)
|
28
26
|
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: buildkite-builder
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.
|
4
|
+
version: 3.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Ngan Pham
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: exe
|
11
11
|
cert_chain: []
|
12
|
-
date: 2022-
|
12
|
+
date: 2022-06-13 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rainbow
|
@@ -116,7 +116,6 @@ files:
|
|
116
116
|
- lib/buildkite/builder.rb
|
117
117
|
- lib/buildkite/builder/commands.rb
|
118
118
|
- lib/buildkite/builder/commands/abstract.rb
|
119
|
-
- lib/buildkite/builder/commands/files.rb
|
120
119
|
- lib/buildkite/builder/commands/preview.rb
|
121
120
|
- lib/buildkite/builder/commands/run.rb
|
122
121
|
- lib/buildkite/builder/data.rb
|
@@ -129,19 +128,16 @@ files:
|
|
129
128
|
- lib/buildkite/builder/extensions/lib.rb
|
130
129
|
- lib/buildkite/builder/extensions/notify.rb
|
131
130
|
- lib/buildkite/builder/extensions/steps.rb
|
131
|
+
- lib/buildkite/builder/extensions/sub_pipelines.rb
|
132
132
|
- lib/buildkite/builder/extensions/use.rb
|
133
|
-
- lib/buildkite/builder/file_resolver.rb
|
134
|
-
- lib/buildkite/builder/github.rb
|
135
133
|
- lib/buildkite/builder/group.rb
|
136
134
|
- lib/buildkite/builder/loaders.rb
|
137
135
|
- lib/buildkite/builder/loaders/abstract.rb
|
138
136
|
- lib/buildkite/builder/loaders/extensions.rb
|
139
|
-
- lib/buildkite/builder/loaders/manifests.rb
|
140
137
|
- lib/buildkite/builder/loaders/templates.rb
|
141
138
|
- lib/buildkite/builder/logging_utils.rb
|
142
|
-
- lib/buildkite/builder/manifest.rb
|
143
|
-
- lib/buildkite/builder/manifest/rule.rb
|
144
139
|
- lib/buildkite/builder/pipeline.rb
|
140
|
+
- lib/buildkite/builder/pipeline_collection.rb
|
145
141
|
- lib/buildkite/builder/plugin.rb
|
146
142
|
- lib/buildkite/builder/plugin_collection.rb
|
147
143
|
- lib/buildkite/builder/plugin_manager.rb
|
@@ -1,24 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Buildkite
|
4
|
-
module Builder
|
5
|
-
module Commands
|
6
|
-
class Files < Abstract
|
7
|
-
private
|
8
|
-
|
9
|
-
self.description = 'Outputs files that match the specified manifest.'
|
10
|
-
|
11
|
-
def run
|
12
|
-
manifests = Loaders::Manifests.load(pipeline_path)
|
13
|
-
puts manifests[options[:manifest]].files.sort.join("\n")
|
14
|
-
end
|
15
|
-
|
16
|
-
def parse_options(opts)
|
17
|
-
opts.on('--manifest MANIFEST', 'The manifest to use') do |manifest|
|
18
|
-
options[:manifest] = manifest
|
19
|
-
end
|
20
|
-
end
|
21
|
-
end
|
22
|
-
end
|
23
|
-
end
|
24
|
-
end
|
@@ -1,59 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require 'open3'
|
4
|
-
require 'set'
|
5
|
-
|
6
|
-
module Buildkite
|
7
|
-
module Builder
|
8
|
-
class FileResolver
|
9
|
-
@cache = true
|
10
|
-
|
11
|
-
attr_reader :modified_files
|
12
|
-
|
13
|
-
class << self
|
14
|
-
attr_accessor :cache
|
15
|
-
|
16
|
-
def resolve(reset = false)
|
17
|
-
@resolve = nil if !cache || reset
|
18
|
-
@resolve ||= new
|
19
|
-
end
|
20
|
-
end
|
21
|
-
|
22
|
-
def initialize
|
23
|
-
@modified_files = Set.new(pull_request? ? files_from_pull_request.sort! : files_from_git.sort!)
|
24
|
-
end
|
25
|
-
|
26
|
-
private
|
27
|
-
|
28
|
-
def files_from_pull_request
|
29
|
-
Github.pull_request_files.map { |f| f.fetch('filename') }
|
30
|
-
end
|
31
|
-
|
32
|
-
def files_from_git
|
33
|
-
if Buildkite.env
|
34
|
-
changed_files = command("git diff-tree --no-commit-id --name-only -r #{Buildkite.env.commit}")
|
35
|
-
else
|
36
|
-
default_branch = command('git symbolic-ref refs/remotes/origin/HEAD').strip
|
37
|
-
changed_files = command("git diff --name-only #{default_branch}")
|
38
|
-
changed_files << command('git diff --name-only')
|
39
|
-
end
|
40
|
-
|
41
|
-
changed_files.split.uniq.sort
|
42
|
-
end
|
43
|
-
|
44
|
-
def pull_request?
|
45
|
-
Buildkite.env&.pull_request
|
46
|
-
end
|
47
|
-
|
48
|
-
def command(cmd)
|
49
|
-
output, status = Open3.capture2(*cmd.split)
|
50
|
-
|
51
|
-
if status.success?
|
52
|
-
output
|
53
|
-
else
|
54
|
-
raise "Command failed (exit #{status.exitstatus}): #{cmd}"
|
55
|
-
end
|
56
|
-
end
|
57
|
-
end
|
58
|
-
end
|
59
|
-
end
|
@@ -1,71 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require 'json'
|
4
|
-
require 'net/http'
|
5
|
-
require 'uri'
|
6
|
-
|
7
|
-
module Buildkite
|
8
|
-
module Builder
|
9
|
-
class Github
|
10
|
-
BASE_URI = URI('https://api.github.com').freeze
|
11
|
-
ACCEPT_HEADER = 'application/vnd.github.v3+json'
|
12
|
-
LINK_HEADER = 'link'
|
13
|
-
NEXT_LINK_REGEX = /<(?<uri>.+)>; rel="next"/.freeze
|
14
|
-
REPO_REGEX = /github\.com(?::|\/)(.*?)(?:\.git)?\z/.freeze
|
15
|
-
PER_PAGE = 100
|
16
|
-
|
17
|
-
def self.pull_request_files
|
18
|
-
new.pull_request_files
|
19
|
-
end
|
20
|
-
|
21
|
-
def initialize(env = ENV)
|
22
|
-
@env = env
|
23
|
-
end
|
24
|
-
|
25
|
-
def pull_request_files
|
26
|
-
files = []
|
27
|
-
next_uri = URI.join(BASE_URI, "repos/#{repo}/pulls/#{pull_request_number}/files?per_page=#{PER_PAGE}")
|
28
|
-
|
29
|
-
while next_uri
|
30
|
-
response = request(next_uri)
|
31
|
-
files.concat(JSON.parse(response.body))
|
32
|
-
next_uri = parse_next_uri(response)
|
33
|
-
end
|
34
|
-
|
35
|
-
files
|
36
|
-
end
|
37
|
-
|
38
|
-
private
|
39
|
-
|
40
|
-
def repo
|
41
|
-
Buildkite.env.repo[REPO_REGEX, 1]
|
42
|
-
end
|
43
|
-
|
44
|
-
def token
|
45
|
-
@env.fetch('GITHUB_API_TOKEN')
|
46
|
-
end
|
47
|
-
|
48
|
-
def pull_request_number
|
49
|
-
Buildkite.env.pull_request
|
50
|
-
end
|
51
|
-
|
52
|
-
def request(uri)
|
53
|
-
Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) do |http|
|
54
|
-
request = Net::HTTP::Get.new(uri)
|
55
|
-
request['Authorization'] = "token #{token}"
|
56
|
-
request['Accept'] = ACCEPT_HEADER
|
57
|
-
|
58
|
-
http.request(request)
|
59
|
-
end
|
60
|
-
end
|
61
|
-
|
62
|
-
def parse_next_uri(response)
|
63
|
-
links = response[LINK_HEADER]
|
64
|
-
return unless links
|
65
|
-
|
66
|
-
matches = links.match(NEXT_LINK_REGEX)
|
67
|
-
URI.parse(matches[:uri]) if matches
|
68
|
-
end
|
69
|
-
end
|
70
|
-
end
|
71
|
-
end
|
@@ -1,23 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Buildkite
|
4
|
-
module Builder
|
5
|
-
module Loaders
|
6
|
-
class Manifests < Abstract
|
7
|
-
MANIFESTS_PATH = Pathname.new('manifests').freeze
|
8
|
-
|
9
|
-
def load
|
10
|
-
return unless manifests_path.directory?
|
11
|
-
|
12
|
-
manifests_path.children.map do |file|
|
13
|
-
add(file.basename, Manifest.new(Buildkite::Builder.root, file.readlines))
|
14
|
-
end
|
15
|
-
end
|
16
|
-
|
17
|
-
def manifests_path
|
18
|
-
root.join(MANIFESTS_PATH)
|
19
|
-
end
|
20
|
-
end
|
21
|
-
end
|
22
|
-
end
|
23
|
-
end
|
@@ -1,51 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require 'set'
|
4
|
-
require 'pathname'
|
5
|
-
|
6
|
-
module Buildkite
|
7
|
-
module Builder
|
8
|
-
class Manifest::Rule
|
9
|
-
GLOB_OPTIONS = File::FNM_PATHNAME | File::FNM_DOTMATCH | File::FNM_EXTGLOB
|
10
|
-
|
11
|
-
attr_reader :exclude
|
12
|
-
attr_reader :glob
|
13
|
-
|
14
|
-
def initialize(root, pattern)
|
15
|
-
@root = Pathname.new(root)
|
16
|
-
@exclude = false
|
17
|
-
@glob = @root
|
18
|
-
|
19
|
-
if pattern[0] == '!'
|
20
|
-
@exclude = true
|
21
|
-
pattern = pattern[1..-1]
|
22
|
-
end
|
23
|
-
|
24
|
-
if pattern.start_with?('/')
|
25
|
-
pattern = pattern[1..-1]
|
26
|
-
else
|
27
|
-
@glob = @glob.join('**')
|
28
|
-
end
|
29
|
-
|
30
|
-
@glob = @glob.join(pattern).to_s
|
31
|
-
end
|
32
|
-
|
33
|
-
def files
|
34
|
-
@files ||= begin
|
35
|
-
matched = Dir.glob(glob, GLOB_OPTIONS)
|
36
|
-
matched.map! { |file| Pathname.new(file) }
|
37
|
-
matched.reject!(&:directory?)
|
38
|
-
matched.map! { |file| file.relative_path_from(Builder.root) }
|
39
|
-
Set.new(matched.sort!)
|
40
|
-
end
|
41
|
-
end
|
42
|
-
|
43
|
-
def match?(file)
|
44
|
-
file = Pathname.new(file)
|
45
|
-
file = @root.join(file) unless file.absolute?
|
46
|
-
|
47
|
-
File.fnmatch?(glob, file.to_s, GLOB_OPTIONS)
|
48
|
-
end
|
49
|
-
end
|
50
|
-
end
|
51
|
-
end
|
@@ -1,88 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require 'digest/md5'
|
4
|
-
require 'pathname'
|
5
|
-
|
6
|
-
module Buildkite
|
7
|
-
module Builder
|
8
|
-
class Manifest
|
9
|
-
autoload :Rule, File.expand_path('manifest/rule', __dir__)
|
10
|
-
|
11
|
-
class << self
|
12
|
-
def resolve(root, patterns)
|
13
|
-
new(root, Array(patterns)).modified?
|
14
|
-
end
|
15
|
-
|
16
|
-
def manifests
|
17
|
-
@manifests ||= {}
|
18
|
-
end
|
19
|
-
|
20
|
-
def [](name)
|
21
|
-
manifests[name.to_s]
|
22
|
-
end
|
23
|
-
|
24
|
-
def []=(name, manifest)
|
25
|
-
name = name.to_s
|
26
|
-
if manifests.key?(name)
|
27
|
-
raise ArgumentError, "manifest #{name} already exists"
|
28
|
-
end
|
29
|
-
|
30
|
-
manifests[name] = manifest
|
31
|
-
end
|
32
|
-
end
|
33
|
-
|
34
|
-
attr_reader :root
|
35
|
-
|
36
|
-
def initialize(root, patterns)
|
37
|
-
@root = Pathname.new(root)
|
38
|
-
@root = Buildkite::Builder.root.join(@root) unless @root.absolute?
|
39
|
-
@patterns = patterns.map(&:to_s)
|
40
|
-
end
|
41
|
-
|
42
|
-
def modified?
|
43
|
-
# DO NOT intersect FileResolver with manifest files. If the manifest is
|
44
|
-
# large, the operation can be expensive. It's always cheaper to loop
|
45
|
-
# through the changed files and compare them against the rules.
|
46
|
-
unless defined?(@modified)
|
47
|
-
@modified = FileResolver.resolve.modified_files.any? do |file|
|
48
|
-
file = Buildkite::Builder.root.join(file)
|
49
|
-
inclusion_rules.any? { |rule| rule.match?(file) } &&
|
50
|
-
exclusion_rules.none? { |rule| rule.match?(file) }
|
51
|
-
end
|
52
|
-
end
|
53
|
-
|
54
|
-
@modified
|
55
|
-
end
|
56
|
-
|
57
|
-
def files
|
58
|
-
@files ||= (inclusion_rules.map(&:files).reduce(Set.new, :merge) - exclusion_rules.map(&:files).reduce(Set.new, :merge)).sort.to_set
|
59
|
-
end
|
60
|
-
|
61
|
-
def digest
|
62
|
-
@digest ||= begin
|
63
|
-
digests = files.map { |file| Digest::MD5.file(Buildkite::Builder.root.join(file)).hexdigest }
|
64
|
-
Digest::MD5.hexdigest(digests.join)
|
65
|
-
end
|
66
|
-
end
|
67
|
-
|
68
|
-
private
|
69
|
-
|
70
|
-
def rules
|
71
|
-
@rules ||= @patterns.each_with_object([]) do |pattern, rules|
|
72
|
-
pattern = pattern.strip
|
73
|
-
unless pattern.match?(/\A(#|\z)/)
|
74
|
-
rules << Rule.new(root, pattern)
|
75
|
-
end
|
76
|
-
end
|
77
|
-
end
|
78
|
-
|
79
|
-
def inclusion_rules
|
80
|
-
@inclusion_rules ||= rules.reject(&:exclude)
|
81
|
-
end
|
82
|
-
|
83
|
-
def exclusion_rules
|
84
|
-
@exclusion_rules ||= rules.select(&:exclude)
|
85
|
-
end
|
86
|
-
end
|
87
|
-
end
|
88
|
-
end
|