Skip to content

Commit 247f4d9

Browse files
authored
Merge branch 'master' into scraps/loader
2 parents 7ec4d33 + c2b23ac commit 247f4d9

File tree

20 files changed

+343
-16
lines changed

20 files changed

+343
-16
lines changed

src/sentry/features/temporary.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -431,6 +431,9 @@ def register_temporary_features(manager: FeatureManager) -> None:
431431
# Use workflow engine exclusively for ProjectRuleDetailsEndpoint.get results.
432432
# See src/sentry/workflow_engine/docs/legacy_backport.md for context.
433433
manager.add("organizations:workflow-engine-projectruledetailsendpoint-get", OrganizationFeature, FeatureHandlerStrategy.FLAGPOLE, api_expose=False)
434+
# Use workflow engine exclusively for OrganizationCombinedRuleIndexEndpoint.get results.
435+
# See src/sentry/workflow_engine/docs/legacy_backport.md for context.
436+
manager.add("organizations:workflow-engine-combinedruleindex-get", OrganizationFeature, FeatureHandlerStrategy.FLAGPOLE, api_expose=False)
434437
# Enable metric detector limits by plan type
435438
manager.add("organizations:workflow-engine-metric-detector-limit", OrganizationFeature, FeatureHandlerStrategy.FLAGPOLE, api_expose=True)
436439
# Enable EventUniqueUserFrequencyConditionWithConditions special alert condition

src/sentry/incidents/endpoints/organization_alert_rule_index.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -607,7 +607,9 @@ def get(self, request: Request, organization: Organization) -> Response:
607607
# Common setup: type filter
608608
type_filter = request.GET.getlist("alertType", [])
609609

610-
if features.has("organizations:workflow-engine-rule-serializers", organization):
610+
if features.has(
611+
"organizations:workflow-engine-rule-serializers", organization
612+
) or features.has("organizations:workflow-engine-combinedruleindex-get", organization):
611613
return self._get_workflow_engine(
612614
request=request,
613615
organization=organization,

src/sentry/integrations/gitlab/client.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -690,6 +690,18 @@ def get_pr_diffs(self, repo: Repository, pr: PullRequest) -> list[dict[str, Any]
690690
path = GitLabApiClientPath.build_pr_diffs(project=project_id, pr_key=pr.key, unidiff=True)
691691
return self.get(path)
692692

693+
def get_repository_tree(
694+
self, project_id: str, ref: str, recursive: bool = True
695+
) -> list[dict[str, Any]]:
696+
"""List repository tree at a given ref.
697+
698+
See https://docs.gitlab.com/ee/api/repositories.html#list-repository-tree
699+
"""
700+
params: dict[str, str] = {"ref": ref, "per_page": "100"}
701+
if recursive:
702+
params["recursive"] = "true"
703+
return self.get(GitLabApiClientPath.tree.format(project=project_id), params=params)
704+
693705
def get_merge_request_diffs(self, project_id: str, pr_key: str) -> list[dict[str, Any]]:
694706
return self.get(GitLabApiClientPath.pr_diffs.format(project=project_id, pr_key=pr_key))
695707

src/sentry/integrations/gitlab/utils.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@ class GitLabApiClientPath:
7474
statuses = "/projects/{project}/statuses/{sha}"
7575
commit_statuses = "/projects/{project}/repository/commits/{sha}/statuses"
7676
archive = "/projects/{project}/repository/archive{format}"
77+
tree = "/projects/{project}/repository/tree"
7778
branches = "/projects/{project_id}/repository/branches"
7879
branch = "/projects/{project_id}/repository/branches/{branch}"
7980
user = "/user"

src/sentry/pipeline/base.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,10 @@ def unpack_state(cls, request: HttpRequest) -> PipelineRequestState[M, S] | None
8181
provider_model = None
8282
if state.provider_model_id:
8383
assert cls.provider_model_cls is not None
84-
provider_model = cls.provider_model_cls.objects.get(id=state.provider_model_id)
84+
try:
85+
provider_model = cls.provider_model_cls.objects.get(id=state.provider_model_id)
86+
except cls.provider_model_cls.DoesNotExist:
87+
return None
8588

8689
organization: RpcOrganization | None = None
8790
if state.org_id:

src/sentry/preprod/size_analysis/grouptype.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -193,7 +193,7 @@ def extract_value(self, data_packet: SizeAnalysisDataPacket) -> SizeAnalysisEval
193193
return self._extract_head(data_packet) - self._extract_base(data_packet)
194194
case "relative_diff":
195195
base = self._extract_base(data_packet)
196-
return (self._extract_head(data_packet) - base) / base
196+
return ((self._extract_head(data_packet) - base) / base) * 100
197197
case _:
198198
raise ValueError(f"Unknown threshold_type: {threshold_type}")
199199

src/sentry/scm/private/providers/gitlab.py

Lines changed: 65 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,7 @@
1010
* create_pull_request_draft
1111
* create_review
1212
* get_check_run
13-
* get_git_commit
1413
* get_pull_request_diff
15-
* get_tree
1614
* minimize_comment
1715
* request_review
1816
* resolve_review_thread
@@ -40,7 +38,10 @@
4038
Commit,
4139
CommitAuthor,
4240
FileContent,
41+
GitCommitObject,
42+
GitCommitTree,
4343
GitRef,
44+
GitTree,
4445
PaginatedActionResult,
4546
PaginatedResponseMeta,
4647
PaginationParams,
@@ -56,6 +57,7 @@
5657
RequestOptions,
5758
ReviewComment,
5859
ReviewSide,
60+
TreeEntry,
5961
)
6062
from sentry.shared_integrations.exceptions import ApiError
6163

@@ -330,6 +332,47 @@ def create_branch(self, branch: BranchName, sha: SHA) -> ActionResult[GitRef]:
330332
raw = self.client.create_branch(self._repo_id, branch, sha)
331333
return make_result(map_git_ref, raw)
332334

335+
@catch_provider_exception
336+
def get_tree(
337+
self,
338+
tree_sha: SHA,
339+
recursive: bool = True,
340+
pagination: PaginationParams | None = None,
341+
request_options: RequestOptions | None = None,
342+
) -> ActionResult[GitTree]:
343+
"""List the repository tree at a given ref.
344+
345+
GitLab's tree API takes a ref (commit SHA, branch, tag) rather than a
346+
tree-object SHA. We treat ``tree_sha`` as a ref so callers can pass a
347+
commit SHA obtained from ``get_git_commit``.
348+
"""
349+
raw = self.client.get_repository_tree(self._repo_id, ref=tree_sha, recursive=recursive)
350+
return ActionResult(
351+
data=GitTree(
352+
sha=tree_sha,
353+
tree=[map_tree_entry(e) for e in raw],
354+
truncated=False,
355+
),
356+
type="gitlab",
357+
raw=raw,
358+
meta={},
359+
)
360+
361+
@catch_provider_exception
362+
def get_git_commit(
363+
self,
364+
sha: SHA,
365+
request_options: RequestOptions | None = None,
366+
) -> ActionResult[GitCommitObject]:
367+
"""Get a commit as a git object.
368+
369+
GitLab's commit endpoint does not expose the tree-object SHA. We set
370+
``tree.sha`` to the commit SHA so that downstream code can pass it to
371+
``get_tree`` (which accepts any ref).
372+
"""
373+
raw = self.client.get_commit(self._repo_id, sha)
374+
return make_result(map_git_commit_object, raw)
375+
333376
@catch_provider_exception
334377
def get_archive_link(
335378
self,
@@ -667,6 +710,26 @@ def map_reaction_result(raw: dict[str, Any]) -> ReactionResult:
667710
)
668711

669712

713+
def map_git_commit_object(raw: dict[str, Any]) -> GitCommitObject:
714+
return GitCommitObject(
715+
sha=raw["id"],
716+
# GitLab's commit API does not return a tree-object SHA. We use the
717+
# commit SHA so callers can pass it to get_tree (which accepts any ref).
718+
tree=GitCommitTree(sha=raw["id"]),
719+
message=raw["message"],
720+
)
721+
722+
723+
def map_tree_entry(raw: dict[str, Any]) -> TreeEntry:
724+
return TreeEntry(
725+
path=raw["path"],
726+
mode=raw["mode"],
727+
type=raw["type"],
728+
sha=raw["id"],
729+
size=None,
730+
)
731+
732+
670733
def map_review_comment(discussion_id: str) -> Callable[[dict[str, Any]], ReviewComment]:
671734
def _map_review_comment(raw: dict[str, Any]) -> ReviewComment:
672735
return ReviewComment(

static/app/components/commandPalette/useCommandPaletteActions.tsx

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -39,9 +39,10 @@ function addKeysToChildActions(
3939
actions: Array<CommandPaletteActionLink | CommandPaletteActionCallback>
4040
): Array<CommandPaletteActionLinkWithKey | CommandPaletteActionCallbackWithKey> {
4141
return actions.map(action => {
42-
const actionKey = `${id}:${action.type}:${action.display.label
43-
.toLowerCase()
44-
.replace(/ /g, '-')}`;
42+
const label = action.display.label.toLowerCase().replace(/ /g, '-');
43+
const disambiguator =
44+
action.type === 'navigate' ? `:${JSON.stringify(action.to)}` : '';
45+
const actionKey = `${id}:${action.type}:${label}${disambiguator}`;
4546
return {
4647
...action,
4748
key: actionKey,

static/app/components/commandPalette/useGlobalCommandPaletteActions.tsx

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import {ProjectAvatar} from '@sentry/scraps/avatar';
2+
13
import {addLoadingMessage, addSuccessMessage} from 'sentry/actionCreators/indicator';
24
import {openInviteMembersModal} from 'sentry/actionCreators/modal';
35
import {
@@ -28,6 +30,7 @@ import {
2830
import {t} from 'sentry/locale';
2931
import {useMutateUserOptions} from 'sentry/utils/useMutateUserOptions';
3032
import {useOrganization} from 'sentry/utils/useOrganization';
33+
import {useProjects} from 'sentry/utils/useProjects';
3134
import {useGetStarredDashboards} from 'sentry/views/dashboards/hooks/useGetStarredDashboards';
3235
import {AGENTS_LANDING_SUB_PATH} from 'sentry/views/insights/pages/agents/settings';
3336
import {BACKEND_LANDING_SUB_PATH} from 'sentry/views/insights/pages/backend/settings';
@@ -49,6 +52,7 @@ function useNavigationActions(): CommandPaletteAction[] {
4952
const prefix = `/organizations/${slug}`;
5053
const {starredViews} = useStarredIssueViews();
5154
const {data: starredDashboards = []} = useGetStarredDashboards();
55+
const {projects} = useProjects();
5256

5357
const issuesChildren: CommandPaletteActionChild[] = [
5458
makeCommandPaletteLink({
@@ -218,6 +222,19 @@ function useNavigationActions(): CommandPaletteAction[] {
218222
)
219223
);
220224

225+
const projectSettingsChildren: CommandPaletteActionChild[] =
226+
organization.features.includes('cmd-k-supercharged')
227+
? projects.map(project =>
228+
makeCommandPaletteLink({
229+
display: {
230+
label: project.name,
231+
icon: <ProjectAvatar project={project} size={16} />,
232+
},
233+
to: `/settings/${slug}/projects/${project.slug}/`,
234+
})
235+
)
236+
: [];
237+
221238
return [
222239
makeCommandPaletteGroup({
223240
groupingKey: 'navigate',
@@ -260,7 +277,17 @@ function useNavigationActions(): CommandPaletteAction[] {
260277
},
261278
actions: settingsChildren,
262279
}),
263-
];
280+
organization.features.includes('cmd-k-supercharged')
281+
? makeCommandPaletteGroup({
282+
groupingKey: 'navigate',
283+
display: {
284+
label: t('Project Settings'),
285+
icon: <IconSettings />,
286+
},
287+
actions: projectSettingsChildren,
288+
})
289+
: null,
290+
].filter(x => x !== null);
264291
}
265292

266293
function useNavigationToggleCollapsed(): CommandPaletteAction {

static/app/components/core/useScrollLock.tsx

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,10 @@ class Lock {
4141
document.body.style.left = '0';
4242
document.body.style.right = '0';
4343
document.body.style.width = '100%';
44+
document.documentElement.style.setProperty(
45+
'--scrollbar-size',
46+
`${scrollbarWidth}px`
47+
);
4448
document.body.style.paddingRight = `${existingPaddingRight + scrollbarWidth}px`;
4549
} else {
4650
this.initialOverflow = this.container.style.overflow;
@@ -61,6 +65,7 @@ class Lock {
6165
document.body.style.right = this.initialBodyStyles.right;
6266
document.body.style.width = this.initialBodyStyles.width;
6367
document.body.style.paddingRight = this.initialBodyStyles.paddingRight;
68+
document.documentElement.style.removeProperty('--scrollbar-size');
6469
const {x, y} = this.scroll;
6570
requestAnimationFrame(() => {
6671
if (this.acquiredBy.size === 0) {

0 commit comments

Comments
 (0)