Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@ RUN apk --no-cache add \
&& npm install -g pnpm@10 \
&& rm -rf /var/cache/apk/*

# workaround for node >= 22.18.0 on alpine 3.22. Remove when upgrading to alpine 3.23
COPY --from=docker.io/node:22-alpine3.22 /usr/local/bin/node /usr/local/bin/node

# Setup repo
COPY . ${GOPATH}/src/code.gitea.io/gitea
WORKDIR ${GOPATH}/src/code.gitea.io/gitea
Expand Down
3 changes: 3 additions & 0 deletions Dockerfile.rootless
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@ RUN apk --no-cache add \
&& npm install -g pnpm@10 \
&& rm -rf /var/cache/apk/*

# workaround for node >= 22.18.0 on alpine 3.22. Remove when upgrading to alpine 3.23
COPY --from=docker.io/node:22-alpine3.22 /usr/local/bin/node /usr/local/bin/node

# Setup repo
COPY . ${GOPATH}/src/code.gitea.io/gitea
WORKDIR ${GOPATH}/src/code.gitea.io/gitea
Expand Down
16 changes: 8 additions & 8 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ GO_TEST_PACKAGES ?= $(filter-out $(shell $(GO) list code.gitea.io/gitea/models/m
MIGRATE_TEST_PACKAGES ?= $(shell $(GO) list code.gitea.io/gitea/models/migrations/...)

WEBPACK_SOURCES := $(shell find web_src/js web_src/css -type f)
WEBPACK_CONFIGS := webpack.config.js tailwind.config.js
WEBPACK_CONFIGS := webpack.config.ts tailwind.config.ts
WEBPACK_DEST := public/assets/js/index.js public/assets/css/index.css
WEBPACK_DEST_ENTRIES := public/assets/js public/assets/css public/assets/fonts

Expand All @@ -153,9 +153,9 @@ TAR_EXCLUDES := .git data indexers queues log node_modules $(EXECUTABLE) $(DIST)
GO_DIRS := build cmd models modules routers services tests
WEB_DIRS := web_src/js web_src/css

ESLINT_FILES := web_src/js tools *.js *.ts *.cjs tests/e2e
ESLINT_FILES := web_src/js tools *.ts *.cjs tests/e2e
STYLELINT_FILES := web_src/css web_src/js/components/*.vue
SPELLCHECK_FILES := $(GO_DIRS) $(WEB_DIRS) templates options/locale/locale_en-US.ini .github $(filter-out CHANGELOG.md, $(wildcard *.go *.js *.md *.yml *.yaml *.toml)) $(filter-out tools/misspellings.csv, $(wildcard tools/*))
SPELLCHECK_FILES := $(GO_DIRS) $(WEB_DIRS) templates options/locale/locale_en-US.ini .github $(filter-out CHANGELOG.md, $(wildcard *.go *.md *.yml *.yaml *.toml)) $(filter-out tools/misspellings.csv, $(wildcard tools/*))
EDITORCONFIG_FILES := templates .github/workflows options/locale/locale_en-US.ini

GO_SOURCES := $(wildcard *.go)
Expand Down Expand Up @@ -407,7 +407,7 @@ lint-actions: ## lint action workflow files

.PHONY: lint-templates
lint-templates: .venv node_modules ## lint template files
@node tools/lint-templates-svg.js
@node tools/lint-templates-svg.ts
@uv run --frozen djlint $(shell find templates -type f -iname '*.tmpl')

.PHONY: lint-yaml
Expand All @@ -421,7 +421,7 @@ watch: ## watch everything and continuously rebuild
.PHONY: watch-frontend
watch-frontend: node-check node_modules ## watch frontend files and continuously rebuild
@rm -rf $(WEBPACK_DEST_ENTRIES)
NODE_ENV=development pnpm exec webpack --watch --progress
NODE_ENV=development pnpm exec webpack --watch --progress --disable-interpret

.PHONY: watch-backend
watch-backend: go-check ## watch backend files and continuously rebuild
Expand Down Expand Up @@ -877,13 +877,13 @@ $(WEBPACK_DEST): $(WEBPACK_SOURCES) $(WEBPACK_CONFIGS) pnpm-lock.yaml
@$(MAKE) -s node-check node_modules
@rm -rf $(WEBPACK_DEST_ENTRIES)
@echo "Running webpack..."
@BROWSERSLIST_IGNORE_OLD_DATA=true pnpm exec webpack
@BROWSERSLIST_IGNORE_OLD_DATA=true pnpm exec webpack --disable-interpret
@touch $(WEBPACK_DEST)

.PHONY: svg
svg: node-check | node_modules ## build svg files
rm -rf $(SVG_DEST_DIR)
node tools/generate-svg.js
node tools/generate-svg.ts

.PHONY: svg-check
svg-check: svg
Expand Down Expand Up @@ -922,7 +922,7 @@ generate-gitignore: ## update gitignore files

.PHONY: generate-images
generate-images: | node_modules ## generate images
cd tools && node generate-images.js $(TAGS)
cd tools && node generate-images.ts $(TAGS)

.PHONY: generate-manpage
generate-manpage: ## generate manpage
Expand Down
6 changes: 2 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@
"type": "module",
"packageManager": "[email protected]",
"engines": {
"node": ">= 20.0.0",
"pnpm": ">=10.0.0"
"node": ">= 22.18.0",
"pnpm": ">= 10.0.0"
},
"dependencies": {
"@citation-js/core": "0.7.18",
Expand Down Expand Up @@ -31,7 +31,6 @@
"dropzone": "6.0.0-beta.2",
"easymde": "2.20.0",
"esbuild-loader": "4.3.0",
"fast-glob": "3.3.3",
"htmx.org": "2.0.6",
"idiomorph": "0.7.3",
"jquery": "3.7.1",
Expand Down Expand Up @@ -110,7 +109,6 @@
"stylelint-config-recommended": "17.0.0",
"stylelint-declaration-block-no-ignored-properties": "2.8.0",
"stylelint-declaration-strict-value": "1.10.11",
"stylelint-define-config": "16.22.0",
"stylelint-value-no-unknown-custom-properties": "6.0.1",
"svgo": "4.0.0",
"type-fest": "4.41.0",
Expand Down
17 changes: 0 additions & 17 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 3 additions & 5 deletions stylelint.config.js → stylelint.config.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,13 @@
// @ts-check
import {defineConfig} from 'stylelint-define-config';
import {fileURLToPath} from 'node:url';
import type {Config} from 'stylelint';

const cssVarFiles = [
fileURLToPath(new URL('web_src/css/base.css', import.meta.url)),
fileURLToPath(new URL('web_src/css/themes/theme-gitea-light.css', import.meta.url)),
fileURLToPath(new URL('web_src/css/themes/theme-gitea-dark.css', import.meta.url)),
];

export default defineConfig({
export default {
extends: 'stylelint-config-recommended',
reportUnscopedDisables: true,
reportNeedlessDisables: true,
Expand Down Expand Up @@ -124,7 +123,6 @@ export default defineConfig({
'csstools/value-no-unknown-custom-properties': [true, {importFrom: cssVarFiles}],
'declaration-block-no-duplicate-properties': [true, {ignore: ['consecutive-duplicates-with-different-values']}],
'declaration-block-no-redundant-longhand-properties': [true, {ignoreShorthands: ['flex-flow', 'overflow', 'grid-template']}],
// @ts-expect-error - https://github.com/stylelint-types/stylelint-define-config/issues/1
'declaration-property-unit-disallowed-list': {'line-height': ['em']},
'declaration-property-value-disallowed-list': {'word-break': ['break-word']},
'font-family-name-quotes': 'always-where-recommended',
Expand All @@ -148,4 +146,4 @@ export default defineConfig({
'shorthand-property-no-redundant-values': true,
'value-no-vendor-prefix': [true, {ignoreValues: ['box', 'inline-box']}],
},
});
} satisfies Config;
13 changes: 7 additions & 6 deletions tailwind.config.js → tailwind.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,18 @@ import {readFileSync} from 'node:fs';
import {env} from 'node:process';
import {parse} from 'postcss';
import plugin from 'tailwindcss/plugin.js';
import type {Config} from 'tailwindcss';

const isProduction = env.NODE_ENV !== 'development';

function extractRootVars(css) {
function extractRootVars(css: string) {
const root = parse(css);
const vars = new Set();
const vars = new Set<string>();
root.walkRules((rule) => {
if (rule.selector !== ':root') return;
rule.each((decl) => {
if (decl.value && decl.prop.startsWith('--')) {
vars.add(decl.prop.substring(2));
rule.each((node) => {
if (node.type === 'decl' && node.value && node.prop.startsWith('--')) {
vars.add(node.prop.substring(2));
}
});
});
Expand Down Expand Up @@ -120,4 +121,4 @@ export default {
});
}),
],
};
} satisfies Config;
16 changes: 7 additions & 9 deletions tools/generate-images.js → tools/generate-images.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,7 @@ import {optimize} from 'svgo';
import {readFile, writeFile} from 'node:fs/promises';
import {argv, exit} from 'node:process';

function doExit(err) {
if (err) console.error(err);
exit(err ? 1 : 0);
}

async function generate(svg, path, {size, bg}) {
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')) {
Expand All @@ -19,7 +14,9 @@ async function generate(svg, path, {size, bg}) {
'removeDimensions',
{
name: 'addAttributesToSVGElement',
params: {attributes: [{width: size}, {height: size}]},
params: {
attributes: [{width: String(size)}, {height: String(size)}],
},
},
],
});
Expand Down Expand Up @@ -57,7 +54,8 @@ async function main() {
}

try {
doExit(await main());
await main();
} catch (err) {
doExit(err);
console.error(err);
exit(1);
}
48 changes: 25 additions & 23 deletions tools/generate-svg.js → tools/generate-svg.ts
Original file line number Diff line number Diff line change
@@ -1,27 +1,29 @@
#!/usr/bin/env node
import fastGlob from 'fast-glob';
import {optimize} from 'svgo';
import {parse} from 'node:path';
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 * as fs from 'node:fs';
import type {Manifest} from 'material-icon-theme';

const glob = (pattern) => fastGlob.sync(pattern, {
cwd: fileURLToPath(new URL('..', import.meta.url)),
absolute: true,
});
const glob = (pattern: string) => globSync(pattern, {cwd: dirname(import.meta.dirname)});

async function processAssetsSvgFile(file, {prefix, fullName} = {}) {
type Opts = {
prefix?: string,
fullName?: string,
};

async function processAssetsSvgFile(path: string, {prefix, fullName}: Opts = {}) {
let name = fullName;
if (!name) {
name = parse(file).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(file, 'utf8'), {
const {data} = optimize(await readFile(path, 'utf8'), {
plugins: [
{name: 'preset-default'},
{name: 'removeDimensions'},
Expand All @@ -41,33 +43,33 @@ async function processAssetsSvgFile(file, {prefix, fullName} = {}) {
await writeFile(fileURLToPath(new URL(`../public/assets/img/svg/${name}.svg`, import.meta.url)), data);
}

function processAssetsSvgFiles(pattern, opts) {
return glob(pattern).map((file) => processAssetsSvgFile(file, opts));
function processAssetsSvgFiles(pattern: string, opts: Opts = {}) {
return glob(pattern).map((path) => processAssetsSvgFile(path, opts));
}

async function processMaterialFileIcons() {
const files = glob('node_modules/material-icon-theme/icons/*.svg');
const svgSymbols = {};
for (const file of files) {
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(file, 'utf8'), {
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(file).name;
const svgName = parse(path).name;
// intentionally use single quote here to avoid escaping
svgSymbols[svgName] = data.replace(/"/g, `'`);
}
fs.writeFileSync(fileURLToPath(new URL(`../options/fileicon/material-icon-svgs.json`, import.meta.url)), JSON.stringify(svgSymbols, null, 2));
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)));
const vscodeExtensions = JSON.parse(vscodeExtensionsJson);
const iconRulesJson = await readFile(fileURLToPath(new URL(`../node_modules/material-icon-theme/dist/material-icons.json`, import.meta.url)));
const iconRules = JSON.parse(iconRulesJson);
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:
Expand All @@ -91,7 +93,7 @@ async function processMaterialFileIcons() {
}
}
const iconRulesPretty = JSON.stringify(iconRules, null, 2);
fs.writeFileSync(fileURLToPath(new URL(`../options/fileicon/material-icon-rules.json`, import.meta.url)), iconRulesPretty);
writeFileSync(fileURLToPath(new URL(`../options/fileicon/material-icon-rules.json`, import.meta.url)), iconRulesPretty);
}

async function main() {
Expand Down
7 changes: 3 additions & 4 deletions tools/lint-templates-svg.js → tools/lint-templates-svg.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,18 @@
#!/usr/bin/env node
import {readdirSync, readFileSync} from 'node:fs';
import {readdirSync, readFileSync, globSync} from 'node:fs';
import {parse, relative} from 'node:path';
import {fileURLToPath} from 'node:url';
import {exit} from 'node:process';
import fastGlob from 'fast-glob';

const knownSvgs = new Set();
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 fastGlob.sync(fileURLToPath(new URL('../templates/**/*.tmpl', import.meta.url)))) {
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)) {
Expand Down
1 change: 1 addition & 0 deletions tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
"types": [
"vitest/globals",
"./web_src/js/globals.d.ts",
"./types.d.ts",
],
}
}
9 changes: 9 additions & 0 deletions types.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
declare module 'add-asset-webpack-plugin' {
const plugin: any;
export = plugin
}

declare module '@techknowlogick/license-checker-webpack-plugin' {
const plugin: any;
export = plugin
}
Loading