Skip to content
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

Pull Requests for Data #8235

Merged
merged 7 commits into from
Sep 30, 2024
Merged
Show file tree
Hide file tree
Changes from 4 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
15 changes: 4 additions & 11 deletions webui/src/lib/components/repository/tabs.jsx
Copy link
Contributor Author

Choose a reason for hiding this comment

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

This reveals PRfD to everyone.

Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,6 @@ import {Link, NavItem} from "../nav";
import {useRouter} from "../../hooks/router";
import {RefTypeBranch} from "../../../constants";

// TODO (gilo): this is temp, until PRfD will be ready
const showPulls = false;

export const RepositoryNavTabs = ({ active }) => {
const { reference } = useRefs();
const router = useRouter();
Expand Down Expand Up @@ -60,14 +57,10 @@ export const RepositoryNavTabs = ({ active }) => {
<Link active={active === 'tags'} href={`/repositories/${repoId}/tags`} component={NavItem}>
<TagIcon/> Tags
</Link>
{
// TODO (gilo): this is temp, until PRfD will be ready
showPulls &&
Comment on lines -63 to -65
Copy link
Contributor

Choose a reason for hiding this comment

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

😄

<Link active={active === 'pulls'} href={`/repositories/${repoId}/pulls`} component={NavItem}>
{/* TODO (gilo): the icon is very similar to the compare icon, consider changing it*/}
<GitPullRequestIcon/> Pull Requests
</Link>
}
<Link active={active === 'pulls'} href={`/repositories/${repoId}/pulls`} component={NavItem}>
{/* TODO (gilo): the icon is very similar to the compare icon, consider changing it*/}
<GitPullRequestIcon/> Pull Requests
</Link>
<Link active={active === 'compare'} href={withRefAndCompareContext(`/repositories/${repoId}/compare`)} component={NavItem}>
<GitCompareIcon/> Compare
</Link>
Expand Down
6 changes: 3 additions & 3 deletions webui/src/pages/repositories/repository/pulls/pullsList.jsx
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Added classes to make elements more discoverable.

Original file line number Diff line number Diff line change
Expand Up @@ -48,14 +48,14 @@ const PullWidget = ({repo, pull}) => {
<h6>
<PullIcon status={pull.status}/>
{" "}
<Link href={{
<Link className="pull-title" href={{
pathname: '/repositories/:repoId/pulls/:pullId',
params: {repoId: repo.id, pullId: pull.id}
}}>
{pull.title}
</Link>
</h6>
<small>{getDescription()}</small>
<small className="pull-description">{getDescription()}</small>
</div>
<div className="float-end mt-2">
<div className="btn btn-light btn-sm">{pull.destination_branch}</div>
Expand All @@ -81,7 +81,7 @@ const PullsList = ({repo, after, prefix, onPaginate}) => {
else content = (results && !!results.length ?
<>
<Card>
<ListGroup variant="flush">
<ListGroup variant="flush" className="pulls-list">
{results.map(pull => (
<PullWidget key={pull.id} repo={repo} pull={pull}/>
))}
Expand Down
215 changes: 130 additions & 85 deletions webui/test/e2e/common/quickstart.spec.ts
Copy link
Contributor Author

Choose a reason for hiding this comment

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

For non "pull requests" tests -
It's only about auto-formatting, plus removing some redundant awaits (as wisely suggested by IntelliJ).

Original file line number Diff line number Diff line change
Expand Up @@ -2,101 +2,146 @@ import { test, expect } from "@playwright/test";
import { RepositoriesPage } from "../poms/repositoriesPage";
import { RepositoryPage } from "../poms/repositoryPage";
import { ObjectViewerPage } from "../poms/objectViewerPage";
import { PullsPage } from "../poms/pullsPage";

const QUICKSTART_REPO_NAME = "quickstart";
const PARQUET_OBJECT_NAME = "lakes.parquet";
const NEW_BRANCH_NAME = "denmark-lakes";

const SELECT_QUERY =
"SELECT country, COUNT(*) FROM READ_PARQUET('lakefs://quickstart/main/lakes.parquet') GROUP BY country ORDER BY COUNT(*) DESC LIMIT 5;";
"SELECT country, COUNT(*) FROM READ_PARQUET('lakefs://quickstart/main/lakes.parquet') GROUP BY country ORDER BY COUNT(*) DESC LIMIT 5;";
const CREATE_TABLE_QUERY =
"CREATE OR REPLACE TABLE lakes AS SELECT * FROM READ_PARQUET('lakefs://quickstart/denmark-lakes/lakes.parquet');";
"CREATE OR REPLACE TABLE lakes AS SELECT * FROM READ_PARQUET('lakefs://quickstart/denmark-lakes/lakes.parquet');";
const DELETE_QUERY = "DELETE FROM lakes WHERE Country != 'Denmark';";
const COPY_QUERY =
"COPY lakes TO 'lakefs://quickstart/denmark-lakes/lakes.parquet';";
"COPY lakes TO 'lakefs://quickstart/denmark-lakes/lakes.parquet';";
const SELECT_NEW_BRANCH =
"DROP TABLE lakes; SELECT country, COUNT(*) FROM READ_PARQUET('lakefs://quickstart/denmark-lakes/lakes.parquet') GROUP BY country ORDER BY COUNT(*) DESC LIMIT 5;";
"DROP TABLE lakes; SELECT country, COUNT(*) FROM READ_PARQUET('lakefs://quickstart/denmark-lakes/lakes.parquet') GROUP BY country ORDER BY COUNT(*) DESC LIMIT 5;";

test.describe("Quickstart", () => {
test.describe.configure({ mode: "serial" });
test("create repo w/ sample data", async ({ page }) => {
const repositoriesPage = new RepositoriesPage(page);
await repositoriesPage.goto();
await repositoriesPage.createRepository(QUICKSTART_REPO_NAME, true);
});

test("view and query parquet object", async ({ page }) => {
const repositoriesPage = new RepositoriesPage(page);
await repositoriesPage.goto();
await repositoriesPage.goToRepository(QUICKSTART_REPO_NAME);

const repositoryPage = new RepositoryPage(page);
await repositoryPage.clickObject(PARQUET_OBJECT_NAME);
await expect(page.getByText("Loading...")).not.toBeVisible();

const objectViewerPage = new ObjectViewerPage(page);
await objectViewerPage.enterQuery(SELECT_QUERY);
await objectViewerPage.clickExecuteButton();
await expect(await objectViewerPage.getResultRowCount()).toEqual(5);
});

test("transforming data", async ({ page }) => {
const repositoriesPage = new RepositoriesPage(page);
await repositoriesPage.goto();
await repositoriesPage.goToRepository(QUICKSTART_REPO_NAME);

const repositoryPage = new RepositoryPage(page);
await repositoryPage.createBranch(NEW_BRANCH_NAME);

await repositoryPage.gotoObjectsTab();
await repositoryPage.clickObject(PARQUET_OBJECT_NAME);
await expect(page.getByText("Loading...")).not.toBeVisible();

const objectViewerPage = new ObjectViewerPage(page);
await objectViewerPage.enterQuery(CREATE_TABLE_QUERY);
await objectViewerPage.clickExecuteButton();

await objectViewerPage.enterQuery(DELETE_QUERY);
await objectViewerPage.clickExecuteButton();

await objectViewerPage.enterQuery(COPY_QUERY);
await objectViewerPage.clickExecuteButton();

await objectViewerPage.enterQuery(SELECT_NEW_BRANCH);
await objectViewerPage.clickExecuteButton();
await expect(await objectViewerPage.getResultRowCount()).toEqual(1);
});

test("commit and merge", async ({ page }) => {
const repositoriesPage = new RepositoriesPage(page);
await repositoriesPage.goto();
await repositoriesPage.goToRepository(QUICKSTART_REPO_NAME);

const repositoryPage = new RepositoryPage(page);
await repositoryPage.gotoUncommittedChangeTab();
await repositoryPage.switchBranch(NEW_BRANCH_NAME);
await expect(
await page.getByText("Showing changes for branch")
).toBeVisible();
await expect(await repositoryPage.getUncommittedCount()).toEqual(1);

await repositoryPage.commitChanges("denmark");
await expect(page.getByText("No changes")).toBeVisible();

await repositoryPage.gotoCompareTab();
await repositoryPage.switchBaseBranch("main");
await expect(await page.getByText("Showing changes between")).toBeVisible();
await expect(await repositoryPage.getUncommittedCount()).toEqual(1);
await repositoryPage.merge("merge commit");
await expect(page.getByText("No changes")).toBeVisible();

await repositoriesPage.goto();
await repositoriesPage.goToRepository(QUICKSTART_REPO_NAME);
await repositoryPage.clickObject(PARQUET_OBJECT_NAME);
await expect(page.getByText("Loading...")).not.toBeVisible();
const objectViewerPage = new ObjectViewerPage(page);
await objectViewerPage.enterQuery(SELECT_QUERY);
await objectViewerPage.clickExecuteButton();
await expect(await objectViewerPage.getResultRowCount()).toEqual(1);
});
test.describe.configure({mode: "serial"});
test("create repo w/ sample data", async ({page}) => {
const repositoriesPage = new RepositoriesPage(page);
await repositoriesPage.goto();
await repositoriesPage.createRepository(QUICKSTART_REPO_NAME, true);
});

test("view and query parquet object", async ({page}) => {
const repositoriesPage = new RepositoriesPage(page);
await repositoriesPage.goto();
await repositoriesPage.goToRepository(QUICKSTART_REPO_NAME);

const repositoryPage = new RepositoryPage(page);
await repositoryPage.clickObject(PARQUET_OBJECT_NAME);
await expect(page.getByText("Loading...")).not.toBeVisible();

const objectViewerPage = new ObjectViewerPage(page);
await objectViewerPage.enterQuery(SELECT_QUERY);
await objectViewerPage.clickExecuteButton();
expect(await objectViewerPage.getResultRowCount()).toEqual(5);
});

test("transforming data", async ({page}) => {
const repositoriesPage = new RepositoriesPage(page);
await repositoriesPage.goto();
await repositoriesPage.goToRepository(QUICKSTART_REPO_NAME);

const repositoryPage = new RepositoryPage(page);
await repositoryPage.createBranch(NEW_BRANCH_NAME);

await repositoryPage.gotoObjectsTab();
await repositoryPage.clickObject(PARQUET_OBJECT_NAME);
await expect(page.getByText("Loading...")).not.toBeVisible();

const objectViewerPage = new ObjectViewerPage(page);
await objectViewerPage.enterQuery(CREATE_TABLE_QUERY);
await objectViewerPage.clickExecuteButton();

await objectViewerPage.enterQuery(DELETE_QUERY);
await objectViewerPage.clickExecuteButton();

await objectViewerPage.enterQuery(COPY_QUERY);
await objectViewerPage.clickExecuteButton();

await objectViewerPage.enterQuery(SELECT_NEW_BRANCH);
await objectViewerPage.clickExecuteButton();
expect(await objectViewerPage.getResultRowCount()).toEqual(1);
});

test("commit and merge", async ({page}) => {
const repositoriesPage = new RepositoriesPage(page);
await repositoriesPage.goto();
await repositoriesPage.goToRepository(QUICKSTART_REPO_NAME);

const repositoryPage = new RepositoryPage(page);
await repositoryPage.gotoUncommittedChangeTab();
await repositoryPage.switchBranch(NEW_BRANCH_NAME);
await expect(page.getByText("Showing changes for branch")).toBeVisible();
expect(await repositoryPage.getUncommittedCount()).toEqual(1);

await repositoryPage.commitChanges("denmark");
await expect(page.getByText("No changes")).toBeVisible();

await repositoryPage.gotoCompareTab();
await repositoryPage.switchBaseBranch("main");
await expect(page.getByText("Showing changes between")).toBeVisible();
expect(await repositoryPage.getUncommittedCount()).toEqual(1);
await repositoryPage.merge("merge commit");
await expect(page.getByText("No changes")).toBeVisible();

await repositoriesPage.goto();
await repositoriesPage.goToRepository(QUICKSTART_REPO_NAME);
await repositoryPage.clickObject(PARQUET_OBJECT_NAME);
await expect(page.getByText("Loading...")).not.toBeVisible();
const objectViewerPage = new ObjectViewerPage(page);
await objectViewerPage.enterQuery(SELECT_QUERY);
await objectViewerPage.clickExecuteButton();
expect(await objectViewerPage.getResultRowCount()).toEqual(1);
});

test("pull requests", async ({page}) => {
const repositoriesPage = new RepositoriesPage(page);
await repositoriesPage.goto();
await repositoriesPage.goToRepository(QUICKSTART_REPO_NAME);

const branchNameForPull = "branch-for-pull-1";

const repositoryPage = new RepositoryPage(page);
await repositoryPage.createBranch(branchNameForPull);

// delete a file in the branch
await repositoryPage.gotoObjectsTab();
await repositoryPage.switchBranch(branchNameForPull);
await repositoryPage.deleteFirstFileInDirectory("images/");

// commit the change
await repositoryPage.gotoUncommittedChangeTab();
expect(await repositoryPage.getUncommittedCount()).toEqual(1);
await repositoryPage.commitChanges("Commit for pull-1");
await expect(page.getByText("No changes")).toBeVisible();

// pulls list sanity
await repositoryPage.gotoPullRequestsTab();
await expect(page.getByText("Create Pull Request")).toBeVisible();
const pullsPage = new PullsPage(page);
expect(await pullsPage.getPullsListCount()).toEqual(0);

// create a pull request
await pullsPage.clickCreatePullButton();
await expect(page.getByRole("heading", {name: "Create Pull Request"})).toBeVisible();
await pullsPage.switchCompareBranch(branchNameForPull);
const pullDetails = {title: "PR for branch 1", description: "A description for PR 1"};
await pullsPage.fillPullTitle(pullDetails.title);
await pullsPage.fillPullDescription(pullDetails.description);
await pullsPage.clickCreatePullButton();
expect(await pullsPage.getBranchesCompareURI()).toEqual(`main...${branchNameForPull}/`);

// merge the pull request
await pullsPage.clickMergePullButton();
await repositoryPage.gotoPullRequestsTab();
await pullsPage.gotoPullsTab("closed");
const firstPullRowDetails = await pullsPage.getFirstPullsRowDetails();
expect(firstPullRowDetails.title).toEqual(pullDetails.title);
expect(firstPullRowDetails.description).toMatch(/^Merged/)
});
});
53 changes: 53 additions & 0 deletions webui/test/e2e/poms/pullsPage.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import { Locator, Page } from "@playwright/test";

export class PullsPage {
private page: Page;

constructor(page: Page) {
this.page = page;
}

async getPullsListCount(): Promise<number> {
await this.page.locator("div.pulls-list").isVisible();
return this.page
.locator("div.pulls-list")
.locator("pull-row")
.count();
}

async switchCompareBranch(name: string): Promise<void> {
await this.page.getByRole("button", {name: "to branch: "}).click();
await this.page.getByRole("button", {name}).click();
}

async clickCreatePullButton(): Promise<void> {
await this.page.getByRole("button", {name: "Create Pull Request"}).click();
}

async getBranchesCompareURI(): Promise<string> {
return await this.page.locator("div.lakefs-uri").innerText();
}

async clickMergePullButton(): Promise<void> {
await this.page.getByRole("button", {name: "Merge pull request"}).click();
}

async fillPullTitle(title: string): Promise<void> {
await this.page.getByPlaceholder("Add a title...").fill(title);
}

async fillPullDescription(description: string): Promise<void> {
await this.page.getByPlaceholder("Describe your changes...").fill(description);
}

async gotoPullsTab(id: string): Promise<void> {
await this.page.locator(`#pulls-tabs-tab-${id}`).click();
}

async getFirstPullsRowDetails(): Promise<{title: string, description: string}> {
const firstPullRow = this.page.locator("div.pull-row").first();
const title = await firstPullRow.locator(".pull-title").innerText();
const description = await firstPullRow.locator(".pull-description").innerText();
return {title, description};
}
}
Loading
Loading