diff options
-rw-r--r-- | source/features/sync-pr-commit-title.tsx | 62 | ||||
-rw-r--r-- | source/github-helpers/index.test.ts | 12 | ||||
-rw-r--r-- | source/github-helpers/index.ts | 4 | ||||
-rw-r--r-- | source/helpers/pr-commit-cleaner.test.ts | 13 | ||||
-rw-r--r-- | source/helpers/pr-commit-cleaner.ts | 6 |
5 files changed, 59 insertions, 38 deletions
diff --git a/source/features/sync-pr-commit-title.tsx b/source/features/sync-pr-commit-title.tsx index 37ad9a27..36aa04d1 100644 --- a/source/features/sync-pr-commit-title.tsx +++ b/source/features/sync-pr-commit-title.tsx @@ -1,21 +1,25 @@ import React from 'dom-chef'; import select from 'select-dom'; import delegate from 'delegate-it'; -import regexJoin from 'regex-join'; import * as pageDetect from 'github-url-detection'; import * as textFieldEdit from 'text-field-edit'; +import * as api from '../github-helpers/api'; import features from '../feature-manager'; -import onPrMergePanelOpen from '../github-events/on-pr-merge-panel-open'; import {getConversationNumber, userCanLikelyMergePR} from '../github-helpers'; import onCommitTitleUpdate from '../github-events/on-commit-title-update'; +import observe from '../helpers/selector-observer'; +import cleanPrCommitTitle from '../helpers/pr-commit-cleaner'; -const mergeFormSelector = '.is-squashing form:not([hidden])'; -const prTitleFieldSelector = '.js-issue-update input[name="issue[title]"]'; -const prTitleSubmitSelector = '.js-issue-update button[type="submit"]'; +const prTitleFieldSelector = 'input#issue_title'; +const commitTitleFieldSelector = '.is-squashing form:not([hidden]) input#merge_title_field'; -function getCommitTitleField(): HTMLInputElement | undefined { - return select(`${mergeFormSelector} input#merge_title_field`); +function getCurrentCommitTitleField(): HTMLInputElement | undefined { + return select(commitTitleFieldSelector); +} + +function getCurrentCommitTitle(): string | undefined { + return getCurrentCommitTitleField()?.value.trim(); } function createCommitTitle(): string { @@ -24,52 +28,43 @@ function createCommitTitle(): string { } function needsSubmission(): boolean { - const inputField = getCommitTitleField(); - if (!inputField || inputField.value === '') { - return false; - } - - // Ensure that the required fields are on the page - if (!select.exists(prTitleFieldSelector + ',' + prTitleSubmitSelector)) { - features.log.error(import.meta.url, 'Can’t update the PR title'); - return false; - } - - return createCommitTitle() !== inputField.value; + const currentCommitTitle = getCurrentCommitTitle(); + return Boolean(currentCommitTitle) && (createCommitTitle() !== currentCommitTitle); } function getUI(): HTMLElement { - return select(`${mergeFormSelector} .rgh-sync-pr-commit-title-note`) ?? ( + const cancelButton = <button type="button" className="btn-link Link--muted text-underline rgh-sync-pr-commit-title">Cancel</button>; + return select('.rgh-sync-pr-commit-title-note') ?? ( <p className="note rgh-sync-pr-commit-title-note"> - The title of this PR will be updated to match this title. <button type="button" className="btn-link Link--muted text-underline rgh-sync-pr-commit-title">Cancel</button> + The title of this PR will be updated to match this title. {cancelButton} </p> ); } function updateUI(): void { if (needsSubmission()) { - getCommitTitleField()!.after(getUI()); + getCurrentCommitTitleField()!.after(getUI()); } else { getUI().remove(); } } -function updatePRTitle(): void { +async function updatePRTitle(): Promise<void> { if (!needsSubmission()) { return; } // Remove PR number from commit title - const prTitle = getCommitTitleField()!.value - .replace(regexJoin(/\s*\(/, '#' + getConversationNumber()!, /\)$/), ''); + const title = cleanPrCommitTitle(getCurrentCommitTitle()!, getConversationNumber()!); - // Fill and submit title-change form - select(prTitleFieldSelector)!.value = prTitle; - select(prTitleSubmitSelector)!.click(); // `form.submit()` isn't sent via ajax + await api.v3(`pulls/${getConversationNumber()!}`, { + method: 'PATCH', + body: {title}, + }); } async function updateCommitTitle(): Promise<void> { - const field = getCommitTitleField()!; + const field = getCurrentCommitTitleField()!; if (field) { textFieldEdit.set(field, createCommitTitle()); } @@ -81,10 +76,17 @@ function disableSubmission(): void { } function init(signal: AbortSignal): void { - onPrMergePanelOpen(updateCommitTitle, signal); + // PR title -> Commit title field + observe(commitTitleFieldSelector, updateCommitTitle, {signal}); // On panel open + observe('.gh-header-title', updateCommitTitle, {signal}); // On PR title change + + // Commit title field -> toggle checkbox visibility onCommitTitleUpdate(updateUI, signal); + // On submission, update PR delegate('form.js-merge-pull-request', 'submit', updatePRTitle, {signal}); + + // On "Cancel", disable the feature delegate('.rgh-sync-pr-commit-title', 'click', disableSubmission, {signal}); } diff --git a/source/github-helpers/index.test.ts b/source/github-helpers/index.test.ts index 04bf91cb..4f1a9d08 100644 --- a/source/github-helpers/index.test.ts +++ b/source/github-helpers/index.test.ts @@ -9,7 +9,7 @@ import { } from '.'; test('getConversationNumber', () => { - const pairs = new Map<string, string | undefined>([ + const pairs = new Map<string, number | undefined>([ [ 'https://github.com', undefined, @@ -48,23 +48,23 @@ test('getConversationNumber', () => { ], [ 'https://github.com/refined-github/refined-github/pull/148/commits/0019603b83bd97c2f7ef240969f49e6126c5ec85', - '148', + 148, ], [ 'https://github.com/refined-github/refined-github/pull/148/commits/00196', - '148', + 148, ], [ 'https://github.com/refined-github/refined-github/pull/148/commits', - '148', + 148, ], [ 'https://github.com/refined-github/refined-github/pull/148', - '148', + 148, ], [ 'https://github.com/refined-github/refined-github/issues/146', - '146', + 146, ], [ 'https://github.com/refined-github/refined-github/issues', diff --git a/source/github-helpers/index.ts b/source/github-helpers/index.ts index 156fe18a..c42790a6 100644 --- a/source/github-helpers/index.ts +++ b/source/github-helpers/index.ts @@ -9,9 +9,9 @@ import * as pageDetect from 'github-url-detection'; export const getUsername = onetime(pageDetect.utils.getUsername); export const {getRepositoryInfo: getRepo, getCleanPathname} = pageDetect.utils; -export const getConversationNumber = (): string | undefined => { +export const getConversationNumber = (): number | undefined => { if (pageDetect.isPR() || pageDetect.isIssue()) { - return location.pathname.split('/')[4]; + return Number(location.pathname.split('/')[4]); } return undefined; diff --git a/source/helpers/pr-commit-cleaner.test.ts b/source/helpers/pr-commit-cleaner.test.ts new file mode 100644 index 00000000..f7771ddf --- /dev/null +++ b/source/helpers/pr-commit-cleaner.test.ts @@ -0,0 +1,13 @@ +import {test, assert} from 'vitest'; + +import cleanPrCommitTitle from './pr-commit-cleaner'; + +test('cleanPrCommitTitle', () => { + const clean = 'Something done'; + assert.equal(cleanPrCommitTitle('Something done (#123)', 123), clean); + assert.equal(cleanPrCommitTitle(' Something done (#123) ', 123), clean); + assert.equal(cleanPrCommitTitle(' Something done ', 123), clean); + + assert.notEqual(cleanPrCommitTitle('Something done (fixes #123)', 123), clean); + assert.notEqual(cleanPrCommitTitle('Something done (#23454)', 123), clean); +}); diff --git a/source/helpers/pr-commit-cleaner.ts b/source/helpers/pr-commit-cleaner.ts new file mode 100644 index 00000000..52cd7f2b --- /dev/null +++ b/source/helpers/pr-commit-cleaner.ts @@ -0,0 +1,6 @@ +/** +@example 'Something done (#123)' => 'Something done' +*/ +export default function cleanPrCommitTitle(commitTitle: string, pr: number): string { + return commitTitle.replace(new RegExp(`\\(#${pr}\\)\\s*$`), '').trim(); +} |