summaryrefslogtreecommitdiff
path: root/source/features/ci-link.tsx
blob: daf3fa9570646fa323b9364ea5cf5d3898def6ef (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
import './ci-link.css';
import React from 'dom-chef';
import * as pageDetect from 'github-url-detection';

import features from '../feature-manager.js';
import api from '../github-helpers/api.js';
import {buildRepoURL} from '../github-helpers/index.js';
import observe from '../helpers/selector-observer.js';
import getChecks from './ci-link.gql';

async function getCommitWithChecks(): Promise<string | undefined> {
	const {repository} = await api.v4(getChecks);
	// Check earlier commits just in case the last one is CI-generated and doesn't have checks
	for (const commit of repository.defaultBranchRef.target.history.nodes) {
		if (commit.statusCheckRollup) {
			return commit.oid;
		}
	}

	return undefined;
}

async function add(anchor: HTMLElement): Promise<void> {
	const commit = await getCommitWithChecks();
	if (!commit) {
		return;
	}

	const endpoint = buildRepoURL('commits/checks-statuses-rollups');
	anchor.parentElement!.append(
		<span className="rgh-ci-link ml-1">
			<batch-deferred-content hidden data-url={endpoint}>
				<input
					name="oid"
					value={commit}
					data-targets="batch-deferred-content.inputs"
				/>
			</batch-deferred-content>
		</span>,
	);

	// A parent is clipping the popup
	anchor.closest('.AppHeader-context-full')?.style.setProperty('overflow', 'visible');
}

async function init(signal: AbortSignal): Promise<void> {
	observe([
		// Desktop
		'.AppHeader-context-item:not([data-hovercard-type])',

		// Mobile. `> *:first-child` avoids finding our own element
		'.AppHeader-context-compact-mainItem > span:first-child',

		// Old selector: `.avatar` excludes "Global navigation update"
		// Repo title (aware of forks and private repos)
		'[itemprop="name"]:not(.avatar ~ [itemprop])',
	], add, {signal});
}

void features.add(import.meta.url, {
	include: [
		pageDetect.hasRepoHeader,
	],
	init,
});

/*
Test URLs

CI:
https://github.com/refined-github/refined-github

No CI:
https://github.com/fregante/.github
*/