Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Project Specific environment variables in preview #3559

Merged
merged 4 commits into from
Oct 24, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -264,7 +264,7 @@ GEM
connection_pool (2.2.1)
crack (0.4.3)
safe_yaml (~> 1.0.0)
crass (1.0.4)
crass (1.0.5)
dalli (2.7.6)
ddtrace (0.14.2)
msgpack
Expand Down Expand Up @@ -344,7 +344,7 @@ GEM
railties (>= 4)
request_store (~> 1.0)
logstash-event (1.2.02)
loofah (2.2.3)
loofah (2.3.1)
crass (~> 1.0.2)
nokogiri (>= 1.5.9)
mail (2.7.1)
Expand Down Expand Up @@ -587,6 +587,7 @@ GEM

PLATFORMS
ruby
x86_64-darwin-18

DEPENDENCIES
active_hash
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,10 @@ def preview
@project = Project.find(params[:project_id])
end

@groups = SamsonEnv.env_groups(Deploy.new(project: @project), deploy_groups, preview: true)
options = {project_specific: params[:project_specific]}
options.merge!(params[:preview].to_s == "false" ? {resolve_secrets: false} : {preview: true, resolve_secrets: true})

@groups = SamsonEnv.env_groups(Deploy.new(project: @project), deploy_groups, **options)

respond_to do |format|
format.html
Expand Down
14 changes: 12 additions & 2 deletions plugins/env/app/decorators/project_decorator.rb
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,18 @@ def serialized_environment_variables
EnvironmentVariable.serialize(nested_environment_variables, @env_scopes)
end

def nested_environment_variables
[self, *environment_variable_groups].flat_map(&:environment_variables)
def nested_environment_variables(project_specific: nil)
# Project Specific:
# nil => project env + groups env
# true/"true" => project env
# false/"false" => groups env
if project_specific.to_s == "true"
environment_variables
elsif project_specific.to_s == "false"
environment_variable_groups.flat_map(&:environment_variables)
else
[self, *environment_variable_groups].flat_map(&:environment_variables)
end
end

private
Expand Down
8 changes: 4 additions & 4 deletions plugins/env/app/models/environment_variable.rb
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ class << self
# preview parameter can be used to not raise an error,
# but return a value with a helpful message
# also used by an external plugin
def env(deploy, deploy_group, preview: false, resolve_secrets: true)
def env(deploy, deploy_group, preview: false, resolve_secrets: true, project_specific: nil)
env = {}

if deploy_group && deploy.project.config_service?
Expand All @@ -36,7 +36,7 @@ def env(deploy, deploy_group, preview: false, resolve_secrets: true)
env.merge! env_vars_from_repo(env_repo_name, deploy.project, deploy_group)
end

env.merge! env_vars_from_db(deploy, deploy_group)
env.merge! env_vars_from_db(deploy, deploy_group, project_specific: project_specific)

resolve_dollar_variables(env)
resolve_secrets(deploy.project, deploy_group, env, preview: preview) if resolve_secrets
Expand Down Expand Up @@ -73,11 +73,11 @@ def config_service_location(project, deploy_group, display:)

private

def env_vars_from_db(deploy, deploy_group)
def env_vars_from_db(deploy, deploy_group, **args)
variables =
deploy.environment_variables +
(deploy.stage&.environment_variables || []) +
deploy.project.nested_environment_variables
deploy.project.nested_environment_variables(**args)
variables.sort_by!(&:priority)
variables.each_with_object({}) do |ev, all|
all[ev.name] = ev.value if !all[ev.name] && ev.matches_scope?(deploy_group)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,17 @@ def self.it_destroys
}
)
end

let!(:other_env_group) do
EnvironmentVariableGroup.create!(
name: "OtherG1",
environment_variables_attributes: {
0 => {name: "X", value: "Y"},
1 => {name: "Y", value: "Z", scope_type_and_id: "DeployGroup-#{deploy_group.id}"}
}
)
end

let(:other_project) do
p = project.dup
p.name = 'xxxxx'
Expand Down Expand Up @@ -128,15 +139,16 @@ def unauthorized_env_group
end

it "calls env with preview" do
EnvironmentVariable.expects(:env).with(anything, anything, preview: true).times(3)
EnvironmentVariable.expects(:env).
with(anything, anything, project_specific: nil, preview: true, resolve_secrets: true).times(3)
get :preview, params: {group_id: env_group.id}
assert_response :success
end
end

describe "a json GET to #preview" do
it "succeeds" do
get :preview, params: {group_id: env_group.id, project_id: project.id}, format: :json
get :preview, params: {group_id: env_group.id, project_id: project.id, preview: false}, format: :json
assert_response :success
json_response = JSON.parse response.body
json_response['groups'].sort.must_equal [
Expand All @@ -160,6 +172,45 @@ def unauthorized_env_group
get :preview, params: {group_id: env_group.id, project_id: project.id, deploy_group: "pod23"}, format: :json
end
end

describe "project_specific" do
before do
EnvironmentVariable.create!(parent: project, name: 'B', value: 'b')
ProjectEnvironmentVariableGroup.create!(environment_variable_group: other_env_group, project: project)
end
it "renders only project env" do
get :preview, params: {project_id: project.id, project_specific: true}, format: :json
assert_response :success
json_response = JSON.parse response.body
json_response['groups'].sort.must_equal [
[".pod-100", {"B" => "b"}],
[".pod1", {"B" => "b"}],
[".pod2", {"B" => "b"}]
]
end

it "renders only groups env" do
get :preview, params: {project_id: project.id, project_specific: false}, format: :json
assert_response :success
json_response = JSON.parse response.body
json_response['groups'].sort.must_equal [
[".pod-100", {"Y" => "Z", "X" => "Y"}],
[".pod1", {"X" => "Y"}],
[".pod2", {"X" => "Y"}]
]
end

it "renders without project_specific" do
get :preview, params: {project_id: project.id, project_specific: nil}, format: :json
assert_response :success
json_response = JSON.parse response.body
json_response['groups'].sort.must_equal [
[".pod-100", {"B" => "b", "Y" => "Z", "X" => "Y"}],
[".pod1", {"B" => "b", "X" => "Y"}],
[".pod2", {"B" => "b", "X" => "Y"}]
]
end
end
end
end

Expand Down
29 changes: 26 additions & 3 deletions plugins/env/test/decorators/project_decorator_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,10 @@

describe Project do
let(:project) { projects(:test) }
let(:group) { EnvironmentVariableGroup.create!(name: "Foo", environment_variables_attributes: [env_attributes]) }
let(:env_attributes) { {name: "A", value: "B", scope_type_and_id: "Environment-#{environments(:production)}"} }

describe "auditing" do
let(:group) { EnvironmentVariableGroup.create!(name: "Foo", environment_variables_attributes: [env_attributes]) }
let(:env_attributes) { {name: "A", value: "B", scope_type_and_id: "Environment-#{environments(:production)}"} }

it "does not audit when var did not change" do
project.update_attributes!(name: 'Bar')
project.audits.map(&:audited_changes).must_equal([{'name' => ['Foo', 'Bar']}])
Expand Down Expand Up @@ -56,4 +55,28 @@
refute project.audits.last
end
end

describe "nested_environment_variables" do
let(:group_env) { project.environment_variable_groups.flat_map(&:environment_variables) }

before do
@project_env = EnvironmentVariable.create!(parent: project, name: 'B', value: 'b')
ProjectEnvironmentVariableGroup.create!(environment_variable_group: group, project: project)
end

it "includes only project specific environment variables" do
project.nested_environment_variables(project_specific: true).
must_equal [@project_env]
end

it "includes only project groups environment variables" do
project.nested_environment_variables(project_specific: false).
must_equal group_env
end

it "includes both project and groups environment variables" do
project.nested_environment_variables.
must_equal group_env.unshift(@project_env)
end
end
end
10 changes: 10 additions & 0 deletions plugins/env/test/models/environment_variable_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -243,6 +243,16 @@ def fake_response(response)
)
end

it "includes only project specific environment variables" do
EnvironmentVariable.env(deploy, nil, project_specific: true).
must_equal("PROJECT" => "PROJECT")
end

it "includes only project groups environment variables" do
EnvironmentVariable.env(deploy, nil, project_specific: false).
must_equal("X" => "Y", "Y" => "Z")
end

describe "secrets" do
before do
create_secret 'global/global/global/foobar'
Expand Down