diff --git a/lib/fastlane/plugin/wpmreleasetoolkit/actions/common/buildkite_upload_pipeline_action.rb b/lib/fastlane/plugin/wpmreleasetoolkit/actions/common/buildkite_upload_pipeline_action.rb new file mode 100644 index 000000000..474c87805 --- /dev/null +++ b/lib/fastlane/plugin/wpmreleasetoolkit/actions/common/buildkite_upload_pipeline_action.rb @@ -0,0 +1,70 @@ +module Fastlane + module Actions + class BuildkiteUploadPipelineAction < Action + def self.run(params) + branch = params[:branch] + pipeline_file = params[:pipeline_file] + commit = params[:commit] + env_file = params[:env_file] + + UI.user_error!("Pipeline file not found: #{pipeline_file}") unless File.exist?(pipeline_file) + + UI.message "Uploading pipeline #{pipeline_file} on branch #{branch}, commit #{commit}" + + ENV['BUILDKITE_BRANCH'] = branch + ENV['BUILDKITE_COMMIT'] = commit + + if env_file && File.exist?(env_file) + UI.message("Sourcing environment file: #{env_file}") + + sh(". #{env_file} && buildkite-agent pipeline upload #{pipeline_file}") + else + sh('buildkite-agent', 'pipeline', 'upload', pipeline_file) + end + end + + def self.description + # https://buildkite.com/docs/agent/v3/cli-pipeline#uploading-pipelines + 'Uploads a pipeline to Buildkite, adding all its steps to the current build' + end + + def self.available_options + [ + FastlaneCore::ConfigItem.new( + key: :env_file, + description: 'The path to the environment variables file to be sourced before uploading the pipeline', + optional: true, + type: String + ), + FastlaneCore::ConfigItem.new( + key: :pipeline_file, + description: 'The path to the Buildkite pipeline file', + optional: false, + type: String + ), + FastlaneCore::ConfigItem.new( + key: :branch, + description: 'The branch you want to run the pipeline on', + optional: false, + type: String + ), + FastlaneCore::ConfigItem.new( + key: :commit, + description: 'The commit hash you want to run the pipeline on', + optional: true, + default_value: 'HEAD', + type: String + ), + ] + end + + def self.authors + ['Automattic'] + end + + def self.is_supported?(platform) + true + end + end + end +end diff --git a/spec/buildkite_upload_pipeline_action_spec.rb b/spec/buildkite_upload_pipeline_action_spec.rb new file mode 100644 index 000000000..1449e6272 --- /dev/null +++ b/spec/buildkite_upload_pipeline_action_spec.rb @@ -0,0 +1,113 @@ +require 'spec_helper' + +describe Fastlane::Actions::BuildkiteUploadPipelineAction do + let(:pipeline_file) { 'path/to/pipeline.yml' } + let(:branch) { 'feature-branch' } + let(:commit) { 'abc123' } + + describe 'parameter validation' do + it 'raises an error when pipeline_file is not provided' do + expect do + run_described_fastlane_action(branch: branch) + end.to raise_error(FastlaneCore::Interface::FastlaneError, /pipeline_file/) + end + + it 'raises an error when branch is not provided' do + expect do + run_described_fastlane_action(pipeline_file: pipeline_file) + end.to raise_error(FastlaneCore::Interface::FastlaneError, /branch/) + end + + it 'raises an error when pipeline_file does not exist' do + allow(File).to receive(:exist?).with(pipeline_file).and_return(false) + expect do + run_described_fastlane_action( + pipeline_file: pipeline_file, + branch: branch + ) + end.to raise_error(FastlaneCore::Interface::FastlaneError, /Pipeline file not found/) + end + end + + describe 'pipeline upload' do + before do + allow(File).to receive(:exist?).with(pipeline_file).and_return(true) + end + + it 'calls the right command to upload the pipeline without env_file' do + expect(Fastlane::Action).to receive(:sh).with('buildkite-agent', 'pipeline', 'upload', pipeline_file) + expect(Fastlane::UI).to receive(:message).with("Uploading pipeline #{pipeline_file} on branch #{branch}, commit #{commit}") + + run_described_fastlane_action( + pipeline_file: pipeline_file, + branch: branch, + commit: commit + ) + + expect(ENV['BUILDKITE_BRANCH']).to eq(branch) + expect(ENV['BUILDKITE_COMMIT']).to eq(commit) + end + + it 'calls the right command to upload the pipeline with env_file' do + env_file = 'path/to/env_file' + allow(File).to receive(:exist?).with(env_file).and_return(true) + expect(Fastlane::Action).to receive(:sh).with(". #{env_file} && buildkite-agent pipeline upload #{pipeline_file}") + expect(Fastlane::UI).to receive(:message).with("Uploading pipeline #{pipeline_file} on branch #{branch}, commit #{commit}") + expect(Fastlane::UI).to receive(:message).with("Sourcing environment file: #{env_file}") + + run_described_fastlane_action( + pipeline_file: pipeline_file, + branch: branch, + commit: commit, + env_file: env_file + ) + + expect(ENV['BUILDKITE_BRANCH']).to eq(branch) + expect(ENV['BUILDKITE_COMMIT']).to eq(commit) + end + + it 'skips sourcing env_file when it does not exist' do + env_file = 'path/to/non_existent_env_file' + allow(File).to receive(:exist?).with(env_file).and_return(false) + expect(Fastlane::Action).to receive(:sh).with('buildkite-agent', 'pipeline', 'upload', pipeline_file) + expect(Fastlane::UI).not_to receive(:message).with(/Sourcing environment file/) + + run_described_fastlane_action( + pipeline_file: pipeline_file, + branch: branch, + commit: commit, + env_file: env_file + ) + end + end + + describe 'default values' do + it 'uses default value for commit when not provided' do + allow(File).to receive(:exist?).with(pipeline_file).and_return(true) + expect(Fastlane::Action).to receive(:sh).with('buildkite-agent', 'pipeline', 'upload', pipeline_file) + expect(Fastlane::UI).to receive(:message).with("Uploading pipeline #{pipeline_file} on branch #{branch}, commit HEAD") + + run_described_fastlane_action( + pipeline_file: pipeline_file, + branch: branch + ) + + expect(ENV['BUILDKITE_BRANCH']).to eq(branch) + expect(ENV['BUILDKITE_COMMIT']).to eq('HEAD') + end + end + + describe 'error handling' do + it 'raises an error when the pipeline upload fails' do + allow(File).to receive(:exist?).with(pipeline_file).and_return(true) + allow(Fastlane::Action).to receive(:sh).and_raise(StandardError.new('Upload failed')) + + expect do + run_described_fastlane_action( + pipeline_file: pipeline_file, + branch: branch + ) + end.to raise_error(StandardError, 'Upload failed') + end + end +end