Skip to content

Commit 9384ae2

Browse files
committed
Review fixes
1 parent 46d5c60 commit 9384ae2

10 files changed

+95
-75
lines changed

CHANGELOG.md

+4-4
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,10 @@ Changes since the last non-beta release.
1414

1515
_Please add entries here for your pull requests that have not yet been released._
1616

17+
### Added
18+
19+
- Added `use-digest-image-ref` (also configurable through `use_digest_image_ref` in `controlplane.yml`) option to `deploy-image` and `promote-app-from-upstream` commands. [PR 249](https://github.com/shakacode/control-plane-flow/pull/249) by [Zakir Dzhamaliddinov](https://github.com/zzaakiirr).
20+
1721
## [4.1.0] - 2024-12-17
1822

1923
### Fixed
@@ -28,10 +32,6 @@ _Please add entries here for your pull requests that have not yet been released.
2832
- Added `--docker-context` option to `build-image` command. [PR 250](https://github.com/shakacode/control-plane-flow/pull/250) by [Sergey Tarasov](https://github.com/dzirtusss).
2933

3034

31-
### Changed
32-
33-
- Providing digest (SHA256 value) for image link on promotion from upstream. [PR 249](https://github.com/shakacode/control-plane-flow/pull/249) by [Zakir Dzhamaliddinov](https://github.com/zzaakiirr).
34-
3535
## [4.0.0] - 2024-08-21
3636

3737
### Fixed

README.md

+3
Original file line numberDiff line numberDiff line change
@@ -316,6 +316,9 @@ apps:
316316
# This is relative to the `.controlplane/` directory.
317317
release_script: release_script
318318

319+
# Used by the `cpflow deploy-image` and `cpflow promote-app-from-upstream` commands to include Docker image's digest (SHA256 value) in its reference.
320+
use_digest_image_ref: true
321+
319322
# default_domain is used for commands that require a domain
320323
# including `maintenance`, `maintenance:on`, `maintenance:off`.
321324
default_domain: domain.com

docs/commands.md

+2
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,7 @@ cpflow delete -a $APP_NAME -w $WORKLOAD_NAME
127127
- Runs a release script before deploying if `release_script` is specified in the `.controlplane/controlplane.yml` file and `--run-release-phase` is provided
128128
- The release script is run in the context of `cpflow run` with the latest image
129129
- If the release script exits with a non-zero code, the command will stop executing and also exit with a non-zero code
130+
- If `use_digest_image_ref` is `true` in the `.controlplane/controlplane.yml` file or `--use-digest-image-ref` option is provided, deployed image's reference will include its digest
130131

131132
```sh
132133
cpflow deploy-image -a $APP_NAME
@@ -295,6 +296,7 @@ cpflow open-console -a $APP_NAME
295296
- Runs `cpflow deploy-image` to deploy the image
296297
- If `.controlplane/controlplane.yml` includes the `release_script`, `cpflow deploy-image` will use the `--run-release-phase` option
297298
- If the release script exits with a non-zero code, the command will stop executing and also exit with a non-zero code
299+
- If `use_digest_image_ref` is `true` in the `.controlplane/controlplane.yml` file or `--use-digest-image-ref` option is provided, deployed image's reference will include its digest
298300
299301
```sh
300302
cpflow promote-app-from-upstream -a $APP_NAME -t $UPSTREAM_TOKEN

lib/command/base.rb

+2-2
Original file line numberDiff line numberDiff line change
@@ -454,9 +454,9 @@ def self.docker_context_option
454454
}
455455
end
456456

457-
def self.use_digest_ref_option(required: false)
457+
def self.use_digest_image_ref_option(required: false)
458458
{
459-
name: :use_digest_ref,
459+
name: :use_digest_image_ref,
460460
params: {
461461
desc: "Uses the image's digest (SHA256 value) for referencing the Docker image",
462462
type: :boolean,

lib/command/deploy_image.rb

+3-2
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,15 @@ class DeployImage < Base
88
OPTIONS = [
99
app_option(required: true),
1010
run_release_phase_option,
11-
use_digest_ref_option
11+
use_digest_image_ref_option
1212
].freeze
1313
DESCRIPTION = "Deploys the latest image to app workloads, and runs a release script (optional)"
1414
LONG_DESCRIPTION = <<~DESC
1515
- Deploys the latest image to app workloads
1616
- Runs a release script before deploying if `release_script` is specified in the `.controlplane/controlplane.yml` file and `--run-release-phase` is provided
1717
- The release script is run in the context of `cpflow run` with the latest image
1818
- If the release script exits with a non-zero code, the command will stop executing and also exit with a non-zero code
19+
- If `use_digest_image_ref` is `true` in the `.controlplane/controlplane.yml` file or `--use-digest-image-ref` option is provided, deployed image's reference will include its digest
1920
DESC
2021

2122
def call # rubocop:disable Metrics/MethodLength, Metrics/CyclomaticComplexity
@@ -31,7 +32,7 @@ def call # rubocop:disable Metrics/MethodLength, Metrics/CyclomaticComplexity
3132
"Use `cpflow build-image` first."
3233
end
3334

34-
image = "#{image_details['name']}@#{image_details['digest']}" if config.options[:use_digest_ref]
35+
image = "#{image_details['name']}@#{image_details['digest']}" if config.use_digest_image_ref?
3536

3637
config[:app_workloads].each do |workload|
3738
workload_data = cp.fetch_workload!(workload)

lib/command/promote_app_from_upstream.rb

+5-2
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,8 @@ class PromoteAppFromUpstream < Base
55
NAME = "promote-app-from-upstream"
66
OPTIONS = [
77
app_option(required: true),
8-
upstream_token_option(required: true)
8+
upstream_token_option(required: true),
9+
use_digest_image_ref_option
910
].freeze
1011
DESCRIPTION = "Copies the latest image from upstream, runs a release script (optional), and deploys the image"
1112
LONG_DESCRIPTION = <<~DESC
@@ -15,6 +16,7 @@ class PromoteAppFromUpstream < Base
1516
- Runs `cpflow deploy-image` to deploy the image
1617
- If `.controlplane/controlplane.yml` includes the `release_script`, `cpflow deploy-image` will use the `--run-release-phase` option
1718
- If the release script exits with a non-zero code, the command will stop executing and also exit with a non-zero code
19+
- If `use_digest_image_ref` is `true` in the `.controlplane/controlplane.yml` file or `--use-digest-image-ref` option is provided, deployed image's reference will include its digest
1820
DESC
1921

2022
def call
@@ -32,7 +34,8 @@ def copy_image_from_upstream
3234
def deploy_image
3335
args = []
3436
args.push("--run-release-phase") if config.current[:release_script]
35-
run_cpflow_command("deploy-image", "-a", config.app, "--use-digest-ref", *args)
37+
args.push("--use-digest-image-ref") if config.use_digest_image_ref?
38+
run_cpflow_command("deploy-image", "-a", config.app, *args)
3639
end
3740
end
3841
end

lib/core/config.rb

+4
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,10 @@ def find_app_config(app_name1)
145145
end&.last
146146
end
147147

148+
def use_digest_image_ref?
149+
current&.dig(:use_digest_image_ref) || options[:use_digest_image_ref]
150+
end
151+
148152
private
149153

150154
def ensure_current_config!

spec/command/deploy_image_spec.rb

+2-2
Original file line numberDiff line numberDiff line change
@@ -47,11 +47,11 @@
4747
end
4848
end
4949

50-
context "with --use-digest-ref option" do
50+
context "with --use-digest-image-ref option" do
5151
let!(:app) { dummy_test_app("rails-non-app-image", create_if_not_exists: true) }
5252

5353
it "deploys latest image with digest reference", :slow do
54-
result = run_cpflow_command("deploy-image", "-a", app, "--use-digest-ref")
54+
result = run_cpflow_command("deploy-image", "-a", app, "--use-digest-image-ref")
5555

5656
expect(result[:status]).to eq(0)
5757
expect(result[:stderr]).to match(/Deploying image '#{app}:\d+@sha256:[a-fA-F0-9]{64}'/)

spec/command/promote_app_from_upstream_spec.rb

+63-63
Original file line numberDiff line numberDiff line change
@@ -3,60 +3,83 @@
33
require "spec_helper"
44

55
describe Command::PromoteAppFromUpstream do
6-
context "when release script is not provided" do
7-
let!(:token) { Shell.cmd("cpln", "profile", "token", "default")[:output].strip }
8-
let!(:upstream_app) { dummy_test_app }
9-
let!(:app) { dummy_test_app("nothing") }
6+
subject(:result) do
7+
run_cpflow_command("promote-app-from-upstream", "-a", app, "--upstream-token", token, *extra_args)
8+
end
109

11-
before do
12-
stub_env("CPLN_UPSTREAM", upstream_app)
13-
# Ideally, we should have a different org, but for testing purposes, this works
14-
stub_env("CPLN_ORG_UPSTREAM", dummy_test_org)
10+
let(:upstream_app) { dummy_test_app }
11+
let(:token) { Shell.cmd("cpln", "profile", "token", "default")[:output].strip }
12+
let(:extra_args) { [] }
1513

16-
run_cpflow_command!("apply-template", "app", "-a", upstream_app)
17-
run_cpflow_command!("apply-template", "app", "rails", "-a", app)
18-
run_cpflow_command!("build-image", "-a", upstream_app)
19-
end
14+
before do
15+
stub_env("CPLN_UPSTREAM", upstream_app)
16+
# Ideally, we should have a different org, but for testing purposes, this works
17+
stub_env("CPLN_ORG_UPSTREAM", dummy_test_org)
18+
stub_env("APP_NAME", app)
2019

21-
after do
22-
run_cpflow_command!("delete", "-a", upstream_app, "--yes")
23-
run_cpflow_command!("delete", "-a", app, "--yes")
24-
end
20+
run_cpflow_command!("apply-template", "app", "-a", upstream_app)
21+
run_cpflow_command!("apply-template", "app", "rails", "postgres", "-a", app)
22+
run_cpflow_command!("build-image", "-a", upstream_app)
23+
end
2524

26-
it "copies latest image from upstream, skips release script and deploys image", :slow do
27-
result = run_cpflow_command("promote-app-from-upstream", "-a", app, "--upstream-token", token)
25+
after do
26+
run_cpflow_command!("delete", "-a", upstream_app, "--yes")
27+
run_cpflow_command!("delete", "-a", app, "--yes")
28+
end
2829

30+
shared_examples "copies latest image from upstream and deploys image" do |**options|
31+
it "#{options[:runs_release_script] ? 'runs' : 'does not run'} release script", :slow do
2932
expect(result[:status]).to eq(0)
3033
expect(result[:stderr]).to match(%r{Pulling image from '.+?/#{upstream_app}:1'})
3134
expect(result[:stderr]).to match(%r{Pushing image to '.+?/#{app}:1'})
32-
expect(result[:stderr]).not_to include("Running release script")
33-
expect(result[:stderr]).to match(/Deploying image '#{app}:1@sha256:[a-fA-F0-9]{64}'/)
35+
36+
if options[:runs_release_script]
37+
expect(result[:stderr]).to include("Running release script")
38+
else
39+
expect(result[:stderr]).not_to include("Running release script")
40+
end
41+
42+
if options[:uses_digest_image_ref]
43+
expect(result[:stderr]).to match(/Deploying image '#{app}:1@sha256:[a-fA-F0-9]{64}'/)
44+
else
45+
expect(result[:stderr]).to match(/Deploying image '#{app}:1(?!@)'/)
46+
end
47+
3448
expect(result[:stderr]).to match(%r{rails: https://rails-.+?.cpln.app})
3549
end
3650
end
3751

52+
context "when release script is not provided" do
53+
let(:app) { dummy_test_app("nothing") }
54+
55+
it_behaves_like "copies latest image from upstream and deploys image",
56+
runs_release_script: false,
57+
uses_digest_image_ref: false
58+
59+
context "with use_digest_image_ref from YAML file" do
60+
let(:app) { dummy_test_app("use-digest-image-ref") }
61+
62+
it_behaves_like "copies latest image from upstream and deploys image",
63+
runs_release_script: false,
64+
uses_digest_image_ref: true
65+
end
66+
67+
context "with --use-digest-image-ref option" do
68+
let(:extra_args) { ["--use-digest-image-ref"] }
69+
70+
it_behaves_like "copies latest image from upstream and deploys image",
71+
runs_release_script: false,
72+
uses_digest_image_ref: true
73+
end
74+
end
75+
3876
context "when release script is invalid" do
39-
let!(:token) { Shell.cmd("cpln", "profile", "token", "default")[:output].strip }
40-
let!(:upstream_app) { dummy_test_app }
41-
let!(:app) { dummy_test_app("invalid-release-script") }
77+
let(:app) { dummy_test_app("invalid-release-script") }
4278

4379
before do
44-
stub_env("CPLN_UPSTREAM", upstream_app)
45-
# Ideally, we should have a different org, but for testing purposes, this works
46-
stub_env("CPLN_ORG_UPSTREAM", dummy_test_org)
47-
stub_env("APP_NAME", app)
48-
49-
run_cpflow_command!("apply-template", "app", "-a", upstream_app)
50-
run_cpflow_command!("apply-template", "app", "rails", "postgres", "-a", app)
51-
run_cpflow_command!("build-image", "-a", upstream_app)
5280
run_cpflow_command!("ps:start", "-a", app, "--workload", "postgres", "--wait")
5381
end
5482

55-
after do
56-
run_cpflow_command!("delete", "-a", upstream_app, "--yes")
57-
run_cpflow_command!("delete", "-a", app, "--yes")
58-
end
59-
6083
it "copies latest image from upstream, fails to run release script and fails to deploy image", :slow do
6184
result = run_cpflow_command("promote-app-from-upstream", "-a", app, "--upstream-token", token)
6285

@@ -71,37 +94,14 @@
7194
end
7295

7396
context "when release script is valid" do
74-
let!(:token) { Shell.cmd("cpln", "profile", "token", "default")[:output].strip }
75-
let!(:upstream_app) { dummy_test_app }
76-
let!(:app) { dummy_test_app }
97+
let(:app) { dummy_test_app }
7798

7899
before do
79-
stub_env("CPLN_UPSTREAM", upstream_app)
80-
# Ideally, we should have a different org, but for testing purposes, this works
81-
stub_env("CPLN_ORG_UPSTREAM", dummy_test_org)
82-
stub_env("APP_NAME", app)
83-
84-
run_cpflow_command!("apply-template", "app", "-a", upstream_app)
85-
run_cpflow_command!("apply-template", "app", "rails", "postgres", "-a", app)
86-
run_cpflow_command!("build-image", "-a", upstream_app)
87100
run_cpflow_command!("ps:start", "-a", app, "--workload", "postgres", "--wait")
88101
end
89102

90-
after do
91-
run_cpflow_command!("delete", "-a", upstream_app, "--yes")
92-
run_cpflow_command!("delete", "-a", app, "--yes")
93-
end
94-
95-
it "copies latest image from upstream, runs release script and deploys image", :slow do
96-
result = run_cpflow_command("promote-app-from-upstream", "-a", app, "--upstream-token", token)
97-
98-
expect(result[:status]).to eq(0)
99-
expect(result[:stderr]).to match(%r{Pulling image from '.+?/#{upstream_app}:1'})
100-
expect(result[:stderr]).to match(%r{Pushing image to '.+?/#{app}:1'})
101-
expect(result[:stderr]).to include("Running release script")
102-
expect(result[:stderr]).to include("Finished running release script")
103-
expect(result[:stderr]).to match(/Deploying image '#{app}:1@sha256:[a-fA-F0-9]{64}'/)
104-
expect(result[:stderr]).to match(%r{rails: https://rails-.+?.cpln.app})
105-
end
103+
it_behaves_like "copies latest image from upstream and deploys image",
104+
runs_release_script: true,
105+
uses_digest_image_ref: false
106106
end
107107
end

spec/dummy/.controlplane/controlplane.yml

+7
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,13 @@ apps:
133133
upstream: dummy-test-upstream
134134
release_script: release-invalid.sh
135135

136+
dummy-test-use-digest-image-ref-{GLOBAL_IDENTIFIER}:
137+
<<: *common
138+
139+
match_if_app_name_starts_with: true
140+
upstream: dummy-test-upstream
141+
use_digest_image_ref: true
142+
136143
dummy-test-external-maintenance-image-{GLOBAL_IDENTIFIER}:
137144
<<: *common
138145

0 commit comments

Comments
 (0)