bosh-workspace 0.9.2 → 0.9.3

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 (38) hide show
  1. checksums.yaml +4 -4
  2. data/bosh-workspace.gemspec +5 -4
  3. data/lib/bosh/cli/commands/deployment_patch.rb +0 -1
  4. data/lib/bosh/cli/commands/prepare.rb +12 -11
  5. data/lib/bosh/workspace.rb +4 -3
  6. data/lib/bosh/workspace/credentials.rb +12 -5
  7. data/lib/bosh/workspace/git_credentials_provider.rb +80 -0
  8. data/lib/bosh/workspace/{git_remote_url.rb → helpers/git_protocol_helper.rb} +4 -8
  9. data/lib/bosh/workspace/helpers/project_deployment_helper.rb +10 -2
  10. data/lib/bosh/workspace/helpers/release_helper.rb +33 -7
  11. data/lib/bosh/workspace/manifest_builder.rb +6 -8
  12. data/lib/bosh/workspace/merge_tool.rb +73 -0
  13. data/lib/bosh/workspace/project_deployment.rb +20 -5
  14. data/lib/bosh/workspace/release.rb +103 -67
  15. data/lib/bosh/workspace/schemas/credentials.rb +22 -0
  16. data/lib/bosh/workspace/schemas/project_deployment.rb +14 -1
  17. data/lib/bosh/workspace/version.rb +1 -1
  18. data/spec/assets/bin/spruce +0 -0
  19. data/spec/assets/manifests-repo/deployments/foo.yml +1 -0
  20. data/spec/assets/manifests-repo/stubs/foo.yml +4 -0
  21. data/spec/commands/prepare_spec.rb +39 -12
  22. data/spec/credentials_spec.rb +8 -0
  23. data/spec/git_credentials_provider_spec.rb +82 -0
  24. data/spec/{git_remote_url_spec.rb → helpers/git_protocol_helper_spec.rb} +10 -11
  25. data/spec/helpers/project_deployment_helper_spec.rb +12 -1
  26. data/spec/helpers/release_helper_spec.rb +157 -73
  27. data/spec/manifest_builder_spec.rb +6 -5
  28. data/spec/merge_tool_spec.rb +98 -0
  29. data/spec/project_deployment_spec.rb +43 -1
  30. data/spec/release_spec.rb +369 -354
  31. data/spec/rugged_spec.rb +64 -0
  32. data/spec/schemas/credentials_spec.rb +22 -5
  33. data/spec/spec_helper.rb +1 -0
  34. metadata +35 -15
  35. data/lib/bosh/workspace/helpers/git_credentials_helper.rb +0 -111
  36. data/lib/bosh/workspace/helpers/spiff_helper.rb +0 -34
  37. data/spec/helpers/git_credentials_helper_spec.rb +0 -190
  38. data/spec/helpers/spiff_helper_spec.rb +0 -68
@@ -23,6 +23,14 @@ module Bosh::Workspace
23
23
  end
24
24
  end
25
25
 
26
+ describe '#url_protocols' do
27
+ it "returns credentials when found multiple times" do
28
+ expect(subject).to receive(:git_protocol_from_url)
29
+ .with('foo').and_return(:https)
30
+ expect(subject.url_protocols).to eq('foo' => :https)
31
+ end
32
+ end
33
+
26
34
  describe '#perform_validation' do
27
35
  context "valid" do
28
36
  it "validates" do
@@ -0,0 +1,82 @@
1
+ module Bosh::Workspace
2
+ describe GitCredentialsProvider do
3
+ let!(:credentials_provider) { GitCredentialsProvider.new(file) }
4
+ let(:file) { "credentials_file" }
5
+ let(:file_exist) { true }
6
+ let(:valid) { true }
7
+ let(:url_protocols) { [] }
8
+ let(:url) { 'http://foo.com/bar.git' }
9
+ let(:user) { nil }
10
+ let(:result) { nil }
11
+ let(:allowed_types) { [:plain_text] }
12
+ let(:credentials) do
13
+ instance_double "Bosh::Workspace::Credentials",
14
+ :valid? => valid, url_protocols: url_protocols
15
+ end
16
+
17
+ subject { credentials_provider.callback.call url, user, allowed_types }
18
+
19
+ before do
20
+ allow(Credentials).to receive(:new).and_return(credentials)
21
+ allow(File).to receive(:exist?).and_return(file_exist)
22
+ allow(credentials).to receive(:find_by_url).with(url).and_return(result)
23
+ end
24
+
25
+ describe '#callback' do
26
+ context "with sshkey" do
27
+ let(:user) { 'git' }
28
+ let(:result) { { private_key: 'barkey' } }
29
+ let(:allowed_types) { [:ssh_key] }
30
+
31
+ it 'returns Rugged sshkey credentials' do
32
+ expect(Rugged::Credentials::SshKey).to receive(:new) do |args|
33
+ expect(args[:username]).to eq user
34
+ expect(IO.read(args[:privatekey])).to eq('barkey')
35
+ end; subject
36
+ end
37
+ end
38
+
39
+ context "with username/password" do
40
+ let(:result) { { username: user, password: 'barpw' } }
41
+ let(:allowed_types) { [:plain_text] }
42
+
43
+ it 'returns Rugged user password credentials' do
44
+ expect(Rugged::Credentials::UserPassword).to receive(:new) do |args|
45
+ expect(args[:username]).to eq user
46
+ expect(args[:password]).to eq 'barpw'
47
+ end; subject
48
+ end
49
+ end
50
+
51
+ context "without credentials file" do
52
+ let(:file_exist) { false }
53
+ it 'raises an error' do
54
+ expect{ subject }.to raise_error /credentials file does not exist/i
55
+ end
56
+ end
57
+
58
+ context "with invalid credentials file" do
59
+ let(:valid) { false }
60
+ before { expect(credentials).to receive(:errors) { ['foo error'] } }
61
+ it 'raises an error' do
62
+ expect{ subject }.to raise_error /is not valid/i
63
+ end
64
+ end
65
+
66
+ context "without credentials for given url" do
67
+ let(:result) { nil }
68
+ it 'raises an error' do
69
+ expect{ subject }.to raise_error /no credentials found/i
70
+ end
71
+ end
72
+
73
+ context "without protocol support" do
74
+ let(:url_protocols) { {"https://foo.com" => :https } }
75
+ before { expect(Rugged).to receive(:features).and_return([]) }
76
+ it 'raises an error' do
77
+ expect{ subject }.to raise_error /requires https support/i
78
+ end
79
+ end
80
+ end
81
+ end
82
+ end
@@ -1,38 +1,37 @@
1
1
  module Bosh::Workspace
2
- describe GitRemoteUrl do
3
- describe '.protocol' do
4
- subject { GitRemoteUrl.new(url) }
2
+ describe GitProtocolHelper do
3
+ include GitProtocolHelper
4
+ describe '#git_protocol_from_url' do
5
+ subject { git_protocol_from_url(url) }
5
6
 
6
7
  context 'git protocol' do
7
8
  let(:url) { "git://example.com/foo" }
8
- its(:protocol) { is_expected.to eq(:git) }
9
+ it { is_expected.to eq(:git) }
9
10
  end
10
11
 
11
12
  context 'https protocol' do
12
13
  let(:url) { "https://example.com/foo" }
13
- its(:protocol) { is_expected.to eq(:https) }
14
+ it { is_expected.to eq(:https) }
14
15
  end
15
16
 
16
17
  context 'http protocol' do
17
18
  let(:url) { "http://example.com/foo" }
18
- its(:protocol) { is_expected.to eq(:http) }
19
+ it { is_expected.to eq(:http) }
19
20
  end
20
21
 
21
22
  context 'ssh protocol style 1' do
22
23
  let(:url) { "foo@example.com:foo" }
23
- its(:protocol) { is_expected.to eq(:ssh) }
24
+ it { is_expected.to eq(:ssh) }
24
25
  end
25
26
 
26
27
  context 'ssh protocol style 2' do
27
28
  let(:url) { "ssh://foo@example.com/foo" }
28
- its(:protocol) { is_expected.to eq(:ssh) }
29
+ it { is_expected.to eq(:ssh) }
29
30
  end
30
31
 
31
32
  context 'unsupported protocol' do
32
33
  let(:url) { "foo://foo@example.com/foo" }
33
- it 'raises' do
34
- expect { subject.protocol() }.to raise_error /unsupported protocol/i
35
- end
34
+ it { is_expected.to eq(nil) }
36
35
  end
37
36
  end
38
37
  end
@@ -23,7 +23,7 @@ describe Bosh::Workspace::ProjectDeploymentHelper do
23
23
  describe "project_deployment?" do
24
24
  subject { project_deployment_helper.project_deployment? }
25
25
  let(:project_deployment_helper) { ProjectDeploymentHelperTester.new(director, deployment) }
26
- let(:deployment) { File.join work_dir, deployment_path }
26
+ let(:deployment) { File.join(work_dir, deployment_path) }
27
27
 
28
28
  context "deployment" do
29
29
  context "without associated project deployment" do
@@ -206,4 +206,15 @@ describe Bosh::Workspace::ProjectDeploymentHelper do
206
206
  end
207
207
  end
208
208
  end
209
+
210
+ describe "#offline!" do
211
+ it "enforces offline mode" do
212
+ subject.offline!
213
+ expect(subject.offline?).to eq(true)
214
+ end
215
+
216
+ it "defaults to online" do
217
+ expect(subject.offline?).to eq(nil)
218
+ end
219
+ end
209
220
  end
@@ -1,92 +1,176 @@
1
- describe Bosh::Workspace::ReleaseHelper do
2
- class ReleaseHelperTester
3
- include Bosh::Workspace::ReleaseHelper
1
+ module Bosh::Workspace
2
+ describe ReleaseHelper do
3
+ class ReleaseHelperTester
4
+ include ReleaseHelper
4
5
 
5
- attr_reader :director, :work_dir
6
+ attr_reader :director, :work_dir
6
7
 
7
- def initialize(director, work_dir)
8
- @director = director
9
- @work_dir = work_dir
8
+ def initialize(director, work_dir)
9
+ @director = director
10
+ @work_dir = work_dir
11
+ end
10
12
  end
11
- end
12
-
13
- subject { release_helper }
14
- let(:release_helper) { ReleaseHelperTester.new(director, work_dir) }
15
- let(:director) { instance_double('Bosh::Cli::Client::Director') }
16
- let(:work_dir) { asset_dir("manifests-repo") }
17
13
 
18
- describe "#release_upload" do
19
- let(:release_cmd) do
20
- instance_double "Bosh::Cli::Command::Release::UploadRelease"
21
- end
14
+ subject { release_helper }
15
+ let(:release_helper) { ReleaseHelperTester.new(director, work_dir) }
16
+ let(:director) { instance_double('Bosh::Cli::Client::Director') }
17
+ let(:work_dir) { asset_dir("manifests-repo") }
22
18
 
23
- before do
24
- allow(Bosh::Cli::Command::Release::UploadRelease).to receive(:new)
25
- .and_return(release_cmd)
19
+ def expect_option(subject, *args)
20
+ expect(subject).to receive(:add_option).with(*args)
26
21
  end
27
22
 
28
- let(:manifest_file) { "foo-1.yml." }
29
- subject { release_helper.release_upload(manifest_file, work_dir) }
30
-
31
- it "uploads release" do
32
- expect(release_cmd).to receive(:upload).with(manifest_file)
33
- subject
23
+ context "with upload release command" do
24
+ let(:upload_release_cmd) do
25
+ instance_double "Bosh::Cli::Command::Release::UploadRelease"
26
+ end
27
+
28
+ before do
29
+ allow(Bosh::Cli::Command::Release::UploadRelease)
30
+ .to receive(:new).and_return(upload_release_cmd)
31
+ end
32
+
33
+ describe "#release_upload_from_url" do
34
+ let(:url) { "http://example.com/release.tgz" }
35
+ subject { release_helper.release_upload_from_url(url) }
36
+
37
+ it "uploads release" do
38
+ expect(upload_release_cmd).to receive(:upload).with(url)
39
+ subject
40
+ end
41
+ end
42
+
43
+ describe "#release_upload" do
44
+ let(:manifest) { "foo-1.yml" }
45
+ let(:tarball) { "foo-1.tgz" }
46
+ let(:release_dir) { "foo-release" }
47
+ let(:exist) { true }
48
+ let(:create_release_cmd) do
49
+ instance_double("Bosh::Cli::Command::Release::CreateRelease")
50
+ end
51
+
52
+ subject { release_helper.release_upload(manifest, release_dir) }
53
+
54
+ before do
55
+ allow(Bosh::Cli::Command::Release::CreateRelease)
56
+ .to receive(:new).and_return(create_release_cmd)
57
+ allow(File).to receive(:exist?).with(tarball).and_return(exist)
58
+ end
59
+
60
+ context "when offline" do
61
+ before { release_helper.offline! }
62
+
63
+ context "with final release tarball" do
64
+ it "uploads final release" do
65
+ expect(upload_release_cmd).to receive(:upload).with(tarball)
66
+ subject
67
+ end
68
+ end
69
+
70
+ context "without final release tarball" do
71
+ let(:exist) { false }
72
+ it "raises an error" do
73
+ expect{subject}.to raise_error /tarball missing.+#{tarball}/
74
+ end
75
+ end
76
+ end
77
+
78
+ context "when online" do
79
+ context "with final release tarball" do
80
+ it "uploads final release" do
81
+ expect(upload_release_cmd).to receive(:upload).with(tarball)
82
+ subject
83
+ end
84
+ end
85
+
86
+ context "without final release tarball" do
87
+ let(:exist) { false }
88
+ it "creates and uploads final release" do
89
+ expect_option(create_release_cmd, :with_tarball, true)
90
+ expect_option(create_release_cmd, :dir, release_dir)
91
+ expect(create_release_cmd).to receive(:create).with(manifest)
92
+ expect(upload_release_cmd).to receive(:upload).with(tarball)
93
+ subject
94
+ end
95
+ end
96
+ end
97
+ end
34
98
  end
35
- end
36
99
 
37
- describe "#release_uploaded?" do
38
- let(:releases) { { "versions" => %w(1 2 3) } }
39
- subject { release_helper.release_uploaded?("foo", version) }
40
- before do
41
- expect(director).to receive(:get_release)
42
- .with("foo").and_return(releases)
100
+ describe "#release_uploaded?" do
101
+ let(:releases) { { "versions" => %w(1 2 3) } }
102
+ subject { release_helper.release_uploaded?("foo", version) }
103
+ before do
104
+ expect(director).to receive(:get_release)
105
+ .with("foo").and_return(releases)
106
+ end
107
+
108
+ context "release exists" do
109
+ let(:version) { 2 }
110
+ it { should be true }
111
+ end
112
+
113
+ context "release not found" do
114
+ let(:version) { "8" }
115
+ it { should be false }
116
+ end
43
117
  end
44
118
 
45
- context "release exists" do
46
- let(:version) { 2 }
47
- it { should be true }
48
- end
119
+ describe "#release_dir" do
120
+ let(:releases_dir) { File.join(work_dir, ".releases") }
121
+ subject { release_helper.releases_dir }
49
122
 
50
- context "release not found" do
51
- let(:version) { "8" }
52
- it { should be false }
53
- end
54
- end
55
-
56
- describe "#release_dir" do
57
- let(:releases_dir) { File.join(work_dir, ".releases") }
58
- subject { release_helper.releases_dir }
59
-
60
- before do
61
- expect(FileUtils).to receive(:mkdir_p).once
62
- .with(releases_dir).and_return([releases_dir])
63
- end
64
-
65
- it { should eq releases_dir }
66
-
67
- it "memoizes" do
68
- subject
69
- expect(subject).to eq releases_dir
70
- end
71
- end
123
+ before do
124
+ expect(FileUtils).to receive(:mkdir_p).once
125
+ .with(releases_dir).and_return([releases_dir])
126
+ end
72
127
 
73
- describe "#project_deployment_releases" do
74
- subject { release_helper.project_deployment_releases }
75
- let(:release) { instance_double("Bosh::Workspace::Release") }
76
- let(:release_data) { { name: "foo" } }
77
- let(:releases) { [release_data, release_data] }
128
+ it { should eq releases_dir }
78
129
 
79
- before do
80
- expect(release_helper)
81
- .to receive_message_chain("project_deployment.releases")
82
- .and_return(releases)
130
+ it "memoizes" do
131
+ subject
132
+ expect(subject).to eq releases_dir
133
+ end
83
134
  end
84
135
 
85
- it "inits releases once" do
86
- expect(Bosh::Workspace::Release).to receive(:new).twice
87
- .with(release_data, /\/.releases/).and_return(release)
88
- subject
89
- expect(subject).to eq [release, release]
136
+ describe "#project_deployment_releases" do
137
+ subject { release_helper.project_deployment_releases }
138
+ let(:release) { instance_double("Bosh::Workspace::Release") }
139
+ let(:release_data) { { name: "foo" } }
140
+ let(:releases) { [release_data, release_data] }
141
+ let(:options) { { offline: offline } }
142
+ let(:offline) { nil }
143
+ let(:credentials_provider) do
144
+ instance_double('Bosh::Workspace::GitCredentialsProvider',
145
+ callback: :callback)
146
+ end
147
+
148
+ before do
149
+ expect(release_helper)
150
+ .to receive_message_chain("project_deployment.releases")
151
+ .and_return(releases)
152
+ expect(GitCredentialsProvider).to receive(:new).with(/.credentials.yml/)
153
+ .and_return(credentials_provider)
154
+ end
155
+
156
+ it "inits releases" do
157
+ expect(Release).to receive(:new).twice
158
+ .with(release_data, /\/.releases/, :callback, options)
159
+ .and_return(release)
160
+ expect(subject).to eq [release, release]
161
+ end
162
+
163
+ context "when offline" do
164
+ before { release_helper.offline! }
165
+ let(:offline) { true }
166
+
167
+ it "inits releases" do
168
+ expect(Release).to receive(:new).twice
169
+ .with(release_data, /\/.releases/, :callback, options)
170
+ .and_return(release)
171
+ expect(subject).to eq [release, release]
172
+ end
173
+ end
90
174
  end
91
175
  end
92
176
  end
@@ -2,7 +2,8 @@ describe Bosh::Workspace::ManifestBuilder do
2
2
  let(:project_deployment) { instance_double("Bosh::Workspace::Project_Deployment",
3
3
  name: "bar",
4
4
  templates: ["foo.yml"],
5
- merged_file: ".deployments/foo.yml")
5
+ merged_file: ".deployments/foo.yml",
6
+ merge_tool: Bosh::Workspace::MergeTool.new)
6
7
  }
7
8
  let(:work_dir) { asset_dir("manifests-repo") }
8
9
 
@@ -20,7 +21,7 @@ describe Bosh::Workspace::ManifestBuilder do
20
21
  end
21
22
 
22
23
  describe "#merge_templates" do
23
- subject { Bosh::Workspace::ManifestBuilder.new project_deployment, work_dir }
24
+ subject { Bosh::Workspace::ManifestBuilder.new(project_deployment, work_dir) }
24
25
 
25
26
  before do
26
27
  allow(File).to receive(:exists?).with(/templates\//)
@@ -30,7 +31,7 @@ describe Bosh::Workspace::ManifestBuilder do
30
31
  context "missing template" do
31
32
  let(:template_exists) { false }
32
33
  it "raises error" do
33
- expect{ subject.merge_templates }.to raise_error(/does not exist/)
34
+ expect { subject.merge_templates }.to raise_error(/does not exist/)
34
35
  end
35
36
  end
36
37
 
@@ -47,14 +48,14 @@ describe Bosh::Workspace::ManifestBuilder do
47
48
  context "no hidden dirs" do
48
49
  let(:dir_exists) { false }
49
50
  it "creates hidden dirs" do
50
- expect(subject).to receive(:spiff_merge)
51
+ expect(subject.merge_tool).to receive(:merge)
51
52
  expect(Dir).to receive(:mkdir).with(/.stubs/)
52
53
  subject.merge_templates
53
54
  end
54
55
  end
55
56
 
56
57
  it "generates manifest with spiff" do
57
- expect(subject).to receive(:spiff_merge) do |args|
58
+ expect(subject.merge_tool).to receive(:merge) do |args|
58
59
  if args.is_a?(Array)
59
60
  expect(args.first).to match(/\/templates\/.+yml/)
60
61
  expect(args.last).to match(/\.stubs\/.+yml/)