Skip to content
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
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,59 @@ import {
make,
} from "./BitbucketPullRequestProvider.ts";

it.effect.each([
{
metadata: "source commit hash",
commit: { hash: "9f3a7c2d8b1e6f045a9c3d7e2b8f1a6c0d4e5f93" },
headSha: "9f3a7c2d8b1e6f045a9c3d7e2b8f1a6c0d4e5f93",
},
{ metadata: "absent commit", commit: undefined, headSha: undefined },
{ metadata: "null commit", commit: null, headSha: undefined },
{ metadata: "absent hash", commit: {}, headSha: undefined },
{ metadata: "null hash", commit: { hash: null }, headSha: undefined },
])("reads change request details with $metadata", ({ commit, headSha }) =>
Effect.gen(function* () {
const pullRequest = Result.getOrThrow(
decodePullRequestJson(
JSON.stringify({
id: 897,
title: "Add trustabl-pipe",
state: "OPEN",
source: {
branch: { name: "feat/page" },
commit,
repository: { full_name: "fork/web" },
},
destination: { branch: { name: "master" }, commit: { hash: "base-commit" } },
created_on: "2026-06-16T05:04:32.258456+00:00",
updated_on: "2026-06-16T05:04:33.750542+00:00",
links: { html: { href: "https://bitbucket.org/acme/web/pull-requests/897" } },
}),
),
);
const provider = yield* make.pipe(
Effect.provide(
Layer.mock(BitbucketPullRequestApi.BitbucketPullRequestApi)({
getPullRequest: () => Effect.succeed(pullRequest),
getDiffStat: () => Effect.succeed({ additions: 0, deletions: 0, changedFiles: 0 }),
getMergeability: () => Effect.succeed("unknown"),
listChecks: () => Effect.succeed([]),
getRepositoryPermission: () => Effect.succeed(true),
}),
),
);
const detail = yield* provider.getChangeRequest({
cwd: "/repo",
repository: "acme/web",
host: "bitbucket.org",
number: 897,
});

expect(detail).toMatchObject({ number: 897, headBranch: "feat/page" });
expect(detail.headSha).toBe(headSha);
}),
);

for (const operation of [
"getMergeability",
"listChecks",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ function toChangeRequest(pullRequest: BitbucketPullRequest): ProviderChangeReque
url: pullRequest.url,
author: pullRequest.author,
headBranch: pullRequest.headBranch,
...(pullRequest.headSha ? { headSha: pullRequest.headSha } : {}),
...(pullRequest.headRepositoryNameWithOwner
? { headRepositoryNameWithOwner: pullRequest.headRepositoryNameWithOwner }
: {}),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,12 @@ function pullRequest(overrides: Record<string, unknown> = {}): Record<string, un
created_on: "2026-06-16T05:04:32.258456+00:00",
updated_on: "2026-06-16T05:04:33.750542+00:00",
author: { display_name: "Bilal Hassan", nickname: "bilal", type: "user" },
source: { branch: { name: "feat/page" }, repository: { full_name: "fork/web" } },
destination: { branch: { name: "master" } },
source: {
branch: { name: "feat/page" },
commit: { hash: "9f3a7c2d8b1e6f045a9c3d7e2b8f1a6c0d4e5f93", type: "commit" },
repository: { full_name: "fork/web" },
},
destination: { branch: { name: "master" }, commit: { hash: "base-commit" } },
links: { html: { href: "https://bitbucket.org/acme/web/pull-requests/897" } },
...overrides,
};
Expand All @@ -52,6 +56,7 @@ describe("decodePullRequestPageJson", () => {
url: "https://bitbucket.org/acme/web/pull-requests/897",
author: { login: "bilal", name: "Bilal Hassan" },
headBranch: "feat/page",
headSha: "9f3a7c2d8b1e6f045a9c3d7e2b8f1a6c0d4e5f93",
headRepositoryNameWithOwner: "fork/web",
baseBranch: "master",
state: "open",
Expand Down Expand Up @@ -106,6 +111,27 @@ describe("decodePullRequestPageJson", () => {
});

describe("decodePullRequestJson", () => {
it("preserves the source commit hash as the head SHA", () => {
const decoded = expectSuccess(decodePullRequestJson(JSON.stringify(pullRequest())));

expect(decoded).toMatchObject({ headSha: "9f3a7c2d8b1e6f045a9c3d7e2b8f1a6c0d4e5f93" });
});

it.each([
{ metadata: "absent commit", commit: undefined },
{ metadata: "null commit", commit: null },
{ metadata: "absent hash", commit: {} },
{ metadata: "null hash", commit: { hash: null } },
])("reads detail and list payloads with $metadata", ({ commit }) => {
const raw = pullRequest({ source: { branch: { name: "feat/page" }, commit } });
const detail = expectSuccess(decodePullRequestJson(JSON.stringify(raw)));
const list = expectSuccess(decodePullRequestPageJson(page([raw])));

expect(detail).toMatchObject({ number: 897, headBranch: "feat/page", headSha: null });
expect(list.items).toHaveLength(1);
expect(list.items[0]).toMatchObject({ number: 897, headBranch: "feat/page", headSha: null });
});

it("reads reviewers as review requests", () => {
const decoded = expectSuccess(
decodePullRequestJson(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,9 @@ const RawUserSchema = Schema.Struct({
*/
const RawBranchSchema = Schema.Struct({
branch: Schema.Struct({ name: TrimmedNonEmptyString }),
commit: Schema.optional(
Schema.NullOr(Schema.Struct({ hash: Schema.optional(Schema.NullOr(Schema.String)) })),
),
repository: Schema.optional(Schema.NullOr(Schema.Struct({ full_name: TrimmedNonEmptyString }))),
});

Expand Down Expand Up @@ -178,6 +181,7 @@ export interface BitbucketPullRequest {
readonly url: string;
readonly author: PullRequestActor | null;
readonly headBranch: string;
readonly headSha: string | null;
readonly headRepositoryNameWithOwner: string | null;
readonly baseBranch: string;
readonly state: PullRequestState;
Expand Down Expand Up @@ -293,6 +297,7 @@ function toPullRequest(raw: Schema.Schema.Type<typeof RawPullRequestSchema>): Bi
url: raw.links.html.href,
author: toActor(raw.author),
headBranch: raw.source.branch.name,
headSha: trimmed(raw.source.commit?.hash),
headRepositoryNameWithOwner: raw.source.repository?.full_name ?? null,
baseBranch: raw.destination.branch.name,
state: toState(raw),
Expand Down
Loading