File size: 2,037 Bytes
21dd449
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
import { HUB_URL } from "../consts";
import { createApiError } from "../error";
import type { ApiCommitData } from "../types/api/api-commit";
import type { CredentialsParams, RepoDesignation } from "../types/public";
import { checkCredentials } from "../utils/checkCredentials";
import { parseLinkHeader } from "../utils/parseLinkHeader";
import { toRepoId } from "../utils/toRepoId";

export interface CommitData {
	oid: string;
	title: string;
	message: string;
	authors: Array<{ username: string; avatarUrl: string }>;
	date: Date;
}

export async function* listCommits(
	params: {
		repo: RepoDesignation;
		/**
		 * Revision to list commits from. Defaults to the default branch.
		 */
		revision?: string;
		hubUrl?: string;
		/**
		 * Number of commits to fetch from the hub each http call. Defaults to 100. Can be set to 1000.
		 */
		batchSize?: number;
		/**
		 * Custom fetch function to use instead of the default one, for example to use a proxy or edit headers.
		 */
		fetch?: typeof fetch;
	} & Partial<CredentialsParams>
): AsyncGenerator<CommitData> {
	const accessToken = checkCredentials(params);
	const repoId = toRepoId(params.repo);

	// Could upgrade to 1000 commits per page
	let url: string | undefined = `${params.hubUrl ?? HUB_URL}/api/${repoId.type}s/${repoId.name}/commits/${
		params.revision ?? "main"
	}?limit=${params.batchSize ?? 100}`;

	while (url) {
		const res: Response = await (params.fetch ?? fetch)(url, {
			headers: accessToken ? { Authorization: `Bearer ${accessToken}` } : {},
		});

		if (!res.ok) {
			throw await createApiError(res);
		}

		const resJson: ApiCommitData[] = await res.json();
		for (const commit of resJson) {
			yield {
				oid: commit.id,
				title: commit.title,
				message: commit.message,
				authors: commit.authors.map((author) => ({
					username: author.user,
					avatarUrl: author.avatar,
				})),
				date: new Date(commit.date),
			};
		}

		const linkHeader = res.headers.get("Link");

		url = linkHeader ? parseLinkHeader(linkHeader).next : undefined;
	}
}