Tucker McKnight <tucker@pangolin.lan> | Sun Nov 16 2025
More implementation of the new type The new commit field and branch heads work now, and other functions/filters/template pages work as expected with those new fields. Switch to the new Repository type is pretty much done now. Also did some miscellaneous things, like adding basic string types to some function arguments. Also started changing all uses of "patch" to "commit," which is a holdover from when this project started with darcs.
4 5 6 7 8 9
import branches from './src/branches.ts'
import flatFiles from './src/flatFiles.ts'
import flatPatches from './src/flatPatches.ts'
import paginatedPatches from './src/paginatedPatches.ts'
import {getLocation} from './src/helpers.ts'
import repoOperations from './src/vcses/operations.ts'
import {ReposConfiguration} from './src/configTypes.ts'4 5 6 7 8 9
import branches from './src/branches.ts'
import flatFiles from './src/flatFiles.ts'
import flatPatches from './src/flatPatches.ts'
import paginatedPatches, {type PatchPage} from './src/paginatedPatches.ts'
import {getLocation} from './src/helpers.ts'
import repoOperations from './src/vcses/operations.ts'
import {ReposConfiguration} from './src/configTypes.ts'48 49 50 51 52 53
eleventyConfig.on(
"eleventy.after",
async ({ directories, results, runMode, outputMode }) => {
const cwd = process.cwd()
// Check to see if there is already a repo in all of the locations
// that should have one.48 49 50 51 52 53
eleventyConfig.on(
"eleventy.after",
async ({ directories }) => {
const cwd = process.cwd()
// Check to see if there is already a repo in all of the locations
// that should have one.73 74 75 76 77 78
const tempDirName = `temp_${Math.floor(Math.random() * 10000).toString()}`
const tempDir = `${directories.output}${reposPath}${tempDirName}`
const tempDirRepoPath = `${tempDir}/${eleventyConfig.getFilter("slugify")(repoName)}`
const mkdirresult = await exec(`mkdir ${tempDir}`)
await exec(`git clone -s ${directories.output}${eleventyConfig.getFilter("slugify")(repoName)}.git ${tempDirRepoPath}`)
for (let branch of repoConfig.branchesToPull) {
await exec(`(cd ${tempDirRepoPath} && git checkout ${branch})`)73 74 75 76 77 78
const tempDirName = `temp_${Math.floor(Math.random() * 10000).toString()}`
const tempDir = `${directories.output}${reposPath}${tempDirName}`
const tempDirRepoPath = `${tempDir}/${eleventyConfig.getFilter("slugify")(repoName)}`
await exec(`mkdir ${tempDir}`)
await exec(`git clone -s ${directories.output}${eleventyConfig.getFilter("slugify")(repoName)}.git ${tempDirRepoPath}`)
for (let branch of repoConfig.branchesToPull) {
await exec(`(cd ${tempDirRepoPath} && git checkout ${branch})`)91 92 93 94 95 96 97 98 99 100 101 102 103 104
}
);
eleventyConfig.addFilter("getDirectoryContents", (repo, branch, dirPath) => {
return reposData.find(current => current.name === repo).branches[branch].fileList.filter(file => file.startsWith(dirPath) && file !== dirPath)
})
eleventyConfig.addFilter("getRelativePath", (currentDir, fullFilePath) => {
return fullFilePath.replace(`${currentDir}/`, "")
})
eleventyConfig.addFilter("lineNumbers", (code) => {
const numLines = code.split('\n').length
const lineNumbers = []
for (let i = 1; i <= numLines; i++) {91 92 93 94 95 96 97 98 99 100 101 102 103 104
}
);
eleventyConfig.addFilter("getDirectoryContents", (repo: string, branch: string, dirPath: string) => {
return reposData.find(current => current.name === repo).branches.find(current => current.name === branch).fileList.filter(file => file.startsWith(dirPath) && file !== dirPath)
})
eleventyConfig.addFilter("getRelativePath", (currentDir: string, fullFilePath: string) => {
return fullFilePath.replace(`${currentDir}/`, "")
})
eleventyConfig.addFilter("lineNumbers", (code: string) => {
const numLines = code.split('\n').length
const lineNumbers = []
for (let i = 1; i <= numLines; i++) {119 120 121 122 123 124
}
})
eleventyConfig.addAsyncFilter("renderContentIfAvailable", async (contentString, contentType) => {
const renderer = eleventyConfig?.javascript?.functions?.renderContent
if (renderer) {
return await renderer.bind({})(contentString, contentType)119 120 121 122 123 124
}
})
eleventyConfig.addAsyncFilter("renderContentIfAvailable", async (contentString: string, contentType: string) => {
const renderer = eleventyConfig?.javascript?.functions?.renderContent
if (renderer) {
return await renderer.bind({})(contentString, contentType)129 130 131 132 133 134 135 136 137 138 139 140 141
}
})
eleventyConfig.addFilter("languageExtension", (filename, repoName) => {
let extension = filename.split(".")
extension = extension[extension.length - 1]
const extensionsConfig = reposConfiguration.repos[repoName].languageExtensions
return extensionsConfig && extensionsConfig[extension] ? extensionsConfig[extension] : extension
})
eleventyConfig.addFilter("topLevelFilesOnly", (files, currentLevel) => {
const onlyUnique = (value, index, array) => {
return array.findIndex(test => test.name === value.name) === index;
}129 130 131 132 133 134 135 136 137 138 139 140 141
}
})
eleventyConfig.addFilter("languageExtension", (filename: string, repoName: string) => {
let filenameParts = filename.split(".")
let extension = filenameParts[filenameParts.length - 1]
const extensionsConfig = reposConfiguration.repos[repoName].languageExtensions
return extensionsConfig && extensionsConfig[extension] ? extensionsConfig[extension] : extension
})
eleventyConfig.addFilter("topLevelFilesOnly", (files: Array<string>, currentLevel: string) => {
const onlyUnique = (value, index, array) => {
return array.findIndex(test => test.name === value.name) === index;
}174 175 176 177 178 179 180 181 182 183 184 185 186 187
return sortedByDirectory
})
eleventyConfig.addAsyncFilter("getFileLastTouchInfo", async (repo, branch, filename) => {
const ignoreExtensions = ['.png', '.jpg']
if (ignoreExtensions.some(extension => filename.endsWith(extension))) {
return ""
}
const config = reposConfiguration.repos[repo]
const location = getLocation(reposConfiguration, branch, repo)
return repoOperations[config._type].getFileLastTouchInfo(repo, branch, filename, location)
})
eleventyConfig.addFilter("isDirectory", (filename: string, repoName: string, branchName: string) => {174 175 176 177 178 179 180 181 182 183 184 185 186 187
return sortedByDirectory
})
eleventyConfig.addAsyncFilter("getFileLastTouchInfo", async (repo: string, branch: string, filename: string) => {
const ignoreExtensions = ['.png', '.jpg']
if (ignoreExtensions.some(extension => filename.endsWith(extension))) {
return ""
}
const config = reposConfiguration.repos[repo]
const location = getLocation(reposConfiguration, repo)
return repoOperations[config._type].getFileLastTouchInfo(branch, filename, location)
})
eleventyConfig.addFilter("isDirectory", (filename: string, repoName: string, branchName: string) => {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
})
eleventyConfig.addAsyncFilter("getFileContents", async (repo: string, branch: string, filename: string) => {
const location = getLocation(reposConfiguration, branch, repo)
const command = `git show ${branch}:${filename}`
const res = await exec(`(cd ${location} && ${command})`)
return res.stdout
})
eleventyConfig.addFilter("pagesJustForBranch", (pages, repoName, branchName) => {
return pages.filter(page => page.repoName === repoName && page.branchName === branchName)
})
eleventyConfig.addFilter("date", (dateString) => {
return new Date(dateString).toDateString()
})
eleventyConfig.addFilter("toDateObj", (dateString) => {
return new Date(dateString)
})
eleventyConfig.addAsyncFilter("getReadMe", async (repoName, branchName) => {
const location = getLocation(reposConfiguration, branchName, repoName)
const command = `git show ${branchName}:README.md`
try {
const res = await exec(`(cd ${location} && ${command})`)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
})
eleventyConfig.addAsyncFilter("getFileContents", async (repo: string, branch: string, filename: string) => {
const location = getLocation(reposConfiguration, repo)
const command = `git show ${branch}:${filename}`
const res = await exec(`(cd ${location} && ${command})`)
return res.stdout
})
eleventyConfig.addFilter("pagesJustForBranch", (pages: Array<PatchPage>, repoName: string, branchName: string) => {
return pages.filter(page => page.repoName === repoName && page.branchName === branchName)
})
eleventyConfig.addFilter("date", (dateString: string) => {
return new Date(dateString).toDateString()
})
eleventyConfig.addFilter("toDateObj", (dateString: string) => {
return new Date(dateString)
})
eleventyConfig.addAsyncFilter("getReadMe", async (repoName: string, branchName: string) => {
const location = getLocation(reposConfiguration, repoName)
const command = `git show ${branchName}:README.md`
try {
const res = await exec(`(cd ${location} && ${command})`)259 260 261 262 263 264
nav: {
repoName: (data) => data.branchInfo.repoName,
branchName: (data) => data.branchInfo.branchName,
}
},
navTab: "branches",
}259 260 261 262 263 264 265 266 267 268 269 270 271 272 273
nav: {
repoName: (data) => data.branchInfo.repoName,
branchName: (data) => data.branchInfo.branchName,
path: "list"
},
currentRepo: (data) => reposData.find(repo => {
return repo.name === data.branchInfo.repoName
}),
currentBranch: (data) => reposData.find(repo => {
return repo.name === data.branchInfo.repoName
}).branches.find(branch => {
return branch.name === data.branchInfo.branchName
}),
},
navTab: "branches",
}287 288 289 290 291 292
nav: {
repoName: (data) => data.fileInfo.repoName,
branchName: (data) => data.fileInfo.branchName,
}
},
navTab: "files",
}287 288 289 290 291 292 293 294 295 296 297 298 299 300 301
nav: {
repoName: (data) => data.fileInfo.repoName,
branchName: (data) => data.fileInfo.branchName,
path: "files",
},
currentRepo: (data) => reposData.find(repo => {
return repo.name === data.fileInfo.repoName
}),
currentBranch: (data) => reposData.find(repo => {
return repo.name === data.fileInfo.repoName
}).branches.find(branch => {
return branch.name === data.fileInfo.branchName
}),
},
navTab: "files",
}334 335 336 337 338
nav: {
repoName: (data) => data.branchInfo.repoName,
branchName: (data) => data.branchInfo.branchName,
},
currentRepo: (data) => reposData.find(repo => {
return repo.name === data.branchInfo.repoName334 335 336 337 338 339
nav: {
repoName: (data) => data.branchInfo.repoName,
branchName: (data) => data.branchInfo.branchName,
path: "files",
},
currentRepo: (data) => reposData.find(repo => {
return repo.name === data.branchInfo.repoName368 369 370 371 372
nav: {
repoName: (data) => data.branch.repoName,
branchName: (data) => data.branch.branchName,
},
currentRepo: (data) => reposData.find(repo => {
return repo.name === data.branch.repoName368 369 370 371 372 373
nav: {
repoName: (data) => data.branch.repoName,
branchName: (data) => data.branch.branchName,
path: "",
},
currentRepo: (data) => reposData.find(repo => {
return repo.name === data.branch.repoName404 405 406 407 408 409
nav: {
repoName: (data) => data.patchPage.repoName,
branchName: (data) => data.patchPage.branchName,
}
},
navTab: "patches",
}404 405 406 407 408 409 410 411 412 413 414 415 416 417 418
nav: {
repoName: (data) => data.patchPage.repoName,
branchName: (data) => data.patchPage.branchName,
path: "patches/page1",
},
currentRepo: (data) => reposData.find(repo => {
return repo.name === data.patchPage.repoName
}),
currentBranch: (data) => reposData.find(repo => {
return repo.name === data.patchPage.repoName
}).branches.find(branch => {
return branch.name === data.patchPage.branchName
}),
},
navTab: "patches",
}426 427 428 429 430 431 432 433 434 435 436 437
permalink: (data) => {
const repoName = data.patchInfo.repoName
const branchName = data.patchInfo.branchName
return `${reposPath}/${eleventyConfig.getFilter("slugify")(repoName)}/branches/${eleventyConfig.getFilter("slugify")(branchName)}/patches/${data.patchInfo.patch.hash}/`
},
eleventyComputed: {
nav: {
repoName: (data) => data.patchInfo.repoName,
branchName: (data) => data.patchInfo.branchName,
}
},
width: "full",
navTab: "patches",426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446
permalink: (data) => {
const repoName = data.patchInfo.repoName
const branchName = data.patchInfo.branchName
return `${reposPath}/${eleventyConfig.getFilter("slugify")(repoName)}/branches/${eleventyConfig.getFilter("slugify")(branchName)}/patches/${data.patchInfo.commit.hash}/`
},
eleventyComputed: {
nav: {
repoName: (data) => data.patchInfo.repoName,
branchName: (data) => data.patchInfo.branchName,
path: "patches/page1",
},
currentRepo: (data) => reposData.find(repo => {
return repo.name === data.patchInfo.repoName
}),
currentBranch: (data) => reposData.find(repo => {
return repo.name === data.patchInfo.repoName
}).branches.find(branch => {
return branch.name === data.patchInfo.branchName
}),
},
width: "full",
navTab: "patches",12 13 14 15 16 17
window.jsVars['cloneDiv'] = `<label class="form-label">HTTPS URL</label>
<div class="input-group d-flex flex-nowrap">
<span class="clone overflow-hidden input-group-text">
{% set url = repos[nav.repoName].cloneUrl %}
{{ url }}
</span>
<button data-clone-url="{{url}}" class="btn btn-primary" id="clone-button">Copy</button>12 13 14 15 16 17
window.jsVars['cloneDiv'] = `<label class="form-label">HTTPS URL</label>
<div class="input-group d-flex flex-nowrap">
<span class="clone overflow-hidden input-group-text">
{% set url = currentRepo.cloneUrl %}
{{ url }}
</span>
<button data-clone-url="{{url}}" class="btn btn-primary" id="clone-button">Copy</button>82 83 84 85 86 87 88
<div class="input-group input-group-sm">
<span class="input-group-text">Branch</span>
<select class="form-select" onchange="selectBranch(this)" aria-label="Repository branch selector">
{% for branch in repos[nav.repoName].branches %}
<option value="{{branch.repoName | slugify}},{{branch.branchName | slugify}},{{nav.path}}" {% if branch.branchName == nav.branchName %}selected{% endif %}>{{branch.branchName}}</option>
{% endfor %}
</select>
</div>82 83 84 85 86 87 88
<div class="input-group input-group-sm">
<span class="input-group-text">Branch</span>
<select class="form-select" onchange="selectBranch(this)" aria-label="Repository branch selector">
{% for branch in currentRepo.branches %}
<option value="{{currentRepo.name | slugify}},{{branch.name | slugify}},{{nav.path}}" {% if branch.name == nav.branchName %}selected{% endif %}>{{branch.name}}</option>
{% endfor %}
</select>
</div>0 1 2 3 4
import { type Repository } from "./dataTypes.ts"
let cachedBranches = null
export default (repos: Array<Repository>) => {
if (cachedBranches !== null) { return cachedBranches }0 1 2 3 4 5 6 7
import { type Repository } from "./dataTypes.ts"
let cachedBranches: Array<{
branchName: string,
repoName: string,
}> | null = null
export default (repos: Array<Repository>) => {
if (cachedBranches !== null) { return cachedBranches }17 18 19 20 21 22
message: string,
author: string,
date: Date,
parent: string,
diffs: Array<{
fileName: string,
lineNumber: number,17 18 19 20 21 22
message: string,
author: string,
date: Date,
parent: string | null,
diffs: Array<{
fileName: string,
lineNumber: number,0 1 2 3 4 5 6 7 8 9 10 11
import { type Repository } from "./dataTypes.ts"
let cachedFlatPatches = null
export default async (repos: Array<Repository>) => {
if (cachedFlatPatches !== null) { return cachedFlatPatches }
cachedFlatPatches = repos.flatMap((repo) => {
return repo.branches.flatMap((branch) => {
return [] // todo implement this with new commits format
})
})
0 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
import { type Repository } from "./dataTypes.ts"
type FlatPatchRecord = {
commit: ReturnType<Repository['commits']['get']>,
repoName: string,
branchName: string,
}
let cachedFlatPatches: Array<FlatPatchRecord> | null = null
export default async (repos: Array<Repository>)
: Promise<Array<FlatPatchRecord>> => {
if (cachedFlatPatches !== null) { return cachedFlatPatches }
cachedFlatPatches = repos.flatMap((repo) => {
return repo.branches.flatMap((branch) => {
const flatPatches: Array<FlatPatchRecord> = []
let currentCommit: ReturnType<Repository['commits']['get']> | undefined = repo.commits.get(branch.head)
while (currentCommit !== undefined) {
flatPatches.push({
commit: currentCommit,
repoName: repo.name,
branchName: branch.name
})
currentCommit = repo.commits.get(currentCommit.parent)
}
return flatPatches
})
})
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
import _ from 'lodash'
import * as Diff from 'diff'
import {type Repository} from './dataTypes.ts'
type NavValues = {
repoName: string | ((data: any) => string),
branchName: string | ((data: any) => string),
path: string | ((data: any) => string),
title: string | ((data: any) => string),
}
type Hunk = {
file: string,
lineNumber: number,
previousText: string,
afterText: string,
}
type Diffs = ReturnType<Repository['commits']['get']>['diffs']
0 1 2 3 4 5
import _ from 'lodash'
import * as Diff from 'diff'
import {type Repository} from './dataTypes.ts'
import { type ReposConfiguration } from './configTypes.ts'
type Diffs = ReturnType<Repository['commits']['get']>['diffs']
81 82 83 84 85 86 87 88 89 90 91 92
return hunks
}
const getLocation = (reposConfig: any, branchName: string, repoName: string): string => {
const config = reposConfig.repos[repoName]
return config.location
}
export {
NavValues,
getGitDiffsFromPatchText,
getLocation,
}81 82 83 84 85 86 87 88 89 90 91
return hunks
}
const getLocation = (reposConfig: ReposConfiguration, repoName: string): string => {
const config = reposConfig.repos[repoName]
return config.location
}
export {
getGitDiffsFromPatchText,
getLocation,
}0 1 2 3 4 5 6
i
mport flatPatchesFunc from './flatPatches.js'
let paginatedPatches = null
export default async (repos) => {
if (paginatedPatches !== null) { return paginatedPatches }
const flatPatches = await flatPatchesFunc(repos)0 1 2 3 4 5 6 7 8 9 10 11 12 13
import { type Repository } from './dataTypes.ts'
import flatPatchesFunc from './flatPatches.js'
export type PatchPage = {
repoName: string,
branchName: string,
commits: Array<ReturnType<Repository['commits']['get']>>,
pageNumber: number,
}
let paginatedPatches: Array<PatchPage> | null = null
export default async (repos: Array<Repository>) => {
if (paginatedPatches !== null) { return paginatedPatches }
const flatPatches = await flatPatchesFunc(repos)14 15 16 17 18 19
return (
page.repoName === patch.repoName
&& page.branchName == patch.branchName
&& page.patches.length <= patchesPerPage
)
})
14 15 16 17 18 19
return (
page.repoName === patch.repoName
&& page.branchName == patch.branchName
&& page.commits.length <= patchesPerPage
)
})
23 24 25 26 27 28 29 30 31 32 33 34 35
paginatedPatches.push({
repoName: patch.repoName,
branchName: patch.branchName,
patches: [patch.patch],
// current page number is one more than "how many items in paginatedPatches already
// have repoName as their repo name.
pageNumber,
})
}
else {
paginatedPatches[index].patches.push(patch.patch)
}
})
23 24 25 26 27 28 29 30 31 32 33 34 35
paginatedPatches.push({
repoName: patch.repoName,
branchName: patch.branchName,
commits: [patch.commit],
// current page number is one more than "how many items in paginatedPatches already
// have repoName as their repo name.
pageNumber,
})
}
else {
paginatedPatches[index].commits.push(patch.commit)
}
})
2 3 4 5 6 7 8 9
type GitConfig,
} from './configTypes.ts'
import { type Repository} from './dataTypes.ts'
import { addBranchToCommitsMap } from './vcses/git/operations.ts'
import { getLocation} from './helpers.ts'
const getBranchNames = (repoConfig: GitConfig): Array<string> => {
return repoConfig.branchesToPull.map((branch) => {2 3 4 5 6 7 8 9 10 11 12 13 14 15
type GitConfig,
} from './configTypes.ts'
import { type Repository} from './dataTypes.ts'
import util from 'util'
import childProcess from 'child_process'
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 getBranchNames = (repoConfig: GitConfig): Array<string> => {
return repoConfig.branchesToPull.map((branch) => {29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49
const branchNames = getBranchNames(reposConfig.repos[repoName])
const commits: Repository['commits'] = new Map()
for (const branchName of branchNames) {
const repoLocation = getLocation(reposConfig, branchName, repoName)
await addBranchToCommitsMap(branchName, repoLocation, commits)
}
repos.push({
name: repoName,
branches: branchNames.map((branchName) => {
return {
name: branchName,
head: "", // todo
fileList: [], //todo
}
}),
cloneUrl: "",
defaultBranch: "main",
tags: [],
commits,
})
}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
const branchNames = getBranchNames(reposConfig.repos[repoName])
const commits: Repository['commits'] = new Map()
for (const branchName of branchNames) {
const repoLocation = getLocation(reposConfig, repoName)
await addBranchToCommitsMap(branchName, repoLocation, commits)
}
const branches = await Promise.all(branchNames.map(async (branchName) => {
const repoLocation = getLocation(reposConfig, repoName)
const branchHeadRes = await exec(`(cd ${repoLocation} && git show-ref --branch ${branchName})`)
const branchHead = branchHeadRes.stdout.split(" ")[0]
return {
name: branchName,
head: branchHead,
fileList: await getFileList(branchName, repoLocation)
}
}))
repos.push({
name: repoName,
branches,
cloneUrl: cloneUrl.cloneUrl(reposConfig.baseUrl, repoName),
defaultBranch: "main",
tags: [], // todo
commits,
})
}3 4 5 6 7 8
import { getGitDiffsFromPatchText} from '../../helpers.ts'
import { type Repository } from '../../dataTypes.ts'
export const getFileList = async (repoName: string, branchName: string, repoLocation: string) => {
const command = `git ls-tree -r --name-only ${branchName}`
const result = await exec(`(cd ${repoLocation} && ${command})`)3 4 5 6 7 8
import { getGitDiffsFromPatchText} from '../../helpers.ts'
import { type Repository } from '../../dataTypes.ts'
export const getFileList = async (branchName: string, repoLocation: string) => {
const command = `git ls-tree -r --name-only ${branchName}`
const result = await exec(`(cd ${repoLocation} && ${command})`)40 41 42 43 44
export const addBranchToCommitsMap = async(branchName: string, repoLocation: string, commits: Repository['commits']): Promise<void> => {
const totalPatchesCountRes = await exec(`(cd ${repoLocation} && git rev-list --count ${branchName})`)
const totalPatchesCount = parseInt(totalPatchesCountRes.stdout)
for (let i = 0; i < totalPatchesCount; i = i + 10) {
const gitLogSubsetRes = await exec(`(cd ${repoLocation} && git log ${branchName} -p -n 10 --skip ${i})`)
let gitLogSubset = gitLogSubsetRes.stdout.split("\n")40 41 42 43 44 45
export const addBranchToCommitsMap = async(branchName: string, repoLocation: string, commits: Repository['commits']): Promise<void> => {
const totalPatchesCountRes = await exec(`(cd ${repoLocation} && git rev-list --count ${branchName})`)
const totalPatchesCount = parseInt(totalPatchesCountRes.stdout)
let previousHash: null | string = null
for (let i = 0; i < totalPatchesCount; i = i + 10) {
const gitLogSubsetRes = await exec(`(cd ${repoLocation} && git log ${branchName} -p -n 10 --skip ${i})`)
let gitLogSubset = gitLogSubsetRes.stdout.split("\n")53 54 55 56 57 58 59 60
const hash = currentPatch[0].replace("commit ", "").trim()
// exit early if the commits map already includes this hash
if (commits.has(hash)) {
break
}
let author: string, date: string53 54 55 56 57 58 59 60 61 62 63 64 65 66
const hash = currentPatch[0].replace("commit ", "").trim()
// set the parent hash of the previous commit, unless we're on the first commit
if (previousHash !== null) {
commits.get(previousHash)['parent'] = hash
}
previousHash = hash
// exit early if the commits map already includes this hash
if (commits.has(hash)) {
return
}
let author: string, date: string82 83 84 85 86 87 88 89 90 91 92 93 94
message: commitMessage,
author,
date: new Date(date),
diffs,
parent: "todo",
})
} while (gitLogSubset.length > 1)
}
}
export const getFileLastTouchInfo = async (repo: string, branch: string, filename: string, repoLocation: string) => {
const regex = RegExp(".* [0-9]+ [0-9]+")
const command = `git blame --porcelain ${branch} ${filename}`
const res = await exec(`(cd ${repoLocation} && ${command})`)82 83 84 85 86 87 88 89 90 91 92 93 94
message: commitMessage,
author,
date: new Date(date),
diffs,
parent: null,
})
} while (gitLogSubset.length > 1)
}
}
export const getFileLastTouchInfo = async (branch: string, filename: string, repoLocation: string) => {
const regex = RegExp(".* [0-9]+ [0-9]+")
const command = `git blame --porcelain ${branch} ${filename}`
const res = await exec(`(cd ${repoLocation} && ${command})`)5 6 7 8 9 10
type RepoOperationsType = {
[vcs: string]: {
getFileList: (repoName: string, branchName: string, repoLocation: string) => Promise<Array<string>>,
getFileLastTouchInfo: (repoName: string, branchName: string, filename: string, repoLocation: string) => Promise<Array<{sha: string, author: string}>>,
}
}
5 6 7 8 9 10
type RepoOperationsType = {
[vcs: string]: {
getFileList: (repoName: string, branchName: string, repoLocation: string) => Promise<Array<string>>,
getFileLastTouchInfo: (branchName: string, filename: string, repoLocation: string) => Promise<Array<{sha: string, author: string}>>,
}
}
0 1 2 3 4 5 6
<ul>
{% for branch in branches %}
{% set description = reposConfig.repos[branch.repoName].branches[branch.branchName].description %}
{% if branch.repoName == branchInfo.repoName %}
<li><a href="{{reposPath}}/{{branch.repoName | slugify}}/branches/{{branch.branchName | slugify}}">{{branch.branchName}}</a>{% if branch.branchName == branchInfo.branchName %} (current){% endif %}{% if description %} - {{ description }}{% endif %}</li>
{% endif %}
{% endfor %}
</ul>0 1 2 3 4 5
<ul>
{% for branch in branches %}
{% if branch.repoName == branchInfo.repoName %}
<li><a href="{{reposPath}}/{{branch.repoName | slugify}}/branches/{{branch.branchName | slugify}}">{{branch.branchName}}</a>{% if branch.branchName == branchInfo.branchName %} (current){% endif %}</li>
{% endif %}
{% endfor %}
</ul>0 1 2 3 4 5 6 7 8 9 10 11 12 13
<div class="container-lg">
<div class="row">
<div class="col-auto">
<h1>{{patchInfo.patch.name}}</h2>
<p>{{patchInfo.patch.date | date }}</p>
<p>{{patchInfo.patch.author }}</p>
<pre>{{patchInfo.patch.description}}</pre>
</div>
</div>
<div class="row">
<div class="col-auto">
<p class="font-monospace fw-bold text-secondary">{{patchInfo.patch.hash}}</p>
</div>
</div>
</div>0 1 2 3 4 5 6 7 8 9 10 11 12 13
<div class="container-lg">
<div class="row">
<div class="col-auto">
<h1>commit first line goes here</h2>
<p>{{patchInfo.commit.date | date }}</p>
<p>{{patchInfo.commit.author }}</p>
<pre>{{patchInfo.commit.message}}</pre>
</div>
</div>
<div class="row">
<div class="col-auto">
<p class="font-monospace fw-bold text-secondary">{{patchInfo.commit.hash}}</p>
</div>
</div>
</div>23 24 25 26 27 28
</div>
</div>
<div class="row" id="diffs">
{% set patchHunks = patchInfo.patch.diffs %}
{% for hunk in patchHunks %}
<div class=hunk>
<span class="font-monospace fw-bold"><a href="{{reposPath}}/{{patchInfo.repoName | slugify}}/branches/{{patchInfo.branchName | slugify}}/files/{{ hunk.fileName | slugify}}.html">{{ hunk.fileName }}:{{ hunk.lineNumber }}</a></span>23 24 25 26 27 28
</div>
</div>
<div class="row" id="diffs">
{% set patchHunks = patchInfo.commit.diffs %}
{% for hunk in patchHunks %}
<div class=hunk>
<span class="font-monospace fw-bold"><a href="{{reposPath}}/{{patchInfo.repoName | slugify}}/branches/{{patchInfo.branchName | slugify}}/files/{{ hunk.fileName | slugify}}.html">{{ hunk.fileName }}:{{ hunk.lineNumber }}</a></span>8 9 10 11 12 13 14 15 16 17 18 19 20 21
</nav>
<ul>
{% for patch in patchPage.patches %}
<li class="patch">
<div>
<span class="patch-name"><a href="{{reposPath}}/{{patchPage.repoName | slugify}}/branches/{{patchPage.branchName | slugify}}/patches/{{patch.hash}}">{{patch.name}}</a></span>
<br />
<span>{{patch.date | date}}</span>
<br />
<span>{{patch.author}}</span>
<pre class="patch-hash">{{patch.hash}}</pre>
</div>
</li>
{% endfor %}8 9 10 11 12 13 14 15 16 17 18 19 20 21
</nav>
<ul>
{% for commit in patchPage.commits %}
<li class="patch">
<div>
<span class="patch-name"><a href="{{reposPath}}/{{patchPage.repoName | slugify}}/branches/{{patchPage.branchName | slugify}}/patches/{{commit.hash}}">{{commit.message}}</a></span>
<br />
<span>{{commit.date | date}}</span>
<br />
<span>{{commit.author}}</span>
<pre class="patch-hash">{{commit.hash}}</pre>
</div>
</li>
{% endfor %}