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.
Files changed (36) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +12 -0
  3. data/VERSION +1 -1
  4. data/lib/buildkite/builder.rb +10 -1
  5. data/lib/buildkite/builder/commands.rb +2 -2
  6. data/lib/buildkite/builder/commands/abstract.rb +4 -4
  7. data/lib/buildkite/builder/commands/files.rb +6 -7
  8. data/lib/buildkite/builder/commands/preview.rb +1 -1
  9. data/lib/buildkite/builder/commands/run.rb +1 -1
  10. data/lib/buildkite/builder/data.rb +41 -0
  11. data/lib/buildkite/builder/dsl.rb +17 -0
  12. data/lib/buildkite/builder/extension.rb +51 -0
  13. data/lib/buildkite/builder/extension_manager.rb +55 -0
  14. data/lib/buildkite/builder/extensions.rb +12 -0
  15. data/lib/buildkite/builder/extensions/env.rb +21 -0
  16. data/lib/buildkite/builder/extensions/notify.rb +21 -0
  17. data/lib/buildkite/builder/extensions/steps.rb +60 -0
  18. data/lib/buildkite/builder/extensions/use.rb +13 -0
  19. data/lib/buildkite/builder/github.rb +1 -1
  20. data/lib/buildkite/builder/group.rb +41 -0
  21. data/lib/buildkite/builder/loaders.rb +1 -1
  22. data/lib/buildkite/builder/loaders/{processors.rb → extensions.rb} +9 -9
  23. data/lib/buildkite/builder/{context.rb → pipeline.rb} +42 -47
  24. data/lib/buildkite/builder/plugin_registry.rb +27 -0
  25. data/lib/buildkite/builder/step_collection.rb +43 -0
  26. data/lib/buildkite/builder/template_registry.rb +27 -0
  27. data/lib/buildkite/pipelines.rb +0 -1
  28. data/lib/buildkite/pipelines/attributes.rb +1 -1
  29. data/lib/buildkite/pipelines/helpers/command.rb +1 -5
  30. data/lib/buildkite/pipelines/helpers/plugins.rb +1 -1
  31. data/lib/buildkite/pipelines/step_context.rb +0 -4
  32. data/lib/buildkite/pipelines/steps/abstract.rb +12 -7
  33. metadata +19 -9
  34. data/lib/buildkite/builder/processors.rb +0 -9
  35. data/lib/buildkite/builder/processors/abstract.rb +0 -76
  36. data/lib/buildkite/pipelines/pipeline.rb +0 -140
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 6684f24ab3c156884bcd3055fbddbb7831afa03be9e0b0b2056fbedef023084b
4
- data.tar.gz: 64753e7a15224a0b3c161335cfbc9046ecbaa5e015692ace78001eeef550eea3
3
+ metadata.gz: 7a9777c2d258caf0ee500fee89d04fe9385a9357f2df66f007b60c88bd361afa
4
+ data.tar.gz: f8a8e77e07fe770231f00bc7d3a693524cb5495f45c0529313737152dd44be1f
5
5
  SHA512:
6
- metadata.gz: 21b7f849f79acd215f260644f75767143bb10f2eeab88e0edee7c3728024f128b12f421ddd632ed4163fc0501f44051bc065594906d28643642839be934ac152
7
- data.tar.gz: 5bfe120d20cb914525c61dba9ddec9b298058e6ccb01a5b6a4a55cccc95cff1fa993753cf65ba1041615d9adcb735ffb4545c7a58987a004cc3638b11d4eeba3
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.3.0
1
+ 2.0.0.beta1
@@ -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 :Context, File.expand_path('builder/context', __dir__)
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', Context::PIPELINE_DEFINITION_FILE),
12
- File.join('buildkite', Context::PIPELINE_DEFINITION_FILE),
13
- File.join(Context::PIPELINE_DEFINITION_FILE)
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
- pipeline, manifest = ARGV.first.to_s.split('/')
13
- if !pipeline || !manifest
14
- raise 'You must specify a pipeline and a manifest (eg "mypipeline/mymanifest")'
15
- end
12
+ manifests = Loaders::Manifests.load(pipeline_path)
13
+ puts manifests[options[:manifest]].files.sort.join("\n")
14
+ end
16
15
 
17
- manifests = Loaders::Manifests.load(pipeline)
18
- manifests[manifest].files.each do |file|
19
- puts file
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
@@ -9,7 +9,7 @@ module Buildkite
9
9
  self.description = 'Outputs the pipeline YAML.'
10
10
 
11
11
  def run
12
- puts Context.build(pipeline_path).pipeline.to_yaml
12
+ puts Pipeline.build(pipeline_path).to_yaml
13
13
  end
14
14
  end
15
15
  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
- Context.new(pipeline_path, logger: log).upload
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
@@ -0,0 +1,13 @@
1
+ module Buildkite
2
+ module Builder
3
+ module Extensions
4
+ class Use < Extension
5
+ dsl do
6
+ def use(extension_class, **args)
7
+ context.use(extension_class, **args)
8
+ end
9
+ end
10
+ end
11
+ end
12
+ end
13
+ 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(?::|\/)(.*)\.git\z/.freeze
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 :Processors, File.expand_path('loaders/processors', __dir__)
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 Processors < Abstract
9
- PROCESSORS_PATH = Pathname.new('processors').freeze
8
+ class Extensions < Abstract
9
+ EXTENSIONS_PATH = Pathname.new('extensions').freeze
10
10
 
11
11
  def load
12
- load_processors_from_path(global_processors_path)
13
- load_processors_from_path(pipeline_processors_path)
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 load_processors_from_path(path)
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 global_processors_path
28
- buildkite_path.join(PROCESSORS_PATH)
27
+ def global_extensions_path
28
+ buildkite_path.join(EXTENSIONS_PATH)
29
29
  end
30
30
 
31
- def pipeline_processors_path
32
- root.join(PROCESSORS_PATH)
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 Context
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
- attr_reader :logger
14
- attr_reader :root
15
- attr_reader :pipeline
16
- attr_reader :artifacts
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
- context = new(root, logger: logger)
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
- end
29
-
30
- def build
31
- results = benchmark("\nDone (%s)".color(:springgreen)) do
32
- unless @pipeline
33
- @pipeline = Pipelines::Pipeline.new
34
-
35
- load_manifests
36
- load_templates
37
- load_processors
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(pipeline.to_yaml)
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
- private
66
-
67
- def load_manifests
68
- Loaders::Manifests.load(root).each do |name, asset|
69
- Manifest[name] = asset
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 load_templates
74
- Loaders::Templates.load(root).each do |name, asset|
75
- pipeline.template(name, &asset)
76
- end
74
+ def to_yaml
75
+ YAML.dump(to_h)
77
76
  end
78
77
 
79
- def load_processors
80
- Loaders::Processors.load(root)
81
- end
78
+ private
79
+
80
+ attr_reader :extensions
82
81
 
83
- def run_processors
84
- pipeline.processors.each do |processor|
85
- processor.process(self)
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
@@ -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 iff it hasn't been already set. It will return true/false
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?
@@ -8,11 +8,7 @@ module Buildkite
8
8
  return super if values.empty?
9
9
 
10
10
  values.flatten.each do |value|
11
- if value == :noop
12
- super('true')
13
- else
14
- super(value)
15
- end
11
+ super(value)
16
12
  end
17
13
  end
18
14
  end
@@ -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 = pipeline.plugins.fetch(plugin_name)
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
 
@@ -13,10 +13,6 @@ module Buildkite
13
13
  @data = {}
14
14
  end
15
15
 
16
- def pipeline
17
- step.pipeline
18
- end
19
-
20
16
  def [](key)
21
17
  args[key]
22
18
  end
@@ -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
- attr_reader :pipeline
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(pipeline, template = nil, **args, &block)
17
- @pipeline = pipeline
18
- @template = 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: 1.3.0
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-03-02 00:00:00.000000000 Z
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/context.rb
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/processors.rb
149
- - lib/buildkite/builder/processors/abstract.rb
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: '0'
209
+ version: 1.3.1
200
210
  requirements: []
201
211
  rubygems_version: 3.2.2
202
212
  signing_key:
@@ -1,9 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Buildkite
4
- module Builder
5
- module Processors
6
- autoload :Abstract, File.expand_path('processors/abstract', __dir__)
7
- end
8
- end
9
- end
@@ -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