Files snapshot from file-caching
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
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
b8a3bb Tucker McKnight
7e40e5 Tucker McKnight
b8a3bb Tucker McKnight
b8a3bb Tucker McKnight
fb82fe Tucker McKnight
fb82fe Tucker McKnight
88f663 Tucker McKnight
b8a3bb Tucker McKnight
e2d4fd Tucker McKnight
e2d4fd Tucker McKnight
7e40e5 Tucker McKnight
b8a3bb Tucker McKnight
fb82fe Tucker McKnight
fb82fe Tucker McKnight
fb82fe Tucker McKnight
b8a3bb Tucker McKnight
e3012a Tucker McKnight
e3012a Tucker McKnight
e3012a Tucker McKnight
e3012a Tucker McKnight
e3012a Tucker McKnight
e3012a Tucker McKnight
e3012a Tucker McKnight
e3012a Tucker McKnight
e3012a Tucker McKnight
e3012a Tucker McKnight
e2d4fd Tucker McKnight
e3012a Tucker McKnight
e2d4fd Tucker McKnight
9aaaea Tucker McKnight
e3012a Tucker McKnight
e2d4fd Tucker McKnight
e2d4fd Tucker McKnight
e3012a Tucker McKnight
754e1b Tucker McKnight
e3012a Tucker McKnight
e2d4fd Tucker McKnight
e3012a Tucker McKnight
01b859 Tucker McKnight
01b859 Tucker McKnight
01b859 Tucker McKnight
01b859 Tucker McKnight
01b859 Tucker McKnight
e3012a Tucker McKnight
01b859 Tucker McKnight
01b859 Tucker McKnight
01b859 Tucker McKnight
01b859 Tucker McKnight
01b859 Tucker McKnight
01b859 Tucker McKnight
7e40e5 Tucker McKnight
01b859 Tucker McKnight
01b859 Tucker McKnight
01b859 Tucker McKnight
01b859 Tucker McKnight
01b859 Tucker McKnight
01b859 Tucker McKnight
01b859 Tucker McKnight
01b859 Tucker McKnight
e3012a Tucker McKnight
e3012a Tucker McKnight
e3012a Tucker McKnight
e3012a Tucker McKnight
e3012a Tucker McKnight
e3012a Tucker McKnight
e3012a Tucker McKnight
e3012a Tucker McKnight
e3012a Tucker McKnight
e3012a Tucker McKnight
e3012a Tucker McKnight
e3012a Tucker McKnight
e3012a Tucker McKnight
e3012a Tucker McKnight
88f663 Tucker McKnight
e3012a Tucker McKnight
01b859 Tucker McKnight
01b859 Tucker McKnight
01b859 Tucker McKnight
88f663 Tucker McKnight
01b859 Tucker McKnight
01b859 Tucker McKnight
01b859 Tucker McKnight
01b859 Tucker McKnight
01b859 Tucker McKnight
01b859 Tucker McKnight
01b859 Tucker McKnight
01b859 Tucker McKnight
01b859 Tucker McKnight
01b859 Tucker McKnight
01b859 Tucker McKnight
7e40e5 Tucker McKnight
7e40e5 Tucker McKnight
e2d4fd Tucker McKnight
e3012a Tucker McKnight
e3012a Tucker McKnight
e3012a Tucker McKnight
e3012a Tucker McKnight
e3012a Tucker McKnight
e3012a Tucker McKnight
e3012a Tucker McKnight
e3012a Tucker McKnight
e3012a Tucker McKnight
e3012a Tucker McKnight
e3012a Tucker McKnight
e3012a Tucker McKnight
e3012a Tucker McKnight
e3012a Tucker McKnight
e3012a Tucker McKnight
e3012a Tucker McKnight
e3012a Tucker McKnight
01b859 Tucker McKnight
01b859 Tucker McKnight
01b859 Tucker McKnight
01b859 Tucker McKnight
01b859 Tucker McKnight
01b859 Tucker McKnight
01b859 Tucker McKnight
01b859 Tucker McKnight
01b859 Tucker McKnight
01b859 Tucker McKnight
01b859 Tucker McKnight
01b859 Tucker McKnight
e2d4fd Tucker McKnight
e3012a Tucker McKnight
e3012a Tucker McKnight
e3012a Tucker McKnight
e3012a Tucker McKnight
e3012a Tucker McKnight
e3012a Tucker McKnight
e3012a Tucker McKnight
9aaaea Tucker McKnight
9aaaea Tucker McKnight
e2d4fd Tucker McKnight
01b859 Tucker McKnight
e2d4fd Tucker McKnight
e3012a Tucker McKnight
e3012a Tucker McKnight
e3012a Tucker McKnight
e3012a Tucker McKnight
b8a3bb Tucker McKnight
b8a3bb Tucker McKnight
4f267d Tucker McKnight
b8a3bb Tucker McKnight
9aaaea Tucker McKnight
b8a3bb Tucker McKnight
b8a3bb Tucker McKnight
b8a3bb Tucker McKnight
4f267d Tucker McKnight
7e40e5 Tucker McKnight
7e40e5 Tucker McKnight
9aaaea Tucker McKnight
7e40e5 Tucker McKnight
e3012a Tucker McKnight
e3012a Tucker McKnight
e3012a Tucker McKnight
7e40e5 Tucker McKnight
b8a3bb Tucker McKnight
b8a3bb Tucker McKnight
e3012a Tucker McKnight
9aaaea Tucker McKnight
01b859 Tucker McKnight
fb82fe Tucker McKnight
01b859 Tucker McKnight
01b859 Tucker McKnight
b30bd9 Tucker McKnight
01b859 Tucker McKnight
fb82fe Tucker McKnight
01b859 Tucker McKnight
01b859 Tucker McKnight
e07418 Tucker McKnight
01b859 Tucker McKnight
fb82fe Tucker McKnight
fb82fe Tucker McKnight
9aaaea Tucker McKnight
9aaaea Tucker McKnight
9aaaea Tucker McKnight
9aaaea Tucker McKnight
9aaaea Tucker McKnight
9aaaea Tucker McKnight
9aaaea Tucker McKnight
9aaaea Tucker McKnight
9aaaea Tucker McKnight
9aaaea Tucker McKnight
9aaaea Tucker McKnight
9aaaea Tucker McKnight
9aaaea Tucker McKnight
4eaa3d Tucker McKnight
e3012a Tucker McKnight
e07418 Tucker McKnight
4eaa3d Tucker McKnight
e07418 Tucker McKnight
f0856f Tucker McKnight
b30bd9 Tucker McKnight
e07418 Tucker McKnight
e07418 Tucker McKnight
e07418 Tucker McKnight
e07418 Tucker McKnight
e07418 Tucker McKnight
f0856f Tucker McKnight
b30bd9 Tucker McKnight
e07418 Tucker McKnight
e07418 Tucker McKnight
e07418 Tucker McKnight
e07418 Tucker McKnight
e07418 Tucker McKnight
e07418 Tucker McKnight
e07418 Tucker McKnight
f0856f Tucker McKnight
f0856f Tucker McKnight
f0856f Tucker McKnight
f0856f Tucker McKnight
f0856f Tucker McKnight
f0856f Tucker McKnight
4eaa3d Tucker McKnight
4eaa3d Tucker McKnight
4eaa3d Tucker McKnight
4eaa3d Tucker McKnight
4eaa3d Tucker McKnight
4eaa3d Tucker McKnight
4eaa3d Tucker McKnight
4eaa3d Tucker McKnight
e07418 Tucker McKnight
e07418 Tucker McKnight
4f267d Tucker McKnight
7e40e5 Tucker McKnight
4f267d Tucker McKnight
4eaa3d Tucker McKnight
fb82fe Tucker McKnight
95482f Tucker McKnight
9aaaea Tucker McKnight
7e40e5 Tucker McKnight
7e40e5 Tucker McKnight
b8a3bb Tucker McKnight
b8a3bb Tucker McKnight
4f267d Tucker McKnight
b8a3bb Tucker McKnight
b8a3bb Tucker McKnight
e3012a Tucker McKnight
import {
type ReposConfiguration,
type GitConfig,
} from './configTypes.ts'
import util from 'util'
import childProcess from 'child_process'
import {minimatch} from 'minimatch'
import { type Repository} from './dataTypes.ts'
import cloneUrl from './vcses/git/helpers.ts'
import { addBranchToCommitsMap } from './vcses/git/operations.ts'
import { getLocation} from './helpers.ts'
import { getFileList } from './vcses/git/operations.ts'
const exec = util.promisify(childProcess.exec)
const branchesForReposMap: Map<string, Array<{name: string, description?: string, compareTo?: string}>> = new Map()
const tagsForReposMap: Map<string, Array<{name: string}>> = new Map()
const getBranchesAndTags = async (
repoConfig: GitConfig,
repoName: string
): Promise<{
branches: Array<{name: string, description?: string, compareTo?: string}>,
tags: Array<{name: string}>,
}> => {
const cachedBranchNames = branchesForReposMap.get(repoName)
const cachedTagNames = tagsForReposMap.get(repoName)
if (cachedBranchNames !== undefined) {
console.log({branches: cachedBranchNames, tags: cachedTagNames})
return {branches: cachedBranchNames, tags: cachedTagNames}
}
// Get all branches and tags available in the repository
const allBranches = (await exec(`git -C ${repoConfig.location} branch --format="%(refname:short)"`)).stdout.split("\n").filter(branch => branch !== '')
const allTags = (await exec(`git -C ${repoConfig.location} tag`)).stdout.split("\n").filter(tag => tag !== '')
// Sort the list of branch descriptions from `branches` by the length
// of their patterns.
// Then, for each branch from the repository, see if it matches a pattern.
// If that pattern has rules associated with it (like a description or a max),
// apply those.
type RulesObject = {max?: number, description?: string, compareTo?: string}
let branchRules: Array<{pattern: string, matches: Array<string>, rules: RulesObject}> = repoConfig.branches.map((branchDescription) => {
const rules: RulesObject = {}
if (typeof branchDescription !== 'string') {
if (branchDescription.max) { rules.max = branchDescription.max }
if (branchDescription.description) { rules.description = branchDescription.description }
if (branchDescription.compareTo) { rules.compareTo = branchDescription.compareTo }
}
return {
pattern: (typeof branchDescription === 'string' ? branchDescription : branchDescription.pattern),
matches: [],
rules,
}
})
let tagRules: Array<{pattern: string, matches: Array<string>, rules: RulesObject}> = repoConfig.tags.map((tagDescription) => {
const rules: RulesObject = {}
if (typeof tagDescription !== 'string') {
if (tagDescription.max) { rules.max = tagDescription.max }
}
return {
pattern: (typeof tagDescription === 'string' ? tagDescription : tagDescription.pattern),
matches: [],
rules,
}
})
branchRules.sort((a, b) => b.pattern.length - a.pattern.length)
tagRules.sort((a, b) => b.pattern.length - a.pattern.length)
allBranches.forEach((branchName) => {
const matchingPatternIndex = branchRules.findIndex((branchRule) => {
return minimatch(branchName, branchRule.pattern)
})
if (matchingPatternIndex === -1) { return }
const matchedRule = branchRules[matchingPatternIndex]
matchedRule.matches.push(branchName)
if (
matchedRule.rules?.max
&& matchedRule.rules?.max < matchedRule.matches.length
) {
matchedRule.matches.pop()
}
})
allTags.forEach((tagName) => {
const matchingPatternIndex = tagRules.findIndex((tagRule) => {
return minimatch(tagName, tagRule.pattern)
})
if (matchingPatternIndex === -1) { return }
const matchedRule = tagRules[matchingPatternIndex]
matchedRule.matches.push(tagName)
if (
matchedRule.rules?.max
&& matchedRule.rules?.max < matchedRule.matches.length
) {
matchedRule.matches.pop()
}
})
const branches: Array<{
name: string,
description?: string,
compareTo?: string,
}> = branchRules.map((branchRule) => {
return branchRule.matches.map((match) => {
const result = {name: match}
if (branchRule.rules.description) { result['description'] = branchRule.rules.description }
if (branchRule.rules.compareTo) { result['compareTo'] = branchRule.rules.compareTo }
return result
}).flat()
}).flat()
const tags: Array<{ name: string }> = tagRules.map((tagRule) => {
return tagRule.matches.map((match) => {
const result = {name: match}
return result
}).flat()
}).flat()
console.log(tags)
if (branchesForReposMap.get(repoName) === undefined) {
branchesForReposMap.set(repoName, branches)
}
if (tagsForReposMap.get(repoName) === undefined) {
tagsForReposMap.set(repoName, tags)
}
return { branches, tags }
}
let cachedRepos: Array<Repository> | null = null
const repos: (reposConfig: ReposConfiguration, outputDir: string, slugify: Function) => Promise<Array<Repository>> = async (reposConfig, outputDir, slugify) => {
if (cachedRepos !== null) { return cachedRepos }
const repoNames = Object.keys(reposConfig.repos)
cachedRepos = []
for (const repoName of repoNames) {
const repoLocation = getLocation(reposConfig, outputDir, repoName, slugify)
const commits: Repository['commits'] = new Map()
const branchesAndTags = await getBranchesAndTags(reposConfig.repos[repoName], repoName)
const branchNames = branchesAndTags.branches.map(branch => branch.name)
for (const branchName of branchNames) {
await addBranchToCommitsMap(branchName, repoLocation, commits)
}
const branches = await Promise.all(branchesAndTags.branches.map(async (branch) => {
const repoLocation = getLocation(reposConfig, outputDir, repoName, slugify)
const branchHeadRes = await exec(`git -C ${repoLocation} show-ref refs/heads/${branch.name}`)
const branchHead = branchHeadRes.stdout.split(" ")[0]
const result = {
name: branch.name,
sha: branchHead,
fileList: await getFileList(branch.name, repoLocation)
}
if (branch.description) { result['description'] = branch.description }
if (branch.compareTo) { result['compareTo'] = branch.compareTo }
return result
}))
const tags = await Promise.all(branchesAndTags.tags.map(async (tag) => {
const repoLocation = getLocation(reposConfig, outputDir, repoName, slugify)
const tagHeadRes = await exec(`git -C ${repoLocation} show-ref refs/tags/${tag.name}`)
const tagHead = tagHeadRes.stdout.split(" ")[0]
const result = {
name: tag.name,
sha: tagHead,
fileList: await getFileList(tagHead, repoLocation)
}
return result
}))
const branchesWithCompareToInfo: Repository['branches'] = branches.map((branch) => {
const branchDescription = branchesAndTags.branches.find(branchToAdd => branchToAdd.name === branch.name)
const compareTo = branchDescription.compareTo || reposConfig.repos[repoName].defaultBranch
const compareToBranch = branches.find((test) => test.name === compareTo)
const compareToBranchCommits = new Set<string>()
let currentCommit = commits.get(compareToBranch.sha)
while (currentCommit !== undefined) {
compareToBranchCommits.add(currentCommit.hash)
currentCommit = commits.get(currentCommit.parent)
}
const thisBranchCommits = new Set<string>()
currentCommit = commits.get(branch.sha)
while (currentCommit !== undefined) {
thisBranchCommits.add(currentCommit.hash)
currentCommit = commits.get(currentCommit.parent)
}
// At this point, we have all commits in the compareTo branch in one set, and
// all commits from this branch in another set.
const onlyInThisBranch = Array.from(thisBranchCommits).filter((thisBranchCommit) => {
return !commits.get(thisBranchCommit).isMerge && !compareToBranchCommits.has(thisBranchCommit)
}).length
const onlyInCompareToBranch = Array.from(compareToBranchCommits).filter((compareToBranchCommit) => {
return !commits.get(compareToBranchCommit).isMerge && !thisBranchCommits.has(compareToBranchCommit)
}).length
const compareToInfo = {
ahead: onlyInThisBranch,
behind: onlyInCompareToBranch,
compareTo: compareTo,
}
return {...branch, ...compareToInfo}
})
cachedRepos.push({
name: repoName,
description: reposConfig.repos[repoName].description,
branches: branchesWithCompareToInfo,
cloneUrl: cloneUrl.cloneUrl(reposConfig.baseUrl, repoName),
defaultBranch: reposConfig.repos[repoName].defaultBranch,
tags: tags,
commits,
})
}
return cachedRepos
}
export {repos, getBranchesAndTags}