summaryrefslogtreecommitdiff
path: root/source/features/pr-base-commit.tsx
blob: 42d3e3a69ff257a76e400d58e6bae0ca3b5f0cd6 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
import React from 'dom-chef';
import select from 'select-dom';

import * as pageDetect from 'github-url-detection';

import features from '../feature-manager';
import observe from '../helpers/selector-observer';
import * as api from '../github-helpers/api';
import {getBranches} from '../github-helpers/pr-branches';
import getPrInfo, {PullRequestInfo} from '../github-helpers/get-pr-info';
import pluralize from '../helpers/pluralize';
import {buildRepoURL} from '../github-helpers';
import {linkifyCommit} from '../github-helpers/dom-formatters';
import {removeTextNodeContaining} from '../helpers/dom-utils';

function getBaseCommitNotice(prInfo: PullRequestInfo): JSX.Element {
	const {base} = getBranches();
	const commit = linkifyCommit(prInfo.baseRefOid);
	const count = pluralize(prInfo.behindBy, '$$ commit');
	const countLink = (
		<a href={buildRepoURL('compare', `${prInfo.baseRefOid.slice(0, 8)}...${base.branch}`)}>
			{count}
		</a>
	);
	return (
		<>It’s {countLink} behind (base commit: {commit})</>
	);
}

async function addInfo(statusMeta: Element): Promise<void> {
	// Selector copied from GitHub. Don't @ me
	// This excludes hidden ".status-meta" items without adding this longass selector to the observer
	// Added: .rgh-update-pr-from-base-branch-row
	if (!statusMeta.closest('.merge-pr.is-merging .merging-body, .merge-pr.is-merging .merge-commit-author-email-info, .merge-pr.is-merging-solo .merging-body, .merge-pr.is-merging-jump .merging-body, .merge-pr.is-merging-group .merging-body, .merge-pr.is-rebasing .rebasing-body, .merge-pr.is-squashing .squashing-body, .merge-pr.is-squashing .squash-commit-author-email-info, .merge-pr.is-merging .branch-action-state-error-if-merging .merging-body-merge-warning, .rgh-update-pr-from-base-branch-row')) {
		return;
	}

	const {base} = getBranches();
	const prInfo = await getPrInfo(base.relative);
	if (!prInfo.needsUpdate) {
		return;
	}

	const previousMessage = statusMeta.firstChild!; // Extract now because it won't be the first child anymore
	statusMeta.prepend(getBaseCommitNotice(prInfo));
	removeTextNodeContaining(previousMessage, 'Merging can be performed automatically.');
}

async function init(signal: AbortSignal): Promise<false | void> {
	await api.expectToken();

	observe('.branch-action-item .status-meta', addInfo, {signal});
}

void features.add(import.meta.url, {
	include: [
		pageDetect.isPRConversation,
	],
	exclude: [
		pageDetect.isClosedPR,
		() => select('.head-ref')!.title === 'This repository has been deleted',
	],
	awaitDomReady: true, // DOM-based exclusions
	init,
});

/*
Test URLs

PR without conflicts
https://github.com/refined-github/sandbox/pull/60

Draft PR without conflicts
https://github.com/refined-github/sandbox/pull/61

Native "Update branch" button
(pick a conflict-free PR from https://github.com/refined-github/refined-github/pulls?q=is%3Apr+is%3Aopen+sort%3Acreated-asc)

Native "Resolve conflicts" button
https://github.com/refined-github/sandbox/pull/9

Cross-repo PR with long branch names
https://github.com/refined-github/sandbox/pull/13

*/