buildkite-builder 2.4.0 → 3.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 +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 +96 -0
- data/lib/buildkite/builder/extensions.rb +1 -0
- data/lib/buildkite/builder/loaders.rb +0 -1
- data/lib/buildkite/builder/pipeline.rb +3 -8
- 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: bef719c816c5d64756bbcd041ca2a3fabe8fe59bff47cc154948207ce64a672f
|
4
|
+
data.tar.gz: f25762b1422e540f395526df9d6082e1d5908ea0b9b290bf025a365b56c317ff
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c00f3fba91b34cf907c99ff839612270ef8aecb754c988af52226e979d5e743a508963d1d06d9957b529a2e3ba47cf6ba0951ec33290b8581dc9937b4178033a
|
7
|
+
data.tar.gz: 6e62bff8ecdb50b72bdb3afb8fd6fa1385f17ef1852b607f5273570cab1d396ee65d8908a78604d48ccb7a564ad4cb0f9dbff6b94b7a016cfd9ee881e1d4098a
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,12 @@
|
|
1
|
+
## 3.1.0
|
2
|
+
* Add subpipeline support to save triggered pipeline's YML definition beforehand to artifacts and pass down the file to an ENV for pipeline setup.
|
3
|
+
|
4
|
+
## 3.0.0
|
5
|
+
* Remove manifest features to prevent Github API dependency and simplify the gem to focus on Buildkite features.
|
6
|
+
|
7
|
+
## 2.4.1
|
8
|
+
* Fix pipeline upload as artifact logic.
|
9
|
+
|
1
10
|
## 2.4.0
|
2
11
|
* Upload custom pipeline artifacts in a single command.
|
3
12
|
* Only upload the pipeline as an artifact when the pipeline upload fails.
|
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
|
-
|
1
|
+
3.1.0
|
@@ -0,0 +1,96 @@
|
|
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
|
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, steps, &block)
|
20
|
+
@name = name
|
21
|
+
@data = Data.new
|
22
|
+
@data.steps = StepCollection.new(
|
23
|
+
steps.templates,
|
24
|
+
steps.plugins
|
25
|
+
)
|
26
|
+
@data.notify = []
|
27
|
+
@data.env = {}
|
28
|
+
|
29
|
+
@dsl = Dsl.new(self)
|
30
|
+
@dsl.extend(Extensions::Steps)
|
31
|
+
@dsl.extend(Extensions::Notify)
|
32
|
+
@dsl.extend(Extensions::Env)
|
33
|
+
instance_eval(&block) if block_given?
|
34
|
+
self
|
35
|
+
end
|
36
|
+
|
37
|
+
def to_h
|
38
|
+
attributes = super
|
39
|
+
attributes.merge(data.to_definition)
|
40
|
+
end
|
41
|
+
|
42
|
+
def method_missing(method_name, *args, **kwargs, &_block)
|
43
|
+
@dsl.public_send(method_name, *args, **kwargs, &_block)
|
44
|
+
end
|
45
|
+
|
46
|
+
def pipeline_yml
|
47
|
+
@pipeline_yml ||= "tmp/buildkite-builder/#{SecureRandom.urlsafe_base64}.yml"
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def prepare
|
52
|
+
context.data.pipelines = PipelineCollection.new(context.artifacts)
|
53
|
+
end
|
54
|
+
|
55
|
+
dsl do
|
56
|
+
def pipeline(name, template = nil, &block)
|
57
|
+
raise "Subpipeline must have a name" if name.empty?
|
58
|
+
raise "Subpipeline does not allow nested in another Subpipeline" if context.is_a?(Buildkite::Builder::Extensions::SubPipelines::Pipeline)
|
59
|
+
sub_pipeline = Buildkite::Builder::Extensions::SubPipelines::Pipeline.new(name, context.data.steps, &block)
|
60
|
+
|
61
|
+
context.data.pipelines.add(sub_pipeline)
|
62
|
+
|
63
|
+
if template
|
64
|
+
# Use predefined template
|
65
|
+
step = context.data.steps.add(Pipelines::Steps::Trigger, template)
|
66
|
+
|
67
|
+
if step.build.nil?
|
68
|
+
step.build(env: { BKB_SUBPIPELINE_FILE: sub_pipeline.pipeline_yml })
|
69
|
+
else
|
70
|
+
step.build[:env].merge!(BKB_SUBPIPELINE_FILE: sub_pipeline.pipeline_yml)
|
71
|
+
end
|
72
|
+
else
|
73
|
+
# Generic trigger step
|
74
|
+
context.data.steps.add(Pipelines::Steps::Trigger, key: "subpipeline_#{name}_#{context.data.pipelines.count}") do |context|
|
75
|
+
key context[:key]
|
76
|
+
label name.capitalize
|
77
|
+
trigger name
|
78
|
+
build(
|
79
|
+
message: '${BUILDKITE_MESSAGE}',
|
80
|
+
commit: '${BUILDKITE_COMMIT}',
|
81
|
+
branch: '${BUILDKITE_BRANCH}',
|
82
|
+
env: {
|
83
|
+
BUILDKITE_PULL_REQUEST: '${BUILDKITE_PULL_REQUEST}',
|
84
|
+
BUILDKITE_PULL_REQUEST_BASE_BRANCH: '${BUILDKITE_PULL_REQUEST_BASE_BRANCH}',
|
85
|
+
BUILDKITE_PULL_REQUEST_REPO: '${BUILDKITE_PULL_REQUEST_REPO}',
|
86
|
+
BKB_SUBPIPELINE_FILE: sub_pipeline.pipeline_yml
|
87
|
+
}
|
88
|
+
)
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
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
|
@@ -52,9 +52,10 @@ module Buildkite
|
|
52
52
|
file.write(contents)
|
53
53
|
|
54
54
|
logger.info "+++ :pipeline: Uploading pipeline"
|
55
|
-
unless Buildkite::Pipelines::Command.pipeline
|
55
|
+
unless Buildkite::Pipelines::Command.pipeline(:upload, file.path)
|
56
56
|
logger.info "Pipeline upload failed, saving as artifact…"
|
57
57
|
Buildkite::Pipelines::Command.artifact!(:upload, file.path)
|
58
|
+
abort
|
58
59
|
end
|
59
60
|
logger.info "+++ :toolbox: Setting job meta-data to #{Buildkite.env.job_id.color(:yellow)}"
|
60
61
|
Buildkite::Pipelines::Command.meta_data!(:set, Builder::META_DATA.fetch(:job), Buildkite.env.job_id)
|
@@ -81,12 +82,6 @@ module Buildkite
|
|
81
82
|
|
82
83
|
attr_reader :extensions
|
83
84
|
|
84
|
-
def load_manifests
|
85
|
-
Loaders::Manifests.load(root).each do |name, asset|
|
86
|
-
Manifest[name] = asset
|
87
|
-
end
|
88
|
-
end
|
89
|
-
|
90
85
|
def upload_artifacts
|
91
86
|
return if artifacts.empty?
|
92
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:
|
4
|
+
version: 3.1.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-08 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
|