gitea source for verification 2026-05-22
Some checks are pending
release-nightly / nightly-binary (push) Waiting to run
release-nightly / nightly-docker-rootful (push) Waiting to run
release-nightly / nightly-docker-rootless (push) Waiting to run

This commit is contained in:
2026-05-22 16:44:59 +08:00
commit 7a61cd3abc
5650 changed files with 690128 additions and 0 deletions

61
tools/generate-images.ts Executable file
View File

@@ -0,0 +1,61 @@
#!/usr/bin/env node
import {initWasm, Resvg} from '@resvg/resvg-wasm';
import {optimize} from 'svgo';
import {readFile, writeFile} from 'node:fs/promises';
import {argv, exit} from 'node:process';
async function generate(svg: string, path: string, {size, bg}: {size: number, bg?: boolean}) {
const outputFile = new URL(path, import.meta.url);
if (String(outputFile).endsWith('.svg')) {
const {data} = optimize(svg, {
plugins: [
'preset-default',
'removeDimensions',
{
name: 'addAttributesToSVGElement',
params: {
attributes: [{width: String(size)}, {height: String(size)}],
},
},
],
});
await writeFile(outputFile, data);
return;
}
const resvgJS = new Resvg(svg, {
fitTo: {
mode: 'width',
value: size,
},
...(bg && {background: 'white'}),
});
const renderedImage = resvgJS.render();
const pngBytes = renderedImage.asPng();
await writeFile(outputFile, Buffer.from(pngBytes));
}
async function main() {
const gitea = argv.slice(2).includes('gitea');
const logoSvg = await readFile(new URL('../assets/logo.svg', import.meta.url), 'utf8');
const faviconSvg = await readFile(new URL('../assets/favicon.svg', import.meta.url), 'utf8');
await initWasm(await readFile(new URL(import.meta.resolve('@resvg/resvg-wasm/index_bg.wasm'))));
await Promise.all([
generate(logoSvg, '../public/assets/img/logo.svg', {size: 32}),
generate(logoSvg, '../public/assets/img/logo.png', {size: 512}),
generate(faviconSvg, '../public/assets/img/favicon.svg', {size: 32}),
generate(faviconSvg, '../public/assets/img/favicon.png', {size: 180}),
generate(logoSvg, '../public/assets/img/avatar_default.png', {size: 200}),
generate(logoSvg, '../public/assets/img/apple-touch-icon.png', {size: 180, bg: true}),
gitea && generate(logoSvg, '../public/assets/img/gitea.svg', {size: 32}),
]);
}
try {
await main();
} catch (err) {
console.error(err);
exit(1);
}

View File

@@ -0,0 +1,570 @@
{
"pkg:bat": {
"bat": [
".bat",
".cmd"
]
},
"pkg:clojure": {
"clojure": [
".clj",
".cljs",
".cljc",
".cljx",
".clojure",
".edn"
]
},
"pkg:coffeescript": {
"coffeescript": [
".coffee",
".cson",
".iced"
]
},
"pkg:configuration-editing": {
"jsonc": [
".code-workspace",
"language-configuration.json",
"icon-theme.json",
"color-theme.json"
],
"json": [
".code-profile"
]
},
"pkg:cpp": {
"c": [
".c",
".i"
],
"cpp": [
".cpp",
".cppm",
".cc",
".ccm",
".cxx",
".cxxm",
".c++",
".c++m",
".hpp",
".hh",
".hxx",
".h++",
".h",
".ii",
".ino",
".inl",
".ipp",
".ixx",
".tpp",
".txx",
".hpp.in",
".h.in"
],
"cuda-cpp": [
".cu",
".cuh"
]
},
"pkg:csharp": {
"csharp": [
".cs",
".csx",
".cake"
]
},
"pkg:css": {
"css": [
".css"
]
},
"pkg:dart": {
"dart": [
".dart"
]
},
"pkg:diff": {
"diff": [
".diff",
".patch",
".rej"
]
},
"pkg:docker": {
"dockerfile": [
".dockerfile",
".containerfile"
]
},
"pkg:fsharp": {
"fsharp": [
".fs",
".fsi",
".fsx",
".fsscript"
]
},
"pkg:git-base": {
"ignore": [
".gitignore_global",
".gitignore",
".git-blame-ignore-revs"
]
},
"pkg:go": {
"go": [
".go"
]
},
"pkg:groovy": {
"groovy": [
".groovy",
".gvy",
".gradle",
".jenkinsfile",
".nf"
]
},
"pkg:handlebars": {
"handlebars": [
".handlebars",
".hbs",
".hjs"
]
},
"pkg:hlsl": {
"hlsl": [
".hlsl",
".hlsli",
".fx",
".fxh",
".vsh",
".psh",
".cginc",
".compute"
]
},
"pkg:html": {
"html": [
".html",
".htm",
".shtml",
".xhtml",
".xht",
".mdoc",
".jsp",
".asp",
".aspx",
".jshtm",
".volt",
".ejs",
".rhtml"
]
},
"pkg:ini": {
"ini": [
".ini"
],
"properties": [
".conf",
".properties",
".cfg",
".directory",
".gitattributes",
".gitconfig",
".gitmodules",
".editorconfig",
".repo"
]
},
"pkg:java": {
"java": [
".java",
".jav"
]
},
"pkg:javascript": {
"javascriptreact": [
".jsx"
],
"javascript": [
".js",
".es6",
".mjs",
".cjs",
".pac"
]
},
"pkg:json": {
"json": [
".json",
".bowerrc",
".jscsrc",
".webmanifest",
".js.map",
".css.map",
".ts.map",
".har",
".jslintrc",
".jsonld",
".geojson",
".ipynb",
".vuerc"
],
"jsonc": [
".jsonc",
".eslintrc",
".eslintrc.json",
".jsfmtrc",
".jshintrc",
".swcrc",
".hintrc",
".babelrc"
],
"jsonl": [
".jsonl",
".ndjson"
],
"snippets": [
".code-snippets"
]
},
"pkg:julia": {
"julia": [
".jl"
],
"juliamarkdown": [
".jmd"
]
},
"pkg:latex": {
"tex": [
".sty",
".cls",
".bbx",
".cbx"
],
"latex": [
".tex",
".ltx",
".ctx"
],
"bibtex": [
".bib"
]
},
"pkg:less": {
"less": [
".less"
]
},
"pkg:log": {
"log": [
".log",
"*.log.?"
]
},
"pkg:lua": {
"lua": [
".lua"
]
},
"pkg:make": {
"makefile": [
".mak",
".mk"
]
},
"pkg:markdown-basics": {
"markdown": [
".md",
".mkd",
".mdwn",
".mdown",
".markdown",
".markdn",
".mdtxt",
".mdtext",
".workbook"
]
},
"pkg:ms-vscode.js-debug": {
"wat": [
".wat",
".wasm"
]
},
"pkg:npm": {
"ignore": [
".npmignore"
],
"properties": [
".npmrc"
]
},
"pkg:objective-c": {
"objective-c": [
".m"
],
"objective-cpp": [
".mm"
]
},
"pkg:perl": {
"perl": [
".pl",
".pm",
".pod",
".t",
".PL",
".psgi"
],
"raku": [
".raku",
".rakumod",
".rakutest",
".rakudoc",
".nqp",
".p6",
".pl6",
".pm6"
]
},
"pkg:php": {
"php": [
".php",
".php4",
".php5",
".phtml",
".ctp"
]
},
"pkg:powershell": {
"powershell": [
".ps1",
".psm1",
".psd1",
".pssc",
".psrc"
]
},
"pkg:pug": {
"jade": [
".pug",
".jade"
]
},
"pkg:python": {
"python": [
".py",
".rpy",
".pyw",
".cpy",
".gyp",
".gypi",
".pyi",
".ipy",
".pyt"
]
},
"pkg:r": {
"r": [
".r",
".rhistory",
".rprofile",
".rt"
]
},
"pkg:razor": {
"razor": [
".cshtml",
".razor"
]
},
"pkg:restructuredtext": {
"restructuredtext": [
".rst"
]
},
"pkg:ruby": {
"ruby": [
".rb",
".rbx",
".rjs",
".gemspec",
".rake",
".ru",
".erb",
".podspec",
".rbi"
]
},
"pkg:rust": {
"rust": [
".rs"
]
},
"pkg:scss": {
"scss": [
".scss"
]
},
"pkg:search-result": {
"search-result": [
".code-search"
]
},
"pkg:shaderlab": {
"shaderlab": [
".shader"
]
},
"pkg:shellscript": {
"shellscript": [
".sh",
".bash",
".bashrc",
".bash_aliases",
".bash_profile",
".bash_login",
".ebuild",
".eclass",
".profile",
".bash_logout",
".xprofile",
".xsession",
".xsessionrc",
".Xsession",
".zsh",
".zshrc",
".zprofile",
".zlogin",
".zlogout",
".zshenv",
".zsh-theme",
".fish",
".ksh",
".csh",
".cshrc",
".tcshrc",
".yashrc",
".yash_profile"
]
},
"pkg:sql": {
"sql": [
".sql",
".dsql"
]
},
"pkg:swift": {
"swift": [
".swift"
]
},
"pkg:typescript-basics": {
"typescript": [
".ts",
".cts",
".mts"
],
"typescriptreact": [
".tsx"
],
"json": [
".tsbuildinfo"
]
},
"pkg:vb": {
"vb": [
".vb",
".brs",
".vbs",
".bas",
".vba"
]
},
"pkg:xml": {
"xml": [
".xml",
".xsd",
".ascx",
".atom",
".axml",
".axaml",
".bpmn",
".cpt",
".csl",
".csproj",
".csproj.user",
".dita",
".ditamap",
".dtd",
".ent",
".mod",
".dtml",
".fsproj",
".fxml",
".iml",
".isml",
".jmx",
".launch",
".menu",
".mxml",
".nuspec",
".opml",
".owl",
".proj",
".props",
".pt",
".publishsettings",
".pubxml",
".pubxml.user",
".rbxlx",
".rbxmx",
".rdf",
".rng",
".rss",
".shproj",
".storyboard",
".svg",
".targets",
".tld",
".tmx",
".vbproj",
".vbproj.user",
".vcxproj",
".vcxproj.filters",
".wsdl",
".wxi",
".wxl",
".wxs",
".xaml",
".xbl",
".xib",
".xlf",
".xliff",
".xpdl",
".xul",
".xoml"
],
"xsl": [
".xsl",
".xslt"
]
},
"pkg:yaml": {
"yaml": [
".yaml",
".yml",
".eyaml",
".eyml",
".cff",
".yaml-tmlanguage",
".yaml-tmpreferences",
".yaml-tmtheme",
".winget"
]
}
}

114
tools/generate-svg.ts Executable file
View File

@@ -0,0 +1,114 @@
#!/usr/bin/env node
import {optimize} from 'svgo';
import {dirname, parse} from 'node:path';
import {globSync, writeFileSync} from 'node:fs';
import {readFile, writeFile, mkdir} from 'node:fs/promises';
import {fileURLToPath} from 'node:url';
import {exit} from 'node:process';
import type {Manifest} from 'material-icon-theme';
const glob = (pattern: string) => globSync(pattern, {cwd: dirname(import.meta.dirname)});
type Opts = {
prefix?: string,
fullName?: string,
};
async function processAssetsSvgFile(path: string, {prefix, fullName}: Opts = {}) {
let name = fullName;
if (!name) {
name = parse(path).name;
if (prefix) name = `${prefix}-${name}`;
if (prefix === 'octicon') name = name.replace(/-[0-9]+$/, ''); // chop of '-16' on octicons
}
// Set the `xmlns` attribute so that the files are displayable in standalone documents
// The svg backend module will strip the attribute during startup for inline display
const {data} = optimize(await readFile(path, 'utf8'), {
plugins: [
{name: 'preset-default'},
{name: 'removeDimensions'},
{name: 'removeTitle'},
{name: 'prefixIds', params: {prefix: () => name}},
{name: 'addClassesToSVGElement', params: {classNames: ['svg', name]}},
{
name: 'addAttributesToSVGElement', params: {
attributes: [
{'xmlns': 'http://www.w3.org/2000/svg'},
{'width': '16'}, {'height': '16'}, {'aria-hidden': 'true'},
],
},
},
],
});
await writeFile(fileURLToPath(new URL(`../public/assets/img/svg/${name}.svg`, import.meta.url)), data);
}
function processAssetsSvgFiles(pattern: string, opts: Opts = {}) {
return glob(pattern).map((path) => processAssetsSvgFile(path, opts));
}
async function processMaterialFileIcons() {
const paths = glob('node_modules/material-icon-theme/icons/*.svg');
const svgSymbols: Record<string, string> = {};
for (const path of paths) {
// remove all unnecessary attributes, only keep "viewBox"
const {data} = optimize(await readFile(path, 'utf8'), {
plugins: [
{name: 'preset-default'},
{name: 'removeDimensions'},
{name: 'removeXMLNS'},
{name: 'removeAttrs', params: {attrs: 'xml:space', elemSeparator: ','}},
],
});
const svgName = parse(path).name;
// intentionally use single quote here to avoid escaping
svgSymbols[svgName] = data.replace(/"/g, `'`);
}
writeFileSync(fileURLToPath(new URL(`../options/fileicon/material-icon-svgs.json`, import.meta.url)), JSON.stringify(svgSymbols, null, 2));
const vscodeExtensionsJson = await readFile(fileURLToPath(new URL(`generate-svg-vscode-extensions.json`, import.meta.url)), 'utf8');
const vscodeExtensions = JSON.parse(vscodeExtensionsJson) as Record<string, string>;
const iconRulesJson = await readFile(fileURLToPath(new URL(`../node_modules/material-icon-theme/dist/material-icons.json`, import.meta.url)), 'utf8');
const iconRules = JSON.parse(iconRulesJson) as Manifest;
// The rules are from VSCode material-icon-theme, we need to adjust them to our needs
// 1. We only use lowercase filenames to match (it should be good enough for most cases and more efficient)
// 2. We do not have a "Language ID" system:
// * https://code.visualstudio.com/docs/languages/identifiers#_known-language-identifiers
// * https://github.com/microsoft/vscode/tree/1.98.0/extensions
delete iconRules.iconDefinitions;
for (const [k, v] of Object.entries(iconRules.fileNames)) iconRules.fileNames[k.toLowerCase()] = v;
for (const [k, v] of Object.entries(iconRules.folderNames)) iconRules.folderNames[k.toLowerCase()] = v;
for (const [k, v] of Object.entries(iconRules.fileExtensions)) iconRules.fileExtensions[k.toLowerCase()] = v;
// Use VSCode's "Language ID" mapping from its extensions
for (const [_, langIdExtMap] of Object.entries(vscodeExtensions)) {
for (const [langId, names] of Object.entries(langIdExtMap)) {
for (const name of names) {
const nameLower = name.toLowerCase();
if (nameLower[0] === '.') {
iconRules.fileExtensions[nameLower.substring(1)] ??= langId;
} else {
iconRules.fileNames[nameLower] ??= langId;
}
}
}
}
const iconRulesPretty = JSON.stringify(iconRules, null, 2);
writeFileSync(fileURLToPath(new URL(`../options/fileicon/material-icon-rules.json`, import.meta.url)), iconRulesPretty);
}
async function main() {
await mkdir(fileURLToPath(new URL('../public/assets/img/svg', import.meta.url)), {recursive: true});
await Promise.all([
...processAssetsSvgFiles('node_modules/@primer/octicons/build/svg/*-16.svg', {prefix: 'octicon'}),
...processAssetsSvgFiles('web_src/svg/*.svg'),
...processAssetsSvgFiles('public/assets/img/gitea.svg', {fullName: 'gitea-gitea'}),
processMaterialFileIcons(),
]);
}
try {
await main();
} catch (err) {
console.error(err);
exit(1);
}

23
tools/lint-go-gopls.sh Executable file
View File

@@ -0,0 +1,23 @@
#!/bin/bash
set -uo pipefail
cd "$(dirname -- "${BASH_SOURCE[0]}")" && cd ..
IGNORE_PATTERNS=(
"is deprecated" # TODO: fix these
)
# lint all go files with 'gopls check' and look for lines starting with the
# current absolute path, indicating a error was found. This is necessary
# because the tool does not set non-zero exit code when errors are found.
# ref: https://github.com/golang/go/issues/67078
ERROR_LINES=$("$GO" run "$GOPLS_PACKAGE" check -severity=warning "$@" 2>/dev/null | grep -E "^$PWD" | grep -vFf <(printf '%s\n' "${IGNORE_PATTERNS[@]}"));
NUM_ERRORS=$(echo -n "$ERROR_LINES" | wc -l)
if [ "$NUM_ERRORS" -eq "0" ]; then
exit 0;
else
echo "$ERROR_LINES"
echo "Found $NUM_ERRORS 'gopls check' errors"
exit 1;
fi

25
tools/lint-templates-svg.ts Executable file
View File

@@ -0,0 +1,25 @@
#!/usr/bin/env node
import {readdirSync, readFileSync, globSync} from 'node:fs';
import {parse, relative} from 'node:path';
import {fileURLToPath} from 'node:url';
import {exit} from 'node:process';
const knownSvgs = new Set<string>();
for (const file of readdirSync(new URL('../public/assets/img/svg', import.meta.url))) {
knownSvgs.add(parse(file).name);
}
const rootPath = fileURLToPath(new URL('..', import.meta.url));
let hadErrors = false;
for (const file of globSync(fileURLToPath(new URL('../templates/**/*.tmpl', import.meta.url)))) {
const content = readFileSync(file, 'utf8');
for (const [_, name] of content.matchAll(/svg ["'`]([^"'`]+)["'`]/g)) {
if (!knownSvgs.has(name)) {
console.info(`SVG "${name}" not found, used in ${relative(rootPath, file)}`);
hadErrors = true;
}
}
}
exit(hadErrors ? 1 : 0);

21
tools/misspellings.csv Normal file
View File

@@ -0,0 +1,21 @@
acounts,accounts
canidate,candidate
comfirm,confirm
converage,coverage
currrently,currently
delimeter,delimiter
differrent,different
exclusing,excluding
finshed,finished
formated,formatted
inderect,indirect
insuficient,insufficient
likly,likely
mergable,mergeable
overrided,overridden
priortized,prioritized
registeration,registration
reuqest,request
reviwer,reviewer
superceded,superseded
underlaying,underlying
1 acounts accounts
2 canidate candidate
3 comfirm confirm
4 converage coverage
5 currrently currently
6 delimeter delimiter
7 differrent different
8 exclusing excluding
9 finshed finished
10 formated formatted
11 inderect indirect
12 insuficient insufficient
13 likly likely
14 mergable mergeable
15 overrided overridden
16 priortized prioritized
17 registeration registration
18 reuqest request
19 reviwer reviewer
20 superceded superseded
21 underlaying underlying

8
tools/watch.sh Normal file
View File

@@ -0,0 +1,8 @@
#!/bin/bash
set -euo pipefail
make --no-print-directory watch-frontend &
make --no-print-directory watch-backend &
trap 'kill $(jobs -p)' EXIT
wait