Skip to content

Commit 8e7fd4e

Browse files
authored
feat(front): invalidate branch page cache when branch becomes unmergeable (#391)
When a pull request branch becomes unmergeable, we invalidate the branch page for it, so we can display the pull request unmergeable warning.
1 parent 2edc439 commit 8e7fd4e

File tree

6 files changed

+109
-16
lines changed

6 files changed

+109
-16
lines changed

front/lib/front/branch_page/cache_invalidator.ex

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,8 @@ defmodule Front.BranchPage.CacheInvalidator do
1919
{"pipeline_state_exchange", "running", :pipeline_event},
2020
{"pipeline_state_exchange", "stopping", :pipeline_event},
2121
{"pipeline_state_exchange", "done", :pipeline_event},
22-
{"velocity_pipeline_summary_exchange", "done", :pipeline_summary_event}
22+
{"velocity_pipeline_summary_exchange", "done", :pipeline_summary_event},
23+
{"hook_exchange", "pr_unmergeable", :pr_unmergeable_event}
2324
]
2425

2526
@metric_name "branch_page.cache_invalidator.process"
@@ -61,6 +62,24 @@ defmodule Front.BranchPage.CacheInvalidator do
6162
)
6263
end
6364

65+
def pr_unmergeable_event(message) do
66+
Watchman.benchmark({@metric_name, ["pr_unmergeable_event"]}, fn ->
67+
event = InternalApi.RepoProxy.PullRequestUnmergeable.decode(message)
68+
69+
measure_queue_time(event, "pr_unmergeable_event")
70+
invalidate_with_pr_branch(event.project_id, event.branch_name)
71+
72+
Logger.info(
73+
"#{@log_prefix} [PR UNMERGEABLE EVENT] [project_id=#{event.project_id} branch=#{event.branch_name}] Processing finished"
74+
)
75+
end)
76+
rescue
77+
e in Protobuf.DecodeError ->
78+
Logger.error(
79+
"#{@log_prefix} [PR UNMERGEABLE EVENT] Processing failed message: #{inspect(message)} error: #{inspect(e)}"
80+
)
81+
end
82+
6483
def measure_queue_time(event, tag) do
6584
fetched_for_processing_at = :os.system_time(:millisecond)
6685
emitted_at = event.timestamp.seconds * 1000 + div(event.timestamp.nanos, 1_000_000)
@@ -84,4 +103,24 @@ defmodule Front.BranchPage.CacheInvalidator do
84103
struct!(BranchPage.Model.LoadParams, branch_id: pipeline.branch_id)
85104
|> BranchPage.Model.invalidate()
86105
end
106+
107+
defp invalidate_with_pr_branch(project_id, branch_name) do
108+
#
109+
# Find the latest workflow for the branch,
110+
# and invalidate the cache for it, since it's from that workflow
111+
# that we determine the conflict status of the branch.
112+
#
113+
workflow =
114+
Models.Workflow.find_latest(
115+
project_id: project_id,
116+
branch_name: branch_name
117+
)
118+
119+
Models.RepoProxy.invalidate(workflow.hook_id)
120+
Models.Workflow.invalidate(workflow.id)
121+
122+
{:ok, _} =
123+
struct!(BranchPage.Model.LoadParams, branch_id: workflow.branch_id)
124+
|> BranchPage.Model.invalidate()
125+
end
87126
end

front/lib/front/models/repo_proxy.ex

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ defmodule Front.Models.RepoProxy do
4545

4646
def find(id, tracing_headers) do
4747
Watchman.benchmark("fetch_repo_proxy.duration", fn ->
48-
Cacheman.fetch(:front, cache_key(id), fn ->
48+
Cacheman.fetch(:front, cache_key(id), [ttl: :timer.hours(1)], fn ->
4949
request = %RepoProxy.DescribeRequest{hook_id: id}
5050

5151
{:ok, response} = Stub.describe(channel(), request, options(tracing_headers))
@@ -231,6 +231,11 @@ defmodule Front.Models.RepoProxy do
231231
|> Enum.filter(fn id -> !Enum.any?(cached, fn hook -> hook.id == id end) end)
232232
end
233233

234+
def invalidate(id) do
235+
cache_key(id)
236+
|> then(&Cacheman.delete(:front, &1))
237+
end
238+
234239
defp sort_in_requested_order(hooks, ids) do
235240
ids
236241
|> Enum.map(fn id ->
Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,15 @@
1-
<div class="mv3 pa3 bg-lightest-orange ba b--black-15">
1+
<div class="mv3 pa3 ph4 bg-lightest-orange ba b--black-15">
22
<div class="flex-m items-center justify-between">
33
<div class="mb3 mb0-m pr3-m">
44
<div class="flex-m items-center">
5-
<div class="flex-shrink-0 mb2 mb0-m pr3">
6-
<img src="<%= assets_path() %>/images/icn-warning.svg">
7-
</div>
85
<div class="flex-auto">
96
<p class="b mb0">This Pull Request has conflicts that must be resolved</p>
10-
<p class="mb0">Please go to repository and resolve the conflicts before starting a new workflow</p>
7+
<p class="mb0">Please go to the repository and resolve the conflicts before starting a new workflow.</p>
118
</div>
129
</div>
1310
</div>
1411
<div class="flex-shrink-0">
15-
<a href="<%= human_accessible_repository_url(@project, @branch) %>#partial-pull-merging" class="btn btn-warning">Resolve conflicts ↗</a>
12+
<a href="<%= human_accessible_repository_url(@project, @branch) %>" class="btn btn-link">Resolve conflicts ↗</a>
1613
</div>
1714
</div>
1815
</div>

front/lib/internal_api/organization.pb.ex

Lines changed: 39 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,15 @@ defmodule InternalApi.Organization.DescribeRequest do
55
@type t :: %__MODULE__{
66
org_id: String.t(),
77
org_username: String.t(),
8-
include_quotas: boolean
8+
include_quotas: boolean,
9+
soft_deleted: boolean
910
}
10-
defstruct [:org_id, :org_username, :include_quotas]
11+
defstruct [:org_id, :org_username, :include_quotas, :soft_deleted]
1112

1213
field(:org_id, 1, type: :string)
1314
field(:org_username, 2, type: :string)
1415
field(:include_quotas, 3, type: :bool)
16+
field(:soft_deleted, 4, type: :bool)
1517
end
1618

1719
defmodule InternalApi.Organization.DescribeResponse do
@@ -33,11 +35,13 @@ defmodule InternalApi.Organization.DescribeManyRequest do
3335
use Protobuf, syntax: :proto3
3436

3537
@type t :: %__MODULE__{
36-
org_ids: [String.t()]
38+
org_ids: [String.t()],
39+
soft_deleted: boolean
3740
}
38-
defstruct [:org_ids]
41+
defstruct [:org_ids, :soft_deleted]
3942

4043
field(:org_ids, 1, repeated: true, type: :string)
44+
field(:soft_deleted, 2, type: :bool)
4145
end
4246

4347
defmodule InternalApi.Organization.DescribeManyResponse do
@@ -61,15 +65,17 @@ defmodule InternalApi.Organization.ListRequest do
6165
created_at_gt: Google.Protobuf.Timestamp.t(),
6266
order: integer,
6367
page_size: integer,
64-
page_token: String.t()
68+
page_token: String.t(),
69+
soft_deleted: boolean
6570
}
66-
defstruct [:user_id, :created_at_gt, :order, :page_size, :page_token]
71+
defstruct [:user_id, :created_at_gt, :order, :page_size, :page_token, :soft_deleted]
6772

6873
field(:user_id, 2, type: :string)
6974
field(:created_at_gt, 3, type: Google.Protobuf.Timestamp)
7075
field(:order, 4, type: InternalApi.Organization.ListRequest.Order, enum: true)
7176
field(:page_size, 5, type: :int32)
7277
field(:page_token, 6, type: :string)
78+
field(:soft_deleted, 7, type: :bool)
7379
end
7480

7581
defmodule InternalApi.Organization.ListRequest.Order do
@@ -512,6 +518,18 @@ defmodule InternalApi.Organization.DestroyRequest do
512518
field(:org_id, 1, type: :string)
513519
end
514520

521+
defmodule InternalApi.Organization.RestoreRequest do
522+
@moduledoc false
523+
use Protobuf, syntax: :proto3
524+
525+
@type t :: %__MODULE__{
526+
org_id: String.t()
527+
}
528+
defstruct [:org_id]
529+
530+
field(:org_id, 1, type: :string)
531+
end
532+
515533
defmodule InternalApi.Organization.Organization do
516534
@moduledoc false
517535
use Protobuf, syntax: :proto3
@@ -962,6 +980,20 @@ defmodule InternalApi.Organization.OrganizationDailyUpdate do
962980
field(:timestamp, 11, type: Google.Protobuf.Timestamp)
963981
end
964982

983+
defmodule InternalApi.Organization.OrganizationRestored do
984+
@moduledoc false
985+
use Protobuf, syntax: :proto3
986+
987+
@type t :: %__MODULE__{
988+
org_id: String.t(),
989+
timestamp: Google.Protobuf.Timestamp.t()
990+
}
991+
defstruct [:org_id, :timestamp]
992+
993+
field(:org_id, 1, type: :string)
994+
field(:timestamp, 2, type: Google.Protobuf.Timestamp)
995+
end
996+
965997
defmodule InternalApi.Organization.OrganizationService.Service do
966998
@moduledoc false
967999
use GRPC.Service, name: "InternalApi.Organization.OrganizationService"
@@ -1034,6 +1066,7 @@ defmodule InternalApi.Organization.OrganizationService.Service do
10341066
)
10351067

10361068
rpc(:Destroy, InternalApi.Organization.DestroyRequest, Google.Protobuf.Empty)
1069+
rpc(:Restore, InternalApi.Organization.RestoreRequest, Google.Protobuf.Empty)
10371070

10381071
rpc(
10391072
:RepositoryIntegrators,

front/lib/internal_api/repo_proxy.pb.ex

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -338,6 +338,22 @@ defmodule InternalApi.RepoProxy.CreateBlankResponse.Repo do
338338
field(:repository_id, 5, type: :string)
339339
end
340340

341+
defmodule InternalApi.RepoProxy.PullRequestUnmergeable do
342+
@moduledoc false
343+
use Protobuf, syntax: :proto3
344+
345+
@type t :: %__MODULE__{
346+
project_id: String.t(),
347+
branch_name: String.t(),
348+
timestamp: Google.Protobuf.Timestamp.t()
349+
}
350+
defstruct [:project_id, :branch_name, :timestamp]
351+
352+
field(:project_id, 1, type: :string)
353+
field(:branch_name, 2, type: :string)
354+
field(:timestamp, 3, type: Google.Protobuf.Timestamp)
355+
end
356+
341357
defmodule InternalApi.RepoProxy.RepoProxyService.Service do
342358
@moduledoc false
343359
use GRPC.Service, name: "InternalApi.RepoProxy.RepoProxyService"

front/lib/internal_api/secrethub.pb.ex

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -673,7 +673,8 @@ defmodule InternalApi.Secrethub.GenerateOpenIDConnectTokenRequest do
673673
job_type: String.t(),
674674
git_pull_request_branch: String.t(),
675675
repo_slug: String.t(),
676-
triggerer: String.t()
676+
triggerer: String.t(),
677+
project_name: String.t()
677678
}
678679
defstruct [
679680
:org_id,
@@ -694,7 +695,8 @@ defmodule InternalApi.Secrethub.GenerateOpenIDConnectTokenRequest do
694695
:job_type,
695696
:git_pull_request_branch,
696697
:repo_slug,
697-
:triggerer
698+
:triggerer,
699+
:project_name
698700
]
699701

700702
field(:org_id, 1, type: :string)
@@ -716,6 +718,7 @@ defmodule InternalApi.Secrethub.GenerateOpenIDConnectTokenRequest do
716718
field(:git_pull_request_branch, 17, type: :string)
717719
field(:repo_slug, 18, type: :string)
718720
field(:triggerer, 19, type: :string)
721+
field(:project_name, 20, type: :string)
719722
end
720723

721724
defmodule InternalApi.Secrethub.GenerateOpenIDConnectTokenResponse do

0 commit comments

Comments
 (0)