// Use this body as both repository scripts for standalone builds.
// Add API_TOKEN and APP_SLUG secrets. Keep Git status reporting enabled.
const base =
"https://api.bitrise.io/v0.1/apps/" +
encodeURIComponent(context.secrets.APP_SLUG);
async function api(path, body) {
const response = await fetch(base + path, {
method: body === undefined ? "GET" : "POST",
headers: {
Authorization: context.secrets.API_TOKEN,
"Content-Type": "application/json",
},
...(body === undefined ? {} : { body: JSON.stringify(body) }),
});
if (!response.ok) throw new Error("Provider HTTP " + response.status);
return response.json();
}
const slugs = new Set();
let needsLookup = false;
for (const job of context.externalJobs) {
const match = (job.targetUrl || "").match(
/^https:\/\/(?:app\.)?bitrise\.io\/build\/([^/?#]+)/,
);
if (match) slugs.add(decodeURIComponent(match[1]));
else needsLookup = true;
}
if (needsLookup || !slugs.size) {
const listing = await api("/builds?limit=100");
const matches = listing.data.filter(
(build) =>
build.commit_hash === context.pipeline.sha &&
build.branch === context.pipeline.branch,
);
if (matches.length !== 1)
throw new Error(
"No unique provider build; check target URLs or extend the lookup",
);
slugs.add(matches[0].slug);
}
for (const slug of slugs) {
const original = (await api("/builds/" + encodeURIComponent(slug))).data;
const params = original.original_build_params || {};
if ((original.commit_hash || params.commit_hash) !== context.pipeline.sha)
throw new Error("Provider build does not match the original GitLab commit");
if (context.action === "cancel") {
await api("/builds/" + encodeURIComponent(slug) + "/abort", {
abort_reason: "Requested from repository pipeline controls",
abort_with_success: false,
skip_git_status_report: false,
});
} else {
const workflow = original.triggered_workflow || params.workflow_id;
if (!workflow) throw new Error("Original workflow is unavailable");
const mr = context.mergeRequest;
const buildParams = {
branch: original.branch || params.branch || context.pipeline.branch,
commit_hash: context.pipeline.sha,
workflow_id: workflow,
skip_git_status_report: false,
};
// Preserve the original fork/PR parameters without copying signing envs or overrides.
for (const key of [
"branch_dest",
"branch_repo_owner",
"branch_dest_repo_owner",
"pull_request_id",
"pull_request_author",
"pull_request_head_branch",
"pull_request_merge_branch",
"pull_request_repository_url",
"base_repository_url",
"head_repository_url",
]) {
if (params[key] != null) buildParams[key] = params[key];
}
if (original.pull_request_id > 0)
buildParams.pull_request_id =
params.pull_request_id ?? original.pull_request_id;
if (original.pull_request_target_branch)
buildParams.branch_dest =
params.branch_dest ?? original.pull_request_target_branch;
if (mr) {
const originalPullRequest =
params.pull_request_id ?? original.pull_request_id;
buildParams.pull_request_id =
Number(originalPullRequest) > 0 ? originalPullRequest : mr.iid;
buildParams.branch_dest =
params.branch_dest ??
original.pull_request_target_branch ??
mr.targetBranch;
buildParams.pull_request_head_branch =
params.pull_request_head_branch ?? mr.sourceBranch;
}
const result = await api("/builds", {
hook_info: { type: "bitrise" },
build_params: buildParams,
});
if (
!result.results?.length ||
result.results.some((item) => item.status && item.status !== "ok")
)
throw new Error("Provider did not accept the new build");
}
}
return { requested: slugs.size };