Skip to content
Open
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 @@ -552,6 +552,54 @@ describe("GitHubSourceControlProvider writes", () => {
}).pipe(Effect.provide(Layer.merge(layer, NodeServices.layer)), Effect.scoped);
});

it.effect.each([
{ host: "github.com", status: 422, field: "base", rejectedBase: true },
{ host: "code.example.test", status: 422, field: "base", rejectedBase: true },
{ host: "github.com", status: 422, field: "head", rejectedBase: false },
{ host: "github.com", status: 500, field: "base", rejectedBase: false },
])(
"explains a rejected PR base without replacing other API failures: $host $status $field",
({ host, status, field, rejectedBase }) => {
const cause = new GitHubRequestPolicy.GitHubApiResponseError({
host,
operation: "createPullRequest",
status,
githubErrors: ["Validation Failed", `${field} invalid`],
});
const { layer } = harness({
remotes: remotesOutput(
["origin", `git@${host}:me/web.git`],
["upstream", `git@${host}:acme/web.git`],
),
api: { rest: () => Effect.fail(cause) },
});
return Effect.gen(function* () {
const fs = yield* FileSystem.FileSystem;
const bodyFile = yield* fs.makeTempFileScoped({ suffix: ".md" });
yield* fs.writeFileString(bodyFile, "Body");
const gh = yield* GitHubSourceControlProvider.make;
const error = yield* gh
.createChangeRequest({
cwd: "/repo",
context: githubContext(host),
baseRefName: "stack/parent",
headSelector: "me:child",
title: "Title",
bodyFile,
})
.pipe(Effect.flip);
assert.strictEqual(error.operation, "createChangeRequest");
assert.strictEqual(error.cause, cause);
assert.strictEqual(
error.detail,
rejectedBase
? `GitHub rejected base branch "stack/parent" for ${host}/acme/web. Push the intended base branch to that repository, or choose an existing base branch and retry.`
: cause.message,
);
}).pipe(Effect.provide(layer), Effect.scoped);
},
);

it.effect("creates a repository under an organization the viewer is not", () => {
const requests: Array<string> = [];
const { layer } = harness({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -985,21 +985,40 @@ export const make = Effect.gen(function* () {
failure("The pull request description could not be read.", cause),
),
);
yield* rest({
host: locator.host,
operation: "createPullRequest",
method: "POST",
allowReserve: true,
path: `repos/${encodeURIComponent(locator.owner)}/${encodeURIComponent(locator.name)}/pulls`,
// Explicitly allow maintainer edits to match gh; the API default is undocumented.
body: {
base: input.baseRefName,
head: input.headSelector,
title: input.title,
body,
maintainer_can_modify: true,
},
});
yield* api
.rest({
host: locator.host,
operation: "createPullRequest",
method: "POST",
allowReserve: true,
path: `repos/${encodeURIComponent(locator.owner)}/${encodeURIComponent(locator.name)}/pulls`,
// Explicitly allow maintainer edits to match gh; the API default is undocumented.
body: {
base: input.baseRefName,
head: input.headSelector,
title: input.title,
body,
maintainer_can_modify: true,
},
})
.pipe(
Effect.mapError((error) => {
if (
error._tag === "GitHubApiResponseError" &&
error.status === 422 &&
error.githubErrors?.includes("base invalid")
) {
const base = SourceControlProvider.transportSafeSourceControlErrorValue(
input.baseRefName,
);
return failure(
`GitHub rejected base branch ${JSON.stringify(base)} for ${locator.host}/${locator.owner}/${locator.name}. Push the intended base branch to that repository, or choose an existing base branch and retry.`,
error,
);
}
return fromGitHubApiError(error);
}),
);
},
(effect, input) =>
effect.pipe(
Expand Down
Loading