Skip to content

Commit 62ed7d5

Browse files
Tu Quoc Tranphong-nguyen-duy
authored andcommitted
FEATURE: MSF-17743 upgrade custom v2 for rollout brick
1 parent d4a35da commit 62ed7d5

14 files changed

Lines changed: 65788 additions & 45028 deletions

File tree

Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
# frozen_string_literal: true
2+
# (C) 2019-2020 GoodData Corporation
3+
require_relative 'base_action'
4+
5+
# Migrate date dimension urn:gooddata:date or urn:custom:date to urn:custom_v2:date
6+
module GoodData
7+
module LCM2
8+
class MigrateGdcDateDimension < BaseAction
9+
DESCRIPTION = 'Migrate Gdc Date Dimension'
10+
DATE_DIMENSION_CUSTOM_V2 = 'urn:custom_v2:date'
11+
DATE_DIMENSION_OLD = %w[urn:gooddata:date urn:custom:date]
12+
13+
PARAMS = define_params(self) do
14+
description 'Client Used for Connecting to GD'
15+
param :gdc_gd_client, instance_of(Type::GdClientType), required: true
16+
17+
description 'Specifies how to synchronize LDM and resolve possible conflicts'
18+
param :synchronize_ldm, instance_of(Type::SynchronizeLDM), required: false, default: 'diff_against_master_with_fallback'
19+
20+
description 'Synchronization Info'
21+
param :synchronize, array_of(instance_of(Type::SynchronizationInfoType)), required: true, generated: true
22+
end
23+
24+
RESULT_HEADER = %i[from to status]
25+
26+
class << self
27+
def call(params)
28+
results = []
29+
params.synchronize.map do |segment_info|
30+
result = migrate_date_dimension(params, segment_info)
31+
results.concat(result)
32+
end
33+
34+
{
35+
results: results
36+
}
37+
end
38+
39+
def migrate_date_dimension(params, segment_info)
40+
results = []
41+
client = params.gdc_gd_client
42+
latest_blueprint = segment_info[:from_blueprint]
43+
# don't migrate when latest master doesn't contain custom v2 date.
44+
return results unless contain_v2?(latest_blueprint)
45+
46+
previous_blueprint = segment_info[:previous_master]&.blueprint
47+
# check latest master and previous master
48+
master_upgrade_datasets = get_upgrade_dates(latest_blueprint, previous_blueprint) if params[:synchronize_ldm].downcase == 'diff_against_master' && previous_blueprint
49+
unless master_upgrade_datasets&.empty?
50+
segment_info[:to].pmap do |entry|
51+
pid = entry[:pid]
52+
to_project = client.projects(pid) || fail("Invalid 'to' project specified - '#{pid}'")
53+
to_blueprint = to_project.blueprint
54+
upgrade_datasets = get_upgrade_dates(latest_blueprint, to_blueprint)
55+
next if upgrade_datasets.empty?
56+
57+
message = get_upgrade_message(upgrade_datasets)
58+
59+
results << {
60+
from: segment_info[:from],
61+
to: pid,
62+
status: to_project.upgrade_custom_v2(message)
63+
}
64+
end
65+
end
66+
67+
results
68+
end
69+
70+
def get_upgrade_dates(src_blueprint, dest_blueprint)
71+
dest_dates = get_date_dimensions(dest_blueprint) if dest_blueprint
72+
src_dates = get_date_dimensions(src_blueprint) if src_blueprint
73+
74+
return false if dest_dates.empty? || src_dates.empty?
75+
76+
upgrade_datasets = []
77+
dest_dates.each do |dest|
78+
src_dim = get_date_dimension(src_blueprint, dest[:id])
79+
next unless src_dim
80+
81+
upgrade_datasets << src_dim[:identifier] if upgrade?(src_dim, dest) && src_dim[:identifier]
82+
end
83+
84+
upgrade_datasets
85+
end
86+
87+
def get_upgrade_message(upgrade_datasets)
88+
{
89+
upgrade: {
90+
dateDatasets: {
91+
upgrade: "exact",
92+
datasets: upgrade_datasets
93+
}
94+
}
95+
}
96+
end
97+
98+
def upgrade?(src_dim, dest_dim)
99+
src_dim[:urn] == DATE_DIMENSION_CUSTOM_V2 && DATE_DIMENSION_OLD.any? { |e| dest_dim[:urn] == e }
100+
end
101+
102+
def contain_v2?(blueprint)
103+
get_date_dimensions(blueprint).any? { |e| e[:urn] == DATE_DIMENSION_CUSTOM_V2 }
104+
end
105+
106+
def get_date_dimension(blueprint, id)
107+
GoodData::Model::ProjectBlueprint.find_date_dimension(blueprint, id)
108+
end
109+
110+
def get_date_dimensions(blueprint)
111+
GoodData::Model::ProjectBlueprint.date_dimensions(blueprint)
112+
end
113+
end
114+
end
115+
end
116+
end

lib/gooddata/lcm/actions/synchronize_ldm.rb

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,8 @@ class SynchronizeLdm < BaseAction
4949
param :include_deprecated, instance_of(Type::BooleanType), required: false, default: false
5050
end
5151

52+
RESULT_HEADER = %i[from to status]
53+
5254
class << self
5355
def call(params)
5456
results = []
@@ -76,9 +78,9 @@ def sync_segment_ldm(params, segment_info)
7678
include_deprecated = params.include_deprecated.to_b
7779
from_pid = segment_info[:from]
7880
from = params.development_client.projects(from_pid) || fail("Invalid 'from' project specified - '#{from_pid}'")
79-
8081
GoodData.logger.info "Creating Blueprint, project: '#{from.title}', PID: #{from_pid}"
8182
blueprint = from.blueprint(include_ca: params.include_computed_attributes.to_b)
83+
segment_info[:from_blueprint] = blueprint
8284
maql_diff = nil
8385
previous_master = segment_info[:previous_master]
8486
diff_against_master = %w(diff_against_master_with_fallback diff_against_master)

lib/gooddata/lcm/lcm2.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,7 @@ def respond_to_missing?(name, *_args)
138138
EnsureTechnicalUsersDomain,
139139
EnsureTechnicalUsersProject,
140140
SynchronizeLdm,
141+
MigrateGdcDateDimension,
141142
SynchronizeClients,
142143
SynchronizeComputedAttributes,
143144
CollectDymanicScheduleParams,

lib/gooddata/models/from_wire.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,7 @@ def self.parse_date_dimensions(date_dim)
105105
d[:title] = date_dim['dateDimension']['title']
106106
d[:urn] = date_dim['dateDimension']['urn']
107107
d[:identifier_prefix] = date_dim['dateDimension']['identifierPrefix']
108+
d[:identifier] = date_dim['dateDimension']['identifier'] if date_dim['dateDimension']['identifier']
108109
d[:columns] = parse_bridges(date_dim)
109110
end
110111
end

lib/gooddata/models/project.rb

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -625,6 +625,7 @@ def attributes_by_title(title)
625625
def blueprint(options = {})
626626
options = { include_ca: true }.merge(options)
627627
result = client.get("/gdc/projects/#{pid}/model/view", params: { includeDeprecated: true, includeGrain: true, includeCA: options[:include_ca] })
628+
628629
polling_url = result['asyncTask']['link']['poll']
629630
model = client.poll_on_code(polling_url, options)
630631
bp = GoodData::Model::FromWire.from_wire(model, options)
@@ -1922,6 +1923,20 @@ def resolve_roles(login, desired_roles, options = {})
19221923
[user, roles]
19231924
end
19241925

1926+
def upgrade_custom_v2(message, options = {})
1927+
uri = "/gdc/md/#{pid}/datedimension/upgrade"
1928+
poll_result = client&.post(uri, message)
1929+
1930+
return poll_result['wTaskStatus']['status'] if poll_result['wTaskStatus'] && poll_result['wTaskStatus']['status']
1931+
1932+
polling_uri = poll_result['asyncTask']['link']['poll']
1933+
result = client&.poll_on_response(polling_uri, options) do |body|
1934+
body && body['wTaskStatus'] && body['wTaskStatus']['status'] == 'RUNNING'
1935+
end
1936+
1937+
result['wTaskStatus']['status'] == 'OK' ? 'OK' : 'FAIL'
1938+
end
1939+
19251940
def add
19261941
@add ||= GoodData::AutomatedDataDistribution.new(self)
19271942
@add
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
{
2+
"title": "blueprint old date dimension",
3+
"include_ca": true,
4+
"datasets": [
5+
{
6+
"type": "dataset",
7+
"title": "person",
8+
"id": "dataset.person",
9+
"columns": [
10+
{
11+
"type": "anchor",
12+
"id": "attr.person.factsof",
13+
"title": "Records of person",
14+
"description": "Records of person",
15+
"folder": "person"
16+
},
17+
{
18+
"type": "attribute",
19+
"id": "attr.person.name",
20+
"title": "name",
21+
"description": "name",
22+
"folder": "person"
23+
},
24+
{
25+
"type": "label",
26+
"id": "label.person.name",
27+
"reference": "attr.person.name",
28+
"title": "name",
29+
"gd_data_type": "VARCHAR(128)",
30+
"gd_type": "GDC.text",
31+
"default_label": true
32+
},
33+
{
34+
"type": "fact",
35+
"id": "fact.person.id",
36+
"title": "id",
37+
"description": "id",
38+
"folder": "person",
39+
"gd_data_type": "DECIMAL(12,2)"
40+
},
41+
{
42+
"type": "date",
43+
"dataset": "datecustom"
44+
},
45+
{
46+
"type": "date",
47+
"dataset": "dategooddata"
48+
}
49+
]
50+
}
51+
],
52+
"date_dimensions": [
53+
{
54+
"type": "date_dimension",
55+
"id": "datecustom",
56+
"title": "DateCustom",
57+
"urn": "urn:custom:date",
58+
"identifier_prefix": "datecustom",
59+
"columns": [
60+
61+
]
62+
},
63+
{
64+
"type": "date_dimension",
65+
"id": "dategooddata",
66+
"title": "DateGooddata",
67+
"urn": "urn:gooddata:date",
68+
"identifier_prefix": "dategooddata",
69+
"columns": [
70+
71+
]
72+
}
73+
]
74+
}
Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
# (C) 2019-2020 GoodData Corporation
2+
require 'gooddata'
3+
4+
describe 'Should upgrade custom v2 for project', :vcr, :constraint => 'slow' do
5+
before(:all) do
6+
@client = ConnectionHelper.create_default_connection
7+
@blueprint = GoodData::Model::ProjectBlueprint.from_json('./spec/data/blueprints/old_date_dimension.json')
8+
end
9+
10+
after(:all) do
11+
@client&.disconnect
12+
end
13+
14+
it 'upgrade all date dimension to custom v2' do
15+
to_project = @client&.create_project_from_blueprint(@blueprint, auth_token: ConnectionHelper::SECRETS[:gd_project_token], environment: ProjectHelper::ENVIRONMENT)
16+
blueprint = to_project.blueprint(include_ca: true)
17+
date_old = GoodData::Model::ProjectBlueprint.date_dimensions(blueprint)
18+
19+
expect(date_old).not_to be_nil
20+
date_old.each do |date|
21+
expect(%w[datecustom dategooddata].any? { |e| date[:id] == e }).to be_truthy
22+
expect(GoodData::LCM2::MigrateGdcDateDimension::DATE_DIMENSION_OLD.any? { |e| date[:urn]&.include?(e) }).to be_truthy
23+
end
24+
25+
message = get_upgrade_message(true, nil)
26+
to_project&.upgrade_custom_v2(message)
27+
28+
blueprint = to_project.blueprint(include_ca: true)
29+
date_new = GoodData::Model::ProjectBlueprint.date_dimensions(blueprint)
30+
expect(date_new).not_to be_nil
31+
date_new.each do |date|
32+
expect(%w[datecustom dategooddata].any? { |e| date[:id] == e }).to be_truthy
33+
expect(date[:urn]&.include?(GoodData::LCM2::MigrateGdcDateDimension::DATE_DIMENSION_CUSTOM_V2)).to be_truthy
34+
end
35+
36+
to_project&.delete
37+
end
38+
39+
it 'upgrade a date dimension to custom v2' do
40+
to_project = @client&.create_project_from_blueprint(@blueprint, auth_token: ConnectionHelper::SECRETS[:gd_project_token], environment: ProjectHelper::ENVIRONMENT)
41+
blueprint = to_project.blueprint(include_ca: true)
42+
date_old = GoodData::Model::ProjectBlueprint.date_dimensions(blueprint)
43+
44+
expect(date_old).not_to be_nil
45+
date_old.each do |date|
46+
expect(%w[datecustom dategooddata].any? { |e| date[:id] == e }).to be_truthy
47+
expect(GoodData::LCM2::MigrateGdcDateDimension::DATE_DIMENSION_OLD.any? { |e| date[:urn]&.include?(e) }).to be_truthy
48+
end
49+
50+
message = get_upgrade_message(false, ['datecustom.dataset.dt'])
51+
to_project&.upgrade_custom_v2(message)
52+
53+
blueprint = to_project.blueprint(include_ca: true)
54+
date_new = GoodData::Model::ProjectBlueprint.date_dimensions(blueprint)
55+
expect(date_new).not_to be_nil
56+
date_new.each do |date|
57+
expect(%w[datecustom dategooddata].any? { |e| date[:id] == e }).to be_truthy
58+
if date[:id] == 'datecustom'
59+
expect(date[:urn]&.include?(GoodData::LCM2::MigrateGdcDateDimension::DATE_DIMENSION_CUSTOM_V2)).to be_truthy
60+
else
61+
expect(date[:urn]&.include?('gooddata')).to be_truthy
62+
end
63+
end
64+
65+
to_project&.delete
66+
end
67+
68+
it 'upgrade multiple date dimension to custom v2' do
69+
to_project = @client&.create_project_from_blueprint(@blueprint, auth_token: ConnectionHelper::SECRETS[:gd_project_token], environment: ProjectHelper::ENVIRONMENT)
70+
blueprint = to_project.blueprint(include_ca: true)
71+
date_old = GoodData::Model::ProjectBlueprint.date_dimensions(blueprint)
72+
73+
expect(date_old).not_to be_nil
74+
date_old.each do |date|
75+
expect(%w[datecustom dategooddata].any? { |e| date[:id] == e }).to be_truthy
76+
expect(GoodData::LCM2::MigrateGdcDateDimension::DATE_DIMENSION_OLD.any? { |e| date[:urn]&.include?(e) }).to be_truthy
77+
end
78+
79+
message = get_upgrade_message(false, ['datecustom.dataset.dt','dategooddata.dataset.dt'])
80+
to_project&.upgrade_custom_v2(message)
81+
82+
blueprint = to_project.blueprint(include_ca: true)
83+
date_new = GoodData::Model::ProjectBlueprint.date_dimensions(blueprint)
84+
expect(date_new).not_to be_nil
85+
date_new.each do |date|
86+
expect(%w[datecustom dategooddata].any? { |e| date[:id] == e }).to be_truthy
87+
expect(date[:urn]&.include?(GoodData::LCM2::MigrateGdcDateDimension::DATE_DIMENSION_CUSTOM_V2)).to be_truthy
88+
end
89+
90+
to_project&.delete
91+
end
92+
93+
def get_upgrade_message(is_all, upgrade_datasets)
94+
if is_all
95+
{
96+
upgrade: {
97+
dateDatasets: {
98+
upgrade: "all"
99+
}
100+
}
101+
}
102+
else
103+
{
104+
upgrade: {
105+
dateDatasets: {
106+
upgrade: "exact",
107+
datasets: upgrade_datasets
108+
}
109+
}
110+
}
111+
end
112+
end
113+
end

0 commit comments

Comments
 (0)