Skip to content

[server] add searchString to getRepositoriesForAutomatedPrebuilds – EXP-461 #18533

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Aug 17, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
77 changes: 51 additions & 26 deletions components/dashboard/src/projects/NewProject.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,16 @@
* See License.AGPL.txt in the project root for license information.
*/

import { AuthProviderInfo, Project, ProviderRepository, Team } from "@gitpod/gitpod-protocol";
import {
AuthProviderInfo,
Disposable,
DisposableCollection,
Project,
ProviderRepository,
Team,
} from "@gitpod/gitpod-protocol";
import dayjs from "dayjs";
import { useCallback, useContext, useEffect, useState } from "react";
import { useCallback, useContext, useEffect, useMemo, useState } from "react";
import { trackEvent } from "../Analytics";
import ContextMenu, { ContextMenuEntry } from "../components/ContextMenu";
import ErrorMessage from "../components/ErrorMessage";
Expand All @@ -25,6 +32,8 @@ import { projectsPathNew } from "./projects.routes";
import { Heading1, Subheading } from "../components/typography/headings";
import { useAuthProviders } from "../data/auth-providers/auth-provider-query";
import { AuthorizeGit, useNeedsGitAuthorization } from "../components/AuthorizeGit";
import { useToast } from "../components/toasts/Toasts";
import { CancellationTokenSource, CancellationToken } from "vscode-jsonrpc";

export default function NewProject() {
const currentTeam = useCurrentOrg()?.data;
Expand All @@ -45,12 +54,20 @@ export default function NewProject() {
const authProviders = useAuthProviders();
const [isGitHubAppEnabled, setIsGitHubAppEnabled] = useState<boolean>();
const [isGitHubWebhooksUnauthorized, setIsGitHubWebhooksUnauthorized] = useState<boolean>();
const { toast } = useToast();
const toDispose = useMemo(() => new DisposableCollection(), []);

useEffect(() => {
const { server } = getGitpodService();
Promise.all([server.isGitHubAppEnabled().then((v) => () => setIsGitHubAppEnabled(v))]).then((setters) =>
setters.forEach((s) => s()),
);
return () => {
if (!toDispose.disposed) {
toDispose.dispose();
}
};
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);

useEffect(() => {
Expand Down Expand Up @@ -116,15 +133,43 @@ export default function NewProject() {
setRepoSearchFilter("");
}, [selectedAccount]);

const updateReposInAccounts = useCallback(
async (cancellationToken: CancellationToken, installationId?: string) => {
setLoaded(false);
setReposInAccounts([]);
if (!selectedProviderHost) {
return [];
}
try {
const repos = await getGitpodService().server.getProviderRepositoriesForUser(
{
provider: selectedProviderHost,
hints: { installationId },
},
cancellationToken,
);
setReposInAccounts(repos);
setLoaded(true);
} catch (error) {
console.log(error);
setLoaded(true);
toast(error?.message || "Oh no, there was a problem with fetching repositories.");
}
},
[selectedProviderHost, toast],
);

useEffect(() => {
if (!selectedProviderHost) {
return;
}
const cancellation = new CancellationTokenSource();
toDispose.push(Disposable.create(() => cancellation.cancel()));
(async () => {
await updateReposInAccounts();
await updateReposInAccounts(cancellation.token);
})();
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [selectedProviderHost]);
return () => cancellation.cancel();
}, [selectedProviderHost, updateReposInAccounts, toDispose]);

useEffect(() => {
if (project) {
Expand All @@ -134,31 +179,11 @@ export default function NewProject() {

const isGitHub = () => selectedProviderHost === "github.com";

const updateReposInAccounts = async (installationId?: string) => {
setLoaded(false);
setReposInAccounts([]);
if (!selectedProviderHost) {
return [];
}
try {
const repos = await getGitpodService().server.getProviderRepositoriesForUser({
provider: selectedProviderHost,
hints: { installationId },
});
setReposInAccounts(repos);
setLoaded(true);
return repos;
} catch (error) {
console.log(error);
}
return [];
};

const reconfigure = () => {
openReconfigureWindow({
account: selectedAccount,
onSuccess: (p: { installationId: string; setupAction?: string }) => {
updateReposInAccounts(p.installationId);
updateReposInAccounts(CancellationToken.None, p.installationId);
trackEvent("organisation_authorised", {
installation_id: p.installationId,
setup_action: p.setupAction,
Expand Down
8 changes: 6 additions & 2 deletions components/gitpod-protocol/src/gitpod-service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ import {
OrganizationSettings,
} from "./teams-projects-protocol";
import { JsonRpcProxy, JsonRpcServer } from "./messaging/proxy-factory";
import { Disposable, CancellationTokenSource } from "vscode-jsonrpc";
import { Disposable, CancellationTokenSource, CancellationToken } from "vscode-jsonrpc";
import { HeadlessLogUrls } from "./headless-workspace-log";
import {
WorkspaceInstance,
Expand Down Expand Up @@ -175,7 +175,10 @@ export interface GitpodServer extends JsonRpcServer<GitpodClient>, AdminServer,
getOnboardingState(): Promise<GitpodServer.OnboardingState>;

// Projects
getProviderRepositoriesForUser(params: GetProviderRepositoriesParams): Promise<ProviderRepository[]>;
getProviderRepositoriesForUser(
params: GetProviderRepositoriesParams,
cancellationToken?: CancellationToken,
): Promise<ProviderRepository[]>;
createProject(params: CreateProjectParams): Promise<Project>;
deleteProject(projectId: string): Promise<void>;
getTeamProjects(teamId: string): Promise<Project[]>;
Expand Down Expand Up @@ -291,6 +294,7 @@ export interface FindPrebuildsParams {
export interface GetProviderRepositoriesParams {
provider: string;
hints?: { installationId: string } | object;
searchString?: string;
}
export interface ProviderRepository {
name: string;
Expand Down
129 changes: 119 additions & 10 deletions components/server/src/bitbucket-server/bitbucket-server-api.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ class TestBitbucketServerApi {
id: "MyBitbucketServer",
type: "BitbucketServer",
verified: true,
host: "bitbucket.gitpod-self-hosted.com",
host: "bitbucket.gitpod-dev.com",
oauth: {} as any,
};

Expand Down Expand Up @@ -77,12 +77,12 @@ class TestBitbucketServerApi {
};
}

@test async test_currentUsername_ok() {
@test.skip async test_currentUsername_ok() {
const result = await this.api.currentUsername(process.env["GITPOD_TEST_TOKEN_BITBUCKET_SERVER"]!);
expect(result).to.equal("AlexTugarev");
}

@test async test_getUserProfile_ok() {
@test.skip async test_getUserProfile_ok() {
const result = await this.api.getUserProfile(process.env["GITPOD_TEST_TOKEN_BITBUCKET_SERVER"]!, "AlexTugarev");
expect(result).to.deep.include({
id: 105, // Identity.authId
Expand All @@ -92,17 +92,126 @@ class TestBitbucketServerApi {
});
}

@test async test_getRepos_ok() {
@test async test_getRepos_no_searchString() {
const result = await this.api.getRepos(process.env["GITPOD_TEST_TOKEN_BITBUCKET_SERVER"]!, {
permission: "REPO_READ",
});
expect(result.length).to.be.equal(28);
expect(result.length).to.be.equal(9177);

// TestBitbucketServerApi
// BBS: GET https://7990-alextugarev-bbs-6v0gqcpgvj7.ws-eu102.gitpod.io/rest/api/1.0/repos?permission=REPO_READ&start=0 - OK
// BBS: GET https://7990-alextugarev-bbs-6v0gqcpgvj7.ws-eu102.gitpod.io/rest/api/1.0/repos?permission=REPO_READ&start=27 - OK
// βœ“ test_getRepos_ok (87ms)
// 1 passing (93ms)
// BBS: GET https://bitbucket.gitpod-dev.com/rest/api/1.0/repos?permission=REPO_READ&limit=1000&start=0&limit=1000 - OK
// BBS: GET https://bitbucket.gitpod-dev.com/rest/api/1.0/repos?permission=REPO_READ&limit=1000&start=1002&limit=1000 - OK
// BBS: GET https://bitbucket.gitpod-dev.com/rest/api/1.0/repos?permission=REPO_READ&limit=1000&start=2002&limit=1000 - OK
// BBS: GET https://bitbucket.gitpod-dev.com/rest/api/1.0/repos?permission=REPO_READ&limit=1000&start=3002&limit=1000 - OK
// BBS: GET https://bitbucket.gitpod-dev.com/rest/api/1.0/repos?permission=REPO_READ&limit=1000&start=4002&limit=1000 - OK
// BBS: GET https://bitbucket.gitpod-dev.com/rest/api/1.0/repos?permission=REPO_READ&limit=1000&start=5002&limit=1000 - OK
// BBS: GET https://bitbucket.gitpod-dev.com/rest/api/1.0/repos?permission=REPO_READ&limit=1000&start=6002&limit=1000 - OK
// BBS: GET https://bitbucket.gitpod-dev.com/rest/api/1.0/repos?permission=REPO_READ&limit=1000&start=7002&limit=1000 - OK
// BBS: GET https://bitbucket.gitpod-dev.com/rest/api/1.0/repos?permission=REPO_READ&limit=1000&start=8002&limit=1000 - OK
// BBS: GET https://bitbucket.gitpod-dev.com/rest/api/1.0/repos?permission=REPO_READ&limit=1000&start=9002&limit=1000 - OK
// βœ“ test_getRepos_no_searchString (3746ms)
}

@test async test_getRepos_cap_no_searchstring() {
const result = await this.api.getRepos(process.env["GITPOD_TEST_TOKEN_BITBUCKET_SERVER"]!, {
permission: "REPO_READ",
cap: 3,
});
expect(result.length).to.be.equal(3000);

// BBS: GET https://bitbucket.gitpod-dev.com/rest/api/1.0/repos?permission=REPO_READ&limit=1000&start=0&limit=1000 - OK
// BBS: GET https://bitbucket.gitpod-dev.com/rest/api/1.0/repos?permission=REPO_READ&limit=1000&start=1002&limit=1000 - OK
// BBS: GET https://bitbucket.gitpod-dev.com/rest/api/1.0/repos?permission=REPO_READ&limit=1000&start=2002&limit=1000 - OK
// βœ“ test_getRepos_cap_no_searchstring (1007ms)
}

@test async test_getRepos_searchString() {
const result = await this.api.getRepos(process.env["GITPOD_TEST_TOKEN_BITBUCKET_SERVER"]!, {
permission: "REPO_READ",
searchString: "zero",
});
expect(result.length).to.be.equal(1000);
expect(result[0].links.clone[0].href).to.equal("https://bitbucket.gitpod-dev.com/scm/tes/zero-minus-1.git");

// BBS: GET https://bitbucket.gitpod-dev.com/rest/api/1.0/repos?permission=REPO_READ&limit=1000&start=0&name=zero - OK
// BBS: GET https://bitbucket.gitpod-dev.com/rest/api/1.0/repos?permission=REPO_READ&limit=1000&start=0&projectname=zero - OK
// βœ“ test_getRepos_searchString (552ms)
}

@test async test_getRepos_searchString_2() {
const result = await this.api.getRepos(process.env["GITPOD_TEST_TOKEN_BITBUCKET_SERVER"]!, {
permission: "REPO_READ",
searchString: "zero-minus-1",
});
expect(result.length).to.be.equal(112);

// BBS: GET https://bitbucket.gitpod-dev.com/rest/api/1.0/repos?permission=REPO_READ&limit=1000&start=0&name=zero-minus-1 - OK
// BBS: GET https://bitbucket.gitpod-dev.com/rest/api/1.0/repos?permission=REPO_READ&limit=1000&start=0&projectname=zero-minus-1 - OK
// βœ“ test_getRepos_searchString_2 (172ms)
}

@test async test_getRepos_searchString_works_for_prefix_only() {
const result = await this.api.getRepos(process.env["GITPOD_TEST_TOKEN_BITBUCKET_SERVER"]!, {
permission: "REPO_READ",
searchString: "-minus-1",
});
expect(result.length).to.be.equal(0);

// BBS: GET https://bitbucket.gitpod-dev.com/rest/api/1.0/repos?permission=REPO_READ&limit=1000&start=0&name=zero-minus-1 - OK
// BBS: GET https://bitbucket.gitpod-dev.com/rest/api/1.0/repos?permission=REPO_READ&limit=1000&start=0&projectname=zero-minus-1 - OK
// βœ“ test_getRepos_searchString_works_for_prefix_only (172ms)
}

@test async test_getRepos_searchString_wildcards_are_not_supported() {
const result = await this.api.getRepos(process.env["GITPOD_TEST_TOKEN_BITBUCKET_SERVER"]!, {
permission: "REPO_READ",
searchString: "*-minus-1",
});
expect(result.length).to.be.equal(0);

// BBS: GET https://bitbucket.gitpod-dev.com/rest/api/1.0/repos?permission=REPO_READ&limit=1000&start=0&name=zero-minus-1 - OK
// BBS: GET https://bitbucket.gitpod-dev.com/rest/api/1.0/repos?permission=REPO_READ&limit=1000&start=0&projectname=zero-minus-1 - OK
// βœ“ test_getRepos_searchString_wildcards_are_not_supported (172ms)
}

@test async test_getRepos_searchString_single_char_is_ignored() {
const result = await this.api.getRepos(process.env["GITPOD_TEST_TOKEN_BITBUCKET_SERVER"]!, {
permission: "REPO_READ",
searchString: "t",
});
expect(result.length).to.be.equal(9177);

// BBS: GET https://bitbucket.gitpod-dev.com/rest/api/1.0/repos?permission=REPO_READ&limit=1000&start=0&name=t - OK
// BBS: GET https://bitbucket.gitpod-dev.com/rest/api/1.0/repos?permission=REPO_READ&limit=1000&start=1000&name=t - OK
// BBS: GET https://bitbucket.gitpod-dev.com/rest/api/1.0/repos?permission=REPO_READ&limit=1000&start=2000&name=t - OK
// BBS: GET https://bitbucket.gitpod-dev.com/rest/api/1.0/repos?permission=REPO_READ&limit=1000&start=3000&name=t - OK
// BBS: GET https://bitbucket.gitpod-dev.com/rest/api/1.0/repos?permission=REPO_READ&limit=1000&start=4000&name=t - OK
// BBS: GET https://bitbucket.gitpod-dev.com/rest/api/1.0/repos?permission=REPO_READ&limit=1000&start=5000&name=t - OK
// BBS: GET https://bitbucket.gitpod-dev.com/rest/api/1.0/repos?permission=REPO_READ&limit=1000&start=6000&name=t - OK
// BBS: GET https://bitbucket.gitpod-dev.com/rest/api/1.0/repos?permission=REPO_READ&limit=1000&start=7000&name=t - OK
// BBS: GET https://bitbucket.gitpod-dev.com/rest/api/1.0/repos?permission=REPO_READ&limit=1000&start=8000&name=t - OK
// BBS: GET https://bitbucket.gitpod-dev.com/rest/api/1.0/repos?permission=REPO_READ&limit=1000&start=0&projectname=t - OK
// BBS: GET https://bitbucket.gitpod-dev.com/rest/api/1.0/repos?permission=REPO_READ&limit=1000&start=1000&projectname=t - OK
// BBS: GET https://bitbucket.gitpod-dev.com/rest/api/1.0/repos?permission=REPO_READ&limit=1000&start=2000&projectname=t - OK
// BBS: GET https://bitbucket.gitpod-dev.com/rest/api/1.0/repos?permission=REPO_READ&limit=1000&start=3000&projectname=t - OK
// BBS: GET https://bitbucket.gitpod-dev.com/rest/api/1.0/repos?permission=REPO_READ&limit=1000&start=4000&projectname=t - OK
// BBS: GET https://bitbucket.gitpod-dev.com/rest/api/1.0/repos?permission=REPO_READ&limit=1000&start=5000&projectname=t - OK
// BBS: GET https://bitbucket.gitpod-dev.com/rest/api/1.0/repos?permission=REPO_READ&limit=1000&start=6000&projectname=t - OK
// BBS: GET https://bitbucket.gitpod-dev.com/rest/api/1.0/repos?permission=REPO_READ&limit=1000&start=7000&projectname=t - OK
// BBS: GET https://bitbucket.gitpod-dev.com/rest/api/1.0/repos?permission=REPO_READ&limit=1000&start=8000&projectname=t - OK
// BBS: GET https://bitbucket.gitpod-dev.com/rest/api/1.0/repos?permission=REPO_READ&limit=1000&start=9000&projectname=t - OK
// βœ“ test_getRepos_searchString_single_char_is_ignored (7329ms)
}

@test async test_getRepos_searchString_unmatched() {
const result = await this.api.getRepos(process.env["GITPOD_TEST_TOKEN_BITBUCKET_SERVER"]!, {
permission: "REPO_READ",
searchString: "RANDOM_asd8sdh7s8hsdhvisduh",
});
expect(result.length).to.be.equal(0);

// BBS: GET https://bitbucket.gitpod-dev.com/rest/api/1.0/repos?permission=REPO_READ&limit=1000&start=0&name=RANDOM_asd8sdh7s8hsdhvisduh - OK
// BBS: GET https://bitbucket.gitpod-dev.com/rest/api/1.0/repos?permission=REPO_READ&limit=1000&start=0&projectname=RANDOM_asd8sdh7s8hsdhvisduh - OK
// βœ“ test_getRepos_searchString_unmatched (126ms)
}
}

Expand Down
Loading