summaryrefslogtreecommitdiffstats
path: root/build/release/authors.js
blob: fec5104c5463c318a23615084a249b63ca6a8249 (plain)
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
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
import fs from "node:fs/promises";
import util from "node:util";
import { exec as nodeExec } from "node:child_process";

const exec = util.promisify( nodeExec );

const rnewline = /\r?\n/;
const rdate = /^\[(\d+)\] /;

const ignore = [
	/dependabot\[bot\]/
];

function compareAuthors( a, b ) {
	const aName = a.replace( rdate, "" ).replace( / <.*>/, "" );
	const bName = b.replace( rdate, "" ).replace( / <.*>/, "" );
	return aName === bName;
}

function uniq( arr ) {
	const unique = [];
	for ( const item of arr ) {
		if ( ignore.some( re => re.test( item ) ) ) {
			continue;
		}
		if ( item && !unique.find( ( e ) => compareAuthors( e, item ) ) ) {
			unique.push( item );
		}
	}
	return unique;
}

function cleanupSizzle() {
	console.log( "Cleaning up..." );
	return exec( "npx rimraf .sizzle" );
}

function cloneSizzle() {
	console.log( "Cloning Sizzle..." );
	return exec( "git clone https://github.com/jquery/sizzle .sizzle" );
}

async function getLastAuthor() {
	const authorsTxt = await fs.readFile( "AUTHORS.txt", "utf8" );
	return authorsTxt.trim().split( rnewline ).pop();
}

async function logAuthors( preCommand ) {
	let command = "git log --pretty=format:\"[%at] %aN <%aE>\"";
	if ( preCommand ) {
		command = `${ preCommand } && ${ command }`;
	}
	const { stdout } = await exec( command );
	return uniq( stdout.trim().split( rnewline ).reverse() );
}

async function getSizzleAuthors() {
	await cloneSizzle();
	const authors = await logAuthors( "cd .sizzle" );
	await cleanupSizzle();
	return authors;
}

function sortAuthors( a, b ) {
	const [ , aDate ] = rdate.exec( a );
	const [ , bDate ] = rdate.exec( b );
	return Number( aDate ) - Number( bDate );
}

function formatAuthor( author ) {
	return author.replace( rdate, "" );
}

export async function getAuthors() {
	console.log( "Getting authors..." );
	const authors = await logAuthors();
	const sizzleAuthors = await getSizzleAuthors();
	return uniq( authors.concat( sizzleAuthors ) ).sort( sortAuthors ).map( formatAuthor );
}

export async function checkAuthors() {
	const authors = await getAuthors();
	const lastAuthor = await getLastAuthor();

	if ( authors[ authors.length - 1 ] !== lastAuthor ) {
		console.log( "AUTHORS.txt: ", lastAuthor );
		console.log( "Last 20 in git: ", authors.slice( -20 ) );
		throw new Error( "Last author in AUTHORS.txt does not match last git author" );
	}
	console.log( "AUTHORS.txt is up to date" );
}

export async function updateAuthors() {
	const authors = await getAuthors();

	const authorsTxt = "Authors ordered by first contribution.\n\n" + authors.join( "\n" ) + "\n";
	await fs.writeFile( "AUTHORS.txt", authorsTxt );

	console.log( "AUTHORS.txt updated" );
}