From 8d728a97e621ab2fa099a5db8111afebd541e16e Mon Sep 17 00:00:00 2001 From: Andrii Mysko Date: Wed, 2 Aug 2023 19:02:03 +0300 Subject: [PATCH] [PRD] TCI/Assembla Handshake with SVN/P4 (#2080) --- lib/travis/build/data.rb | 4 +- lib/travis/build/data/ssh_key.rb | 2 +- lib/travis/vcs.rb | 2 + lib/travis/vcs/perforce.rb | 9 -- lib/travis/vcs/perforce/clone.rb | 35 +++- lib/travis/vcs/svn/clone.rb | 38 +++++ lib/travis/vcs/svn/ssh_key.rb | 8 +- spec/build/data_spec.rb | 9 ++ spec/build/vcs/perforce/clone_spec.rb | 51 ++++++ spec/build/vcs/perforce_spec.rb | 26 +++ spec/build/vcs/svn/clone_spec.rb | 37 +++++ spec/build/vcs/svn/ssh_key_spec.rb | 34 ++++ spec/build/vcs_spec.rb | 25 +++ spec/support/payloads.rb | 225 ++++++++++++++++++++++++++ 14 files changed, 487 insertions(+), 18 deletions(-) create mode 100644 spec/build/vcs/perforce/clone_spec.rb create mode 100644 spec/build/vcs/perforce_spec.rb create mode 100644 spec/build/vcs/svn/clone_spec.rb create mode 100644 spec/build/vcs/svn/ssh_key_spec.rb create mode 100644 spec/build/vcs_spec.rb diff --git a/lib/travis/build/data.rb b/lib/travis/build/data.rb index 6022e4aa24..3f3387d8e8 100644 --- a/lib/travis/build/data.rb +++ b/lib/travis/build/data.rb @@ -99,9 +99,9 @@ def ssh_key? def ssh_key @ssh_key ||= if ssh_key = data[:ssh_key] - SshKey.new(ssh_key[:value], ssh_key[:source], ssh_key[:encoded]) + SshKey.new(ssh_key[:value], ssh_key[:source], ssh_key[:encoded], ssh_key[:public_key]) elsif source_key = data[:config][:source_key] - SshKey.new(source_key, nil, true) + SshKey.new(source_key, nil, true, nil) end end diff --git a/lib/travis/build/data/ssh_key.rb b/lib/travis/build/data/ssh_key.rb index 5418c09c52..7794e2cc60 100644 --- a/lib/travis/build/data/ssh_key.rb +++ b/lib/travis/build/data/ssh_key.rb @@ -3,7 +3,7 @@ module Travis module Build class Data - class SshKey < Struct.new(:value, :source, :encoded) + class SshKey < Struct.new(:value, :source, :encoded, :public_key) CUSTOM = %w(repository_settings travis_yaml) def value diff --git a/lib/travis/vcs.rb b/lib/travis/vcs.rb index 31ed44c425..51cb770e9f 100644 --- a/lib/travis/vcs.rb +++ b/lib/travis/vcs.rb @@ -49,6 +49,7 @@ def checkout(sh,data) def defaults(server_type) @provider_name = server_type + @provider_name = 'svn' if @provider_name == 'subversion' "Travis::Vcs::#{provider_name.to_s.camelize}".constantize.defaults rescue NameError raise Travis::Build::UnknownServiceTypeError.new provider_name @@ -57,6 +58,7 @@ def defaults(server_type) private def vcs(sh,data) provider = data[:repository][:server_type] if data.key?(:repository) + provider = 'svn' if provider == 'subversion' provider = provider_name unless provider @provider_name = provider "Travis::Vcs::#{provider.to_s.camelize}".constantize.new(sh,data) diff --git a/lib/travis/vcs/perforce.rb b/lib/travis/vcs/perforce.rb index 57c822a2aa..cfaa14e2dc 100644 --- a/lib/travis/vcs/perforce.rb +++ b/lib/travis/vcs/perforce.rb @@ -51,7 +51,6 @@ def self.defaults def checkout disable_interactive_auth enable_longpaths if config[:os] == 'windows' - install_ssh_key if install_ssh_key? write_netrc if write_netrc? sh.newline @@ -75,10 +74,6 @@ def enable_longpaths #TODO ? end - def install_ssh_key? - data.ssh_key? - end - def netrc @netrc ||= Netrc.new(sh, data) end @@ -99,10 +94,6 @@ def delete_netrc netrc.delete end - def install_ssh_key - SshKey.new(sh, data).apply - end - def download_tarball Tarball.new(sh, data).apply end diff --git a/lib/travis/vcs/perforce/clone.rb b/lib/travis/vcs/perforce/clone.rb index 8048a12bb1..6fe03898a7 100644 --- a/lib/travis/vcs/perforce/clone.rb +++ b/lib/travis/vcs/perforce/clone.rb @@ -36,13 +36,28 @@ def trace_command def clone sh.export 'P4USER', user, echo: true, assert: false sh.export 'P4CHARSET', 'utf8', echo: false, assert: false - sh.export 'P4PASSWD', ticket, echo: false, assert: false - sh.export 'P4PORT', port, echo: false, assert: false + sh.export 'P4PORT', port, echo: false, assert: false sh.cmd 'p4 trust -y' + if data[:repository][:vcs_type] == 'AssemblaRepository' + sh.cmd "echo $(p4 info | grep 'Server address:' | cut -d ' ' -f 3- 2>/dev/null)=#{user}:#{ticket} > /tmp/p4ticket", echo: false, assert: false + sh.export 'P4TICKETS', '/tmp/p4ticket', echo: false, assert: false + else + sh.export 'P4PASSWD', ticket, echo: false, assert: false + end + + return clone_merge if vcs_pull_request? + sh.cmd "p4 #{p4_opt} client -S //#{dir}/#{checkout_ref} -o | p4 #{p4_opt} client -i" sh.cmd "p4 #{p4_opt} sync -p" end + def clone_merge + sh.cmd "p4 #{p4_opt} client -S //#{dir}/#{pull_request_base_branch} -o | p4 #{p4_opt} client -i" + sh.cmd "p4 #{p4_opt} sync -p" + sh.cmd "p4 #{p4_opt} merge //#{dir}/#{pull_request_head_branch}/... //#{dir}/#{pull_request_base_branch}/..." + sh.cmd "p4 #{p4_opt} resolve -am" + end + def p4_opt '-v ssl.client.trust.name=1' end @@ -105,11 +120,11 @@ def port end def user - data[:sender_login] + data[:repository][:vcs_type] == 'AssemblaRepository' ? data.ssh_key.public_key : data[:sender_login] end def ticket - data[:build_token] + data[:build_token] || data.ssh_key.value end def config @@ -119,6 +134,18 @@ def config def assembla? @assembla ||= data[:repository][:source_url].include? 'assembla' end + + def pull_request_head_branch + data.job[:pull_request_head_branch].shellescape if data.job[:pull_request_head_branch] + end + + def pull_request_base_branch + data.job[:pull_request_base_ref].shellescape if data.job[:pull_request_base_ref] + end + + def vcs_pull_request? + data.repository[:vcs_type].to_s == 'AssemblaRepository' && data.pull_request + end end end end diff --git a/lib/travis/vcs/svn/clone.rb b/lib/travis/vcs/svn/clone.rb index c1d7b57a16..f2d7ba8885 100644 --- a/lib/travis/vcs/svn/clone.rb +++ b/lib/travis/vcs/svn/clone.rb @@ -48,13 +48,37 @@ def trace_command end def clone + return clone_merge if vcs_pull_request? sh.cmd "svn co #{source_url}#{clone_args} #{repository_name}", assert: false, retry: true end def checkout + return checkout_merge if vcs_pull_request? sh.cmd "svn update -r #{checkout_ref}", timing: false end + def clone_merge + target_args = "" + if pull_request_base_branch && pull_request_base_branch == 'trunk' + target_args << "/#{pull_request_base_branch}" + else + target_args << "/branches/#{pull_request_base_branch}" if pull_request_base_branch + end + + sh.cmd "svn co #{source_url}#{target_args} #{repository_name}", assert: false, retry: true + end + + def checkout_merge + source_args = "" + if pull_request_head_branch && pull_request_head_branch == 'trunk' + source_args << "/#{pull_request_head_branch}" + else + source_args << "/branches/#{pull_request_head_branch}" if pull_request_head_branch + end + + sh.cmd "svn merge --non-interactive ^#{source_args}", timing: false + end + def checkout_ref ref = if data.tag tag @@ -70,6 +94,8 @@ def clone_args args = "" if branch && branch == 'trunk' args << "/#{branch}" + elsif data.tag + args << "/tags/#{tag}" if tag else args << "/branches/#{branch}" if branch end @@ -92,6 +118,14 @@ def tag data.tag.shellescape if data.tag end + def pull_request_head_branch + data.job[:pull_request_head_branch].shellescape if data.job[:pull_request_head_branch] + end + + def pull_request_base_branch + data.job[:pull_request_base_ref].shellescape if data.job[:pull_request_base_ref] + end + def user data[:sender_login] end @@ -99,6 +133,10 @@ def user def config data.config end + + def vcs_pull_request? + data.repository[:vcs_type].to_s == 'AssemblaRepository' && data.pull_request + end end end end diff --git a/lib/travis/vcs/svn/ssh_key.rb b/lib/travis/vcs/svn/ssh_key.rb index d1a7a2076b..6486adf73c 100644 --- a/lib/travis/vcs/svn/ssh_key.rb +++ b/lib/travis/vcs/svn/ssh_key.rb @@ -21,11 +21,15 @@ def apply private def key - data[:build_token] + data[:build_token] || data.ssh_key.value end def repository_name - repo_slug&.split('/').last + if assembla? + repo_slug&.gsub('/', '^') + else + repo_slug&.split('/').last + end end def repo_slug diff --git a/spec/build/data_spec.rb b/spec/build/data_spec.rb index dd30f259ee..6059447a04 100644 --- a/spec/build/data_spec.rb +++ b/spec/build/data_spec.rb @@ -9,6 +9,7 @@ it { expect(data.ssh_key.source).to be_nil } it { expect(data.ssh_key).to be_encoded } it { expect(data.ssh_key.fingerprint).to eq('57:78:65:c2:c9:c8:c9:f7:dd:2b:35:39:40:27:d2:40') } + it { expect(data.ssh_key.public_key).to be_nil } end describe 'returns nil if there is no ssh_key' do @@ -24,6 +25,14 @@ it { expect(data.ssh_key.fingerprint).to eq('57:78:65:c2:c9:c8:c9:f7:dd:2b:35:39:40:27:d2:40') } end + context 'when public key is provided' do + let(:public_key) { 'ssh-rsa public-key' } + let(:data) { Travis::Build::Data.new(ssh_key: { value: TEST_PRIVATE_KEY, public_key: public_key, source: 'the source' }) } + + it { expect(data.ssh_key.value).to eql(TEST_PRIVATE_KEY) } + it { expect(data.ssh_key.public_key).to eql(public_key) } + end + describe 'does not fail on an invalid key' do let(:data) { Travis::Build::Data.new(config: { source_key: 'foo' }) } it { expect { data }.to_not raise_error } diff --git a/spec/build/vcs/perforce/clone_spec.rb b/spec/build/vcs/perforce/clone_spec.rb new file mode 100644 index 0000000000..139084d7c6 --- /dev/null +++ b/spec/build/vcs/perforce/clone_spec.rb @@ -0,0 +1,51 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe Travis::Vcs::Perforce::Clone, :sexp do + let(:data) { payload_for(payload_name, :ruby, config: {}) } + let(:sh) { Travis::Shell::Builder.new } + let(:clone) { described_class.new(sh, Travis::Build::Data.new(data)) } + + describe '#apply' do + let(:payload_name) { :perforce } + let(:key_sexp) { [:cmd, "echo $(p4 info | grep 'Server address:' | cut -d ' ' -f 3- 2>/dev/null)=pubkey:privatekey > /tmp/p4ticket"] } + let(:tickets_sexp) { [:export, ['P4TICKETS', '/tmp/p4ticket']] } + let(:client_sexp) { [:cmd, 'p4 -v ssl.client.trust.name=1 client -S //depot/main -o | p4 -v ssl.client.trust.name=1 client -i'] } + + subject { sh.to_sexp } + + before { clone.apply } + + it { is_expected.to include_sexp([:export, ['P4USER', 'pubkey'], echo: true]) } + it { is_expected.to include_sexp([:export, ['P4CHARSET', 'utf8']]) } + it { is_expected.to include_sexp([:export, ['P4PORT', 'ssl:perforce.assembla.com']]) } + it { is_expected.to include_sexp([:cmd, 'p4 trust -y']) } + it { is_expected.to include_sexp(key_sexp) } + it { is_expected.to include_sexp(tickets_sexp) } + it { is_expected.to include_sexp(client_sexp) } + it { is_expected.to include_sexp([:cmd, 'p4 -v ssl.client.trust.name=1 sync -p']) } + it { is_expected.to include_sexp([:cd, 'tempdir', echo: true]) } + it { is_expected.not_to include_sexp([:mkdir, '~/.ssh', recursive: true]) } + + context 'when repository is not from Assembla' do + let(:payload_name) { :perforce_non_assembla } + + it { is_expected.to include_sexp([:export, ['P4USER', 'travisuser'], echo: true]) } + it { is_expected.not_to include_sexp(key_sexp) } + it { is_expected.to include_sexp([:export, ['P4PASSWD', 'mybuildtoken']]) } + it { is_expected.not_to include_sexp(tickets_sexp) } + end + + context 'when the job is a PR' do + let(:payload_name) { :perforce_pull_request } + + it { is_expected.not_to include(client_sexp) } + it { is_expected.to include_sexp(tickets_sexp) } + it { is_expected.to include_sexp([:cmd, 'p4 -v ssl.client.trust.name=1 client -S //depot/main -o | p4 -v ssl.client.trust.name=1 client -i']) } + it { is_expected.to include_sexp([:cmd, 'p4 -v ssl.client.trust.name=1 sync -p']) } + it { is_expected.to include_sexp([:cmd, 'p4 -v ssl.client.trust.name=1 merge //depot/newfeature/... //depot/main/...']) } + it { is_expected.to include_sexp([:cmd, 'p4 -v ssl.client.trust.name=1 resolve -am']) } + end + end +end \ No newline at end of file diff --git a/spec/build/vcs/perforce_spec.rb b/spec/build/vcs/perforce_spec.rb new file mode 100644 index 0000000000..2473bb02d8 --- /dev/null +++ b/spec/build/vcs/perforce_spec.rb @@ -0,0 +1,26 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe Travis::Vcs::Perforce, :sexp do + let(:data) { payload_for(:perforce, :ruby, config: {}) } + let(:sh) { Travis::Shell::Builder.new } + let(:perforce) { described_class.new(sh, Travis::Build::Data.new(data)) } + + describe '#checkout' do + subject { sh.to_sexp } + + before { perforce.checkout } + + it { is_expected.to include_sexp([:export, ['P4USER', 'pubkey'], echo: true]) } + it { is_expected.to include_sexp([:export, ['P4CHARSET', 'utf8']]) } + it { is_expected.to include_sexp([:export, ['P4PORT', 'ssl:perforce.assembla.com']]) } + it { is_expected.to include_sexp([:cmd, 'p4 trust -y']) } + it { is_expected.to include_sexp([:cmd, "echo $(p4 info | grep 'Server address:' | cut -d ' ' -f 3- 2>/dev/null)=pubkey:privatekey > /tmp/p4ticket"]) } + it { is_expected.to include_sexp([:export, ['P4TICKETS', '/tmp/p4ticket']]) } + it { is_expected.to include_sexp([:cmd, 'p4 -v ssl.client.trust.name=1 client -S //depot/main -o | p4 -v ssl.client.trust.name=1 client -i']) } + it { is_expected.to include_sexp([:cmd, 'p4 -v ssl.client.trust.name=1 sync -p']) } + it { is_expected.to include_sexp([:cd, 'tempdir', echo: true]) } + it { is_expected.not_to include_sexp([:mkdir, '~/.ssh', recursive: true]) } + end +end \ No newline at end of file diff --git a/spec/build/vcs/svn/clone_spec.rb b/spec/build/vcs/svn/clone_spec.rb new file mode 100644 index 0000000000..64cd153295 --- /dev/null +++ b/spec/build/vcs/svn/clone_spec.rb @@ -0,0 +1,37 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe Travis::Vcs::Svn::Clone, :sexp do + let(:data) { payload_for(payload_name, :ruby, config: {}) } + let(:sh) { Travis::Shell::Builder.new } + let(:clone) { described_class.new(sh, Travis::Build::Data.new(data)) } + + describe '#apply' do + let(:assembla_checkout_sexp) { [:cmd, 'svn co svn+ssh://assembla.com/branches/main ruby-example', retry: true] } + let(:update_sexp) { [:cmd, 'svn update -r 9500504'] } + let(:payload_name) { :svn } + + subject { sh.to_sexp } + + before { clone.apply } + + it { is_expected.to include_sexp(assembla_checkout_sexp) } + it { is_expected.to include_sexp(update_sexp) } + + context 'when repository is not from Assembla' do + let(:payload_name) { :svn_non_assembla } + + it { is_expected.to include_sexp([:cmd, 'svn co /branches/main ruby-example', retry: true]) } + it { is_expected.to include_sexp(update_sexp) } + end + + context 'when the job is a PR' do + let(:payload_name) { :svn_pull_request } + + it { is_expected.to include_sexp(assembla_checkout_sexp) } + it { is_expected.not_to include(update_sexp) } + it { is_expected.to include_sexp([:cmd, 'svn merge --non-interactive ^/branches/newfeature']) } + end + end +end \ No newline at end of file diff --git a/spec/build/vcs/svn/ssh_key_spec.rb b/spec/build/vcs/svn/ssh_key_spec.rb new file mode 100644 index 0000000000..7cfab0727a --- /dev/null +++ b/spec/build/vcs/svn/ssh_key_spec.rb @@ -0,0 +1,34 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe Travis::Vcs::Svn::SshKey, :sexp do + let(:data) { payload_for(payload_name, :ruby, config: {}) } + let(:sh) { Travis::Shell::Builder.new } + let(:ssh_key) { described_class.new(sh, Travis::Build::Data.new(data)) } + + describe '#apply' do + let(:payload_name) { :svn } + + subject { sh.to_sexp } + + before { ssh_key.apply } + + it { is_expected.to include_sexp([:mkdir, '~/.ssh', recursive: true]) } + it { is_expected.to include_sexp([:file, ['~/.ssh/id_rsa', 'privatekey']]) } + it { is_expected.to include_sexp([:chmod, [600, '~/.ssh/id_rsa']]) } + it { is_expected.to include_sexp([:raw, 'eval `ssh-agent` &> /dev/null']) } + it { is_expected.to include_sexp([:raw, 'ssh-add ~/.ssh/id_rsa &> /dev/null']) } + it { is_expected.to include_sexp([:file, ['~/.ssh/config', "Host assembla.com\n\tBatchMode yes\n\tStrictHostKeyChecking no\n\tSendEnv REPO_NAME"], append: true]) } + it { is_expected.to include_sexp([:export, ['REPO_NAME', 'travis-ci-examples^ruby-example']]) } + it { is_expected.to include_sexp([:file, ['~/.ssh/id_rsa', 'privatekey']]) } + it { is_expected.to include_sexp([:export, ['SVN_SSH', '"ssh -o SendEnv=REPO_NAME -o StrictHostKeyChecking=no -l svn"']]) } + + context 'when repository is not from Assembla' do + let(:payload_name) { :svn_non_assembla } + + it { is_expected.to include_sexp([:export, ["REPO_NAME", "ruby-example"]]) } + it { is_expected.to include_sexp([:file, ['~/.ssh/id_rsa', 'mybuildtoken']]) } + end + end +end \ No newline at end of file diff --git a/spec/build/vcs_spec.rb b/spec/build/vcs_spec.rb new file mode 100644 index 0000000000..345ba7562f --- /dev/null +++ b/spec/build/vcs_spec.rb @@ -0,0 +1,25 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe Travis::Vcs do + describe '#defaults' do + subject { described_class.defaults(server_type) } + + context 'when server_type is subversion' do + let(:server_type) { 'subversion' } + + it 'returns svn defaults' do + expect(subject).to eq(Travis::Vcs::Svn::DEFAULTS) + end + end + + context 'when server_type is git' do + let(:server_type) { 'git' } + + it 'returns svn defaults' do + expect(subject).to eq(Travis::Vcs::Git::DEFAULTS) + end + end + end +end \ No newline at end of file diff --git a/spec/support/payloads.rb b/spec/support/payloads.rb index 30fe947945..ab970dd65d 100644 --- a/spec/support/payloads.rb +++ b/spec/support/payloads.rb @@ -70,6 +70,231 @@ } } }, + perforce: { + 'type' => 'test', + 'enterprise' => 'false', + 'prefer_https' => false, + 'host' => 'travis-ci.com', + 'config' => { + 'os' => 'linux', + 'arch' => 'amd64', + 'env' => ['FOO=foo', 'SECURE BAR=bar'], + 'server_type' => 'perforce' + }, + 'repository' => { + 'vcs_id' => '123', + 'source_url' => 'ssl:perforce.assembla.com', + 'vcs_type' => 'AssemblaRepository', + 'source_host' => 'assembla.com', + 'default_branch' => 'main' + }, + 'build' => { + 'id' => '1', + 'number' => '1', + 'previous_state' => 'failed' + }, + 'job' => { + 'id' => '1', + 'number' => '1.1', + 'commit' => '03148a8', + 'branch' => 'main', + 'commit_range' => '03148a8..f9da1fd', + 'commit_message' => 'the commit message', + 'secure_env_enabled' => true + }, + 'ssh_key' => { + 'public_key' => 'pubkey', + 'value' => 'privatekey' + } + }, + perforce_pull_request: { + 'type' => 'test', + 'enterprise' => 'false', + 'prefer_https' => false, + 'host' => 'travis-ci.com', + 'config' => { + 'os' => 'linux', + 'arch' => 'amd64', + 'env' => ['FOO=foo', 'SECURE BAR=bar'], + 'server_type' => 'perforce' + }, + 'repository' => { + 'vcs_id' => '123', + 'source_url' => 'ssl:perforce.assembla.com', + 'vcs_type' => 'AssemblaRepository', + 'source_host' => 'assembla.com', + 'default_branch' => 'main' + }, + 'build' => { + 'id' => '1', + 'number' => '1', + 'previous_state' => 'failed' + }, + 'job' => { + 'id' => '1', + 'number' => '1.1', + 'commit' => '03148a8', + 'branch' => 'main', + 'commit_range' => '03148a8..f9da1fd', + 'commit_message' => 'the commit message', + 'secure_env_enabled' => true, + 'pull_request' => { + 'id' => '1' + }, + 'pull_request_head_branch' => 'newfeature', + 'pull_request_base_ref' => 'main' + }, + 'ssh_key' => { + 'public_key' => 'pubkey', + 'value' => 'privatekey' + }, + }, + perforce_non_assembla: { + 'type' => 'test', + 'enterprise' => 'false', + 'prefer_https' => false, + 'host' => 'travis-ci.com', + 'build_token' => 'mybuildtoken', + 'sender_login' => 'travisuser', + 'config' => { + 'os' => 'linux', + 'arch' => 'amd64', + 'env' => ['FOO=foo', 'SECURE BAR=bar'], + 'server_type' => 'perforce' + }, + 'repository' => { + 'vcs_id' => '123', + 'source_url' => 'ssl:perforce.travis-ci.com', + 'vcs_type' => 'GithubRepository', + 'source_host' => 'assembla.com', + 'default_branch' => 'main' + }, + 'build' => { + 'id' => '1', + 'number' => '1', + 'previous_state' => 'failed' + }, + 'job' => { + 'id' => '1', + 'number' => '1.1', + 'commit' => '03148a8', + 'branch' => 'main', + 'commit_range' => '03148a8..f9da1fd', + 'commit_message' => 'the commit message', + 'secure_env_enabled' => true + }, + }, + svn: { + 'type' => 'test', + 'enterprise' => 'false', + 'prefer_https' => false, + 'host' => 'travis-ci.com', + 'config' => { + 'os' => 'linux', + 'arch' => 'amd64', + 'env' => ['FOO=foo', 'SECURE BAR=bar'], + 'server_type' => 'perforce' + }, + 'repository' => { + 'vcs_id' => '123', + 'vcs_type' => 'AssemblaRepository', + 'source_host' => 'assembla.com', + 'default_branch' => 'main' + }, + 'build' => { + 'id' => '1', + 'number' => '1', + 'previous_state' => 'failed' + }, + 'job' => { + 'id' => '1', + 'number' => '1.1', + 'commit' => '03148a8', + 'branch' => 'main', + 'commit_range' => '03148a8..f9da1fd', + 'commit_message' => 'the commit message', + 'secure_env_enabled' => true + }, + 'ssh_key' => { + 'public_key' => 'pubkey', + 'value' => 'privatekey' + } + }, + svn_pull_request: { + 'type' => 'test', + 'enterprise' => 'false', + 'prefer_https' => false, + 'host' => 'travis-ci.com', + 'config' => { + 'os' => 'linux', + 'arch' => 'amd64', + 'env' => ['FOO=foo', 'SECURE BAR=bar'], + 'server_type' => 'perforce' + }, + 'repository' => { + 'vcs_id' => '123', + 'vcs_type' => 'AssemblaRepository', + 'source_host' => 'assembla.com', + 'default_branch' => 'main' + }, + 'build' => { + 'id' => '1', + 'number' => '1', + 'previous_state' => 'failed' + }, + 'job' => { + 'id' => '1', + 'number' => '1.1', + 'commit' => '03148a8', + 'branch' => 'main', + 'commit_range' => '03148a8..f9da1fd', + 'commit_message' => 'the commit message', + 'secure_env_enabled' => true, + 'pull_request' => { + 'id' => '1' + }, + 'pull_request_head_branch' => 'newfeature', + 'pull_request_base_ref' => 'main' + }, + 'ssh_key' => { + 'public_key' => 'pubkey', + 'value' => 'privatekey' + }, + }, + svn_non_assembla: { + 'type' => 'test', + 'enterprise' => 'false', + 'prefer_https' => false, + 'host' => 'travis-ci.com', + 'build_token' => 'mybuildtoken', + 'sender_login' => 'travisuser', + 'config' => { + 'os' => 'linux', + 'arch' => 'amd64', + 'env' => ['FOO=foo', 'SECURE BAR=bar'], + 'server_type' => 'perforce' + }, + 'repository' => { + 'vcs_id' => '123', + 'vcs_type' => 'GithubRepository', + 'source_host' => 'github.com', + 'default_branch' => 'main' + }, + 'build' => { + 'id' => '1', + 'number' => '1', + 'previous_state' => 'failed' + }, + 'job' => { + 'id' => '1', + 'number' => '1.1', + 'commit' => '03148a8', + 'branch' => 'main', + 'commit_range' => '03148a8..f9da1fd', + 'commit_message' => 'the commit message', + 'secure_env_enabled' => true + }, + }, worker_config: { 'paranoid' => true, 'skip_resolv_updates' => false,