Skip to content

Commit 433fa98

Browse files
[wrangler] Add pull request title to preview deployment annotations (#15307)
Co-authored-by: Dario Piotrowicz <dario@cloudflare.com>
1 parent ad89456 commit 433fa98

6 files changed

Lines changed: 120 additions & 17 deletions

File tree

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
---
2+
"@cloudflare/deploy-helpers": minor
3+
"wrangler": minor
4+
---
5+
6+
Add pull request title to `wrangler preview` deployment annotations
7+
8+
`wrangler preview` now also detects the title of the pull/merge request associated with the current CI run (GitHub Actions and GitLab CI, plus a generic `PULL_REQUEST_TITLE` fallback) and attaches it to the preview deployment as the `workers/pull_request_title` annotation, alongside the existing pull request number/URL, repository URL, and commit SHA annotations.
9+
10+
This is best effort: if no pull request title can be detected, nothing changes.

packages/deploy-helpers/src/preview/api.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@ export interface DeploymentResource {
8383
"workers/commit_sha"?: string;
8484
"workers/message"?: string;
8585
"workers/pull_request_number"?: string;
86+
"workers/pull_request_title"?: string;
8687
"workers/pull_request_url"?: string;
8788
"workers/repository_url"?: string;
8889
"workers/tag"?: string;
@@ -112,6 +113,7 @@ export type CreatePreviewDeploymentRequestParams = {
112113
"workers/commit_sha"?: string;
113114
"workers/message"?: string;
114115
"workers/pull_request_number"?: string;
116+
"workers/pull_request_title"?: string;
115117
"workers/pull_request_url"?: string;
116118
"workers/repository_url"?: string;
117119
"workers/tag"?: string;

packages/deploy-helpers/src/preview/preview.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -466,6 +466,9 @@ async function assemblePreviewDeploymentSettings(
466466
...(pullRequest?.number && {
467467
"workers/pull_request_number": pullRequest.number,
468468
}),
469+
...(pullRequest?.title && {
470+
"workers/pull_request_title": pullRequest.title,
471+
}),
469472
...(pullRequest?.url && { "workers/pull_request_url": pullRequest.url }),
470473
...(repositoryUrl && { "workers/repository_url": repositoryUrl }),
471474
...(options.tag && { "workers/tag": options.tag }),

packages/deploy-helpers/src/preview/shared.ts

Lines changed: 42 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -174,13 +174,14 @@ export function getRepositoryUrl(): string | undefined {
174174
}
175175

176176
/**
177-
* The pull/merge request number and URL detected from the current CI
178-
* environment. Either field may be missing depending on what the detected
179-
* CI provider exposes.
177+
* The pull/merge request number, URL, and title detected from the current CI
178+
* environment. Any field may be missing depending on what the detected CI
179+
* provider exposes.
180180
*/
181181
export type PullRequestMetadata = {
182182
number?: string;
183183
url?: string;
184+
title?: string;
184185
};
185186

186187
/**
@@ -197,30 +198,51 @@ function normalizePullRequestNumber(number: string | number | undefined) {
197198
return normalizedNumber ? normalizedNumber : undefined;
198199
}
199200

201+
/**
202+
* Trims a pull/merge request title, treating a blank value the same as a
203+
* missing one.
204+
*/
205+
function normalizePullRequestTitle(
206+
title: string | undefined
207+
): string | undefined {
208+
if (title === undefined) {
209+
return undefined;
210+
}
211+
212+
const trimmedTitle = title.trim();
213+
return trimmedTitle || undefined;
214+
}
215+
200216
/**
201217
* Detects pull request metadata from a GitHub Actions environment.
202218
*
203219
* Prefers the `pull_request` event payload at `GITHUB_EVENT_PATH` (available
204220
* for `pull_request`/`pull_request_target`-triggered workflows), which
205-
* directly provides the PR number and URL. Falls back to parsing the PR
206-
* number out of `GITHUB_REF` (formatted `refs/pull/<number>/merge`) and
221+
* directly provides the PR number, URL, and title. Falls back to parsing the
222+
* PR number out of `GITHUB_REF` (formatted `refs/pull/<number>/merge`) and
207223
* building the URL from `GITHUB_REPOSITORY`/`GITHUB_SERVER_URL`, which covers
208-
* other trigger types where a `pull_request` payload isn't available.
224+
* other trigger types where a `pull_request` payload isn't available — this
225+
* fallback path can't recover a title, since that isn't encoded in the ref.
209226
*/
210227
function getGitHubPullRequestMetadata(): PullRequestMetadata | undefined {
211228
if (process.env.GITHUB_EVENT_PATH) {
212229
try {
213230
const event = JSON.parse(
214231
readFileSync(process.env.GITHUB_EVENT_PATH, "utf8")
215232
) as {
216-
pull_request?: { html_url?: string; number?: number };
233+
pull_request?: {
234+
html_url?: string;
235+
number?: number;
236+
title?: string;
237+
};
217238
};
218239
const number = normalizePullRequestNumber(event.pull_request?.number);
219240
const url = event.pull_request?.html_url
220241
? normalizeRepositoryUrl(event.pull_request.html_url)
221242
: undefined;
222-
if (number || url) {
223-
return { number, url };
243+
const title = normalizePullRequestTitle(event.pull_request?.title);
244+
if (number || url || title) {
245+
return { number, url, title };
224246
}
225247
} catch {
226248
// Fall back to environment-derived metadata below.
@@ -245,9 +267,9 @@ function getGitHubPullRequestMetadata(): PullRequestMetadata | undefined {
245267

246268
/**
247269
* Detects merge request metadata from a GitLab CI merge request pipeline,
248-
* using `CI_MERGE_REQUEST_IID` for the number and
270+
* using `CI_MERGE_REQUEST_IID` for the number,
249271
* `CI_MERGE_REQUEST_PROJECT_URL` (or `CI_PROJECT_URL` as a fallback) to build
250-
* the merge request URL.
272+
* the merge request URL, and `CI_MERGE_REQUEST_TITLE` for the title.
251273
*/
252274
function getGitLabPullRequestMetadata(): PullRequestMetadata | undefined {
253275
const number = normalizePullRequestNumber(process.env.CI_MERGE_REQUEST_IID);
@@ -265,16 +287,18 @@ function getGitLabPullRequestMetadata(): PullRequestMetadata | undefined {
265287
url: normalizeRepositoryUrl(
266288
`${normalizedProjectUrl}/-/merge_requests/${number}`
267289
),
290+
title: normalizePullRequestTitle(process.env.CI_MERGE_REQUEST_TITLE),
268291
};
269292
}
270293

271294
/**
272295
* Detects pull request metadata from generic, provider-agnostic env vars
273296
* (`PULL_REQUEST_URL`/`PR_URL`/`CHANGE_URL`/`CIRCLE_PULL_REQUEST` for the URL,
274-
* `PULL_REQUEST_NUMBER`/`PR_NUMBER`/`CHANGE_ID` for the number). These are
275-
* conventions used by some CI providers and custom pipelines, but aren't
276-
* officially documented, so this is a lower-confidence, best-effort fallback
277-
* checked before the provider-specific detectors.
297+
* `PULL_REQUEST_NUMBER`/`PR_NUMBER`/`CHANGE_ID` for the number,
298+
* `PULL_REQUEST_TITLE` for the title). These are conventions used by some CI
299+
* providers and custom pipelines, but aren't officially documented, so this
300+
* is a lower-confidence, best-effort fallback checked before the
301+
* provider-specific detectors.
278302
*/
279303
function getDirectPullRequestMetadata(): PullRequestMetadata | undefined {
280304
const directUrl =
@@ -288,9 +312,10 @@ function getDirectPullRequestMetadata(): PullRequestMetadata | undefined {
288312
process.env.CHANGE_ID
289313
);
290314
const url = directUrl ? normalizeRepositoryUrl(directUrl) : undefined;
315+
const title = normalizePullRequestTitle(process.env.PULL_REQUEST_TITLE);
291316

292-
if (number || url) {
293-
return { number, url };
317+
if (number || url || title) {
318+
return { number, url, title };
294319
}
295320

296321
return undefined;

packages/wrangler/src/__tests__/preview.test.ts

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,8 @@ function clearPreviewMetadataEnvs() {
169169
vi.stubEnv("CI_COMMIT_SHA", "");
170170
vi.stubEnv("CIRCLE_SHA1", "");
171171
vi.stubEnv("COMMIT_SHA", "");
172+
vi.stubEnv("CI_MERGE_REQUEST_TITLE", "");
173+
vi.stubEnv("PULL_REQUEST_TITLE", "");
172174
}
173175

174176
describe("wrangler preview", () => {
@@ -388,10 +390,12 @@ describe("wrangler preview", () => {
388390
"https://git.example.com/acme/worker-project/pulls/13"
389391
);
390392
vi.stubEnv("PULL_REQUEST_NUMBER", "13");
393+
vi.stubEnv("PULL_REQUEST_TITLE", "Add a cool new feature");
391394

392395
expect(getPullRequestMetadata()).toEqual({
393396
number: "13",
394397
url: "https://git.example.com/acme/worker-project/pulls/13",
398+
title: "Add a cool new feature",
395399
});
396400
});
397401

@@ -402,11 +406,45 @@ describe("wrangler preview", () => {
402406
pull_request: {
403407
number: 13,
404408
html_url: "https://github.com/acme/worker-project/pull/13",
409+
title: "Add a cool new feature",
405410
},
406411
})
407412
);
408413
vi.stubEnv("GITHUB_EVENT_PATH", "github-event.json");
409414

415+
expect(getPullRequestMetadata()).toEqual({
416+
number: "13",
417+
url: "https://github.com/acme/worker-project/pull/13",
418+
title: "Add a cool new feature",
419+
});
420+
});
421+
422+
test("should not fail when the GitHub event pull request has no title", ({
423+
expect,
424+
}) => {
425+
writeFileSync(
426+
"github-event.json",
427+
JSON.stringify({
428+
pull_request: {
429+
number: 13,
430+
html_url: "https://github.com/acme/worker-project/pull/13",
431+
},
432+
})
433+
);
434+
vi.stubEnv("GITHUB_EVENT_PATH", "github-event.json");
435+
436+
expect(getPullRequestMetadata()).toEqual({
437+
number: "13",
438+
url: "https://github.com/acme/worker-project/pull/13",
439+
});
440+
});
441+
442+
test("should not recover a title from the GITHUB_REF fallback", ({
443+
expect,
444+
}) => {
445+
vi.stubEnv("GITHUB_REF", "refs/pull/13/merge");
446+
vi.stubEnv("GITHUB_REPOSITORY", "acme/worker-project");
447+
410448
expect(getPullRequestMetadata()).toEqual({
411449
number: "13",
412450
url: "https://github.com/acme/worker-project/pull/13",
@@ -419,6 +457,24 @@ describe("wrangler preview", () => {
419457
"https://gitlab.example.com/acme/worker-project"
420458
);
421459
vi.stubEnv("CI_MERGE_REQUEST_IID", "13");
460+
vi.stubEnv("CI_MERGE_REQUEST_TITLE", "Add a cool new feature");
461+
462+
expect(getPullRequestMetadata()).toEqual({
463+
number: "13",
464+
url: "https://gitlab.example.com/acme/worker-project/-/merge_requests/13",
465+
title: "Add a cool new feature",
466+
});
467+
});
468+
469+
test("should treat a blank title the same as a missing one", ({
470+
expect,
471+
}) => {
472+
vi.stubEnv(
473+
"CI_PROJECT_URL",
474+
"https://gitlab.example.com/acme/worker-project"
475+
);
476+
vi.stubEnv("CI_MERGE_REQUEST_IID", "13");
477+
vi.stubEnv("CI_MERGE_REQUEST_TITLE", " ");
422478

423479
expect(getPullRequestMetadata()).toEqual({
424480
number: "13",
@@ -4691,6 +4747,7 @@ describe("wrangler preview", () => {
46914747
"https://gitlab.example.com/acme/worker-project.git"
46924748
);
46934749
vi.stubEnv("CI_MERGE_REQUEST_IID", "13");
4750+
vi.stubEnv("CI_MERGE_REQUEST_TITLE", "Add a cool new feature");
46944751
vi.stubEnv("CI_COMMIT_SHA", "abc123def456");
46954752

46964753
let deploymentRequestBody:
@@ -4699,6 +4756,7 @@ describe("wrangler preview", () => {
46994756
"workers/commit_sha"?: string;
47004757
"workers/message"?: string;
47014758
"workers/pull_request_number"?: string;
4759+
"workers/pull_request_title"?: string;
47024760
"workers/pull_request_url"?: string;
47034761
"workers/repository_url"?: string;
47044762
"workers/tag"?: string;
@@ -4769,6 +4827,7 @@ describe("wrangler preview", () => {
47694827
"workers/commit_sha": "abc123def456",
47704828
"workers/message": "preview note",
47714829
"workers/pull_request_number": "13",
4830+
"workers/pull_request_title": "Add a cool new feature",
47724831
"workers/pull_request_url":
47734832
"https://gitlab.example.com/acme/worker-project/-/merge_requests/13",
47744833
"workers/repository_url":
@@ -4780,6 +4839,8 @@ describe("wrangler preview", () => {
47804839
"https://gitlab.example.com/acme/worker-project/-/merge_requests/13"
47814840
);
47824841
expect(std.out).not.toContain("repository_url");
4842+
expect(std.out).not.toContain("pull_request_title");
4843+
expect(std.out).not.toContain("Add a cool new feature");
47834844
});
47844845

47854846
test("should fall back to HEAD commit metadata for annotations in CI", async ({

turbo.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,13 +44,15 @@
4444
"GITHUB_REF",
4545
"CI_MERGE_REQUEST_IID",
4646
"CI_MERGE_REQUEST_PROJECT_URL",
47+
"CI_MERGE_REQUEST_TITLE",
4748
"PULL_REQUEST_URL",
4849
"PR_URL",
4950
"CHANGE_URL",
5051
"CIRCLE_PULL_REQUEST",
5152
"PULL_REQUEST_NUMBER",
5253
"PR_NUMBER",
5354
"CHANGE_ID",
55+
"PULL_REQUEST_TITLE",
5456
"GITHUB_SHA",
5557
"CI_COMMIT_SHA",
5658
"CIRCLE_SHA1",

0 commit comments

Comments
 (0)