Skip to content

Search for GitLab PRs in Launchpad#3795

Merged
sergeibbb merged 11 commits intomainfrom
3788-launchpad-api-search-for-prs-on-gitlab
Jan 13, 2025
Merged

Search for GitLab PRs in Launchpad#3795
sergeibbb merged 11 commits intomainfrom
3788-launchpad-api-search-for-prs-on-gitlab

Conversation

@sergeibbb
Copy link
Member

@sergeibbb sergeibbb commented Nov 25, 2024

#3788

Description

Checklist

  • I have followed the guidelines in the Contributing document
  • My changes follow the coding style of this project
  • My changes build without any errors or warnings
  • My changes have been formatted and linted
  • My changes include any required corresponding changes to the documentation (including CHANGELOG.md and README.md)
  • My changes have been rebased and squashed to the minimal number (typically 1) of relevant commits
  • My changes have a descriptive commit message with a short title, including a Fixes $XXX - or Closes #XXX - prefix to auto-close the issue that your PR addresses

@sergeibbb sergeibbb linked an issue Nov 25, 2024 that may be closed by this pull request
@sergeibbb sergeibbb requested a review from ramin-t November 25, 2024 04:37
@sergeibbb
Copy link
Member Author

@axosoft-ramint

In the last commit I'm grouping detected PR-identity by providers, because thought that if we know that an URL matches to a GitLab then no need to search for it in GitHub. But if it looks too compicated, then then last commit can be rejected.

Copy link
Contributor

@ramin-t ramin-t left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As it stands, this doesn't quite feel ready. The utils and test files that are provider-specific should be organized into provider-specific directories. The url identity being a mapped object by provider id feels confusing - the identity itself should just come in on the function. Some of the changes to the PR utils need either explanation or rewrite to make more sense (why are we defining an undefined const and then returning it without touching it?). The same function being defined in the PR utils but then also implemented specifically for integrations doesn't quite make sense to me. The checkoutable logic in launchpad shouldn't be necessary - we should always have at least a defined head ref and remote url for a PR, or else we're not fetching enough info.

Can talk on this further on your return.

@sergeibbb sergeibbb force-pushed the 3788-launchpad-api-search-for-prs-on-gitlab branch from 0feb173 to e58350a Compare December 18, 2024 13:18
@sergeibbb sergeibbb force-pushed the 3788-launchpad-api-search-for-prs-on-gitlab branch from e58350a to 8f03c1c Compare December 18, 2024 13:30
sergeibbb added a commit that referenced this pull request Dec 20, 2024
@sergeibbb sergeibbb force-pushed the 3788-launchpad-api-search-for-prs-on-gitlab branch from 4ae8ec0 to 89e0292 Compare December 20, 2024 18:22
sergeibbb added a commit that referenced this pull request Dec 20, 2024
@sergeibbb sergeibbb force-pushed the 3788-launchpad-api-search-for-prs-on-gitlab branch from 89e0292 to 89bd972 Compare December 20, 2024 18:44
@sergeibbb
Copy link
Member Author

@axosoft-ramint

The utils and test files that are provider-specific should be organized into provider-specific directories.

fixed

The url identity being a mapped object by provider id feels confusing - the identity itself should just come in on the function.

fixed

why are we defining an undefined const and then returning it without touching it?

fixed

The same function being defined in the PR utils but then also implemented specifically for integrations doesn't quite make sense to me

I access the necessary implementation of the function through the integration instance that's why it's in method.
But I cannot keep the implementation in the integration because with our current test configuration it cannot be tested (our tests cannot handle importing the Context). To make the function testable as unit I move it to an external file.

But I'm not sure about one thing:

isMaybeSupportedLaunchpadPullRequestSearchUrl(search: string): boolean {
return (
isMaybeGitHubPullRequestUrl(search) ||
isMaybeGitLabPullRequestUrl(search) ||
isMaybeNonSpecificPullRequestSearchUrl(search)
);
}
//// ??? or maybe better just to do this:
// async isMaybeSupportedLaunchpadPullRequestSearchUrl(search: string): Promise<boolean> {
// return (await this.getPullRequestIdentityFromMaybeUrl(search)) != null;
// }
// - pros: it corresponds to active integrations
// - cons: it's async
// What do you think?
async getPullRequestIdentityFromMaybeUrl(search: string): Promise<PullRequestUrlIdentity | undefined> {
const connectedIntegrations = await this.getConnectedIntegrations();
for (const integrationId of supportedLaunchpadIntegrations) {
if (connectedIntegrations.get(integrationId)) {
const integration = await this.container.integrations.get(integrationId);
const prIdentity = integration.getPullRequestIdentityFromMaybeUrl?.(search);
if (prIdentity) {
return prIdentity;
}
}
}
return getPullRequestIdentityFromMaybeUrl(search);
}

The checkoutable logic in launchpad shouldn't be necessary

Fixed.

Copy link
Contributor

@ramin-t ramin-t left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems to work so far on my end, but I noticed an issue with the url reference in the RP repo identity that will likely break functionality in some cases with other features.

return {
remote: {
url: pr.refs?.head?.url,
url: pr.repository.url,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This changes the url ref to the base repository. This would break the model for PRs where the PR is targeting a different repository and (like when the head ref is from someone's fork).

Commands that use this like "open the PR's repository" or "open in worktree" will break in those cases.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@axosoft-ramint
Thank you for catching it.

Question here. pr.refs?.head?.url is a link to a branch to to the repo. It fails matching to uniqueRemoteUrls in the LaunchpadProvider when I try to swtichTo the branch.
So I see 3 ways to fix it:

  1. Add pr.refs.head.repoUrl on the specific provider level.
  2. Fix the matching to uniqueRemoteUrls in launchpadProvider
  3. Cut it right here: url: someOperationOnRefUrl(pr.refs?.head?.url)

I think that the first option is the best because it can respect specifics of each type of integration. What do you think?

Copy link
Contributor

@ramin-t ramin-t Dec 20, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@sergeibbb pr.hefs?.head?.url should be the link to the remote (repository) that the head ref is hosted on, not a link to a branch - at least, with GitHub this is the case. Are you finding that with GitLab, it is giving a path to a branch? If so, whatever we are using to convert GitLab PRs into our PR model, I think we are plugging the wrong datapoint into that property and should start there.

Copy link
Member Author

@sergeibbb sergeibbb Dec 26, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@axosoft-ramint

GitLab REST API does not provide necessary information about source and target repositories. So, I've fixed it by switching to GraphQL. (ffce252)

However I haven't found a good way to search MRs via GraphQL. So I've solved it with 2 requests. I still use REST to search and then I use PRs' IDs to retrieve the rest of the fields from GraphQL. (107da17)

cc @nzaytsev

Comment on lines +217 to +223
const prUrlIdentity: PullRequestUrlIdentity | undefined = await this.getPullRequestIdentityFromMaybeUrl(search);
const result: { readonly value: SearchedPullRequest[]; duration: number } = {
value: [],
duration: 0,
};

const connectedIntegrations = await this.getConnectedIntegrations();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we're already getting the connected integrations below, maybe we can just pass them into this.getPullRequestIdentityFromMaybeUrl

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed

): Promise<undefined | TimedResult<SearchedPullRequest[] | undefined>> => {
const prs = await withDurationAndSlowEventOnTimeout(
integration?.searchPullRequests(search, undefined, cancellation),
integration?.searchPullRequests(search, undefined, cancellation), //
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Empty comment line at the end

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed

Copy link
Contributor

@ramin-t ramin-t left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

On testing, the only issue I'm seeing is that owner/repo are not showing up on GitLab search results:

image

They do for GitLab PRs that are not search results.

Apart from that, some minor nitpicks that should be easy to change:

if (!connected) return undefined;

const pr = this.container.cache.getPullRequest(id, resource, this, () => ({
const pr = await this.container.cache.getPullRequest(id, resource, this, () => ({
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is unnecessary since we return the promise in the next line, similar to other cases. If anything, I would suggest instead that we just combine the two lines to return this.container.cache.get... and do the same in other places where this pattern occurs across the file.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@axosoft-ramint

I did it because I set a breakpoint at this place it was convenient to see a resolved promise.

cancellation?: CancellationToken,
): Promise<PullRequest[] | undefined>;

getPullRequestIdentityFromMaybeUrl?(search: string): PullRequestUrlIdentity | undefined;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's follow a similar pattern for generic and provider-specific function implementation and naming here as we do for other functions, in case we want to expand on the base logic later:

  1. Have a protected getProviderPullRequestIdentityFromMaybeUrl that can be implemented by specific providers (i.e. GitHub, GitLab, etc.)
  2. Have a getPullRequestIdentityFromMaybeUrl that, for now, just does return getProviderPullRequestIdentityFromMaybeUrl and later if we want, we can layer in caching there.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed

);
}

async getPullRequestIdentityFromMaybeUrl(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I suggest calling this one getPullRequestIdentityFromSearch to avoid making it seem as if line 607 is a recursive call to the same function.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed

@sergeibbb
Copy link
Member Author

@axosoft-ramint

I'm seeing is that owner/repo are not showing up on GitLab search results:

fixed

Copy link
Contributor

@ramin-t ramin-t left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wont have the chance to test this morning, but if all my prior comments are addressed, feel free to merge.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Launchpad: API search for PRs on GitLab

3 participants