buildkite-builder 1.3.0 → 2.0.0.beta1
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 +12 -0
- data/VERSION +1 -1
- data/lib/buildkite/builder.rb +10 -1
- data/lib/buildkite/builder/commands.rb +2 -2
- data/lib/buildkite/builder/commands/abstract.rb +4 -4
- data/lib/buildkite/builder/commands/files.rb +6 -7
- data/lib/buildkite/builder/commands/preview.rb +1 -1
- data/lib/buildkite/builder/commands/run.rb +1 -1
- data/lib/buildkite/builder/data.rb +41 -0
- data/lib/buildkite/builder/dsl.rb +17 -0
- data/lib/buildkite/builder/extension.rb +51 -0
- data/lib/buildkite/builder/extension_manager.rb +55 -0
- data/lib/buildkite/builder/extensions.rb +12 -0
- data/lib/buildkite/builder/extensions/env.rb +21 -0
- data/lib/buildkite/builder/extensions/notify.rb +21 -0
- data/lib/buildkite/builder/extensions/steps.rb +60 -0
- data/lib/buildkite/builder/extensions/use.rb +13 -0
- data/lib/buildkite/builder/github.rb +1 -1
- data/lib/buildkite/builder/group.rb +41 -0
- data/lib/buildkite/builder/loaders.rb +1 -1
- data/lib/buildkite/builder/loaders/{processors.rb → extensions.rb} +9 -9
- data/lib/buildkite/builder/{context.rb → pipeline.rb} +42 -47
- data/lib/buildkite/builder/plugin_registry.rb +27 -0
- data/lib/buildkite/builder/step_collection.rb +43 -0
- data/lib/buildkite/builder/template_registry.rb +27 -0
- data/lib/buildkite/pipelines.rb +0 -1
- data/lib/buildkite/pipelines/attributes.rb +1 -1
- data/lib/buildkite/pipelines/helpers/command.rb +1 -5
- data/lib/buildkite/pipelines/helpers/plugins.rb +1 -1
- data/lib/buildkite/pipelines/step_context.rb +0 -4
- data/lib/buildkite/pipelines/steps/abstract.rb +12 -7
- metadata +19 -9
- data/lib/buildkite/builder/processors.rb +0 -9
- data/lib/buildkite/builder/processors/abstract.rb +0 -76
- data/lib/buildkite/pipelines/pipeline.rb +0 -140
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 7a9777c2d258caf0ee500fee89d04fe9385a9357f2df66f007b60c88bd361afa
|
4
|
+
data.tar.gz: f8a8e77e07fe770231f00bc7d3a693524cb5495f45c0529313737152dd44be1f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 824bb77591ec310cace0138dd32269cd379ba244ec0283b53cd86d1e6001b24bd0a208c5662bf1b4d171c773e85c0053decfe619431cccbe6c38e24e7badb32d
|
7
|
+
data.tar.gz: 30502c1de926f6e48423b4d254dc82b86248f2bf5c7e290f50bd972b63ef9d9702bbdd0dd4c81f3cd37aa0da5b3f4076402d72d3f6eb5531b662a96cfdbfa3a4
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,15 @@
|
|
1
|
+
## 1.5.0
|
2
|
+
* Merge `BuildKite::Builder::Context` and `BuildKite::Pipelines::Pipeline` to `BuildKite::Builder::Pipeline` (#37)
|
3
|
+
|
4
|
+
## 1.4.1
|
5
|
+
* Fix the Github API Builder to account for Buildkite having both `.git` and no file exention repository URIs (#33)
|
6
|
+
|
7
|
+
## 1.4.0
|
8
|
+
* Fix the `files` command. You now pass in the manifest with the `--manifest` CLI argument.
|
9
|
+
|
10
|
+
## 1.3.1
|
11
|
+
* Expose `data` from `StepContext` to `Step`
|
12
|
+
|
1
13
|
## 1.3.0
|
2
14
|
* Add ability for step to store data in step context
|
3
15
|
* Move `upload` from `BuildKite::Builder::Commands::Run` to `BuildKite::Builder::Context`
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
|
1
|
+
2.0.0.beta1
|
data/lib/buildkite/builder.rb
CHANGED
@@ -5,8 +5,14 @@ require 'pathname'
|
|
5
5
|
module Buildkite
|
6
6
|
module Builder
|
7
7
|
autoload :Commands, File.expand_path('builder/commands', __dir__)
|
8
|
-
autoload :
|
8
|
+
autoload :Group, File.expand_path('builder/group', __dir__)
|
9
|
+
autoload :Pipeline, File.expand_path('builder/pipeline', __dir__)
|
9
10
|
autoload :Definition, File.expand_path('builder/definition', __dir__)
|
11
|
+
autoload :Data, File.expand_path('builder/data', __dir__)
|
12
|
+
autoload :Dsl, File.expand_path('builder/dsl', __dir__)
|
13
|
+
autoload :Extension, File.expand_path('builder/extension', __dir__)
|
14
|
+
autoload :ExtensionManager, File.expand_path('builder/extension_manager', __dir__)
|
15
|
+
autoload :Extensions, File.expand_path('builder/extensions', __dir__)
|
10
16
|
autoload :FileResolver, File.expand_path('builder/file_resolver', __dir__)
|
11
17
|
autoload :Github, File.expand_path('builder/github', __dir__)
|
12
18
|
autoload :Loaders, File.expand_path('builder/loaders', __dir__)
|
@@ -14,6 +20,9 @@ module Buildkite
|
|
14
20
|
autoload :Manifest, File.expand_path('builder/manifest', __dir__)
|
15
21
|
autoload :Processors, File.expand_path('builder/processors', __dir__)
|
16
22
|
autoload :Rainbow, File.expand_path('builder/rainbow', __dir__)
|
23
|
+
autoload :StepCollection, File.expand_path('builder/step_collection', __dir__)
|
24
|
+
autoload :TemplateRegistry, File.expand_path('builder/template_registry', __dir__)
|
25
|
+
autoload :PluginRegistry, File.expand_path('builder/plugin_registry', __dir__)
|
17
26
|
|
18
27
|
BUILDKITE_DIRECTORY_NAME = Pathname.new('.buildkite').freeze
|
19
28
|
|
@@ -32,10 +32,10 @@ module Buildkite
|
|
32
32
|
puts <<~HELP
|
33
33
|
#{'SYNOPSIS'.bright}
|
34
34
|
\t#{'buildkite-builder'.bright} COMMAND [OPTIONS] [PIPELINE]
|
35
|
-
|
35
|
+
|
36
36
|
\t#{'To see available options for specific commands:'.color(:dimgray)}
|
37
37
|
\t#{'buildkite-builder'.bright} COMMAND --help
|
38
|
-
|
38
|
+
|
39
39
|
#{'COMMANDS'.bright}
|
40
40
|
HELP
|
41
41
|
COMMANDS.each do |command, klass|
|
@@ -8,9 +8,9 @@ module Buildkite
|
|
8
8
|
class Abstract
|
9
9
|
PIPELINES_DIRECTORY = 'pipelines'
|
10
10
|
POSSIBLE_PIPELINE_PATHS = [
|
11
|
-
File.join('.buildkite',
|
12
|
-
File.join('buildkite',
|
13
|
-
File.join(
|
11
|
+
File.join('.buildkite', Pipeline::PIPELINE_DEFINITION_FILE),
|
12
|
+
File.join('buildkite', Pipeline::PIPELINE_DEFINITION_FILE),
|
13
|
+
File.join(Pipeline::PIPELINE_DEFINITION_FILE)
|
14
14
|
].freeze
|
15
15
|
POSSIBLE_PIPELINES_PATHS = [
|
16
16
|
File.join('.buildkite', PIPELINES_DIRECTORY),
|
@@ -91,7 +91,7 @@ module Buildkite
|
|
91
91
|
|
92
92
|
def find_root_by_multi_pipeline
|
93
93
|
pipelines_path = POSSIBLE_PIPELINES_PATHS.map { |path| Builder.root.join(path) }.find(&:directory?)
|
94
|
-
|
94
|
+
|
95
95
|
if pipelines_path
|
96
96
|
if pipeline_slug
|
97
97
|
path = pipelines_path.join(pipeline_slug)
|
@@ -9,14 +9,13 @@ module Buildkite
|
|
9
9
|
self.description = 'Outputs files that match the specified manifest.'
|
10
10
|
|
11
11
|
def run
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
end
|
12
|
+
manifests = Loaders::Manifests.load(pipeline_path)
|
13
|
+
puts manifests[options[:manifest]].files.sort.join("\n")
|
14
|
+
end
|
16
15
|
|
17
|
-
|
18
|
-
|
19
|
-
|
16
|
+
def parse_options(opts)
|
17
|
+
opts.on('--manifest MANIFEST', 'The manifest to use') do |manifest|
|
18
|
+
options[:manifest] = manifest
|
20
19
|
end
|
21
20
|
end
|
22
21
|
end
|
@@ -16,7 +16,7 @@ module Buildkite
|
|
16
16
|
# This entrypoint is for running on CI. It expects certain environment
|
17
17
|
# variables to be set. It also uploads the pipeline to Buildkite.
|
18
18
|
log.info "#{'+++ ' if Buildkite.env}🧰 " + 'Buildkite Builder'.color(:springgreen) + " ─ #{relative_pipeline_path.to_s.yellow}"
|
19
|
-
|
19
|
+
Pipeline.new(pipeline_path, logger: log).upload
|
20
20
|
end
|
21
21
|
|
22
22
|
private
|
@@ -0,0 +1,41 @@
|
|
1
|
+
module Buildkite
|
2
|
+
module Builder
|
3
|
+
class Data
|
4
|
+
def initialize
|
5
|
+
@data = Hash.new
|
6
|
+
end
|
7
|
+
|
8
|
+
def to_definition
|
9
|
+
@data.each_with_object({}) do |(key, value), hash|
|
10
|
+
value = value.respond_to?(:to_definition) ? value.to_definition : value
|
11
|
+
|
12
|
+
next if value.empty?
|
13
|
+
|
14
|
+
hash[key] = value
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
private
|
19
|
+
|
20
|
+
def method_missing(name, *args, &block)
|
21
|
+
if name.end_with?('=')
|
22
|
+
name = name.to_s.delete_suffix('=').to_sym
|
23
|
+
|
24
|
+
if respond_to_missing?(name)
|
25
|
+
raise ArgumentError, "Data already contains key '#{name}'"
|
26
|
+
else
|
27
|
+
return @data[name] = args.first
|
28
|
+
end
|
29
|
+
elsif respond_to_missing?(name)
|
30
|
+
return @data[name]
|
31
|
+
end
|
32
|
+
|
33
|
+
super
|
34
|
+
end
|
35
|
+
|
36
|
+
def respond_to_missing?(name, *)
|
37
|
+
@data.key?(name)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Buildkite
|
4
|
+
module Builder
|
5
|
+
class Dsl
|
6
|
+
attr_reader :context
|
7
|
+
|
8
|
+
def extend(mod)
|
9
|
+
mod < Extension ? super(mod.dsl) : super
|
10
|
+
end
|
11
|
+
|
12
|
+
def initialize(context)
|
13
|
+
@context = context
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Buildkite
|
4
|
+
module Builder
|
5
|
+
class Extension
|
6
|
+
class << self
|
7
|
+
attr_reader :dsl
|
8
|
+
|
9
|
+
def dsl(&block)
|
10
|
+
@dsl = Module.new(&block) if block_given?
|
11
|
+
@dsl
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
attr_reader :context
|
16
|
+
attr_reader :options
|
17
|
+
|
18
|
+
def initialize(context, **options)
|
19
|
+
@context = context
|
20
|
+
@options = options
|
21
|
+
|
22
|
+
prepare
|
23
|
+
end
|
24
|
+
|
25
|
+
def build
|
26
|
+
# Override to provide extra functionality.
|
27
|
+
end
|
28
|
+
|
29
|
+
private
|
30
|
+
|
31
|
+
def buildkite
|
32
|
+
@buildkite ||= begin
|
33
|
+
unless Buildkite.env
|
34
|
+
raise 'Must be in Buildkite environment to access the Buildkite API'
|
35
|
+
end
|
36
|
+
|
37
|
+
Buildkite::Pipelines::Api.new(Buildkite.env.api_token)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def prepare
|
42
|
+
# Override to provide extra functionality.
|
43
|
+
end
|
44
|
+
|
45
|
+
def pipeline(&block)
|
46
|
+
context.dsl.instance_eval(&block) if block_given?
|
47
|
+
context
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
module Buildkite
|
2
|
+
module Builder
|
3
|
+
class ExtensionManager
|
4
|
+
include LoggingUtils
|
5
|
+
using Rainbow
|
6
|
+
|
7
|
+
def initialize(context)
|
8
|
+
@context = context
|
9
|
+
@extensions = []
|
10
|
+
|
11
|
+
Loaders::Extensions.load(@context.root)
|
12
|
+
end
|
13
|
+
|
14
|
+
def use(extension, **args)
|
15
|
+
unless extension < Buildkite::Builder::Extension
|
16
|
+
raise "#{extension} must subclass Buildkite::Builder::Extension"
|
17
|
+
end
|
18
|
+
|
19
|
+
@extensions.push(extension.new(@context, **args))
|
20
|
+
@context.dsl.extend(extension)
|
21
|
+
end
|
22
|
+
|
23
|
+
def build
|
24
|
+
@extensions.each do |extension|
|
25
|
+
log_build(extension.class.name) { extension.build }
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
private
|
30
|
+
|
31
|
+
def log
|
32
|
+
@context.logger
|
33
|
+
end
|
34
|
+
|
35
|
+
def log_build(name)
|
36
|
+
log.info "\nProcessing ".color(:dimgray) + name.color(:springgreen)
|
37
|
+
|
38
|
+
results = benchmark('└──'.color(:springgreen) + ' Finished in %s'.color(:dimgray)) do
|
39
|
+
formatter = log.formatter
|
40
|
+
log.formatter = proc do |_severity, _datetime, _progname, msg|
|
41
|
+
'│'.color(:springgreen) + " #{msg}\n"
|
42
|
+
end
|
43
|
+
|
44
|
+
begin
|
45
|
+
yield
|
46
|
+
ensure
|
47
|
+
log.formatter = formatter
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
log.info results
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Buildkite
|
4
|
+
module Builder
|
5
|
+
module Extensions
|
6
|
+
autoload :Env, File.expand_path('extensions/env', __dir__)
|
7
|
+
autoload :Notify, File.expand_path('extensions/notify', __dir__)
|
8
|
+
autoload :Steps, File.expand_path('extensions/steps', __dir__)
|
9
|
+
autoload :Use, File.expand_path('extensions/use', __dir__)
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module Buildkite
|
2
|
+
module Builder
|
3
|
+
module Extensions
|
4
|
+
class Env < Extension
|
5
|
+
def prepare
|
6
|
+
context.data.env = {}
|
7
|
+
end
|
8
|
+
|
9
|
+
dsl do
|
10
|
+
def env(*args)
|
11
|
+
if args.first.is_a?(Hash)
|
12
|
+
context.data.env.merge!(args.first.transform_keys(&:to_s))
|
13
|
+
else
|
14
|
+
raise ArgumentError, 'value must be hash'
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module Buildkite
|
2
|
+
module Builder
|
3
|
+
module Extensions
|
4
|
+
class Notify < Extension
|
5
|
+
def prepare
|
6
|
+
context.data.notify = []
|
7
|
+
end
|
8
|
+
|
9
|
+
dsl do
|
10
|
+
def notify(*args)
|
11
|
+
if args.first.is_a?(Hash)
|
12
|
+
context.data.notify.push(args.first.transform_keys(&:to_s))
|
13
|
+
else
|
14
|
+
raise ArgumentError, 'value must be hash'
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
module Buildkite
|
2
|
+
module Builder
|
3
|
+
module Extensions
|
4
|
+
class Steps < Extension
|
5
|
+
def prepare
|
6
|
+
context.data.steps = StepCollection.new(
|
7
|
+
TemplateRegistry.new(context.root),
|
8
|
+
PluginRegistry.new
|
9
|
+
)
|
10
|
+
end
|
11
|
+
|
12
|
+
dsl do
|
13
|
+
def group(label = nil, &block)
|
14
|
+
raise "Group does not allow nested in another Group" if context.is_a?(Group)
|
15
|
+
|
16
|
+
context.data.steps.push(Buildkite::Builder::Group.new(label, context.data.steps, &block))
|
17
|
+
end
|
18
|
+
|
19
|
+
def plugin(name, uri, version)
|
20
|
+
context.data.steps.plugins.add(name, uri, version)
|
21
|
+
end
|
22
|
+
|
23
|
+
def block(template = nil, **args, &block)
|
24
|
+
context.data.steps.add(Pipelines::Steps::Block, template, **args, &block)
|
25
|
+
end
|
26
|
+
|
27
|
+
def command(template = nil, **args, &block)
|
28
|
+
context.data.steps.add(Pipelines::Steps::Command, template, **args, &block)
|
29
|
+
end
|
30
|
+
|
31
|
+
def input(template = nil, **args, &block)
|
32
|
+
context.data.steps.add(Pipelines::Steps::Input, template, **args, &block)
|
33
|
+
end
|
34
|
+
|
35
|
+
def trigger(template = nil, **args, &block)
|
36
|
+
context.data.steps.add(Pipelines::Steps::Trigger, template, **args, &block)
|
37
|
+
end
|
38
|
+
|
39
|
+
def skip(template = nil, **args, &block)
|
40
|
+
step = context.data.steps.add(Pipelines::Steps::Skip, template, **args, &block)
|
41
|
+
# A skip step has a nil/noop command.
|
42
|
+
step.command(nil)
|
43
|
+
# Always set the skip attribute if it's in a falsey state.
|
44
|
+
step.skip(true) if !step.get(:skip) || step.skip.empty?
|
45
|
+
step
|
46
|
+
end
|
47
|
+
|
48
|
+
def wait(attributes = {}, &block)
|
49
|
+
step = context.data.steps.add(Pipelines::Steps::Wait, &block)
|
50
|
+
step.wait(nil)
|
51
|
+
attributes.each do |key, value|
|
52
|
+
step.set(key, value)
|
53
|
+
end
|
54
|
+
step
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
@@ -11,7 +11,7 @@ module Buildkite
|
|
11
11
|
ACCEPT_HEADER = 'application/vnd.github.v3+json'
|
12
12
|
LINK_HEADER = 'link'
|
13
13
|
NEXT_LINK_REGEX = /<(?<uri>.+)>; rel="next"/.freeze
|
14
|
-
REPO_REGEX = /github\.com(?::|\/)(
|
14
|
+
REPO_REGEX = /github\.com(?::|\/)(.*?)(?:\.git)?\z/.freeze
|
15
15
|
PER_PAGE = 100
|
16
16
|
|
17
17
|
def self.pull_request_files
|
@@ -0,0 +1,41 @@
|
|
1
|
+
module Buildkite
|
2
|
+
module Builder
|
3
|
+
class Group
|
4
|
+
include Buildkite::Pipelines::Attributes
|
5
|
+
|
6
|
+
attr_reader :label
|
7
|
+
attr_reader :data
|
8
|
+
|
9
|
+
attribute :depends_on, append: true
|
10
|
+
attribute :key
|
11
|
+
|
12
|
+
def self.to_sym
|
13
|
+
name.split('::').last.downcase.to_sym
|
14
|
+
end
|
15
|
+
|
16
|
+
def initialize(label, steps, &block)
|
17
|
+
@label = label
|
18
|
+
@data = Data.new
|
19
|
+
@data.steps = StepCollection.new(
|
20
|
+
steps.templates,
|
21
|
+
steps.plugins
|
22
|
+
)
|
23
|
+
@data.notify = []
|
24
|
+
|
25
|
+
@dsl = Dsl.new(self)
|
26
|
+
@dsl.extend(Extensions::Steps)
|
27
|
+
@dsl.extend(Extensions::Notify)
|
28
|
+
instance_eval(&block)
|
29
|
+
end
|
30
|
+
|
31
|
+
def to_h
|
32
|
+
attributes = super
|
33
|
+
{ group: label }.merge(attributes).merge(data.to_definition)
|
34
|
+
end
|
35
|
+
|
36
|
+
def method_missing(method_name, *_args, &_block)
|
37
|
+
@dsl.public_send(method_name, *_args, &_block)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -6,7 +6,7 @@ module Buildkite
|
|
6
6
|
autoload :Abstract, File.expand_path('loaders/abstract', __dir__)
|
7
7
|
autoload :Manifests, File.expand_path('loaders/manifests', __dir__)
|
8
8
|
autoload :Templates, File.expand_path('loaders/templates', __dir__)
|
9
|
-
autoload :
|
9
|
+
autoload :Extensions, File.expand_path('loaders/extensions', __dir__)
|
10
10
|
end
|
11
11
|
end
|
12
12
|
end
|
@@ -5,17 +5,17 @@ require 'pathname'
|
|
5
5
|
module Buildkite
|
6
6
|
module Builder
|
7
7
|
module Loaders
|
8
|
-
class
|
9
|
-
|
8
|
+
class Extensions < Abstract
|
9
|
+
EXTENSIONS_PATH = Pathname.new('extensions').freeze
|
10
10
|
|
11
11
|
def load
|
12
|
-
|
13
|
-
|
12
|
+
load_extensions_from_path(global_extensions_path)
|
13
|
+
load_extensions_from_path(pipeline_extensions_path)
|
14
14
|
end
|
15
15
|
|
16
16
|
private
|
17
17
|
|
18
|
-
def
|
18
|
+
def load_extensions_from_path(path)
|
19
19
|
return unless path.directory?
|
20
20
|
|
21
21
|
path.children.map do |file|
|
@@ -24,12 +24,12 @@ module Buildkite
|
|
24
24
|
end
|
25
25
|
end
|
26
26
|
|
27
|
-
def
|
28
|
-
buildkite_path.join(
|
27
|
+
def global_extensions_path
|
28
|
+
buildkite_path.join(EXTENSIONS_PATH)
|
29
29
|
end
|
30
30
|
|
31
|
-
def
|
32
|
-
root.join(
|
31
|
+
def pipeline_extensions_path
|
32
|
+
root.join(EXTENSIONS_PATH)
|
33
33
|
end
|
34
34
|
end
|
35
35
|
end
|
@@ -1,59 +1,56 @@
|
|
1
1
|
require 'logger'
|
2
2
|
require 'tempfile'
|
3
|
+
require 'yaml'
|
4
|
+
require 'pathname'
|
5
|
+
require 'forwardable'
|
3
6
|
|
4
7
|
module Buildkite
|
5
8
|
module Builder
|
6
|
-
class
|
9
|
+
class Pipeline
|
10
|
+
extend Forwardable
|
7
11
|
include Definition::Helper
|
8
12
|
include LoggingUtils
|
9
13
|
using Rainbow
|
10
14
|
|
11
15
|
PIPELINE_DEFINITION_FILE = Pathname.new('pipeline.rb').freeze
|
12
16
|
|
13
|
-
|
14
|
-
|
15
|
-
attr_reader :
|
16
|
-
|
17
|
+
def_delegator :@extensions, :use
|
18
|
+
|
19
|
+
attr_reader :logger,
|
20
|
+
:root,
|
21
|
+
:artifacts,
|
22
|
+
:plugins,
|
23
|
+
:dsl,
|
24
|
+
:data
|
17
25
|
|
18
26
|
def self.build(root, logger: nil)
|
19
|
-
|
20
|
-
context.build
|
21
|
-
context
|
27
|
+
new(root, logger: logger)
|
22
28
|
end
|
23
29
|
|
24
30
|
def initialize(root, logger: nil)
|
25
31
|
@root = root
|
26
32
|
@logger = logger || Logger.new(File::NULL)
|
27
33
|
@artifacts = []
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
load_pipeline
|
39
|
-
run_processors
|
40
|
-
end
|
41
|
-
end
|
42
|
-
logger.info(results)
|
43
|
-
|
44
|
-
@pipeline
|
34
|
+
@plugins = {}
|
35
|
+
@dsl = Dsl.new(self)
|
36
|
+
@extensions = ExtensionManager.new(self)
|
37
|
+
@data = Data.new
|
38
|
+
|
39
|
+
use(Extensions::Use)
|
40
|
+
use(Extensions::Env)
|
41
|
+
use(Extensions::Notify)
|
42
|
+
use(Extensions::Steps)
|
43
|
+
load_manifests
|
45
44
|
end
|
46
45
|
|
47
46
|
def upload
|
48
|
-
build unless @pipeline
|
49
|
-
|
50
47
|
logger.info '+++ :paperclip: Uploading artifacts'
|
51
48
|
upload_artifacts
|
52
49
|
|
53
50
|
# Upload the pipeline.
|
54
51
|
Tempfile.create(['pipeline', '.yml']) do |file|
|
55
52
|
file.sync = true
|
56
|
-
file.write(
|
53
|
+
file.write(to_yaml)
|
57
54
|
|
58
55
|
logger.info '+++ :paperclip: Uploading pipeline.yml as artifact'
|
59
56
|
Buildkite::Pipelines::Command.artifact!(:upload, file.path)
|
@@ -62,27 +59,29 @@ module Buildkite
|
|
62
59
|
end
|
63
60
|
end
|
64
61
|
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
62
|
+
def to_h
|
63
|
+
@pipeline_hash ||= begin
|
64
|
+
results = benchmark("\nDone (%s)".color(:springgreen)) do
|
65
|
+
dsl.instance_eval(&pipeline_definition)
|
66
|
+
extensions.build
|
67
|
+
end
|
68
|
+
logger.info(results)
|
69
|
+
# Build the pipeline definition from pipeline data.
|
70
|
+
Pipelines::Helpers.sanitize(data.to_definition)
|
70
71
|
end
|
71
72
|
end
|
72
73
|
|
73
|
-
def
|
74
|
-
|
75
|
-
pipeline.template(name, &asset)
|
76
|
-
end
|
74
|
+
def to_yaml
|
75
|
+
YAML.dump(to_h)
|
77
76
|
end
|
78
77
|
|
79
|
-
|
80
|
-
|
81
|
-
|
78
|
+
private
|
79
|
+
|
80
|
+
attr_reader :extensions
|
82
81
|
|
83
|
-
def
|
84
|
-
|
85
|
-
|
82
|
+
def load_manifests
|
83
|
+
Loaders::Manifests.load(root).each do |name, asset|
|
84
|
+
Manifest[name] = asset
|
86
85
|
end
|
87
86
|
end
|
88
87
|
|
@@ -96,10 +95,6 @@ module Buildkite
|
|
96
95
|
end
|
97
96
|
end
|
98
97
|
|
99
|
-
def load_pipeline
|
100
|
-
pipeline.instance_eval(&pipeline_definition)
|
101
|
-
end
|
102
|
-
|
103
98
|
def pipeline_definition
|
104
99
|
@pipeline_definition ||= load_definition(root.join(PIPELINE_DEFINITION_FILE), Definition::Pipeline)
|
105
100
|
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module Buildkite
|
2
|
+
module Builder
|
3
|
+
class PluginRegistry
|
4
|
+
def initialize
|
5
|
+
@plugins = {}
|
6
|
+
end
|
7
|
+
|
8
|
+
def add(name, uri, version)
|
9
|
+
name = name.to_s
|
10
|
+
|
11
|
+
if @plugins.key?(name)
|
12
|
+
raise ArgumentError, "Plugin already defined: #{name}"
|
13
|
+
end
|
14
|
+
|
15
|
+
@plugins[name] = [uri, version]
|
16
|
+
end
|
17
|
+
|
18
|
+
def fetch(name)
|
19
|
+
@plugins[name]
|
20
|
+
end
|
21
|
+
|
22
|
+
def to_definition
|
23
|
+
# No-op
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
module Buildkite
|
2
|
+
module Builder
|
3
|
+
class StepCollection
|
4
|
+
attr_reader :templates
|
5
|
+
attr_reader :plugins
|
6
|
+
attr_reader :steps
|
7
|
+
|
8
|
+
def initialize(templates, plugins)
|
9
|
+
@templates = templates
|
10
|
+
@plugins = plugins
|
11
|
+
@steps = []
|
12
|
+
end
|
13
|
+
|
14
|
+
def each(*types)
|
15
|
+
types = types.flatten
|
16
|
+
|
17
|
+
@steps.each do |step|
|
18
|
+
if types.include?(step.class.to_sym)
|
19
|
+
yield step
|
20
|
+
end
|
21
|
+
|
22
|
+
if step.is_a?(Group)
|
23
|
+
step.data.steps.each(*types) do |step|
|
24
|
+
yield step
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def add(step_class, template = nil, **args, &block)
|
31
|
+
@steps.push(step_class.new(self, template, **args, &block)).last
|
32
|
+
end
|
33
|
+
|
34
|
+
def push(step)
|
35
|
+
@steps.push(step)
|
36
|
+
end
|
37
|
+
|
38
|
+
def to_definition
|
39
|
+
@steps.map(&:to_h)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module Buildkite
|
2
|
+
module Builder
|
3
|
+
class TemplateRegistry
|
4
|
+
def initialize(root)
|
5
|
+
@templates = {}
|
6
|
+
|
7
|
+
Loaders::Templates.load(root).each do |name, asset|
|
8
|
+
@templates[name.to_s] = asset
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
def find(name)
|
13
|
+
return unless name
|
14
|
+
|
15
|
+
unless definition = @templates[name.to_s]
|
16
|
+
raise ArgumentError, "Template not defined: #{name}"
|
17
|
+
end
|
18
|
+
|
19
|
+
definition
|
20
|
+
end
|
21
|
+
|
22
|
+
def to_definition
|
23
|
+
# No-op
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
data/lib/buildkite/pipelines.rb
CHANGED
@@ -6,7 +6,6 @@ module Buildkite
|
|
6
6
|
autoload :Attributes, File.expand_path('pipelines/attributes', __dir__)
|
7
7
|
autoload :Command, File.expand_path('pipelines/command', __dir__)
|
8
8
|
autoload :Helpers, File.expand_path('pipelines/helpers', __dir__)
|
9
|
-
autoload :Pipeline, File.expand_path('pipelines/pipeline', __dir__)
|
10
9
|
autoload :Plugin, File.expand_path('pipelines/plugin', __dir__)
|
11
10
|
autoload :StepContext, File.expand_path('pipelines/step_context', __dir__)
|
12
11
|
autoload :Steps, File.expand_path('pipelines/steps', __dir__)
|
@@ -84,7 +84,7 @@ module Buildkite
|
|
84
84
|
end
|
85
85
|
|
86
86
|
# Define a helper method that is equivalent to `||=` or `Set#add?`. It will
|
87
|
-
# set the attribute
|
87
|
+
# set the attribute if it hasn't been already set. It will return true/false
|
88
88
|
# for whether or not the value was set.
|
89
89
|
define_method("#{method_name}?") do |*args|
|
90
90
|
if args.empty?
|
@@ -12,7 +12,7 @@ module Buildkite
|
|
12
12
|
raise ArgumentError, "Plugin already used for command step: #{plugin_name}"
|
13
13
|
end
|
14
14
|
|
15
|
-
uri, version =
|
15
|
+
uri, version = step_collection.plugins.fetch(plugin_name)
|
16
16
|
new_plugin = Plugin.new(uri, version, options)
|
17
17
|
@plugins[plugin_name] = new_plugin
|
18
18
|
|
@@ -1,25 +1,30 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require "forwardable"
|
4
|
+
|
3
5
|
module Buildkite
|
4
6
|
module Pipelines
|
5
7
|
module Steps
|
6
8
|
class Abstract
|
9
|
+
extend Forwardable
|
7
10
|
include Attributes
|
8
11
|
|
9
|
-
|
12
|
+
def_delegator :@context, :data
|
13
|
+
|
10
14
|
attr_reader :template
|
15
|
+
attr_reader :step_collection
|
11
16
|
|
12
17
|
def self.to_sym
|
13
18
|
name.split('::').last.downcase.to_sym
|
14
19
|
end
|
15
20
|
|
16
|
-
def initialize(
|
17
|
-
@
|
18
|
-
@template =
|
19
|
-
context = StepContext.new(self, **args)
|
21
|
+
def initialize(step_collection, template_name, **args, &block)
|
22
|
+
@step_collection = step_collection
|
23
|
+
@template = step_collection.templates.find(template_name)
|
24
|
+
@context = StepContext.new(self, **args)
|
20
25
|
|
21
|
-
instance_exec(context, &template) if template
|
22
|
-
instance_exec(context, &block) if block_given?
|
26
|
+
instance_exec(@context, &template) if template
|
27
|
+
instance_exec(@context, &block) if block_given?
|
23
28
|
end
|
24
29
|
end
|
25
30
|
end
|
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: 2.0.0.beta1
|
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: 2021-
|
12
|
+
date: 2021-08-20 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: sorted_set
|
@@ -133,21 +133,32 @@ files:
|
|
133
133
|
- lib/buildkite/builder/commands/files.rb
|
134
134
|
- lib/buildkite/builder/commands/preview.rb
|
135
135
|
- lib/buildkite/builder/commands/run.rb
|
136
|
-
- lib/buildkite/builder/
|
136
|
+
- lib/buildkite/builder/data.rb
|
137
137
|
- lib/buildkite/builder/definition.rb
|
138
|
+
- lib/buildkite/builder/dsl.rb
|
139
|
+
- lib/buildkite/builder/extension.rb
|
140
|
+
- lib/buildkite/builder/extension_manager.rb
|
141
|
+
- lib/buildkite/builder/extensions.rb
|
142
|
+
- lib/buildkite/builder/extensions/env.rb
|
143
|
+
- lib/buildkite/builder/extensions/notify.rb
|
144
|
+
- lib/buildkite/builder/extensions/steps.rb
|
145
|
+
- lib/buildkite/builder/extensions/use.rb
|
138
146
|
- lib/buildkite/builder/file_resolver.rb
|
139
147
|
- lib/buildkite/builder/github.rb
|
148
|
+
- lib/buildkite/builder/group.rb
|
140
149
|
- lib/buildkite/builder/loaders.rb
|
141
150
|
- lib/buildkite/builder/loaders/abstract.rb
|
151
|
+
- lib/buildkite/builder/loaders/extensions.rb
|
142
152
|
- lib/buildkite/builder/loaders/manifests.rb
|
143
|
-
- lib/buildkite/builder/loaders/processors.rb
|
144
153
|
- lib/buildkite/builder/loaders/templates.rb
|
145
154
|
- lib/buildkite/builder/logging_utils.rb
|
146
155
|
- lib/buildkite/builder/manifest.rb
|
147
156
|
- lib/buildkite/builder/manifest/rule.rb
|
148
|
-
- lib/buildkite/builder/
|
149
|
-
- lib/buildkite/builder/
|
157
|
+
- lib/buildkite/builder/pipeline.rb
|
158
|
+
- lib/buildkite/builder/plugin_registry.rb
|
150
159
|
- lib/buildkite/builder/rainbow.rb
|
160
|
+
- lib/buildkite/builder/step_collection.rb
|
161
|
+
- lib/buildkite/builder/template_registry.rb
|
151
162
|
- lib/buildkite/env.rb
|
152
163
|
- lib/buildkite/pipelines.rb
|
153
164
|
- lib/buildkite/pipelines/api.rb
|
@@ -164,7 +175,6 @@ files:
|
|
164
175
|
- lib/buildkite/pipelines/helpers/skip.rb
|
165
176
|
- lib/buildkite/pipelines/helpers/soft_fail.rb
|
166
177
|
- lib/buildkite/pipelines/helpers/timeout_in_minutes.rb
|
167
|
-
- lib/buildkite/pipelines/pipeline.rb
|
168
178
|
- lib/buildkite/pipelines/plugin.rb
|
169
179
|
- lib/buildkite/pipelines/step_context.rb
|
170
180
|
- lib/buildkite/pipelines/steps.rb
|
@@ -194,9 +204,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
194
204
|
version: 2.3.0
|
195
205
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
196
206
|
requirements:
|
197
|
-
- - "
|
207
|
+
- - ">"
|
198
208
|
- !ruby/object:Gem::Version
|
199
|
-
version:
|
209
|
+
version: 1.3.1
|
200
210
|
requirements: []
|
201
211
|
rubygems_version: 3.2.2
|
202
212
|
signing_key:
|
@@ -1,76 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Buildkite
|
4
|
-
module Builder
|
5
|
-
module Processors
|
6
|
-
class Abstract
|
7
|
-
include LoggingUtils
|
8
|
-
using Rainbow
|
9
|
-
|
10
|
-
def self.process(context)
|
11
|
-
new(context).run
|
12
|
-
end
|
13
|
-
|
14
|
-
def initialize(context)
|
15
|
-
@context = context
|
16
|
-
end
|
17
|
-
|
18
|
-
def run
|
19
|
-
_log_run { process }
|
20
|
-
end
|
21
|
-
|
22
|
-
private
|
23
|
-
|
24
|
-
attr_reader :context
|
25
|
-
|
26
|
-
def process
|
27
|
-
raise NotImplementedError
|
28
|
-
end
|
29
|
-
|
30
|
-
def log
|
31
|
-
context.logger
|
32
|
-
end
|
33
|
-
|
34
|
-
def pipeline
|
35
|
-
context.pipeline
|
36
|
-
end
|
37
|
-
|
38
|
-
def buildkite
|
39
|
-
@buildkite ||= begin
|
40
|
-
unless Buildkite.env
|
41
|
-
raise 'Must be in Buildkite environment to access the Buildkite API'
|
42
|
-
end
|
43
|
-
|
44
|
-
Buildkite::Pipelines::Api.new(Buildkite.env.api_token)
|
45
|
-
end
|
46
|
-
end
|
47
|
-
|
48
|
-
def pipeline_steps(*types)
|
49
|
-
steps = pipeline.steps
|
50
|
-
types = types.flatten
|
51
|
-
steps = steps.select { |step| types.include?(step.class.to_sym) } if types.any?
|
52
|
-
steps
|
53
|
-
end
|
54
|
-
|
55
|
-
def _log_run
|
56
|
-
log.info "\nProcessing ".color(:dimgray) + self.class.name.color(:springgreen)
|
57
|
-
|
58
|
-
results = benchmark('└──'.color(:springgreen) + ' Finished in %s'.color(:dimgray)) do
|
59
|
-
formatter = log.formatter
|
60
|
-
log.formatter = proc do |_severity, _datetime, _progname, msg|
|
61
|
-
'│'.color(:springgreen) + " #{msg}\n"
|
62
|
-
end
|
63
|
-
|
64
|
-
begin
|
65
|
-
yield
|
66
|
-
ensure
|
67
|
-
log.formatter = formatter
|
68
|
-
end
|
69
|
-
end
|
70
|
-
|
71
|
-
log.info results
|
72
|
-
end
|
73
|
-
end
|
74
|
-
end
|
75
|
-
end
|
76
|
-
end
|
@@ -1,140 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require 'yaml'
|
4
|
-
require 'pathname'
|
5
|
-
|
6
|
-
module Buildkite
|
7
|
-
module Pipelines
|
8
|
-
class Pipeline
|
9
|
-
attr_reader :steps
|
10
|
-
attr_reader :plugins
|
11
|
-
attr_reader :templates
|
12
|
-
|
13
|
-
def initialize(definition = nil, &block)
|
14
|
-
@env = {}
|
15
|
-
@steps = []
|
16
|
-
@plugins = {}
|
17
|
-
@templates = {}
|
18
|
-
@processors = []
|
19
|
-
@notify = []
|
20
|
-
|
21
|
-
instance_eval(&definition) if definition
|
22
|
-
instance_eval(&block) if block_given?
|
23
|
-
end
|
24
|
-
|
25
|
-
[
|
26
|
-
Steps::Block,
|
27
|
-
Steps::Command,
|
28
|
-
Steps::Input,
|
29
|
-
Steps::Trigger,
|
30
|
-
].each do |type|
|
31
|
-
define_method(type.to_sym) do |template = nil, **args, &block|
|
32
|
-
add(type, template, **args, &block)
|
33
|
-
end
|
34
|
-
end
|
35
|
-
|
36
|
-
def notify(*args)
|
37
|
-
if args.empty?
|
38
|
-
@notify
|
39
|
-
elsif args.first.is_a?(Hash)
|
40
|
-
@notify.push(args.first.transform_keys(&:to_s))
|
41
|
-
else
|
42
|
-
raise ArgumentError, 'value must be hash'
|
43
|
-
end
|
44
|
-
end
|
45
|
-
|
46
|
-
def env(*args)
|
47
|
-
if args.empty?
|
48
|
-
@env
|
49
|
-
elsif args.first.is_a?(Hash)
|
50
|
-
@env.merge!(args.first.transform_keys(&:to_s))
|
51
|
-
else
|
52
|
-
raise ArgumentError, 'value must be hash'
|
53
|
-
end
|
54
|
-
end
|
55
|
-
|
56
|
-
def skip(template = nil, **args, &block)
|
57
|
-
step = add(Steps::Skip, template, **args, &block)
|
58
|
-
# A skip step has a nil/noop command.
|
59
|
-
step.command(nil)
|
60
|
-
# Always set the skip attribute if it's in a falsey state.
|
61
|
-
step.skip(true) if !step.get(:skip) || step.skip.empty?
|
62
|
-
step
|
63
|
-
end
|
64
|
-
|
65
|
-
def wait(attributes = {}, &block)
|
66
|
-
step = add(Steps::Wait, &block)
|
67
|
-
step.wait(nil)
|
68
|
-
attributes.each do |key, value|
|
69
|
-
step.set(key, value)
|
70
|
-
end
|
71
|
-
step
|
72
|
-
end
|
73
|
-
|
74
|
-
def plugin(name, uri, version)
|
75
|
-
name = name.to_s
|
76
|
-
|
77
|
-
if plugins.key?(name)
|
78
|
-
raise ArgumentError, "Plugin already defined: #{name}"
|
79
|
-
end
|
80
|
-
|
81
|
-
@plugins[name] = [uri, version]
|
82
|
-
end
|
83
|
-
|
84
|
-
def template(name, &definition)
|
85
|
-
name = name.to_s
|
86
|
-
|
87
|
-
if templates.key?(name)
|
88
|
-
raise ArgumentError, "Template already defined: #{name}"
|
89
|
-
elsif !block_given?
|
90
|
-
raise ArgumentError, 'Template definition block must be given'
|
91
|
-
end
|
92
|
-
|
93
|
-
@templates[name.to_s] = definition
|
94
|
-
end
|
95
|
-
|
96
|
-
def processors(*processor_classes)
|
97
|
-
unless processor_classes.empty?
|
98
|
-
@processors.clear
|
99
|
-
|
100
|
-
processor_classes.flatten.each do |processor|
|
101
|
-
unless processor < Buildkite::Builder::Processors::Abstract
|
102
|
-
raise "#{processor} must inherit from Buildkite::Builder::Processors::Abstract"
|
103
|
-
end
|
104
|
-
|
105
|
-
@processors << processor
|
106
|
-
end
|
107
|
-
end
|
108
|
-
|
109
|
-
@processors
|
110
|
-
end
|
111
|
-
|
112
|
-
def to_h
|
113
|
-
pipeline = {}
|
114
|
-
pipeline[:env] = env if env.any?
|
115
|
-
pipeline[:notify] = notify if notify.any?
|
116
|
-
pipeline[:steps] = steps.map(&:to_h)
|
117
|
-
|
118
|
-
Helpers.sanitize(pipeline)
|
119
|
-
end
|
120
|
-
|
121
|
-
def to_yaml
|
122
|
-
YAML.dump(to_h)
|
123
|
-
end
|
124
|
-
|
125
|
-
private
|
126
|
-
|
127
|
-
def add(step_class, template = nil, **args, &block)
|
128
|
-
steps.push(step_class.new(self, find_template(template), **args, &block)).last
|
129
|
-
end
|
130
|
-
|
131
|
-
def find_template(name)
|
132
|
-
return unless name
|
133
|
-
|
134
|
-
templates[name.to_s] || begin
|
135
|
-
raise ArgumentError, "Template not defined: #{name}"
|
136
|
-
end
|
137
|
-
end
|
138
|
-
end
|
139
|
-
end
|
140
|
-
end
|