Skip to content

Commit 5ab72fd

Browse files
authored
Merge branch 'main' into migrate-release-changelog
2 parents ade170e + 1958a92 commit 5ab72fd

33 files changed

+257
-88
lines changed

.dockerignore

+1
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
# Ignore all logfiles and tempfiles.
2020
/log/*
2121
/tmp/*
22+
!/tmp/caching-dev.txt
2223
!/log/.keep
2324
!/tmp/.keep
2425

app/components/integration_card_component.html.erb

+1-1
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
<% if connected? %>
2121
<div class="flex justify-between w-full items-baseline">
2222
<%= render BadgeComponent.new(text: "Connected", status: :success) %>
23-
<% if ci_cd? %>
23+
<% if disconnectable_categories? %>
2424
<%= render ButtonComponent.new(
2525
scheme: :danger,
2626
options: app_integration_path(@app, integration),

app/components/integration_card_component.rb

+2-2
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ def initialize(app, integration, category)
1717
end
1818

1919
attr_reader :integration
20-
delegate :connected?, :disconnected?, :providable, :connection_data, :providable_type, :ci_cd?, to: :integration, allow_nil: true
20+
delegate :connected?, :disconnected?, :providable, :connection_data, :providable_type, :disconnectable_categories?, to: :integration, allow_nil: true
2121
alias_method :provider, :providable
2222
delegate :creatable?, :connectable?, to: :provider
2323

@@ -70,6 +70,6 @@ def reusable_integrations_form_partial(existing_integrations)
7070
end
7171

7272
def disconnectable?
73-
integration.disconnectable? && ci_cd?
73+
integration.disconnectable? && disconnectable_categories?
7474
end
7575
end

app/components/live_release/build_component.rb

+1
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ class LiveRelease::BuildComponent < BaseComponent
1010
unavailable: {text: "Build unavailable", status: :failure},
1111
started: {text: "Workflow running", status: :ongoing, kind: :spinner_pill},
1212
failed: {text: "Workflow failed", status: :failure},
13+
trigger_failed: {text: "Failed to trigger workflow", status: :failure},
1314
halted: {text: "Workflow halted", status: :failure},
1415
finished: {text: "Workflow finished", status: :ongoing},
1516
cancelled: {text: "Workflow cancelled", status: :inert},

app/components/live_release/finalize_component.rb

+2-1
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,8 @@ def subtitle
7979
end
8080

8181
def tag_link
82-
link = release.tag_url || release.app.config.code_repo_url
82+
link = release.tag_url || release.app.config&.code_repo_url
83+
return NOT_AVAILABLE if link.blank?
8384
link_to_external train.vcs_provider.display, link, class: "underline"
8485
end
8586
end

app/components/live_release/pre_prod_release/current_release_component.html.erb

+6
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,12 @@
6262
<%= render BadgeComponent.new(**status) %>
6363
</div>
6464

65+
<% if workflow_run.trigger_failed? %>
66+
<div class="self-start">
67+
<%= render AlertComponent.new(type: :error, title: raw(workflow_run.trigger_failed_reason), full_screen: false) %>
68+
</div>
69+
<% end %>
70+
6571
<% if build.present? %>
6672
<%= render LiveRelease::BuildComponent.new(build) %>
6773
<% end %>

app/components/release_list_component.html.erb

+4-10
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
<% if train.hotfixable? %>
33
<% container.with_action do %>
44
<%= render ModalComponent.new(title: "Start a hotfix release",
5-
subtitle: "This will be against your last successful release #{hotfix_from.release_version}") do |modal| %>
5+
subtitle: "This will be against your last successful release #{hotfix_from.release_version}") do |modal| %>
66
<% button = modal.with_button(scheme: :light,
77
type: :action,
88
size: :xxs,
@@ -62,6 +62,7 @@
6262
label: "Configure",
6363
authz: false,
6464
options: edit_app_train_path(app, train),
65+
disabled: !app.ready?,
6566
type: :link) do |b|
6667
b.with_icon("cog.svg")
6768
end %>
@@ -111,15 +112,8 @@
111112
<% end %>
112113

113114
<% container.with_body do %>
114-
<% unless app.ready? %>
115-
<%= render AlertComponent.new(kind: :banner,
116-
type: :notice,
117-
title: "App is not ready",
118-
info: { label: "Configure", link: app_integrations_path(app) },
119-
full_screen: false) do %>
120-
Please finish configuring the required integrations before you can start creating releases.
121-
<% end %>
122-
<% end %>
115+
<%= render partial: "shared/app_not_ready", locals: { app: } %>
116+
123117
<% if train.automatic? %>
124118
<%= render ScheduledTrainComponent.new(train) %>
125119
<% end %>

app/components/release_list_component.rb

+8
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,14 @@ def ios_enabled?
123123
end
124124

125125
def no_release_empty_state
126+
unless app.ready?
127+
return {
128+
title: "App is not ready",
129+
text: "There are required integrations that need to be configured before you can start creating releases.",
130+
content: render(ButtonComponent.new(scheme: :light, type: :link, label: "Configure Integration", options: app_integrations_path(app), size: :xxs, authz: false))
131+
}
132+
end
133+
126134
if train.automatic?
127135
if train.activatable?
128136
{

app/controllers/config/release_platforms_controller.rb

+2-1
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ class Config::ReleasePlatformsController < SignedInApplicationController
88
before_action :set_release_platform, only: %i[edit update]
99
before_action :set_config, only: %i[edit update]
1010
before_action :set_train_config_tabs, only: %i[edit update]
11+
before_action :ensure_app_ready, only: %i[edit update]
1112
before_action :set_ci_actions, only: %i[edit update]
1213
before_action :set_submission_types, only: %i[edit update]
1314
around_action :set_time_zone
@@ -43,7 +44,7 @@ def set_config
4344
end
4445

4546
def set_ci_actions
46-
@ci_actions = @app.config.ci_cd_workflows
47+
@ci_actions = @train.workflows || []
4748
end
4849

4950
def set_submission_types

app/controllers/notification_settings_controller.rb

+1
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ class NotificationSettingsController < SignedInApplicationController
55

66
before_action :require_write_access!, only: %i[update]
77
before_action :set_train, only: %i[index update edit]
8+
before_action :ensure_app_ready, only: %i[index edit update]
89
before_action :set_notification_setting, only: %i[update edit]
910
around_action :set_time_zone
1011

app/controllers/release_health_rules_controller.rb

+1
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ class ReleaseHealthRulesController < SignedInApplicationController
22
before_action :require_write_access!, only: %i[create destroy]
33
before_action :set_train, only: %i[create destroy]
44
before_action :set_release_platform, only: %i[create destroy]
5+
before_action :ensure_app_ready, only: %i[create destroy]
56

67
def create
78
@rule = @release_platform.release_health_rules.new(rule_params)

app/controllers/release_indices_controller.rb

+1
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ class ReleaseIndicesController < SignedInApplicationController
55
before_action :set_train, only: %i[edit update]
66
before_action :set_app_from_train, only: %i[edit update]
77
before_action :set_train_config_tabs, only: %i[edit update]
8+
before_action :ensure_app_ready, only: %i[edit update]
89

910
def edit
1011
@release_index = @train.release_index

app/controllers/signed_in_application_controller.rb

+8-2
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,12 @@ class SignedInApplicationController < ApplicationController
3939

4040
private
4141

42+
def ensure_app_ready
43+
unless @app.ready?
44+
redirect_to app_path(@app), flash: {error: "App is not ready (not fully configured)."}
45+
end
46+
end
47+
4248
def set_page_name
4349
user_facing_actions = %w[new index show edit]
4450

@@ -185,11 +191,11 @@ def new_app
185191
end
186192

187193
def vcs_provider_logo
188-
@vcs_provider_logo ||= "integrations/logo_#{@app.vcs_provider}.png"
194+
@vcs_provider_logo ||= "integrations/logo_#{@app.vcs_provider.presence || "deprecated"}.png"
189195
end
190196

191197
def ci_cd_provider_logo
192-
@ci_cd_provider_logo ||= "integrations/logo_#{@app.ci_cd_provider}.png"
198+
@ci_cd_provider_logo ||= "integrations/logo_#{@app.ci_cd_provider || "deprecated"}.png"
193199
end
194200

195201
def teams_supported?

app/controllers/trains_controller.rb

+1
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ class TrainsController < SignedInApplicationController
77
before_action :require_write_access!, only: %i[new create update destroy activate deactivate]
88
before_action :set_train, only: %i[edit update destroy activate deactivate rules]
99
before_action :set_train_config_tabs, only: %i[edit update rules destroy activate deactivate]
10+
before_action :ensure_app_ready, only: %i[new create edit update activate deactivate rules]
1011
before_action :validate_integration_status, only: %i[new create]
1112
before_action :set_notification_channels, only: %i[new create edit update]
1213
around_action :set_time_zone

app/jobs/workflow_runs/trigger_job.rb

+11
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,22 @@
11
class WorkflowRuns::TriggerJob < ApplicationJob
22
queue_as :high
33

4+
TRIGGER_FAILED_REASONS = [
5+
:workflow_parameter_not_provided,
6+
:workflow_dispatch_missing
7+
]
8+
49
def perform(workflow_run_id, retrigger = false)
510
workflow_run = WorkflowRun.find(workflow_run_id)
611
return unless workflow_run.active?
712
return unless workflow_run.may_initiated?
813

914
workflow_run.trigger!(retrigger:)
15+
rescue Installations::Error => err
16+
if err.reason.in?(TRIGGER_FAILED_REASONS)
17+
workflow_run.trigger_failed!(err)
18+
else
19+
raise
20+
end
1021
end
1122
end

app/libs/coordinators.rb

+4
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,10 @@ def self.beta_release_is_finished!(build)
8080
def self.production_release_is_complete!(release_platform_run)
8181
Coordinators::FinishPlatformRun.call(release_platform_run)
8282
end
83+
84+
def self.workflow_run_trigger_failed!(workflow_run)
85+
workflow_run.triggering_release.fail!
86+
end
8387
end
8488

8589
module Actions

app/libs/installations/bitbucket/api.rb

+1-1
Original file line numberDiff line numberDiff line change
@@ -352,7 +352,7 @@ def get_sha_for_ref(repo_slug, ref, type)
352352
end
353353
end
354354

355-
MAX_PAGES = 10
355+
MAX_PAGES = 100
356356

357357
def find_file(url, files, file_name, page = 0)
358358
return if page == MAX_PAGES

app/libs/installations/github/error.rb

+8
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,14 @@ class Github::Error < Installations::Error
5858
{
5959
message_matcher: /Merge conflict/i,
6060
decorated_reason: :merge_conflict
61+
},
62+
{
63+
message_matcher: /Required input\s+.?\w+.?\s+not provided/,
64+
decorated_reason: :workflow_parameter_not_provided
65+
},
66+
{
67+
message_matcher: /Workflow does not have 'workflow_dispatch' trigger/,
68+
decorated_reason: :workflow_dispatch_missing
6169
}
6270
]
6371

app/models/app_config.rb

+14-13
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,10 @@
66
# bitbucket_workspace :string
77
# bugsnag_android_config :jsonb
88
# bugsnag_ios_config :jsonb
9-
# ci_cd_workflows :jsonb
109
# code_repository :json
1110
# firebase_android_config :jsonb
1211
# firebase_ios_config :jsonb
1312
# jira_config :jsonb not null
14-
# notification_channel :json
1513
# created_at :datetime not null
1614
# updated_at :datetime not null
1715
# app_id :uuid not null, indexed
@@ -22,7 +20,7 @@ class AppConfig < ApplicationRecord
2220
include AppConfigurable
2321

2422
PLATFORM_AWARE_CONFIG_SCHEMA = Rails.root.join("config/schema/platform_aware_integration_config.json")
25-
self.ignored_columns += %w[bugsnag_project_id firebase_crashlytics_android_config firebase_crashlytics_ios_config notification_channel]
23+
self.ignored_columns += %w[bugsnag_project_id firebase_crashlytics_android_config firebase_crashlytics_ios_config notification_channel ci_cd_workflows]
2624

2725
belongs_to :app
2826
has_many :variants, class_name: "AppVariant", dependent: :destroy
@@ -47,28 +45,27 @@ def ready?
4745
end
4846

4947
def code_repository_name
50-
return if code_repository.blank?
51-
code_repository["full_name"]
48+
code_repository&.fetch("full_name", nil)
5249
end
5350

5451
def code_repo_url
55-
code_repository["repo_url"]
52+
code_repository&.fetch("repo_url", nil)
5653
end
5754

5855
def code_repo_namespace
59-
code_repository["namespace"]
56+
code_repository&.fetch("namespace", nil)
6057
end
6158

6259
def code_repo_name_only
63-
code_repository["name"]
60+
code_repository&.fetch("name", nil)
6461
end
6562

6663
def bitrise_project
6764
bitrise_project_id&.fetch("id", nil)
6865
end
6966

7067
def further_setup_by_category?
71-
integrations = app.integrations
68+
integrations = app.integrations.connected
7269
categories = {}.with_indifferent_access
7370

7471
if integrations.version_control.present?
@@ -131,10 +128,14 @@ def ci_cd_workflows
131128
super&.map(&:with_indifferent_access)
132129
end
133130

134-
def set_ci_cd_workflows(workflows)
135-
return if code_repository.nil?
136-
return if app.ci_cd_provider.blank?
137-
update(ci_cd_workflows: workflows)
131+
def disconnect!(integration)
132+
if integration.version_control?
133+
self.code_repository = nil
134+
elsif integration.ci_cd?
135+
self.bitrise_project_id = nil
136+
end
137+
138+
save!
138139
end
139140

140141
private

app/models/app_variant.rb

+4
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,10 @@ def display_text
3333

3434
def config = self
3535

36+
def disconnect!(_)
37+
raise NotImplementedError
38+
end
39+
3640
private
3741

3842
def duplicate_bundle_identifier

app/models/google_play_store_integration.rb

+19-9
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ class GooglePlayStoreIntegration < ApplicationRecord
1616
include Displayable
1717
include Loggable
1818

19+
delegate :cache, to: Rails
1920
delegate :integrable, to: :integration, allow_nil: true
2021
delegate :refresh_external_app, :bundle_identifier, to: :integrable, allow_nil: true
2122

@@ -26,6 +27,7 @@ class GooglePlayStoreIntegration < ApplicationRecord
2627
after_create_commit :draft_check
2728
after_create_commit :refresh_external_app
2829

30+
CACHE_EXPIRY = 1.month
2931
LOCK_ACQUISITION_FAILURE_REASON = :lock_acquisition_failed
3032
LOCK_ACQUISITION_FAILURE_MSG = "Failed to acquire an internal lock to make Play Store calls"
3133
LOCK_NAME_PREFIX = "google_play_store_edit_"
@@ -150,15 +152,6 @@ def connection_data
150152
"Bundle Identifier: #{bundle_identifier}"
151153
end
152154

153-
def channels
154-
default_channels = CHANNELS.map(&:with_indifferent_access)
155-
channel_data.each do |chan|
156-
next if default_channels.pluck(:id).map(&:to_s).include?(chan[:name])
157-
default_channels << {id: chan[:name], name: "Closed testing - #{chan[:name]}", is_production: false}.with_indifferent_access
158-
end
159-
default_channels
160-
end
161-
162155
def pick_default_beta_channel
163156
BETA_CHANNEL
164157
end
@@ -229,6 +222,8 @@ def build_in_progress?(channel, build_number)
229222
response.present? && GooglePlayStoreIntegration::IN_PROGRESS_STORE_STATUS.include?(response[:status])
230223
end
231224

225+
private
226+
232227
def project_id
233228
JSON.parse(json_key)["project_id"]&.split("-")&.third
234229
end
@@ -276,4 +271,19 @@ def api_lock_params(priority: :high)
276271
raise ArgumentError, "Invalid priority: #{priority}"
277272
end
278273
end
274+
275+
def channels
276+
default_channels = CHANNELS.map(&:with_indifferent_access)
277+
cache.fetch(tracks_cache_key, expires_in: CACHE_EXPIRY) do
278+
channel_data&.each do |chan|
279+
next if default_channels.pluck(:id).map(&:to_s).include?(chan[:name])
280+
default_channels << {id: chan[:name], name: "Closed testing - #{chan[:name]}", is_production: false}.with_indifferent_access
281+
end
282+
end
283+
default_channels
284+
end
285+
286+
def tracks_cache_key
287+
"google_play_store_integration/#{id}/tracks"
288+
end
279289
end

0 commit comments

Comments
 (0)