The API endpoint POST /releases/{id}/assets bypasses CreateRelease
and UpdateRelease, so checksums were not generated for API uploads.
Added GenerateReleaseChecksums call after successful asset upload.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
When a release is created or updated with attachments, automatically
compute SHA256 checksums for every file and attach a checksums.sha256
manifest file. The manifest follows the standard sha256sum format:
<hash> <filename>
Existing checksums.sha256 files are replaced when attachments change.
Checksums are generated for both CreateRelease and UpdateRelease flows.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The update checker now emails the first admin user when a new version
is found on the configured channel. Notifications are deduplicated —
only sent once per new version, not on every cron tick.
- Added NotifyFunc callback in updatechecker module
- Wired to mailer in cron task registration
- Created mail_update.go with plain-text email including version,
channel, release URL, and docker pull command
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add a dropdown on the admin dashboard to switch between update streams
(stable, rc, beta, alpha, development) matching the Joomla pattern.
Changes:
- Admin dashboard shows channel selector with descriptions
- POST handler validates and applies channel change in-memory
- Triggers immediate re-check against updates.xml after switch
- updates.xml has all 5 standard channels with descriptions
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Matches the Joomla update server pattern used across all Moko repos.
Removed the non-standard 'security' channel. All five standard
channels now present in updates.xml.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Rename the Go module path from code.gitea.io/gitea to
git.mokoconsulting.tech/MokoConsulting/MokoGitea across the entire
codebase.
Scope:
- go.mod module declaration
- 2,235 Go source files (import paths)
- Dockerfile WORKDIR and COPY paths
- Swagger API templates
- golangci.yml linter config
External dependencies (code.gitea.io/gitea-vet, code.gitea.io/sdk/gitea,
gitea.com/gitea/act, etc.) are intentionally NOT renamed — they are
separate upstream modules.
Closes#132
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The Python heredoc couldn't access shell-local API variable.
Move it to step-level env so os.environ sees it.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The previous workflow had raw XML in bash heredocs that broke the
YAML parser during workflow discovery, causing Gitea to silently
skip the entire workflow.
Fix: all XML generation and API calls now use Python heredocs
(<<'PYEOF') which don't contain characters that confuse the YAML
parser. All github context values passed via env vars instead of
inline expressions in run blocks.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Gitea Actions doesn't reliably evaluate the branches: filter on
pull_request events, causing the workflow to never trigger. Replaced
with a step-level guard that checks github.base_ref at runtime.
Also fixed:
- XML insertion using sed 'e' command instead of shell interpolation
- RC entry removal using Python regex for reliability
- Simplified API URL construction
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Gitea Actions may not evaluate github.event.pull_request.draft
correctly, preventing the workflow from triggering entirely.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Gitea Actions may not evaluate github.event.pull_request.draft
correctly, preventing the workflow from triggering entirely.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Fix missing https:// protocol in pr-rc-release.yml API URL
- Update comment to remove stale fan-out reference
- Add comprehensive CHANGELOG entry for v1.26.1-moko.04.00.00 release
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
When a PR is opened or updated against main:
- Determines RC version from updates.xml base + PR number
- Creates/updates a prerelease on Gitea tagged as v1.26.1-moko.{version}-rc.{PR#}
- Updates updates.xml with RC channel entry pointing to the PR
Admins on the RC update channel will see the PR build as an available
update, matching the Joomla update server pattern.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Replace JSON API-based update checking with Joomla-style updates.xml
that supports multiple update streams (stable, dev, security).
Changes:
- Add updates.xml at repo root with stable/dev/security channels
following the same XML structure as MokoOnyx and other Joomla repos
- Rewrite updatechecker module to parse XML with channel filtering
- Add CHANNEL setting to [update_checker] config (default: stable)
- Show channel name and docker pull command in admin dashboard banner
Config example:
[update_checker]
ENABLED = true
CHANNEL = stable
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The upstream reading permission fix (#37781) refactored Repository
to have direct IsAdmin/CanWrite/CanRead methods, but our fork's
Repository struct still uses the Permission field for these.
Keep the new CheckTokenScopes function but use ctx.Repo.Permission.*
for the middleware functions.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Update deploy workflow description to reflect new versioning scheme:
v{upstream}-moko.{major}.{minor}.{patch} (e.g. v1.26.1-moko.04.00.00)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Remove .mod -> AMPL mapping from conflictingExtLangMap (AMPL lexer
doesn't exist in chroma v2.23.1, causing a panic when viewing .mod
files). Upstream doesn't have this mapping either.
- Update 500 error page issue link to MokoGitea repo
- Update home page install/license links to MokoGitea repo
- Update theme settings link to MokoGitea repo
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This PR hardens artifact URL signing by encoding signature inputs in an
unambiguous binary payload before computing the HMAC.
What it changes:
- replace direct concatenation-style signing inputs with explicit
payload builders
- encode string fields with a length prefix before appending their bytes
- encode integer fields as fixed-width binary values instead of decimal
text
- apply the same hardening to both:
- Actions Artifact V4 signing in `routers/api/actions/artifactsv4.go`
- artifact download signing in `routers/api/v1/repo/action.go`
- add regression tests that verify distinct field combinations produce
distinct payloads and signatures
Why:
The previous signing logic built HMAC inputs by appending multiple
fields without a strongly structured representation. That kind of
construction can create ambiguity at field boundaries, where different
parameter combinations may serialize into the same byte stream for
signing.
This change removes that ambiguity by constructing a deterministic
payload format with explicit boundaries between fields.
Backport #37707
Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
Co-authored-by: silverwind <me@silverwind.io>
Co-authored-by: Claude (Opus 4.7) <noreply@anthropic.com>
backport #37118
This PR closes remaining `public-only` token gaps in the API by making
the restriction apply consistently across repository, organization,
activity, notification, and authenticated `/api/v1/user/...` routes.
Previously, `public-only` tokens were still able to:
- receive private results from some list/search/self endpoints,
- access repository data through ID-based lookups,
- and reach several authenticated self routes that should remain
unavailable for public-only access.
This change treats `public-only` as a cross-cutting visibility boundary:
- list/search endpoints now filter private resources consistently,
- repository lookups enforce the same restriction even when addressed
indirectly,
- and self routes that inherently expose or mutate private account state
now reject `public-only` tokens.
---
Generated by a coding agent with Codex 5.2
Co-authored-by: silverwind <me@silverwind.io>
Co-authored-by: Claude (Opus 4.7) <noreply@anthropic.com>
Co-authored-by: Nicolas <bircni@icloud.com>
Backport #37704
This PR hardens OAuth token exchange validation by binding exchanged
credentials to the client and redirect URI that originally obtained
them.
What it changes:
- reject refresh token exchanges when the refresh token belongs to a
different OAuth application
- reject authorization code exchanges when the `redirect_uri` in the
token request differs from the `redirect_uri` stored with the
authorization code
- add integration coverage for:
- authorization code exchange with a mismatched redirect URI
- refresh token reuse across two different dynamically created OAuth
applications
Why:
OAuth authorization codes and refresh tokens must remain bound to the
client context that originally received them. Without those checks:
- a valid authorization code can be redeemed against a different
registered redirect URI of the same client
- a refresh token can be replayed by a different OAuth client
---------
Co-authored-by: Nicolas <bircni@icloud.com>
Backport #37706
This PR tightens several OAuth validation paths related to PKCE
handling, redirect URI normalization, and refresh-token replay safety.
What it changes:
- switch redirect URI comparison to ASCII-only normalization for
exact-match checks, avoiding Unicode case-folding surprises
- harden PKCE verification by:
- allowing PKCE omission only when no challenge data was stored
- rejecting exchanges with a missing verifier when PKCE was used
- rejecting malformed challenge state where a challenge exists without a
valid method
- comparing derived challenges with constant-time string matching
- make refresh-token invalidation counter updates conditional on the
previously observed counter value, so stale refresh state cannot be
accepted after the grant changes
Why:
These checks close gaps where:
- redirect URI comparisons could rely on broader Unicode normalization
than intended
- malformed or incomplete PKCE state could be treated too permissively
- concurrent or stale refresh-token use could advance the same grant
more than once
Co-authored-by: silverwind <me@silverwind.io>
Co-authored-by: Claude (Opus 4.7) <noreply@anthropic.com>
Co-authored-by: Nicolas <bircni@icloud.com>
Backport #37695 by @lunny
This PR fixes two permission-checking gaps in Git and LFS request
handling.
## What it changes
- keep wiki Git HTTP pushes on the normal write-permission path, even
when proc-receive support is enabled
- revalidate LFS bearer token requests against the current user state
and current repository permissions before allowing access
- add regression coverage for unauthorized wiki HTTP pushes
- add LFS tests for blocked users, revoked repository access, read-only
upload attempts, and valid write access
## Why
- wiki repositories should not inherit the relaxed refs/for handling
used for normal code repositories
- LFS authorization tokens should not remain usable after a user is
disabled or loses repository access
---------
Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
Backport of #37662.
---
This PR was written with the help of Claude Opus 4.7
---------
Co-authored-by: Giteabot <teabot@gitea.io>
Co-authored-by: Claude (Opus 4.7) <noreply@anthropic.com>
Adds a scheduled workflow that runs daily at 08:00 UTC to automatically
detect new bug fixes merged into upstream Gitea's release/v1.26 branch
and create corresponding issues in the MokoGitea tracker.
The workflow:
- Queries GitHub Search API for recently merged fix/security PRs
- Cross-references against existing MokoGitea issues to avoid duplicates
- Creates labeled issues (type: bug, upstream, priority, security)
- Supports manual dispatch with configurable lookback period
Requires secrets: GH_TOKEN (GitHub), GITEA_TOKEN (MokoGitea)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The runs_list.tmpl used old class names (flex-list, flex-item,
flex-item-leading, flex-item-main, flex-item-trailing, flex-item-title,
flex-item-body) that no longer exist in the CSS. The shared flex-list
stylesheet was refactored to use flex-divided-list, items-with-main,
item, item-leading, item-main, item-trailing, item-title, item-body.
Without matching CSS, the Actions runs list lost all flex layout — items
were not displayed as proper rows.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
InsertRun passed nil for the attempt parameter to
EvaluateRunConcurrencyFillModel, which then dereferenced the nil
pointer at concurrency.go:39 when writing ConcurrencyGroup and
ConcurrencyCancel fields. This caused a server panic whenever a PR was
created via the API on a repo with workflow-level concurrency
configured.
The fix:
- Creates an ActionRunAttempt struct in InsertRun before calling
EvaluateRunConcurrencyFillModel, and reuses it for
PrepareToStartRunWithConcurrency
- Updates EvaluateRunConcurrencyFillModel to write concurrency fields
to both the run (for DB persistence) and the attempt (for in-memory
concurrency checks), with a nil guard on the attempt
- Fixes TestEvaluateRunConcurrency_RunIDFallback which had the wrong
argument count and was not testing the attempt path
Closes#136
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Fixes nil pointer dereference in BulkSetIssueAssignees — the issue's
Repo field must be loaded before UpdateAssignees calls CanAssignTo.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add four new API endpoints under /repos/{owner}/{repo}/issues/bulk/ for
performing batch operations across multiple issues in a single request.
Each endpoint returns a partial-failure result with per-issue success/failure.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Restore original modules/badge/badge.go (upstream) and adapt our
presets to use GenerateBadge() and the existing Badge type.
- Rename Generate → GenerateRepoBadge to avoid conflict
- Add FormatRepoBadgeSVG for SVG rendering
- Add RenderFlat/RenderFlatSquare methods on Badge
- Fix API handler to use new function names
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- GetLatestCommitStatus takes db.ListOptions not int
- Use GetRepoLicenses() instead of non-existent repo.License field
- Use repo.Topics instead of repo.HasWiki() (not a method)
- licenseBadge now takes ctx parameter
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add test workflow and issue template under .mokogitea/ to verify
the dot-folder feature works end-to-end on the live server.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Extend the existing /metrics endpoint with 3 new application metrics:
- gitea_active_users_30d: users active in last 30 days
- gitea_actions_queue_length: pending action jobs
- gitea_actions_running_jobs: currently running jobs
No new dependencies — extends existing collector and statistic model.
Closes#42
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Replace removed upstream Gitea update checker with MokoGitea-native
version that checks our own releases API.
- New module: modules/updatechecker/ — fetches latest release from
git.mokoconsulting.tech, compares semver, caches result
- Cron task: runs every 24h (and at startup)
- Admin dashboard: shows green banner when update available
- Configurable via [update_checker] in app.ini
Closes#74
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Updated deploy workflow:
- Builds image, pushes to git.mokoconsulting.tech container registry
- Supports dev and production environments via input selector
- Tags: v1.26.1-moko.N (production) or v1.26.1-moko.N-dev (dev)
- Always pushes :latest alongside versioned tag
- Images pullable from any machine via docker pull
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add ChaCha8-based fast crypto random functions required by the
TemplateContext.CspScriptNonce() method for Content-Security-Policy
nonce generation. ~20x faster than crypto/rand for session IDs.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Restore context_template.go from commit 82bfde2a37 which added:
- ScriptImport() — generates script tags with CSP nonces
- CspScriptNonce() — generates per-request nonces
- HeadMetaContentSecurityPolicy() — CSP meta header
- CurrentWebBanner() — web banner support
- globalVars — cached script import configuration
These methods were missing from our manual TemplateContext definition,
causing "ScriptImport is not a method" runtime template errors.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Minimal dep additions using targeted go get, NOT go mod tidy.
Only adds modernc.org/sqlite v1.20.4 and github.com/getkin/kin-openapi
v0.138.0 with their transitive deps. No existing deps modified.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The project API endpoints (ListProjects, CreateProject, etc.) were
added to the router but their handler implementations don't exist.
Comment out until implementations are available.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Fix all 9 remaining files with CurrentRefSubURL field name
- Fix unused 'attempt' variable in action.go
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- gocron v2.19.1 uses LastRun() not LastRunStartedAt()
- renderhelper.RepoFileOptions uses CurrentRefPath not CurrentRefSubURL
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The full go mod tidy upgraded gocron, renderhelper, and other deps
to incompatible versions. Revert to the original go.mod and add
ONLY modernc.org/sqlite v1.20.4 via targeted go get.
Verified: go build -tags 'bindata timetzdata' ./... compiles clean.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Run go mod tidy on server (golang:1.26-alpine) to properly resolve
all transitive deps for modernc.org/sqlite and other indirect
requirements. This ensures go generate and go build work without
needing go mod tidy in the Dockerfile.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Verified: go build ./... succeeds on the server with current go.mod.
The go mod tidy was upgrading dependencies to incompatible versions,
causing all the TemplateContext/convert/concurrency errors. The
go.mod is now correct as-is.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Fix ToActionWorkflowRun calls in routers and services/actions
- Fix PrepareToStartRunWithConcurrency 3-value return + type mismatch
- Fix PrepareToStartJobWithConcurrency 3-value return in run.go
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Add ConcurrencyGroup and ConcurrencyCancel fields to ActionRun
- Add GetConcurrentRunsAndJobs query function
- Fix PrepareToStartJobWithConcurrency 3-value return
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Replace 9 more files still using gitea.com/gitea/runner/act/model
with github.com/nektos/act/pkg/model (resolved via replace directive)
- Fix ToActionWorkflowRun call: args were (ctx, run, nil) but
signature is (ctx, repo, run)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- structs is imported as 'api' — use api.UserVisibility, api.AccessLevelName
- Fix remaining t.Message on line 731 (sed missed non-parenthesized usage)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The type was used throughout services/context but never defined —
likely lost during upstream merge. It's a map[string]any that
implements context.Context.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The go generate step needs all deps resolved including indirect ones
(modernc.org/sqlite). Running go mod tidy after COPY resolves them.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The gitea.com/gitea/runner module path doesn't match its actual module
declaration (gitea.com/gitea/act_runner) and has version compatibility
issues. Switch imports to github.com/nektos/act which is already
replaced by gitea.com/gitea/act v0.261.10 in go.mod — same packages,
proven compatible.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The module at gitea.com/gitea/runner declares itself as
gitea.com/gitea/act_runner. Add replace to map the import path.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add missing dependencies directly to go.mod instead of relying on
go mod tidy (which pulls incompatible transitive dep upgrades):
- gitea.com/gitea/runner v0.4.1 (for act/workflowpattern imports)
- modernc.org/sqlite v1.20.4 (implicit import from models/auth)
Remove go mod tidy from Dockerfile to prevent version drift.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Add .gitea/workflows/deploy-mokogitea.yml (SSH to server, docker build)
- Custom Moko Consulting logo on home/login page
- Dockerfile: add go mod tidy for missing deps, GOFLAGS=-p 1 for OOM
Reverts the src/ reorganization — Go code stays at root per standard
Go module conventions. All .mokogitea dot-folder support retained.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
MokoGitea now recognizes .mokogitea/ as a first-class directory for:
- Workflow files (.mokogitea/workflows/) with highest priority
- README rendering from .mokogitea/ directory
- Repository template files (.mokogitea/template)
- Vendor path exclusion
The .gitea and .github directories remain supported for compatibility.
Authored-by: Moko Consulting
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The merge conflict resolution incorrectly kept @deltablot/dropzone
imports instead of upstream's dropzone package, causing vite build
failure on unresolved import.
Authored-by: Moko Consulting
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Another merge conflict artifact — function existed but wasn't exported,
causing the vite build to fail on missing export.
Authored-by: Moko Consulting
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Fix duplicated isGiteaError export in errors.ts and add missing
refissue.ts from v1.26.1 merge.
Authored-by: Moko Consulting
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
When viewing repo-level Actions secrets or variables, also display
inherited org-level entries as read-only with an "overridden by
repository" badge when a repo entry shadows an org entry. Includes
a link to org settings for management.
Closes#78
Authored-by: Moko Consulting
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Merges 356 commits from upstream Gitea v1.26.1 (bugfix release).
Resolved conflicts in templates by keeping our HelpURL changes,
all other conflicts resolved by taking upstream.
Closes#70
Authored-by: Moko Consulting
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Remove upstream Gitea update checker, replace all docs.gitea.com references
with configurable HelpURL, rebrand default APP_NAME to MokoGitea, enforce
dot-prefixed repo privacy at creation time (create, fork, push-create), and
add system repo explanation in settings UI.
Closes#75, closes#76
Authored-by: Moko Consulting
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Repositories with names starting with "." are now treated as system
repositories that are always private and cannot be made public. This is
enforced at every code path: API create, web create, migrate, template
create, push-to-create, API edit, web settings, and public access
settings. On creation paths, privacy is silently forced. On edit paths,
a clear error is returned.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Add HELP_URL and SUPPORT_URL settings to app.ini (defaults to docs.gitea.com)
- Replace hardcoded docs.gitea.com in navbar with configurable HelpURL
- Expose HelpURL/SupportURL template functions
- Show Help URL and Support URL in Site Admin > Configuration
- Add locale strings for new admin config entries
- Create VERSION file (gitignored) for local builds with 1261.0.0 convention
The 1261.xx.xx version convention marks the fork starting point from
upstream Gitea. Set via VERSION file locally or GITEA_VERSION env in CI.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add organization-scoped branch protection rules that cascade to all
repos within the org. Repo-level rules take precedence; org rules
serve as the fallback when no repo rule matches a branch.
- New table: org_protected_branch (migration v332)
- OrgProtectedBranch model with full CRUD operations
- API endpoints: GET/POST/PATCH/DELETE /api/v1/orgs/{org}/branch_protections
- Inheritance via GetFirstMatchProtectedBranchRule() fallback
- InheritedFrom field added to BranchProtection API response
- Org rules use team-based whitelists (no per-user IDs at org level)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- make `scale-unlimited/declaration-strict-value` cover fill and stroke
- add new color vars for color series in gitgraph
- move most rule disablement to per-line
- remove dead highlight colors since https://github.com/go-gitea/gitea/pull/34948
- move stylelint config to ts now that the linked issue is fixed
Co-authored-by: Claude (Opus 4.7) <noreply@anthropic.com>
When a workflow job failed, the API response reported all steps as
failed — even steps that had completed successfully before the failing
step. `ToActionWorkflowJob` was calling `ToActionsStatus(job.Status)`
for every step instead of `ToActionsStatus(step.Status)`, so the job's
overall conclusion was propagated to each step.
Each `ActionTaskStep` has its own `Status` field that tracks the actual
outcome of that step independently of the job result.
---------
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
fixes adding collaborative owners in Actions settings when the user or
organization name contains capital letters.
Fixes#37548
---------
Signed-off-by: wxiaoguang <wxiaoguang@gmail.com>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
## Issue
Closes#37217
The error string was getting lost while returning due to `ctx.JSON()`
which cannot serialize the `error` object.
## Fix
Use `ctx.APIError()` to return proper error messages back to the client.
## The issue
Closes#37568. Basically due to empty fields being present in the
actions file, the jobs would be produced as `nil` inside `jobparser.go`
. Because of this when we call `Parse` on the `jobparser` module.
```go
Needs: job.Needs(),
```
would propagate the `nil` job down the chain.
## The fix
For now i decide to fix it by guarding with an `if job == nil` check.
---------
Signed-off-by: wxiaoguang <wxiaoguang@gmail.com>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com>
Co-authored-by: Giteabot <teabot@gitea.io>
1. Sync `RENOVATE_ALLOWED_POST_UPGRADE_COMMANDS` with the recent
`renovate.json5` change (#37537) — the npm group now runs `make svg
nolyfill`, but the workflow allowlist still only matched `^make
(tidy|svg)$`, so the post-upgrade task was being rejected.
2. Bump the cron from daily at 01:00 UTC to hourly at :23, matching the
cadence of Mend's hosted Renovate App. Hourly gives sub-hour
responsiveness to dependency-dashboard checkbox interactions and
PR-close reactions; the `:23` offset avoids the GHA scheduler congestion
at multiples of 15.
Co-authored-by: Claude (Opus 4.7) <noreply@anthropic.com>
## Summary
- Enforce **Conventional Commits** on PR titles (PRs are squash-merged,
so the PR title becomes the final commit message).
- Add a local `make lint-pr-title` target so contributors can validate
titles before pushing.
## Why
We squash-merge PRs, which means the final repository history is largely
shaped by **PR titles**. Enforcing a consistent Conventional Commits
format makes:
- **Release notes & changelogs easier to generate** (types like `feat` /
`fix` can be grouped automatically).
- **History easier to scan** (uniform structure, optional scopes,
explicit breaking changes via `!`).
- **Automation more reliable** (future tooling can infer category and
scope from the title).
## PR title format
```text
type(scope)!: subject
type: one of build|chore|ci|docs|feat|fix|perf|refactor|revert|style|test
scope: optional (e.g. web, api, actions, repo, …)
!: optional, indicates a breaking change
subject: short, imperative, no trailing period
```
## Examples
```text
feat(web): add dark mode toggle
fix(api): avoid panic when repo is missing
chore(ci): lint PR titles with commitlint
refactor(templates): reduce duplication in repo list rendering
feat!: remove legacy OAuth endpoint
```
## Local testing
```text
make deps-frontend
make lint-pr-title PR_TITLE="feat(web): add dark mode toggle"
```
---------
Signed-off-by: Nicolas <bircni@icloud.com>
Co-authored-by: nb <nb@users.noreply.local>
Co-authored-by: GPT-5.2 <gpt-5.2@openai.com>
1. Fix ugly commit form "warning" message
2. Use JSONError for "Update PR Branch" response
3. Remove useless "timeline" class
4. Make timeline review default to "comment" to avoid icon missing
5. Align PR's "command line instructions" UI
6. Simply "Update PR branch" button logic
And then some TODOs are fixed.
---------
Signed-off-by: wxiaoguang <wxiaoguang@gmail.com>
Docs polish — pure typo fixes, nothing under `src/`.
## Files
- `CHANGELOG.md`
- line 1386: `appearence` → `appearance`
- line 2117: `succesfully` → `successfully`
- line 2301: `preceeded` → `preceded`
- line 5593: `paramater` → `parameter`
Fixes were applied from a curated correction list, with code blocks /
inline code / URLs left alone.
Run `nolyfill` as a renovate post-upgrade step alongside `make svg`, so
npm dep bumps keep `pnpm.overrides` in sync.
---
This PR was written with the help of Claude Opus 4.7
---------
Signed-off-by: silverwind <me@silverwind.io>
Co-authored-by: Claude (Opus 4.7) <noreply@anthropic.com>
Almost done
`pull_merge_box.tmpl` only has about 80 lines now, and (almost) all
variable accesses are strictly typed.
---------
Co-authored-by: silverwind <me@silverwind.io>
Co-authored-by: Claude (Opus 4.7) <noreply@anthropic.com>
Co-authored-by: Nicolas <bircni@icloud.com>
Fixes#37446.
The job-status resolver in `checkJobsOfCurrentRunAttempt` only
considered `needs` and job-level concurrency when transitioning jobs out
of `Blocked`. When something drove the resolver against a run blocked
solely by workflow-level concurrency — for example, a sibling run in the
same group entering the queue and triggering `EmitJobsIfReadyByRun` —
the run's job silently became `Waiting` while another run still held the
concurrency group, and the runner could pick it up, defeating the
concurrency guarantee.
The fix bails out of the resolver when the run's latest attempt is still
blocked by run-level concurrency. `checkRunConcurrency` re-evaluates
when the holding run finishes.
Covered by a unit test
(`Test_checkJobsOfCurrentRunAttempt_RunLevelConcurrencyKeepsJobsBlocked`
in `services/actions/job_emitter_test.go`) that sets up a Running holder
attempt and a Blocked sibling attempt in the same concurrency group
directly in the DB, calls `checkJobsOfCurrentRunAttempt`, and asserts
the blocked job stays `Blocked`. Fails on master, passes with the fix.
---
This PR was written with the help of Claude Opus 4.7
---------
Co-authored-by: Claude (Opus 4.7) <noreply@anthropic.com>
The migration repository model now carries Website alongside Description, the GitHub/Gitea downloaders populate it, and mirror finalization persists both description and website so the About section is not empty after creating a mirror.
Fixes#37495
---------
Signed-off-by: cyphercodes <cyphercodes@users.noreply.github.com>
Co-authored-by: cyphercodes <cyphercodes@users.noreply.github.com>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
Purpose:
1. Make the whole code base have unified "item" layout
2. Clarify our "list" styles: "flex-relaxed-list", "flex-divided-list"
3. Prepare to replace legacy "ui relaxed list"
* https://github.com/go-gitea/gitea/pull/37445#discussion_r3144458865
4. Prepare for refactoring the "pull merge box", it needs the
"flex-divided-list"
* related to "Refactor pull request view (*)" like #37451
5. Fix legacy abuses of "flex-list", e.g.: repo home sidebar
When running `gitea dump` with output routed to stdout (--file -),
deprecation warnings from loadAvatarsFrom were written to stdout,
corrupting the archive stream.
Root cause: PrepareConsoleLoggerLevel (called in app.Before) sets up a
console logger via SetConsoleLogger, which used WriterConsoleOption{}
defaulting Stderr to false (i.e. stdout). This logger is installed
before the dump subcommand can redirect logging to stderr in runDump.
Fix: use WriterConsoleOption{Stderr: true} in SetConsoleLogger so all
early CLI diagnostic output goes to stderr from the start. This is
correct for all subcommands — diagnostic/log output should never pollute
stdout.
---------
Signed-off-by: wxiaoguang <wxiaoguang@gmail.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
Co-authored-by: Nicolas <bircni@icloud.com>
After the Webpack-to-Vite migration (#37002), mCaptcha stopped working
entirely on the registration page, throwing an error:
`TypeError: setting getter-only property "INPUT_NAME"`
This fix stops trying to mutate the read-only INPUT_NAME export. Instead
it probes for the Widget constructor at module.default (direct) or
module.default.default (CJS-wrapped), constructs the widget, and then
renames the hidden input element it creates to m-captcha-response which
is the field name Gitea's backend reads from the submitted form.
Generative AI was used to help with making this PR.
---------
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
Co-authored-by: Giteabot <teabot@gitea.io>
Drops `github.com/olivere/elastic/v7` (unmaintained) and replaces it
with a small in-house wrapper that speaks the Elasticsearch REST API
directly via `net/http`. The subset used by Gitea (`_cluster/health`,
`_bulk`, `_doc`, `_delete_by_query`, `_refresh`, `_search`, `HEAD`/`PUT`
index) is stable across the targeted servers, so no client library is
needed.
**Targets tested**
- Elasticsearch 7, 8, 9
- OpenSearch 1, 2, 3
**Why not `go-elasticsearch`?**
The official client enforces an `X-Elastic-Product` server-identity
check that OpenSearch deliberately fails, which would force shipping a
transport shim to defeat it. Going direct over `net/http` removes that
fight along with several MB of transitive deps (`elastic-transport-go`,
`go.opentelemetry.io/otel{,/metric,/trace}`, `auto/sdk`, `easyjson`,
`intern`, `logr`, `stdr`).
Replaces: #30755
Fixes: https://github.com/go-gitea/gitea/issues/30752
---
This PR was written with the help of Claude Opus 4.7
---------
Co-authored-by: Claude (Opus 4.7) <noreply@anthropic.com>
Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com>
1. Make the content area stretch the box, enabling text selection to
start over empty space.
2. Disable linter for markdown, it can never produce lint errors, this
hides the unnecessary lint gutter on markdown files.
3. Verified all languages linter enablement, all accurate.
4. Refactor `getLinterExtension` to not rely on file extensions.
5. Include jsonc/json5 extensions in regex.
---
This PR was written with the help of Claude Opus 4.7
---------
Co-authored-by: Claude (Opus 4.7) <noreply@anthropic.com>
Co-authored-by: Nicolas <bircni@icloud.com>
Clean up legacy copied&pasted code, introduce the unique "database
connection" function. Move migration testing helper function
PrepareTestEnv to a separate package.
By the way, remove "shadow connection secrets" tricks: showing
connection string on UI is useless
---------
Co-authored-by: Nicolas <bircni@icloud.com>
## Summary
This PR adds support for updating pull mirror authentication via the
repository edit API and UI.
It introduces new mirror authentication fields in _EditRepoOption_,
updates the API logic to safely handle partial credential updates, and
fixes the web settings flow so that the existing remote username is
preserved when only the password is changed.
### What changed
- added _auth_username_, _auth_password_, and _auth_token_ to
EditRepoOption
- updated the repository edit API to apply mirror auth changes via
_updateMirror_
- preserved existing username/password when only part of the auth
payload is provided
- used oauth2 as the default username when _auth_token_ is provided
- kept stored mirror URLs sanitized in DB and API responses
- updated Swagger schema for the new API fields
- added API integration tests for password-only and token-only updates
- added a web settings test to ensure username preservation on partial
updates
## Why
Some use cases require automated synchronization of pull mirrors, for
example in CI/CD pipelines or integrations with external systems.
At the same time, many organizations enforce security policies that
require periodic token rotation (e.g., monthly).
Currently, mirror credentials can only be updated via the UI, which
makes automation difficult.
## This change enables:
- automated token rotation
- avoiding manual updates via the UI
- easier integration with secret management systems
## Testing
- added integration coverage for mirror auth updates via _PATCH
/api/v1/repos/{owner}/{repo}_
- added web settings tests for password-only updates preserving the
existing username
## Result
Ability to automate auth update
<img width="2400" height="1245" alt="1"
src="https://github.com/user-attachments/assets/67fd5cca-9cb3-4536-b0e2-4d09b8ebff0f"
/>
<img width="962" height="932" alt="image"
src="https://github.com/user-attachments/assets/5d548f5d-aadf-4807-ba52-9c29df93a4cc"
/>
Generative AI was used to help with making this PR.
##
1. only trigger docker-dryrun arm64&riscv64 when dockerfile changes
2. de-duplicate "contents: read" permission for most workflows
3. merge various "lint-*" jobs into one job
4. add missing lint targets to the "lint" (all) target
1. Rename CompareInfo.MergeBase to CompareBase, it is not merge base
2. Remove unused template variables `ctx.Data["Username"]` and
`ctx.Data["Reponame"]`
3. Decouple some template variable accesses, use typed struct
---------
Co-authored-by: Nicolas <bircni@icloud.com>
Add a build-time conversion step that transforms the existing Swagger
2.0 spec into an OpenAPI 3.0 spec. The OAS3 spec is served alongside the
existing Swagger 2.0 spec, enabling API clients that require OAS3 to
generate code directly from Gitea's API.
This is not to be an answer to how gitea handles OAS3 long term,
but a way to use what we have to move a step forward.
---------
Signed-off-by: wxiaoguang <wxiaoguang@gmail.com>
Co-authored-by: Claude (Opus 4.7) <noreply@anthropic.com>
Co-authored-by: silverwind <me@silverwind.io>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
Avoid per-item DB queries in ListRuns, ListJobs, and ListActionTasks by
batch-loading trigger users, repositories, and task attributes before
the conversion loop. Remove ReferencesGitRepo from the /actions route
group since no task/run endpoints use it.
Added tests for these endpoints as well.
---------
Signed-off-by: wxiaoguang <wxiaoguang@gmail.com>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
Co-authored-by: silverwind <me@silverwind.io>
Co-authored-by: Claude (Opus 4.7) <noreply@anthropic.com>
Adds a new `DEFAULT_TITLE_SOURCE` option under
`[repository.pull-request]` with three values:
- `first-commit` (default): uses the oldest commit summary, current
behavior since v1.26
- `auto`: normalizes branch name as title for multi-commit PRs (just
like GitHub), use commit summary for single-commit PRs
Closes: #37463
Co-authored-by: silverwind <me@silverwind.io>
Co-authored-by: Claude (Opus 4.7) <noreply@anthropic.com>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
Co-authored-by: Giteabot <teabot@gitea.io>
Co-authored-by: Nicolas <bircni@icloud.com>
This fixes the scheduled action panic when an event payload is JSON
`null` by initializing the payload map before adding `schedule`. It also
adds regression coverage for the null-payload case.
Fixes#37447.
Testing:
- `go test -tags 'sqlite sqlite_unlock_notify' ./services/actions -run
'^TestWithScheduleInEventPayload$' -count=1`
- Local note: this agent ran the command as root with a temporary
`GITEA_TEST_CONF=custom/conf/app-test-root.ini` file that only set
`I_AM_BEING_UNSAFE_RUNNING_AS_ROOT = true`.
Authorship: cyphercodes; AI assistance disclosed: Hermes Agent
(GPT-5.5).
---------
Co-authored-by: cyphercodes <cyphercodes@users.noreply.github.com>
Co-authored-by: Hermes Agent (GPT-5.5) <hermes-agent@users.noreply.github.com>
Co-authored-by: Nicolas <bircni@icloud.com>
Co-authored-by: silverwind <me@silverwind.io>
Co-authored-by: Claude (Opus 4.7) <noreply@anthropic.com>
Co-authored-by: Giteabot <teabot@gitea.io>
After using CSP nonce, the "onerror" doesn't work anymore. Change it to
use a global variable to detect
Also help users like #37379 to catch errors more easily.
Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com>
Make the watch, star, and fork buttons in the repo header consistent for
logged-out users:
- Apply the same look to all three buttons (number labels
included), instead of only the action button being grayed.
- Clicking any of them while logged out now leads to the login page
(with a redirect back) instead of being inert.
- Split the per-button markup out of `header.tmpl` into a dedicated
`templates/repo/header/` folder (`fork.tmpl`, `star.tmpl`,
`watch.tmpl`).
---------
Co-authored-by: Claude (Opus 4.7) <noreply@anthropic.com>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
The `Repository` struct in `services/context/repo.go` embedded
`access_model.Permission` anonymously, causing all permission methods to
be promoted directly onto `Repository`. This made it unclear at call
sites whether a method belonged to `Repository` itself or to its
embedded `Permission`.
### Changes
- **`services/context/repo.go`**: Replace anonymous
`access_model.Permission` with named field `Permission
access_model.Permission`
- **49 files** updated to route permission method calls through the
named field:
```go
// Before
ctx.Repo.IsAdmin()
ctx.Repo.CanWrite(unit.TypeCode)
ctx.Repo.CanReadIssuesOrPulls(isPull)
slices.ContainsFunc(unitTypes, ctx.Repo.CanWrite)
// After
ctx.Repo.Permission.IsAdmin()
ctx.Repo.Permission.CanWrite(unit.TypeCode)
ctx.Repo.Permission.CanReadIssuesOrPulls(isPull)
slices.ContainsFunc(unitTypes, ctx.Repo.Permission.CanWrite)
```
Methods defined directly on `*Repository` (`CanWriteToBranch`,
`CanCreateBranch`, etc.) are unchanged.
---------
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: wxiaoguang <2114189+wxiaoguang@users.noreply.github.com>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com>
Co-authored-by: Nicolas <bircni@icloud.com>
Replaces Dependabot with Renovate. The new setup:
- One PR per ecosystem (GitHub Actions, Go modules + Makefile go-tool
pins, npm, Python via uv, Nix flake), opened weekly on Mondays with a
5-day release-age cooldown. Vulnerability PRs ship next-day via daily
cron + Renovate's `vulnerabilityAlerts` schedule bypass.
- All `uses:` action refs SHA-pinned with patch-level version comments
(same format as #36971, which this supersedes);
`helpers:pinGitHubActionDigests` keeps future bumps in that format.
- `renovatebot/github-action` runtime image pinned via the
upstream-recommended `RENOVATE_VERSION` env + magic comment +
`customManagers:githubActionsVersions` preset, so Renovate keeps the pin
updated.
- Custom regex manager tracks the `*_PACKAGE ?= <import-path>@<version>`
lines in `Makefile` (golangci-lint, swagger, actionlint, etc.) and
groups them into the same Go PR via `matchDatasources: ["go"]`.
- Post-upgrade tasks regenerate `assets/go-licenses.json` (`make tidy`)
and the SVG sprite (`make svg`), gated by an env-level command
allowlist.
- Replaces the standalone `cron-flake-updater` workflow — Renovate's nix
manager tracks `flake.nix` inputs and produces the same `flake.lock`
bump PRs on the regular weekly schedule.
- npm and gomod-replace pins live in `renovate.json5` only;
`updates@17.16.3` reads them from there too, so the standalone
`updates.config.ts` is gone and one source of truth covers both tools.
Fixes: https://github.com/go-gitea/gitea/issues/33386
Signed-off-by: silverwind <me@silverwind.io>
Signed-off-by: TheFox0x7 <thefox0x7@gmail.com>
Co-authored-by: Claude (Opus 4.6) <noreply@anthropic.com>
Co-authored-by: TheFox0x7 <thefox0x7@gmail.com>
Co-authored-by: Nicolas <bircni@icloud.com>
Co-authored-by: Giteabot <teabot@gitea.io>
Cache includes go, lint and unittests. Integration tests with their
standalone binaries are uncacheable with their current architecture.
Every Go job uses a new composite action (`.github/actions/go-cache`)
that restores and saves the Go module cache, a shared build cache, and
the golangci-lint cache. A `cache-seeder` workflow runs on `push: main`
to pre-populate those slots; PRs read them via GitHub's default-branch
fallback, so the common case is warm from the first commit.
Also dropped `-coverprofile` from `test-unit` (it silently disabled Go's
test result cache), and `-race` from `test-pgsql` and `test-mysql` (kept
on `test-unit` and `test-sqlite`).
Signed-off-by: silverwind <me@silverwind.io>
Co-authored-by: Claude (Opus 4.7) <noreply@anthropic.com>
Co-authored-by: Nicolas <bircni@icloud.com>
`make test-sqlite#TestName` was much too slow, suggest `go test`. Also
added a similar instruction for js tests.
Signed-off-by: silverwind <me@silverwind.io>
Co-authored-by: Claude (Opus 4.7) <noreply@anthropic.com>
Co-authored-by: Nicolas <bircni@icloud.com>
Automated changes by the
[update-flake-lock](https://github.com/DeterminateSystems/update-flake-lock)
GitHub Action.
```
Flake lock file updates:
• Updated input 'nixpkgs':
'github:nixos/nixpkgs/4bd9165' (2026-04-14)
→ 'github:nixos/nixpkgs/0726a0e' (2026-04-22)
```
### Running GitHub Actions on this PR
GitHub Actions will not run workflows on pull requests which are opened
by a GitHub Action.
**To run GitHub Actions workflows on this PR, close and re-open this
pull request.**
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com>
- fix markup attention block regressions on 2 colors
- added new color "priority" color for important severity in markup
- all message-box style, and error form elements use monochrome text
- tweaked and improved action logs colors
Co-authored-by: Claude (Opus 4.7) <noreply@anthropic.com>
Backport of #37403 to `release/v1.26`.
The `events › logout propagation` e2e test was racing the SSE connection
setup: if page2's SharedWorker had not finished registering its
messenger by the time page1 triggered logout, the event was silently
dropped and page2 stayed on the authenticated page.
Wait 500ms after verifying page2 is signed in, before triggering the
logout from page1, so the SharedWorker has time to register. Comment
points at a cleaner future fix (expose a ready attribute on the page)
that will also work for the planned WebSocket SharedWorker.
---
This PR was written with the help of Claude Opus 4.7
Co-authored-by: Claude (Opus 4.7) <noreply@anthropic.com>
The `events › logout propagation` e2e test ([example
flake](https://github.com/go-gitea/gitea/actions/runs/24878089698/job/72839454932))
was racing the SSE connection setup: if page2's SharedWorker had not
finished registering its messenger by the time page1 triggered logout,
the event was silently dropped and page2 stayed on the authenticated
page.
Wait 500ms after verifying page2 is signed in, before triggering the
logout from page1, so the SharedWorker has time to register. Comment
points at a cleaner future fix (expose a ready attribute on the page)
that will also work for the planned WebSocket SharedWorker.
---
This PR was written with the help of Claude Opus 4.7
---------
Signed-off-by: wxiaoguang <wxiaoguang@gmail.com>
Co-authored-by: Claude (Opus 4.7) <noreply@anthropic.com>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
Refactor preparePullViewPullInfo and related functions, split them into
small ones:
* preparePullViewPullInfo creates PullRequestViewInfo struct
* if the PR is merged: prepareView**Merged**PullInfo
* if the PR is open: prepareView**Open**PullInfo
In prepareViewMergedPullInfo and preparePullViewFillInfo: call
preparePullView**FillInfo** consistnently
preparePullViewFillInfo calls preparePullViewFill**CompareInfo** and
preparePullViewFill**CommitStatusInfo**
Adds points to `AGENTS.md` how to run single tests because AIs get these
wrong too often (either they trigger the whole suite or run into other
errors).
---
This PR was written with the help of Claude Opus 4.7
---------
Signed-off-by: silverwind <me@silverwind.io>
Co-authored-by: Claude (Opus 4.7) <noreply@anthropic.com>
Removes CSS rules that have zero usages across templates, Go source,
JS/TS/Vue, and `options/`. Each selector was cross-checked for runtime
additions (Fomantic JS, library classes) before removal.
A few rules with no current usages are kept as symmetric pairs of
heavily-used classes likely to be needed:
- `.ui.bottom.attached.header` / `.ui.bottom.attached.message` — pair
with the widely-used `top.attached` variants
- `.ui.warning.header` / `.ui.warning.segment` — warning-themed variants
of error-themed classes that are kept
- `.btn.small` — size variant alongside the kept `.btn.tiny`
---
This PR was written with the help of Claude Opus 4.7
---------
Co-authored-by: Claude (Opus 4.7) <noreply@anthropic.com>
- add pr-review e2e test
- speed up most tests by logging in via POST to avoid the login form,
login form is still exercised in a dedicated test
- speed up most tests be removing post-test cleanup, unnecessary because
each repo is created with a unique name
- misc parallelization and api call reduction
- total suite runtime is about the same as before
---------
Co-authored-by: Claude (Opus 4.7) <noreply@anthropic.com>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
Clean up the fomantic helpers that nothing inside fomantic depends on.
Manually tested all functionality.
---------
Co-authored-by: Claude (Opus 4.7) <noreply@anthropic.com>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
Fast-forward-only creates no Gitea commit, so skip the "can Gitea sign"
precheck for it. Pre-check head-commit verification for styles that
preserve user commits on the target (merge, fast-forward-only) so a PR
with unsigned commits surfaces a localized error instead of a 500 at the
pre-receive hook. The dropdown still shows every configured style; the
avatar and signing warning toggle per selection via
data-pull-merge-style.
Fixes#12272
**Note**: Admin force-merge does not bypass the new head-commits check.
This matches the existing `isSignedIfRequired` behavior.
Signed-off-by: Nikita Vakula <programmistov.programmist@gmail.com>
Signed-off-by: wxiaoguang <wxiaoguang@gmail.com>
Co-authored-by: silverwind <me@silverwind.io>
Co-authored-by: Claude (Opus 4.7) <noreply@anthropic.com>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
This PR introduces a new `ActionRunAttempt` model and makes Actions
execution attempt-scoped.
**Main Changes**
- Each workflow run trigger generates a new `ActionRunAttempt`. The
triggered jobs are then associated with this new `ActionRunAttempt`
record.
- Each rerun now creates:
- a new `ActionRunAttempt` record for the workflow run
- a full new set of `ActionRunJob` records for the new
`ActionRunAttempt`
- For jobs that need to be rerun, the new job records are created as
runnable jobs in the new attempt.
- For jobs that do not need to be rerun, new job records are still
created in the new attempt, but they reuse the result of the previous
attempt instead of executing again.
- Introduce `rerunPlan` to manage each rerun and refactored rerun flow
into a two-phase plan-based model:
- `buildRerunPlan`
- `execRerunPlan`
- `RerunFailedWorkflowRun` and `RerunFailed` no longer directly derives
all jobs that need to be rerun; this step is now handled by
`buildRerunPlan`.
- Converted artifacts from run-scoped to attempt-scoped:
- uploads are now associated with `RunAttemptID`
- listing, download, and deletion resolve against the current attempt
- Added attempt-aware web Actions views:
- the default run page shows the latest attempt
(`/actions/runs/{run_id}`)
- previous attempt pages show jobs and artifacts for that attempt
(`/actions/runs/{run_id}/attempts/{attempt_num}`)
- New APIs:
- `/repos/{owner}/{repo}/actions/runs/{run}/attempts/{attempt}`
- `/repos/{owner}/{repo}/actions/runs/{run}/attempts/{attempt}/jobs`
- New configuration `MAX_RERUN_ATTEMPTS`
- https://gitea.com/gitea/docs/pulls/383
**Compatibility**
- Existing legacy runs use `LatestAttemptID = 0` and legacy jobs use
`RunAttemptID = 0`. Therefore, these fields can be used to identify
legacy runs and jobs and provide backward compatibility.
- If a legacy run is rerun, an `ActionRunAttempt` with `attempt=1` will
be created to represent the original execution. Then a new
`ActionRunAttempt` with `attempt=2` will be created for the real rerun.
- Existing artifact records are not backfilled; legacy artifacts
continue to use `RunAttemptID = 0`.
**Improvements**
- It is now easier to inspect and download logs from previous attempts.
-
[`run_attempt`](https://docs.github.com/en/actions/reference/workflows-and-actions/contexts#github-context)
semantics are now aligned with GitHub.
- > A unique number for each attempt of a particular workflow run in a
repository. This number begins at 1 for the workflow run's first
attempt, and increments with each re-run.
- Rerun behavior is now clearer and more explicit.
- Instead of mutating the status of previous jobs in place, each rerun
creates a new attempt with a full new set of job records.
- Artifacts produced by different reruns can now be listed separately.
Signed-off-by: Zettat123 <zettat123@gmail.com>
Co-authored-by: silverwind <me@silverwind.io>
Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
Co-authored-by: Giteabot <teabot@gitea.io>
Backport #37388 by @wxiaoguang
Fix#27120
By the way, refactor ReserveLineBreakForTextarea to NormalizeStringEOL
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
Backport #37365 by @pisarz77
Fix team members missing from assignee list when `team_unit.access_mode`
is 0 but the doer is owner.
Fix #34871
1. Use `GetTeamUserIDsWithAccessToAnyRepoUnit` for repo assignee list
2. Load assignee list for project issues directly
3. Use `GetTeamUserIDsWithAccessToAnyRepoUnit` for repo reviewer list
Signed-off-by: Jakub Pisarczyk <pisarz77@gmail.com>
Signed-off-by: wxiaoguang <wxiaoguang@gmail.com>
Co-authored-by: pisarz77 <pisarz77@gmail.com>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
Co-authored-by: silverwind <me@silverwind.io>
Co-authored-by: Claude (Opus 4.7) <noreply@anthropic.com>
Fix team members missing from assignee list when `team_unit.access_mode`
is 0 but the doer is owner.
Fix #34871
1. Use `GetTeamUserIDsWithAccessToAnyRepoUnit` for repo assignee list
2. Load assignee list for project issues directly
3. Use `GetTeamUserIDsWithAccessToAnyRepoUnit` for repo reviewer list
Signed-off-by: Jakub Pisarczyk <pisarz77@gmail.com>
Signed-off-by: wxiaoguang <wxiaoguang@gmail.com>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
Co-authored-by: silverwind <me@silverwind.io>
Co-authored-by: Claude (Opus 4.7) <noreply@anthropic.com>
Co-authored-by: Giteabot <teabot@gitea.io>
Fix#36859
Replace live third-party API calls in migration tests with a
fixture-based HTTP mock server. Fixtures are committed so tests run
offline by default; live recording is gated per service on an API-token
env var.
Co-authored-by: Claude (Opus 4.7) <noreply@anthropic.com>
Extend the issue context popup beyond markdown. Any link rendered with
the `ref-issue` class now gets the popup, which covers commit titles and
issue titles everywhere they appear (repo home, commits list, blame,
branches, graph, PR commits, issue/PR pages, compare, …). For surfaces
that synthesize links without markdown autolinking (dashboard activity
feed, pulse page, commit merged-PR line), opt in by adding
`data-ref-issue-container` on a parent (or `ref-issue` on the link).
- Use `html_url` from the backend payload instead of synthesizing links
client-side
- Fetch outside the component, stateless, with a per-URL cache
- Small hover delay so passing over a link doesn't fire a request
- Drop the loading state (shifted layout)
- Make both links in the tooltip work; prevent nested tooltips
- Fix feed title `<a>` width so the tooltip only shows on link hover
Co-authored-by: Claude (Opus 4.6) <noreply@anthropic.com>
Fix#34349
By the way, remove `(ctx *APIContext) HasAPIError() ` and `(ctx
*APIContext) GetErrMsg()` because they do nothing, the error handling
has been done in API's middeware
The existing OAuth2 tests were not quite right, refactored them together
After 07ada3666b, PrepareConsoleLoggerLevel can fail in tests when
InstallLock is true, due to the incorrect config file is loaded. This PR
fixes cmd test setup by mocking builtin paths
Fixes#37368
---------
Co-authored-by: Morgan PEYRE <morgan.peyre@brickcode.tech>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
Upgrade the base devcontainer image to prevent the in-container
toolchain upgrade from breaking `make build`.
Solves #37373
Co-authored-by: Morgan PEYRE <morgan.peyre@brickcode.tech>
Use the new "form-fetch-action" for better user experience, and use
JSONError to show error messages.
---------
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
Backport #37288 by @KalashThakare
## Summary
Fixes#37252
The `/api/v1/repos/{owner}/{repo}/actions/runs` endpoint was returning
`event: "push"` for workflow runs triggered by `schedule:` (cron),
instead
of `event: "schedule"`.
## Root Cause
`ActionRun` has two separate fields:
- `Event` — the workflow registration event (e.g. `push`, set when the
workflow file was first pushed)
- `TriggerEvent` — the actual event that triggered the run (e.g.
`schedule`)
`ToActionWorkflowRun` in `services/convert/action.go` was serializing
`run.Event` into the API response instead of `run.TriggerEvent`, causing
scheduled runs to be indistinguishable from push events via the API.
This was already asymmetric — the tasks/jobs API correctly used
`TriggerEvent`.
## Fix
Changed `ToActionWorkflowRun` to use `run.TriggerEvent` for the `event`
field in the API response, consistent with how the jobs API works.
## Before
`event: "push"` returned for all scheduled runs:
<img width="1112" height="191" alt="Screenshot 2026-04-19 115642"
src="https://github.com/user-attachments/assets/c0a169f5-bbd9-4f5d-9474-e4c3795110e4"
/>
## After
`event: "schedule"` correctly returned for scheduled runs:
<img width="890" height="166" alt="Screenshot 2026-04-19 121723"
src="https://github.com/user-attachments/assets/860e99ac-0935-4a43-86a1-7b60f8113480"
/>
## Testing
- Added unit test `TestToActionWorkflowRun_UsesTriggerEvent` in
`services/convert/action_test.go` that explicitly verifies the API
returns `TriggerEvent` and not `Event` for a scheduled run.
- Manually verified via the API against a live Gitea instance with a
`cron: "* * * * *"` workflow.
Co-authored-by: Kalash Thakare ☯︎ <kalashthakare898@gmail.com>
Co-authored-by: Nicolas <bircni@icloud.com>
This PR simplifies URL validation by removing `IsValidExternalURL` and
`IsAPIURL` from `modules/validation/helpers.go` and switching repository
settings/API callers to `IsValidURL`.
It also aligns tracker-format validation and tests with the new helper
surface.
- **Validation helpers**
- Removed `IsValidExternalURL` and `IsAPIURL`.
- Updated `IsValidExternalTrackerURLFormat` to depend on `IsValidURL`.
- **Caller updates**
- Replaced `validation.IsValidExternalURL(...)` with
`validation.IsValidURL(...)` in:
- `routers/web/repo/setting/setting.go`
- `routers/api/v1/repo/repo.go`
- **Tests**
- Removed tests dedicated to `IsValidExternalURL`.
- Updated tracker-format test expectations to match `IsValidURL`-based
behavior.
```go
// before
if !validation.IsValidExternalURL(form.ExternalTrackerURL) { ... }
// after
if !validation.IsValidURL(form.ExternalTrackerURL) { ... }
```
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: wxiaoguang <2114189+wxiaoguang@users.noreply.github.com>
## Summary
Fixes#37252
The `/api/v1/repos/{owner}/{repo}/actions/runs` endpoint was returning
`event: "push"` for workflow runs triggered by `schedule:` (cron),
instead
of `event: "schedule"`.
## Root Cause
`ActionRun` has two separate fields:
- `Event` — the workflow registration event (e.g. `push`, set when the
workflow file was first pushed)
- `TriggerEvent` — the actual event that triggered the run (e.g.
`schedule`)
`ToActionWorkflowRun` in `services/convert/action.go` was serializing
`run.Event` into the API response instead of `run.TriggerEvent`, causing
scheduled runs to be indistinguishable from push events via the API.
This was already asymmetric — the tasks/jobs API correctly used
`TriggerEvent`.
## Fix
Changed `ToActionWorkflowRun` to use `run.TriggerEvent` for the `event`
field in the API response, consistent with how the jobs API works.
## Before
`event: "push"` returned for all scheduled runs:
<img width="1112" height="191" alt="Screenshot 2026-04-19 115642"
src="https://github.com/user-attachments/assets/c0a169f5-bbd9-4f5d-9474-e4c3795110e4"
/>
## After
`event: "schedule"` correctly returned for scheduled runs:
<img width="890" height="166" alt="Screenshot 2026-04-19 121723"
src="https://github.com/user-attachments/assets/860e99ac-0935-4a43-86a1-7b60f8113480"
/>
## Testing
- Added unit test `TestToActionWorkflowRun_UsesTriggerEvent` in
`services/convert/action_test.go` that explicitly verifies the API
returns `TriggerEvent` and not `Event` for a scheduled run.
- Manually verified via the API against a live Gitea instance with a
`cron: "* * * * *"` workflow.
---------
Co-authored-by: Nicolas <bircni@icloud.com>
Backport #37324 by @lunny
A quick fix#37317
---
The current behavior for forks when an organization or repository is
changed to private differs from GitHub.
On GitHub, when a parent repository becomes private, the fork
relationship is removed, which keeps the behavior simple and avoids
visibility conflicts.
I think we need a similar solution to handle cases where the parent
repository becomes private while a fork remains public and the fork
relationship is still preserved.
Signed-off-by: Lunny Xiao <xiaolunwen@gmail.com>
Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com>
Co-authored-by: silverwind <me@silverwind.io>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
A quick fix#37317
---
The current behavior for forks when an organization or repository is
changed to private differs from GitHub.
On GitHub, when a parent repository becomes private, the fork
relationship is removed, which keeps the behavior simple and avoids
visibility conflicts.
I think we need a similar solution to handle cases where the parent
repository becomes private while a fork remains public and the fork
relationship is still preserved.
---------
Signed-off-by: Lunny Xiao <xiaolunwen@gmail.com>
Co-authored-by: silverwind <me@silverwind.io>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
Co-authored-by: Giteabot <teabot@gitea.io>
Fail the vite build on any rolldown warnings when `NODE_ENV=test` is
set. This gate is set on the CI `make frontend` steps (compliance and
e2e workflows) and on the local `make test-e2e` target, so warnings fail
the build both in CI and when running e2e tests locally. Regular `make
frontend` / production builds are unaffected.
Example output:
```
[plugin test-warning-injector] first synthetic warning
[plugin test-warning-injector] second synthetic warning
transforming...✗ Build failed in 14ms
error during build:
Build failed with 1 error:
[plugin fail-on-warnings]
Error: 2 warnings present
at PluginContextImpl.buildEnd (vite.config.ts:50:13)
...
```
---
This PR was written with the help of Claude Opus 4.7
---------
Signed-off-by: silverwind <me@silverwind.io>
Co-authored-by: Claude (Opus 4.7) <noreply@anthropic.com>
Co-authored-by: Nicolas <bircni@icloud.com>
Follow up #37327. See the comments.
* Root problem: the design of OAuth2 providers is a mess, the display
name is used as provider's name and used in the URL directly
* The regressions:
* When trying to fix https://github.com/go-gitea/gitea/issues/36409 , it
introduced inconsistent URL escaping for the "path" part.
* This fix: always use "path escaping" for the path part, add more tests
to cover all escaping cases.
Now, frontend "pathEscape" and "pathEscapeSegments" generate exactly the
same result as backend.
Backport #37327 by @prettysunflower
Nyallo~
In pull request #36901, a change is made so that the link to
authentication sources is now escaped with the QueryEscape filter.
https://github.com/go-gitea/gitea/pull/36901/changes#diff-34c39c9736a8b62e293c0c0b24c4b5b8c1c792790018c5809f9ff2cbc12b16b1R4
The problem is that [QueryEscape replace spaces with the `+`
character](https://cs.opensource.google/go/go/+/refs/tags/go1.26.2:src/net/url/url.go;l=234;drc=917949cc1d16c652cb09ba369718f45e5d814d8f),
and this is not unescaped when a user tries to log in with an
authentication source that contains a space, which throws an error.
This commit fixes that by unescaping the provider name in the URL.
---
Example of the error, on my instance, when I try to log in with
`prettysunflower's auth`
```
2026/04/21 00:11:41 routers/web/auth/oauth.go:42:SignInOAuth() [E] SignIn: oauth2 source not found, name: "prettysunflower's+auth"
/go/src/code.gitea.io/gitea/routers/web/auth/oauth.go:42 (0x2cfa5c5)
/usr/local/go/src/reflect/value.go:586 (0x51e245)
/usr/local/go/src/reflect/value.go:369 (0x51d0f8)
/go/src/code.gitea.io/gitea/modules/web/handler.go:181 (0x1a6aaf6)
/usr/local/go/src/net/http/server.go:2286 (0x94dc88)
/usr/local/go/src/net/http/server.go:2286 (0x94dc88)
/go/src/code.gitea.io/gitea/modules/web/handler.go:188 (0x1a6ab65)
/usr/local/go/src/net/http/server.go:2286 (0x94dc88)
/go/src/code.gitea.io/gitea/modules/web/handler.go:188 (0x1a6ab65)
/usr/local/go/src/net/http/server.go:2286 (0x94dc88)
/go/src/code.gitea.io/gitea/modules/web/handler.go:188 (0x1a6ab65)
/usr/local/go/src/net/http/server.go:2286 (0x94dc88)
/go/src/code.gitea.io/gitea/services/context/context.go:217 (0x2df1b23)
/usr/local/go/src/net/http/server.go:2286 (0x94dc88)
/go/src/code.gitea.io/gitea/modules/web/handler.go:145 (0x1a6afb5)
/usr/local/go/src/net/http/server.go:2286 (0x94dc88)
/go/pkg/mod/gitea.com/go-chi/session@v0.0.0-20251124165456-68e0254e989e/session.go:258 (0x197eb82)
/usr/local/go/src/net/http/server.go:2286 (0x94dc88)
/go/src/code.gitea.io/gitea/modules/web/handler.go:145 (0x1a6afb5)
/usr/local/go/src/net/http/server.go:2286 (0x94dc88)
/go/pkg/mod/github.com/go-chi/chi/v5@v5.2.5/chain.go:31 (0x1a61d05)
/go/pkg/mod/github.com/go-chi/chi/v5@v5.2.5/mux.go:479 (0x1a64fae)
/usr/local/go/src/net/http/server.go:2286 (0x94dc88)
/go/pkg/mod/github.com/go-chi/chi/v5@v5.2.5/mux.go:73 (0x1a628c2)
/go/pkg/mod/github.com/go-chi/chi/v5@v5.2.5/mux.go:321 (0x1a6421a)
/usr/local/go/src/net/http/server.go:2286 (0x94dc88)
/go/pkg/mod/github.com/go-chi/chi/v5@v5.2.5/chain.go:31 (0x1a61d05)
/go/pkg/mod/github.com/go-chi/chi/v5@v5.2.5/mux.go:479 (0x1a64fae)
/usr/local/go/src/net/http/server.go:2286 (0x94dc88)
/go/pkg/mod/github.com/go-chi/chi/v5@v5.2.5/middleware/get_head.go:37 (0x2c33a67)
/usr/local/go/src/net/http/server.go:2286 (0x94dc88)
/go/src/code.gitea.io/gitea/modules/web/handler.go:145 (0x1a6afb5)
/usr/local/go/src/net/http/server.go:2286 (0x94dc88)
/go/pkg/mod/github.com/go-chi/chi/v5@v5.2.5/mux.go:73 (0x1a628c2)
/go/pkg/mod/github.com/go-chi/chi/v5@v5.2.5/mux.go:321 (0x1a6421a)
/usr/local/go/src/net/http/server.go:2286 (0x94dc88)
/go/src/code.gitea.io/gitea/routers/common/maintenancemode.go:50 (0x2b752da)
/usr/local/go/src/net/http/server.go:2286 (0x94dc88)
/go/src/code.gitea.io/gitea/modules/web/handler.go:145 (0x1a6afb5)
/usr/local/go/src/net/http/server.go:2286 (0x94dc88)
/go/pkg/mod/github.com/go-chi/chi/v5@v5.2.5/chain.go:31 (0x1a61d05)
/go/pkg/mod/github.com/go-chi/chi/v5@v5.2.5/mux.go:479 (0x1a64fae)
/usr/local/go/src/net/http/server.go:2286 (0x94dc88)
/go/src/code.gitea.io/gitea/modules/web/routing/logger_manager.go:124 (0x127d1ec)
/usr/local/go/src/net/http/server.go:2286 (0x94dc88)
/go/src/code.gitea.io/gitea/modules/web/handler.go:145 (0x1a6afb5)
/usr/local/go/src/net/http/server.go:2286 (0x94dc88)
/go/pkg/mod/github.com/chi-middleware/proxy@v1.1.1/middleware.go:37 (0x2b76acf)
/usr/local/go/src/net/http/server.go:2286 (0x94dc88)
/go/src/code.gitea.io/gitea/modules/web/handler.go:145 (0x1a6afb5)
/usr/local/go/src/net/http/server.go:2286 (0x94dc88)
/go/src/code.gitea.io/gitea/routers/common/middleware.go:89 (0x2b78cd6)
/usr/local/go/src/net/http/server.go:2286 (0x94dc88)
/go/src/code.gitea.io/gitea/modules/web/handler.go:145 (0x1a6afb5)
/usr/local/go/src/net/http/server.go:2286 (0x94dc88)
/go/src/code.gitea.io/gitea/routers/common/middleware.go:104 (0x2b7890f)
/usr/local/go/src/net/http/server.go:2286 (0x94dc88)
/go/src/code.gitea.io/gitea/modules/web/handler.go:145 (0x1a6afb5)
/usr/local/go/src/net/http/server.go:2286 (0x94dc88)
/go/pkg/mod/github.com/go-chi/chi/v5@v5.2.5/mux.go:90 (0x1a62881)
/go/src/code.gitea.io/gitea/modules/web/router.go:286 (0x1a6d2a2)
/go/src/code.gitea.io/gitea/modules/web/router.go:221 (0x1a6cbc6)
/usr/local/go/src/net/http/server.go:3311 (0x96e36d)
/usr/local/go/src/net/http/server.go:2073 (0x94bd6f)
/usr/local/go/src/runtime/asm_amd64.s:1771 (0x49af20)
```
Signed-off-by: prettysunflower <me@prettysunflower.moe>
Signed-off-by: wxiaoguang <wxiaoguang@gmail.com>
Co-authored-by: prettysunflower <me@prettysunflower.moe>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
Co-authored-by: silverwind <me@silverwind.io>
Backport #37311 by @silverwind
## Problem
Workflow-level concurrency groups were evaluated — and jobs were parsed
— before the run was persisted, so `run.ID` was `0` and `github.run_id`
in the expression context resolved to an empty string. Expressions like:
```yaml
concurrency:
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
cancel-in-progress: true
```
collapsed to `<workflow>-` on every push event (`head_ref` is empty on
push), so `cancel-in-progress` cancelled in-progress runs across
**unrelated branches**, not just the current one.
Reproduced on a 1.26 instance:
- push to `master` → `ci` run starts
- push to `feature-branch` → the `master` run gets cancelled
GitHub Actions' documented semantic: on push events `github.run_id` is
unique per run, so the group is unique → no cancellation; on PR events
`github.head_ref` is the source branch → cancellation is per-PR.
## Fix
Insert the run **before** parsing jobs or evaluating workflow-level
concurrency, so `run.ID` is populated in time for every expression that
reads `github.run_id` — not just the concurrency group, but also
`run-name`, job names, and `runs-on`.
`jobparser.Parse` now runs inside the `InsertRun` transaction, after
`db.Insert(ctx, run)`. Workflow-level concurrency evaluation runs next
and only mutates `run` in memory. All concurrency-derived fields
(`raw_concurrency`, `concurrency_group`, `concurrency_cancel`) plus
`status` and `title` are persisted in a single final `UpdateRun` at
end-of-transaction — one `INSERT` + one `UPDATE` per run in both the
concurrency and non-concurrency paths (matches pre-branch parity, one
fewer `UpdateRepoRunsNumbers` `COUNT` than the interim state).
`GenerateGiteaContext` now sets `run_id` from `run.ID` unconditionally;
every caller passes a persisted run.
**Verification**: tested end-to-end on a 1.26 deployment. Before the
patch, two successive `ci` pushes (one to master, one to a feature
branch) cross-cancelled each other. After the patch, the same pushes —
in both orders (master→branch, branch→master) — run to completion
simultaneously across 15+ runs with zero cancellations.
**Regression tests** in `services/actions/context_test.go`:
- `TestEvaluateRunConcurrency_RunIDFallback` — unit check that
`EvaluateRunConcurrencyFillModel` resolves `github.run_id` from
`run.ID`.
- `TestPrepareRunAndInsert_ExpressionsSeeRunID` — full-flow check: calls
`PrepareRunAndInsert` with `${{ github.run_id }}` in both `run-name` and
the concurrency group, then asserts the persisted `Title`,
`ConcurrencyGroup`, and `RawConcurrency` contain / survive the run's ID.
Re-ordering `db.Insert` relative to either parse or concurrency eval
fails this test.
## Relation to #37119
[#37119](https://github.com/go-gitea/gitea/pull/37119) also moves
concurrency evaluation into `InsertRun` but keeps it **before**
`db.Insert`, then tries to populate `run_id` only when `run.ID > 0` —
which is still `0` at that call site, so the cross-branch leak would
survive that PR as written. This PR fixes the ordering so that `run.ID`
is actually populated at eval time, and broadens it to cover parse-time
expression interpolation too.
---
This PR was written with the help of Claude Opus 4.7
Co-authored-by: silverwind <me@silverwind.io>
Co-authored-by: Claude (Opus 4.7) <noreply@anthropic.com>
The link to authentication sources is now escaped with the QueryEscape.
This commit fixes that by unescaping the provider name in the URL.
---------
Signed-off-by: prettysunflower <me@prettysunflower.moe>
Signed-off-by: wxiaoguang <wxiaoguang@gmail.com>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
## Problem
Workflow-level concurrency groups were evaluated — and jobs were parsed
— before the run was persisted, so `run.ID` was `0` and `github.run_id`
in the expression context resolved to an empty string. Expressions like:
```yaml
concurrency:
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
cancel-in-progress: true
```
collapsed to `<workflow>-` on every push event (`head_ref` is empty on
push), so `cancel-in-progress` cancelled in-progress runs across
**unrelated branches**, not just the current one.
Reproduced on a 1.26 instance:
- push to `master` → `ci` run starts
- push to `feature-branch` → the `master` run gets cancelled
GitHub Actions' documented semantic: on push events `github.run_id` is
unique per run, so the group is unique → no cancellation; on PR events
`github.head_ref` is the source branch → cancellation is per-PR.
## Fix
Insert the run **before** parsing jobs or evaluating workflow-level
concurrency, so `run.ID` is populated in time for every expression that
reads `github.run_id` — not just the concurrency group, but also
`run-name`, job names, and `runs-on`.
`jobparser.Parse` now runs inside the `InsertRun` transaction, after
`db.Insert(ctx, run)`. Workflow-level concurrency evaluation runs next
and only mutates `run` in memory. All concurrency-derived fields
(`raw_concurrency`, `concurrency_group`, `concurrency_cancel`) plus
`status` and `title` are persisted in a single final `UpdateRun` at
end-of-transaction — one `INSERT` + one `UPDATE` per run in both the
concurrency and non-concurrency paths (matches pre-branch parity, one
fewer `UpdateRepoRunsNumbers` `COUNT` than the interim state).
`GenerateGiteaContext` now sets `run_id` from `run.ID` unconditionally;
every caller passes a persisted run.
**Verification**: tested end-to-end on a 1.26 deployment. Before the
patch, two successive `ci` pushes (one to master, one to a feature
branch) cross-cancelled each other. After the patch, the same pushes —
in both orders (master→branch, branch→master) — run to completion
simultaneously across 15+ runs with zero cancellations.
**Regression tests** in `services/actions/context_test.go`:
- `TestEvaluateRunConcurrency_RunIDFallback` — unit check that
`EvaluateRunConcurrencyFillModel` resolves `github.run_id` from
`run.ID`.
- `TestPrepareRunAndInsert_ExpressionsSeeRunID` — full-flow check: calls
`PrepareRunAndInsert` with `${{ github.run_id }}` in both `run-name` and
the concurrency group, then asserts the persisted `Title`,
`ConcurrencyGroup`, and `RawConcurrency` contain / survive the run's ID.
Re-ordering `db.Insert` relative to either parse or concurrency eval
fails this test.
## Relation to #37119
[#37119](https://github.com/go-gitea/gitea/pull/37119) also moves
concurrency evaluation into `InsertRun` but keeps it **before**
`db.Insert`, then tries to populate `run_id` only when `run.ID > 0` —
which is still `0` at that call site, so the cross-branch leak would
survive that PR as written. This PR fixes the ordering so that `run.ID`
is actually populated at eval time, and broadens it to cover parse-time
expression interpolation too.
Co-authored-by: Claude (Opus 4.7) <noreply@anthropic.com>
Replaces `@silverwind/vue3-calendar-heatmap` with an inlined SVG
implementation. Renders pixel-identically to `main`, drops the
`onMounted` legend viewBox workaround, and uses tippy's
`createSingleton` for the hover tooltip. Adds an e2e test for tooltip
display.
This is a prereq for migrating tippy.js to
[floating-ui](https://github.com/floating-ui/floating-ui) to avoid
having two tooltip libs active.
<img width="861" height="168" alt="image"
src="https://github.com/user-attachments/assets/99343cf6-6e09-42c7-a80d-63dbf33cf56a"
/>
---
This PR was written with the help of Claude Opus 4.7
---------
Co-authored-by: Claude (Opus 4.7) <noreply@anthropic.com>
Co-authored-by: Nicolas <bircni@icloud.com>
Backport #37279 by @silverwind
Moves the manifest patching from `closeBundle` to `writeBundle`. Thrown
errors in `writeBundle` work correctly and exit the build.
Signed-off-by: silverwind <me@silverwind.io>
Signed-off-by: wxiaoguang <wxiaoguang@gmail.com>
Co-authored-by: silverwind <me@silverwind.io>
Co-authored-by: Claude (Opus 4.7) <noreply@anthropic.com>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
Enable full TypeScript `strict` mode and fix issues discovered during
this refactor. Introduced a `errorMessage` helper function to cleanly
extract a error messages from the `unknown` type.
Signed-off-by: silverwind <me@silverwind.io>
Co-authored-by: Claude (claude-opus-4-7) <noreply@anthropic.com>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
Moves the manifest patching from `closeBundle` to `writeBundle`. Thrown
errors in `writeBundle` work correctly and exit the build.
Signed-off-by: silverwind <me@silverwind.io>
Signed-off-by: wxiaoguang <wxiaoguang@gmail.com>
Co-authored-by: Claude (Opus 4.7) <noreply@anthropic.com>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
Verified locally with 50 runs, averaging 9 seconds per local test suite
run. Total suite took 15s.
`--with-deps` is needed because webkit's dependencies are not
pre-installed on GHA runners (as opposed to firefox/chrome which are
preinstalled).
---
This PR was written with the help of Claude Opus 4.7
---------
Co-authored-by: Claude (Opus 4.7) <noreply@anthropic.com>
Co-authored-by: Nicolas <bircni@icloud.com>
When generating release notes for v1.26, many pull requests haven't been
given correct labels so that I have to do many manual work. I think this
could be avoid to remove these useless modify labels.
While editing frontend, I found some inconsistencies while testing
transferring repositories:
- No button for accepting/rejecting/cancelling the transfer of an empty
repository.
- The `redirect_to` in `templates/repo/header.tmpl` is useless.
- There's no redirection when there's an error from `handleActionError`
in `routers/web/repo/repo.go`. Therefore, instead of flash message, a
blank page will be displayed.
This pr adds some commits to resolve all these issues.
Update: see the new changes
https://github.com/go-gitea/gitea/pull/37277#issuecomment-4276150232
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
Co-authored-by: Giteabot <teabot@gitea.io>
Backport #37290 by wxiaoguang
Fix#37289
Don't tell container client that the instance needs basic auth if the
public access is available.
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
Automated changes by the
[update-flake-lock](https://github.com/DeterminateSystems/update-flake-lock)
GitHub Action.
```
Flake lock file updates:
• Updated input 'nixpkgs':
'github:nixos/nixpkgs/4c1018d' (2026-04-09)
→ 'github:nixos/nixpkgs/4bd9165' (2026-04-14)
```
### Running GitHub Actions on this PR
GitHub Actions will not run workflows on pull requests which are opened
by a GitHub Action.
**To run GitHub Actions workflows on this PR, close and re-open this
pull request.**
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Co-authored-by: Nicolas <bircni@icloud.com>
Backport #37189 by @bircni
If a workflow is not in default branch the hooks could not be detected
Fixes#37169
Co-authored-by: Nicolas <bircni@icloud.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
If a workflow is not in default branch the hooks could not be detected
Fixes#37169
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-authored-by: Giteabot <teabot@gitea.io>
Backport of go-git upgrade to v5.18.0 for the v1.26 release branch.
Fixes GHSA-3xc5-wrhm-f963 (credential exposure on HTTP redirects).
---
This PR was written with the help of Claude Opus 4.6
Co-authored-by: Claude (Opus 4.6) <noreply@anthropic.com>
Fixes GHSA-3xc5-wrhm-f963 (credential exposure on HTTP redirects).
---
This PR was written with the help of Claude Opus 4.6
Co-authored-by: Claude (Opus 4.6) <noreply@anthropic.com>
Backport #37244 by @JoeGruffins
Patterns starting with "/" (e.g. /docs/.*\.md) never matched because git
returns relative paths without a leading slash. Strip the leading "/"
before compiling the regex since the ^...$ anchoring already provides
root-relative semantics.
closes#28107
Co-authored-by: JoeGruffins <34998433+JoeGruffins@users.noreply.github.com>
Co-authored-by: silverwind <me@silverwind.io>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
Introduces a frontend external-render framework that runs renderer
plugins inside an `iframe` (loaded via `srcdoc` to keep the CSP
`sandbox` directive working without origin-related console noise), and
migrates the 3D viewer and OpenAPI/Swagger renderers onto it. PDF and
asciicast paths are refactored to share the same `data-render-name`
mechanism.
Adds e2e coverage for 3D, PDF, asciicast and OpenAPI render paths, plus
a regression for the `RefTypeNameSubURL` double-escape on non-ASCII
branch names.
Signed-off-by: silverwind <me@silverwind.io>
Co-authored-by: Claude (Opus 4.6) <noreply@anthropic.com>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
Patterns starting with "/" (e.g. /docs/.*\.md) never matched because git
returns relative paths without a leading slash. Strip the leading "/"
before compiling the regex since the ^...$ anchoring already provides
root-relative semantics.
Fixes: #28107
Co-authored-by: silverwind <me@silverwind.io>
Co-authored-by: Giteabot <teabot@gitea.io>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
Backport #37256 by wxiaoguang
1. Make sure OmitEmail won't panic
2. SSH principal keys are not for signing or authentication
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
Use `golangci-lint fmt` to format code, replacing the previous custom
formatter tool. https://github.com/daixiang0/gci is used to order the
imports.
`make fmt` performs ~13% faster while consuming ~57% less cpu while
formatting for me.
`GOFUMPT_PACKAGE` is gone because it's using the builtin package from
golangci-lint.
Co-authored-by: Claude (claude-opus-4-6) <noreply@anthropic.com>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
This PR adds an External ID Claim Name configuration field to the OIDC
auth source. When set, Gitea uses the specified JWT claim as the user's
`ExternalID` instead of the default `sub` claim.
This PR fixes the bug when migrating from Azure AD V2 to OIDC. When an
admin migrates the same auth source to OIDC, goth's `openidConnect`
provider defaults to using the `sub` claim as `UserID`. However, Azure
AD's `sub` is a pairwise identifier:
> `sub`: The subject is a pairwise identifier and is unique to an
application ID. If a single user signs into two different apps using two
different client IDs, those apps receive two different values for the
subject claim.
https://learn.microsoft.com/en-us/entra/identity-platform/id-token-claims-reference#payload-claims
As a result, every existing user appears as a new account after
migration.
To fix this issue, Gitea should use `oid` claim for `UserID`.
> `oid`: This ID uniquely identifies the user across applications - two
different applications signing in the same user receives the same value
in the oid claim.
Note: The `oid` claim is not included in Azure AD tokens by default. The
`profile` scope must be added to the Scopes field of the auth source.
Close#35059
Slightly improved the "fetch action" framework and started adding tests for it.
---------
Signed-off-by: silverwind <me@silverwind.io>
Co-authored-by: silverwind <me@silverwind.io>
The only remaining (hard) part is "templates/repo/editor/edit.tmpl", see the FIXME
By the way:
* Make "user unfollow" use basic color but not red color, indeed it is not dangerous
* Fix "org folllow" layout (use block gap instead of inline gap)
Backport #37193 by @Mohit25022005
fix(api): handle missing base branch in PR commits API
Closes#36366
Previously, the PR commits API returned a 500 Internal Server Error
when the base branch was missing due to an unhandled git "bad revision"
error.
This change:
- Checks for base branch existence before performing git operations
- Returns 404 when the base branch does not exist
- Prevents git errors from surfacing as 500 responses
This improves API robustness and aligns behavior with expected error
handling.
Tested locally by:
- Creating a pull request
- Deleting the base branch
- Verifying that the API returns 404 instead of 500
Co-authored-by: Mohit Swarnkar <mohitswarnkar13@gmail.com>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com>
Backport #37190 by @bircni
`url.PathEscape` unnecessarily encodes ! to %21, causing Matrix
homeservers to reject the request with 401. Replace %21 back to ! after
escaping.
Fixes#36012
Signed-off-by: wxiaoguang <wxiaoguang@gmail.com>
Co-authored-by: Nicolas <bircni@icloud.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
This is the first step (the hardest part):
* repo file list last commit message lazy load
* admin server status monitor
* watch/unwatch (normal page, watchers page)
* star/unstar (normal page, watchers page)
* project view, delete column
* workflow dispatch, switch the branch
* commit page: load branches and tags referencing this commit
The legacy "data-redirect" attribute is removed, it only makes the page
reload (sometimes using an incorrect link).
Also did cleanup for some devtest pages.
Backport #37172 by @xingxing21
Fixes: https://github.com/go-gitea/gitea/issues/36677
The fix is a template-only change in
[templates/repo/diff/compare.tmpl:16-25](vscode-webview://1ca9j6f1e3qtaf59o0cr4ind65ulf8mevvbbbq88int1gg2lncar/templates/repo/diff/compare.tmpl#L16-L25).
Before, the display names were built with conditional logic:
All four variables defaulted to just the owner name (Examples)
$HeadCompareName was only upgraded to owner/repo format in two narrow
cases:
Same org, different repos
A root repo exists with the same owner as the head repo
All other cases (same-repo PRs, cross-org PRs) got owner-only labels
After, all four variables are unconditionally set to owner/repo format
using printf "%s/%s":
```
- {{$BaseCompareName := printf "%s/%s" $.BaseName $.Repository.Name -}}
- {{- $HeadCompareName := printf "%s/%s" $.HeadRepo.OwnerName $.HeadRepo.Name -}}
- {{- $OwnForkCompareName := "" -}}
- {{- if .OwnForkRepo -}}
- {{- $OwnForkCompareName = printf "%s/%s" .OwnForkRepo.OwnerName .OwnForkRepo.Name -}}
- {{- end -}}
- {{- $RootRepoCompareName := "" -}}
- {{- if .RootRepo -}}
- {{- $RootRepoCompareName = printf "%s/%s" .RootRepo.OwnerName .RootRepo.Name -}}
- {{- end -}}
+ {{$BaseCompareName := $.Repository.FullName -}}
+ {{$HeadCompareName := $.HeadRepo.FullName -}}
+ {{$OwnForkCompareName := "" -}}
+ {{if $.OwnForkRepo -}}
+ {{$OwnForkCompareName = $.OwnForkRepo.FullName -}}
+ {{end -}}
+ {{$RootRepoCompareName := "" -}}
+ {{if $.RootRepo -}}
+ {{$RootRepoCompareName = $.RootRepo.FullName -}}
+ {{end -}}
```
These variables drive the labels in the base and head branch selector
buttons and their dropdown items. No backend changes were needed —
$.BaseName, $.Repository.Name, $.HeadRepo.OwnerName, and $.HeadRepo.Name
were already available in the template context.
Co-authored-by: Xing Hong <39619359+xingxing21@users.noreply.github.com>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
`url.PathEscape` unnecessarily encodes ! to %21, causing Matrix
homeservers to reject the request with 401. Replace %21 back to ! after
escaping.
Fixes#36012
---------
Signed-off-by: wxiaoguang <wxiaoguang@gmail.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
Backport #37185 by @Mohit25022005
Fix 500 error when comparing branches across fork repositories
## Problem
The compare API returns a 500 Internal Server Error when comparing
branches where the head commit exists only in the fork repository.
## Cause
The API was using the base repository's GitRepo and repository context
when converting commits. This fails when the commit does not exist in
the base repository, resulting in a "fatal: bad object" error.
## Solution
Use the head repository and HeadGitRepo when available to ensure commits
are resolved in the correct repository context.
## Result
* Fixes "fatal: bad object" error
* Enables proper comparison between base and fork repositories
* Prevents 500 Internal Server Error
Fixes#37168
Co-authored-by: Mohit Swarnkar <mohitswarnkar13@gmail.com>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
Backport #37175 by @silverwind
The `Run As Username` field on the install page was a `readonly` input
that looked editable but wasn't, confusing users. Style `readonly`
inputs with a subtle background, matching other frameworks.
<img width="735" height="131" alt="image"
src="https://github.com/user-attachments/assets/cb76ce71-faab-4300-811e-e4c503b59f9a"
/>
Backport #37180
The comment "so just use current one if config says default" is not
right anymore: "git" isn't the "default" value of RunUser (Comment out
app.example.ini #15807). The RunUser's value is from current session's
username.
Fixes#37174
---------
Signed-off-by: wxiaoguang <wxiaoguang@gmail.com>
Signed-off-by: silverwind <me@silverwind.io>
Co-authored-by: silverwind <me@silverwind.io>
Co-authored-by: Claude (Opus 4.6) <noreply@anthropic.com>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
Fix 500 error when comparing branches across fork repositories
## Problem
The compare API returns a 500 Internal Server Error when comparing
branches where the head commit exists only in the fork repository.
## Cause
The API was using the base repository's GitRepo and repository context
when converting commits. This fails when the commit does not exist in
the base repository, resulting in a "fatal: bad object" error.
## Solution
Use the head repository and HeadGitRepo when available to ensure commits
are resolved in the correct repository context.
## Result
* Fixes "fatal: bad object" error
* Enables proper comparison between base and fork repositories
* Prevents 500 Internal Server Error
Fixes#37168
---------
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
This PR updates `CONTRIBUTING.md` for clarity (code review, maintainers,
PR workflow)
## Suggestion
- majors about every **three months**, with a more predictable cadence
from **v1.26** onward.
- target dates such as **v1.26.0** (April 2026), **v1.27.0** (June
2026), **v1.28.0** (September 2026), **v1.29.0** (December 2026).
- announce feature freeze **two weeks** before each release.
## Other doc changes
- Reviewing PRs: separate guidance for reviewers vs authors; small edits
to maintaining PRs, merge queue, commit messages, co-authors.
- Maintainers: clearer subsections; links to GitHub Docs for 2FA / GPG.
- Split the Contributing.md into more useful markdown files
---------
Signed-off-by: Nicolas <bircni@icloud.com>
That logic is from 2014~2015, it unclear why it is necessary or
whether it is still needed (whether Windows is still special)
The comment "so just use current one if config says default" is not
right anymore: "git" isn't the "default" value of RunUser (Comment out
app.example.ini #15807). The RunUser's value is from current session's
username.
1. Fix the "flash message" layout problem for different cases
* I am sure most of the users should have ever seen the ugly
center-aligned error message with multiple lines.
2. Fix inconsistent "Details" flash message EOL handling, sometimes
`\n`, sometimes `<br>`
* Now, always use "\n" and use `<pre>` to render
3. Remove SanitizeHTML template func because it is not useful and can be
easily abused.
* But it is still kept for mail templates, for example:
https://github.com/go-gitea/gitea/issues/36049
4. Clarify PostProcessCommitMessage's behavior and add FIXME comment
By the way: cleaned up some devtest pages, move embedded style block to
CSS file
The `Run As Username` field on the install page was a `readonly` input
that looked editable but wasn't, confusing users. Style `readonly`
inputs with a subtle background, matching other frameworks.
Fixes: #37174
Signed-off-by: wxiaoguang <wxiaoguang@gmail.com>
Signed-off-by: silverwind <me@silverwind.io>
Co-authored-by: Claude (Opus 4.6) <noreply@anthropic.com>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
Backport #37173 by @silverwind
Remove CSS rules whose HTML classes/IDs are no longer referenced in any
template, Go source, or JavaScript/TypeScript file:
- `.archived-icon`: removed from templates in c85bb62635
- `.bottom-line`: removed from blame rendering in 9c6aeb47f7
- `.commit-status-link`: removed from templates in f3c4baa84b
- `.instruct-toggle`: removed from templates in 75e85c25c1
- `.runner-new-text`, `#runner-new`: never referenced outside CSS
- `.ap-terminal`: stale, asciinema-player uses `.ap-term`, still not
needed
- `.scrolling.dimmable.dimmed`: dimmer stand-in never adds this class
- `.markup span.align-center/align-right/float-left/float-right`: never
produced by any renderer, sanitizer strips class attributes
- `.markup ul.no-list`, `.markup ol.no-list`: same as above
---
This PR was written with the help of Claude Opus 4.6
Signed-off-by: silverwind <me@silverwind.io>
Co-authored-by: silverwind <me@silverwind.io>
Co-authored-by: Claude (Opus 4.6) <noreply@anthropic.com>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
Backport #37159 by @silverwind
`TestCatFileBatch/QueryTerminated` relied on timing to distinguish
`os.ErrClosed` vs `io.EOF` error paths. Replace `time.Sleep`-based
synchronization with a channel-based hook on pipe close, making both
error paths fully deterministic regardless of CI runner speed.
Ref:
https://github.com/go-gitea/gitea/actions/runs/24193070536/job/70615366804
---
This PR was written with the help of Claude Opus 4.6
Co-authored-by: silverwind <me@silverwind.io>
Co-authored-by: Claude (Opus 4.6) <noreply@anthropic.com>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
Remove CSS rules whose HTML classes/IDs are no longer referenced in any
template, Go source, or JavaScript/TypeScript file:
- `.archived-icon`: removed from templates in c85bb62635
- `.bottom-line`: removed from blame rendering in 9c6aeb47f7
- `.commit-status-link`: removed from templates in f3c4baa84b
- `.instruct-toggle`: removed from templates in 75e85c25c1
- `.runner-new-text`, `#runner-new`: never referenced outside CSS
- `.ap-terminal`: stale, asciinema-player uses `.ap-term`, still not
needed
- `.scrolling.dimmable.dimmed`: dimmer stand-in never adds this class
- `.markup span.align-center/align-right/float-left/float-right`: never
produced by any renderer, sanitizer strips class attributes
- `.markup ul.no-list`, `.markup ol.no-list`: same as above
---
This PR was written with the help of Claude Opus 4.6
---------
Signed-off-by: silverwind <me@silverwind.io>
Co-authored-by: Claude (Opus 4.6) <noreply@anthropic.com>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
Backport #36085 by @eliroca
When authentication is handled externally by a reverse proxy SSO
provider, users can be redirected to an external logout URL or relative
path defined on the reverse proxy.
Co-authored-by: Elisei Roca <eroca@suse.de>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
Backport #37162 by @silverwind
When running `golangci-lint` without `GOEXPERIMENT=jsonv2`, a lint error
`import 'encoding/json' is not allowed` is seen.
All other files in the module that import `encodings/json` have
`//nolint` already, so add it.
---
This PR was written with the help of Claude Opus 4.6
Co-authored-by: silverwind <me@silverwind.io>
Co-authored-by: Claude (Opus 4.6) <noreply@anthropic.com>
When authentication is handled externally by a reverse proxy SSO
provider, users can be redirected to an external logout URL or relative
path defined on the reverse proxy.
---------
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
Backport #37130. Only one merge conflict in lockfile.
---
This PR was written with the help of Claude Opus 4.6
Co-authored-by: Claude (Opus 4.6) <noreply@anthropic.com>
When running `golangci-lint` without `GOEXPERIMENT=jsonv2`, a lint error
`import 'encoding/json' is not allowed` is seen.
All other files in the module that import `encodings/json` have
`//nolint` already, so add it.
---
This PR was written with the help of Claude Opus 4.6
Co-authored-by: Claude (Opus 4.6) <noreply@anthropic.com>
Backport #37116 by @bircni
`model.ReadWorkflow` succeeds for YAML that is syntactically valid but
fails deeper parsing in `jobparser.Parse` (e.g. blank lines inside `run:
|` blocks cause a SetJob round-trip error). Add
`ValidateWorkflowContent` which runs the full `jobparser.Parse` to catch
these cases, and use it in the file view, the actions workflow list, and
the workflow detection loop so users see the error instead of silently
getting a 500 or a dropped workflow.
Fixes#37115
Signed-off-by: Nicolas <bircni@icloud.com>
Co-authored-by: Nicolas <bircni@icloud.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-authored-by: Zettat123 <zettat123@gmail.com>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
`model.ReadWorkflow` succeeds for YAML that is syntactically valid but
fails deeper parsing in `jobparser.Parse` (e.g. blank lines inside `run:
|` blocks cause a SetJob round-trip error). Add
`ValidateWorkflowContent` which runs the full `jobparser.Parse` to catch
these cases, and use it in the file view, the actions workflow list, and
the workflow detection loop so users see the error instead of silently
getting a 500 or a dropped workflow.
Fixes#37115
Signed-off-by: Nicolas <bircni@icloud.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-authored-by: Zettat123 <zettat123@gmail.com>
Co-authored-by: Giteabot <teabot@gitea.io>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
Backport #37148 by @silverwind
1. Filter out errors that contain `chrome-extension://` etc protocols
2. Extract filtering into its own function and test it
3. Fix the `window.config.assetUrlPrefix` mock, guaranteed to end with
`/assets`
4. Remove useless `??` and `?.` for properties that always exist
---
This PR was written with the help of Claude Opus 4.6
Co-authored-by: silverwind <me@silverwind.io>
Co-authored-by: Claude (Opus 4.6) <noreply@anthropic.com>
Replace `rollup-plugin-license` and `wrap-ansi` with
[`rolldown-license-plugin`](https://github.com/silverwind/rolldown-license-plugin),
a zero-dependency plugin with async parallel I/O and built-in word
wrapping.
- Removes `rollup-plugin-license` (pulls in `lodash`, `moment`) and
`wrap-ansi` from the dependency tree
- License build time reduced by ~40% (370ms vs 640ms)
- Added e2e test for `licenses.txt`
Signed-off-by: silverwind <me@silverwind.io>
Co-authored-by: Claude (Opus 4.6) <noreply@anthropic.com>
1. Filter out errors that contain `chrome-extension://` etc protocols
2. Extract filtering into its own function and test it
3. Fix the `window.config.assetUrlPrefix` mock, guaranteed to end with
`/assets`
4. Remove useless `??` and `?.` for properties that always exist
Co-authored-by: Claude (Opus 4.6) <noreply@anthropic.com>
1. Make sure you are targeting the `main` branch, pull requests on release branches are only allowed for backports.
2.Make sure you have read contributing guidelines: https://github.com/go-gitea/gitea/blob/main/CONTRIBUTING.md .
3.For documentations contribution, please go to https://gitea.com/gitea/docs
4.Describe what your pull request does and which issue you're targeting (if any).
5.It is recommended to enable "Allow edits by maintainers", so maintainers can help more easily.
6.Your input here will be included in the commit message when this PR has been merged. If you don't want some content to be included, please separate them with a line like `---`.
7.Delete all these tips before posting.
2.Use a Conventional Commits PR title, for example `fix(repo): handle empty branch names`.
3.Make sure you have read contributing guidelines: https://github.com/go-gitea/gitea/blob/main/CONTRIBUTING.md .
4.For documentations contribution, please go to https://gitea.com/gitea/docs
5.Describe what your pull request does and which issue you're targeting (if any).
6.It is recommended to enable "Allow edits by maintainers", so maintainers can help more easily.
7.Your input here will be included in the commit message when this PR has been merged. If you don't want some content to be included, please separate them with a line like `---`.
desc:migrations must not depend on modules/structs (API structures change over time)
nolintlint:
allow-unused:false
require-explanation:true
@@ -109,6 +118,11 @@ linters:
enable:
- nilness
- unusedwrite
goheader:
values:
regexp:
HEADER:'((Copyright [^\n]+|All rights reserved\.)\n)*Copyright \d{4} (The (Gogs|Gitea) Authors|Gitea Authors|Gitea)\.( All rights reserved\.)?(\n(Copyright [^\n]+|All rights reserved\.))*\nSPDX-License-Identifier: [\w.-]+'
- Run `make fmt` to format `.go` files, and run `make lint-go` to lint them
- Run `make lint-js` to lint `.ts` files
- Run `make tidy` after any `go.mod` changes
- Run single go tests with `go test -run '^TestName$' ./modulepath/`
- Run single js test files with `pnpm exec vitest <path-filter>`
- Run single playwright e2e test files with `GITEA_TEST_E2E_FLAGS='<filepath>' make test-e2e`
- Add the current year into the copyright header of new `.go` files
- Ensure no trailing whitespace in edited files
- Use Conventional Commits format for commit messages and PR titles (e.g. `type(scope): subject`)
- Never force-push, amend, or squash unless asked. Use new commits and normal push for pull request updates
- Preserve existing code comments, do not remove or rewrite comments that are still relevant
- In TypeScript, use `!` (non-null assertion) instead of `?.`/`??` when a value is known to always exist
- For CSS layout, prefer `flex-*` helpers over per-child `tw-ml-*` / `tw-mr-*` margins; fall back to `tw-*` utilities when specificity requires `!important`
- Include authorship attribution in issue and pull request comments
- Add `Co-Authored-By` lines to all commits, indicating name and model used
* Closed 24 upstream bug/security issues after backporting
## [MokoGitea Unreleased]
* FEATURES
* feat(api): Bulk issue operations — add/remove/replace labels, close/reopen, set milestone, and set assignees across multiple issues in a single request (#21)
This document explains how to contribute changes to the Gitea project. Topic-specific guides live in separate files so the essentials are easier to find.
| Topic | Document |
| :---- | :------- |
| Backend (Go modules, API v1) | [docs/guideline-backend.md](docs/guideline-backend.md) |
This document explains how to contribute changes to the Gitea project. \
It assumes you have followed the [installation instructions](https://docs.gitea.com/category/installation). \
Sensitive security-related issues should be reported to [security@gitea.io](mailto:security@gitea.io).
@@ -131,34 +108,6 @@ If further discussion is needed, we encourage you to open a new issue instead an
See the [development setup instructions](https://docs.gitea.com/development/hacking-on-gitea).
## Dependencies
### Backend
Go dependencies are managed using [Go Modules](https://go.dev/cmd/go/#hdr-Module_maintenance). \
You can find more details in the [go mod documentation](https://go.dev/ref/mod) and the [Go Modules Wiki](https://github.com/golang/go/wiki/Modules).
Pull requests should only modify `go.mod` and `go.sum` where it is related to your change, be it a bugfix or a new feature. \
Apart from that, these files should only be modified by Pull Requests whose only purpose is to update dependencies.
The `go.mod`, `go.sum` update needs to be justified as part of the PR description,
and must be verified by the reviewers and/or merger to always reference
an existing upstream commit.
### Frontend
For the frontend, we use [npm](https://www.npmjs.com/).
The same restrictions apply for frontend dependencies as for backend dependencies, with the exceptions that the files for it are `package.json` and `package-lock.json`, and that new versions must always reference an existing version.
## Design guideline
Depending on your change, please read the
- [backend development guideline](https://docs.gitea.com/contributing/guidelines-backend)
- [frontend development guideline](https://docs.gitea.com/contributing/guidelines-frontend)
@@ -216,6 +165,8 @@ The tool `go run build/backport-locale.go` can be used to backport locales from
## Code review
How labels, milestones, and the merge queue work is documented in [docs/community-governance.md](docs/community-governance.md).
### Pull request format
Please try to make your pull request easy to review for us. \
@@ -238,6 +189,22 @@ In the PR title, describe the problem you are fixing, not how you are fixing it.
Use the first comment as a summary of your PR. \
In the PR summary, you can describe exactly how you are fixing this problem.
PR titles must follow the [Conventional Commits](https://www.conventionalcommits.org/) format, because PRs are squash-merged and the PR title becomes the resulting commit message:
```text
type(scope)!: subject
```
The allowed types are `build`, `chore`, `ci`, `docs`, `feat`, `fix`, `perf`, `refactor`, `revert`, `style`, and `test`. The generic `chore` type is intentionally not accepted; pick a more descriptive type instead.
Examples:
```text
fix(web): prevent avatar upload crash on empty file
feat(api): add pagination to repo hooks list
ci(workflows): lint PR titles with commitlint
```
Keep this summary up-to-date as the PR evolves. \
If your PR changes the UI, you must add **after** screenshots in the PR summary. \
If you are not implementing a new feature, you should also post **before** screenshots for comparison.
Each issue that will be closed must stand on a separate line.
### Milestone
A PR should only be assigned to a milestone if it will likely be merged into the given version. \
As a rule of thumb, assume that a PR will stay open for an additional month for every 100 added lines. \
PRs without a milestone may not be merged.
### Labels
Almost all labels used inside Gitea can be classified as one of the following:
- `modifies/…`: Determines which parts of the codebase are affected. These labels will be set through the CI.
- `topic/…`: Determines the conceptual component of Gitea that is affected, i.e. issues, projects, or authentication. At best, PRs should only target one component but there might be overlap. Must be set manually.
- `type/…`: Determines the type of an issue or PR (feature, refactoring, docs, bug, …). If GitHub supported scoped labels, these labels would be exclusive, so you should set **exactly** one, not more or less (every PR should fall into one of the provided categories, and only one).
- `issue/…` / `pr/…`: Labels that are specific to issues or PRs respectively and that are only necessary in a given context, i.e. `issue/not-a-bug` or `pr/need-2-approvals`
Every PR should be labeled correctly with every label that applies.
There are also some labels that will be managed automatically.\
In particular, these are
- the amount of pending required approvals
- has all `backport`s or needs a manual backport
### Breaking PRs
#### What is a breaking PR?
@@ -311,165 +255,29 @@ Breaking PRs will not be merged as long as not both of these requirements are me
### Maintaining open PRs
The moment you create a non-draft PR or the moment you convert a draft PR to a non-draft PR is the moment code review starts for it. \
Once that happens, do not rebase or squash your branch anymore as it makes it difficult to review the new changes. \
Merge the base branch into your branch only when you really need to, i.e. because of conflicting changes in the mean time. \
This reduces unnecessary CI runs. \
Don't worry about merge commits messing up your commit history as every PR will be squash merged. \
This means that all changes are joined into a single new commit whose message is as described below.
Code review starts when you open a non-draft PR or move a draft out of draft state. After that, do not rebase or squash your branch; it makes new changes harder to review.
### Getting PRs merged
Merge the base branch into yours only when you need to, for example because of conflicting changes elsewhere. That limits unnecessary CI runs.
Changes to Gitea must be reviewed before they are accepted — no matter who
makes the change, even if they are an owner or a maintainer. \
The only exception are critical bugs that prevent Gitea from being compiled or started. \
Specifically, we require two approvals from maintainers for every PR. \
Once this criteria has been met, your PR receives the `lgtm/done` label. \
From this point on, your only responsibility is to fix merge conflicts or respond to/implement requests by maintainers. \
It is the responsibility of the maintainers from this point to get your PR merged.
Every PR is squash-merged, so merge commits on your branch do not matter for final history. The squash produces a single commit; mergers follow the [commit message format](docs/community-governance.md#commit-messages) in the governance guide.
If a PR has the `lgtm/done` label and there are no open discussions or merge conflicts anymore, any maintainer can add the `reviewed/wait-merge` label. \
This label means that the PR is part of the merge queue and will be merged as soon as possible. \
The merge queue will be cleared in the order of the list below:
Maintainers are encouraged to review pull requests in areas where they have expertise or particular interest.
Gitea uses it's own tool, the <https://github.com/GiteaBot/gitea-backporter> to automate parts of the review process. \
This tool does the things listed below automatically:
#### For PR authors
- create a backport PR if needed once the initial PR was merged
- remove the PR from the merge queue after the PR merged
- keep the oldest branch in the merge queue up to date with merges
- **Response**: When answering reviewer questions, use real-world cases or examples and avoid speculation.
- **Discussion**: A discussion is always welcome and should be used to clarify the changes and the intent of the PR.
- **Help**: If you need help with the PR or comments are unclear, ask for clarification.
### Final call
If a PR has been ignored for more than 7 days with no comments or reviews, and the author or any maintainer believes it will not survive a long wait (such as a refactoring PR), they can send "final call" to the TOC by mentioning them in a comment.
After another 7 days, if there is still zero approval, this is considered a polite refusal, and the PR will be closed to avoid wasting further time. Therefore, the "final call" has a cost, and should be used cautiously.
However, if there are no objections from maintainers, the PR can be merged with only one approval from the TOC (not the author).
### Commit messages
Mergers are able and required to rewrite the PR title and summary (the first comment of a PR) so that it can produce an easily understandable commit message if necessary. \
The final commit message should no longer contain any uncertainty such as `hopefully, <x> won't happen anymore`. Replace uncertainty with certainty.
#### PR Co-authors
A person counts as a PR co-author the moment they (co-)authored a commit that is not simply a `Merge base branch into branch` commit. \
Mergers are required to remove such "false-positive" co-authors when writing the commit message. \
The true co-authors must remain in the commit message.
#### PRs targeting `main`
The commit message of PRs targeting `main` is always
Guidance for reviewers, the merge queue, and the squash commit message format is in [docs/community-governance.md](docs/community-governance.md).
## Documentation
If you add a new feature or change an existing aspect of Gitea, the documentation for that feature must be created or updated in another PR at [https://gitea.com/gitea/docs](https://gitea.com/gitea/docs).
**The docs directory on main repository will be removed at some time. We will have a yaml file to store configuration file's meta data. After that completed, configuration documentation should be in the main repository.**
## API v1
The API is documented by [swagger](https://gitea.com/api/swagger) and is based on [the GitHub API](https://docs.github.com/en/rest).
### GitHub API compatibility
Gitea's API should use the same endpoints and fields as the GitHub API as far as possible, unless there are good reasons to deviate. \
If Gitea provides functionality that GitHub does not, a new endpoint can be created. \
If information is provided by Gitea that is not provided by the GitHub API, a new field can be used that doesn't collide with any GitHub fields. \
Updating an existing API should not remove existing fields unless there is a really good reason to do so. \
The same applies to status responses. If you notice a problem, feel free to leave a comment in the code for future refactoring to API v2 (which is currently not planned).
### Adding/Maintaining API routes
All expected results (errors, success, fail messages) must be documented ([example](https://github.com/go-gitea/gitea/blob/c620eb5b2d0d874da68ebd734d3864c5224f71f7/routers/api/v1/repo/issue.go#L319-L327)). \
All JSON input types must be defined as a struct in [modules/structs/](modules/structs/) ([example](https://github.com/go-gitea/gitea/blob/c620eb5b2d0d874da68ebd734d3864c5224f71f7/modules/structs/issue.go#L76-L91)) \
and referenced in [routers/api/v1/swagger/options.go](https://github.com/go-gitea/gitea/blob/c620eb5b2d0d874da68ebd734d3864c5224f71f7/routers/api/v1/swagger/options.go). \
They can then be used like [this example](https://github.com/go-gitea/gitea/blob/c620eb5b2d0d874da68ebd734d3864c5224f71f7/routers/api/v1/repo/issue.go#L318). \
All JSON responses must be defined as a struct in [modules/structs/](modules/structs/) ([example](https://github.com/go-gitea/gitea/blob/c620eb5b2d0d874da68ebd734d3864c5224f71f7/modules/structs/issue.go#L36-L68)) \
and referenced in its category in [routers/api/v1/swagger/](routers/api/v1/swagger/) ([example](https://github.com/go-gitea/gitea/blob/c620eb5b2d0d874da68ebd734d3864c5224f71f7/routers/api/v1/swagger/issue.go#L11-L16)) \
They can be used like [this example](https://github.com/go-gitea/gitea/blob/c620eb5b2d0d874da68ebd734d3864c5224f71f7/routers/api/v1/repo/issue.go#L277-L279).
### When to use what HTTP method
In general, HTTP methods are chosen as follows:
- **GET** endpoints return the requested object(s) and status **OK (200)**
- **DELETE** endpoints return the status **No Content (204)** and no content either
- **POST** endpoints are used to **create** new objects (e.g. a User) and return the status **Created (201)** and the created object
- **PUT** endpoints are used to **add/assign** existing Objects (e.g. a user to a team) and return the status **No Content (204)** and no content either
- **PATCH** endpoints are used to **edit/change** an existing object and return the changed object and the status **OK (200)**
### Requirements for API routes
All parameters of endpoints changing/editing an object must be optional (except the ones to identify the object, which are required).
Endpoints returning lists must
- support pagination (`page` & `limit` options in query)
- set `X-Total-Count` header via **SetTotalCountHeader** ([example](https://github.com/go-gitea/gitea/blob/7aae98cc5d4113f1e9918b7ee7dd09f67c189e3e/routers/api/v1/repo/issue.go#L444))
## Backports and Frontports
### What is backported?
We backport PRs given the following circumstances:
1. Feature freeze is active, but `<version>-rc0` has not been released yet. Here, we backport as much as possible. <!-- TODO: Is that our definition with the new backport bot? -->
2. `rc0` has been released. Here, we only backport bug- and security-fixes, and small enhancements. Large PRs such as refactors are not backported anymore. <!-- TODO: Is that our definition with the new backport bot? -->
3. We never backport new features.
4. We never backport breaking changes except when
1. The breaking change has no effect on the vast majority of users
2. The component triggering the breaking change is marked as experimental
### How to backport?
In the past, it was necessary to manually backport your PRs. \
Now, that's not a requirement anymore as our [backport bot](https://github.com/GiteaBot) tries to create backports automatically once the PR is merged when the PR
- does not have the label `backport/manual`
- has the label `backport/<version>`
The `backport/manual` label signifies either that you want to backport the change yourself, or that there were conflicts when backporting, thus you **must** do it yourself.
### Format of backport PRs
The title of backport PRs should be
```
<original PR title> (#<original pr number>)
```
The first two lines of the summary of the backporting PR should be
```
Backport #<original pr number>
```
with the rest of the summary and labels matching the original PR.
### Frontports
Frontports behave exactly as described above for backports.
## Developer Certificate of Origin (DCO)
We consider the act of contributing to the code by submitting a Pull Request as the "Sign off" or agreement to the certifications and terms of the [DCO](DCO) and [MIT license](LICENSE). \
@@ -483,148 +291,3 @@ Signed-off-by: Joe Smith <joe.smith@email.com>
If you set the `user.name` and `user.email` Git config options, you can add the line to the end of your commits automatically with `git commit -s`.
We assume in good faith that the information you provide is legally binding.
## Release Cycle
We adopted a release schedule to streamline the process of working on, finishing, and issuing releases. \
The overall goal is to make a major release every three or four months, which breaks down into two or three months of general development followed by one month of testing and polishing known as the release freeze. \
All the feature pull requests should be
merged before feature freeze. All feature pull requests haven't been merged before this feature freeze will be moved to next milestone, please notice our feature freeze announcement on discord. And, during the frozen period, a corresponding
release branch is open for fixes backported from main branch. Release candidates
are made during this period for user testing to
obtain a final version that is maintained in this branch.
During a development cycle, we may also publish any necessary minor releases
for the previous version. For example, if the latest, published release is
v1.2, then minor changes for the previous release—e.g., v1.1.0 -> v1.1.1—are
still possible.
## Maintainers
To make sure every PR is checked, we have [maintainers](MAINTAINERS). \
Every PR **must** be reviewed by at least two maintainers (or owners) before it can get merged. \
For refactoring PRs after a week and documentation only PRs, the approval of only one maintainer is enough. \
A maintainer should be a contributor of Gitea and contributed at least
4 accepted PRs. A contributor should apply as a maintainer in the
[Discord](https://discord.gg/Gitea) `#develop` channel. The team maintainers may invite the contributor. A maintainer
should spend some time on code reviews. If a maintainer has no
time to do that, they should apply to leave the maintainers team
and we will give them the honor of being a member of the [advisors
team](https://github.com/orgs/go-gitea/teams/advisors). Of course, if
an advisor has time to code review, we will gladly welcome them back
to the maintainers team. If a maintainer is inactive for more than 3
months and forgets to leave the maintainers team, the owners may move
him or her from the maintainers team to the advisors team.
For security reasons, Maintainers should use 2FA for their accounts and
At the start of 2023, the `Owners` team was dissolved. Instead, the governance charter proposed a technical oversight committee (TOC) which expands the ownership team of the Gitea project from three elected positions to six positions. Three positions are elected as it has been over the past years, and the other three consist of appointed members from the Gitea company.
https://blog.gitea.com/quarterly-23q1/
### TOC election process
Any maintainer is eligible to be part of the community TOC if they are not associated with the Gitea company.
A maintainer can either nominate themselves, or can be nominated by other maintainers to be a candidate for the TOC election.
If you are nominated by someone else, you must first accept your nomination before the vote starts to be a candidate.
The TOC is elected for one year, the TOC election happens yearly.
After the announcement of the results of the TOC election, elected members have two weeks time to confirm or refuse the seat.
If an elected member does not answer within this timeframe, they are automatically assumed to refuse the seat.
Refusals result in the person with the next highest vote getting the same choice.
As long as seats are empty in the TOC, members of the previous TOC can fill them until an elected member accepts the seat.
If an elected member that accepts the seat does not have 2FA configured yet, they will be temporarily counted as `answer pending` until they manage to configure 2FA, thus leaving their seat empty for this duration.
Each member of the community elected TOC will be granted $500 each month as compensation for their work.
Furthermore, any community release manager for a specific release or LTS will be compensated $500 for the delivery of said release.
These funds will come from community sources like the OpenCollective rather than directly from the company.
Only non-company members are eligible for this compensation, and if a member of the community TOC takes the responsibility of release manager, they would only be compensated for their TOC duties.
Gitea Ltd employees are not eligible to receive any funds from the OpenCollective unless it is reimbursement for a purchase made for the Gitea project itself.
## TOC & Working groups
With Gitea covering many projects outside of the main repository, several groups will be created to help focus on specific areas instead of requiring maintainers to be a jack-of-all-trades. Maintainers are of course more than welcome to be part of multiple groups should they wish to contribute in multiple places.
The currently proposed groups are:
- **Core Group**: maintain the primary Gitea repository
- **Integration Group**: maintain the Gitea ecosystem's related tools, including go-sdk/tea/changelog/bots etc.
- **Documentation Group**: maintain related documents and repositories
- **Translation Group**: coordinate with translators and maintain translations
- **Security Group**: managed by TOC directly, members are decided by TOC, maintains security patches/responsible for security items
## Roadmap
Each year a roadmap will be discussed with the entire Gitea maintainers team, and feedback will be solicited from various stakeholders.
TOC members need to review the roadmap every year and work together on the direction of the project.
When a vote is required for a proposal or other change, the vote of community elected TOC members count slightly more than the vote of company elected TOC members. With this approach, we both avoid ties and ensure that changes align with the mission statement and community opinion.
You can visit our roadmap on the wiki.
## Versions
Gitea has the `main` branch as a tip branch and has version branches
such as `release/v1.19`. `release/v1.19` is a release branch and we will
tag `v1.19.0` for binary download. If `v1.19.0` has bugs, we will accept
pull requests on the `release/v1.19` branch and publish a `v1.19.1` tag,
after bringing the bug fix also to the main branch.
Since the `main` branch is a tip version, if you wish to use Gitea
in production, please download the latest release tag version. All the
branches will be protected via GitHub, all the PRs to every branch must
be reviewed by two maintainers and must pass the automatic tests.
## Releasing Gitea
- Let $vmaj, $vmin and $vpat be Major, Minor and Patch version numbers, $vpat should be rc1, rc2, 0, 1, ...... $vmaj.$vmin will be kept the same as milestones on github or gitea in future.
- Before releasing, confirm all the version's milestone issues or PRs has been resolved. Then discuss the release on Discord channel #maintainers and get agreed with almost all the owners and mergers. Or you can declare the version and if nobody is against it in about several hours.
- If this is a big version first you have to create PR for changelog on branch `main` with PRs with label `changelog` and after it has been merged do following steps:
- Create `-dev` tag as `git tag -s -F release.notes v$vmaj.$vmin.0-dev` and push the tag as `git push origin v$vmaj.$vmin.0-dev`.
- When CI has finished building tag then you have to create a new branch named `release/v$vmaj.$vmin`
- If it is bugfix version create PR for changelog on branch `release/v$vmaj.$vmin` and wait till it is reviewed and merged.
- Add a tag as `git tag -s -F release.notes v$vmaj.$vmin.$`, release.notes file could be a temporary file to only include the changelog this version which you added to `CHANGELOG.md`.
- And then push the tag as `git push origin v$vmaj.$vmin.$`. Drone CI will automatically create a release and upload all the compiled binary. (But currently it doesn't add the release notes automatically. Maybe we should fix that.)
- If needed send a frontport PR for the changelog to branch `main` and update the version in `docs/config.yaml` to refer to the new version.
- Send PR to [blog repository](https://gitea.com/gitea/blog) announcing the release.
- Verify all release assets were correctly published through CI on dl.gitea.com and GitHub releases. Once ACKed:
- bump the version of https://dl.gitea.com/gitea/version.json
- merge the blog post PR
- announce the release in discord `#announcements`
[](https://discord.gg/Gitea "Join the Discord chat at https://discord.gg/Gitea")
[](https://www.codetriage.com/go-gitea/gitea "Help Contribute to Open Source")
[](https://opencollective.com/gitea "Become a backer/sponsor of gitea")
You can find comprehensive documentation on our official [documentation website](https://docs.gitea.com/).
It includes installation, administration, usage, development, contributing guides, and more to help you get started and explore all features effectively.
If you have any suggestions or would like to contribute to it, you can visit the [documentation repository](https://gitea.com/gitea/docs)
## Building
From the root of the source tree, run:
TAGS="bindata" make build
or if SQLite support is required:
TAGS="bindata sqlite sqlite_unlock_notify" make build
The `build` target is split into two sub-targets:
-`make backend` which requires [Go Stable](https://go.dev/dl/), the required version is defined in [go.mod](/go.mod).
-`make frontend` which requires [Node.js LTS](https://nodejs.org/en/download/) or greater and [pnpm](https://pnpm.io/installation).
Internet connectivity is required to download the go and npm modules. When building from the official source tarballs which include pre-built frontend files, the `frontend` target will not be triggered, making it possible to build without Node.js.
More info: https://docs.gitea.com/installation/install-from-source
## Using
After building, a binary file named `gitea` will be generated in the root of the source tree by default. To run it, use:
./gitea web
> [!NOTE]
> If you're interested in using our APIs, we have experimental support with [documentation](https://docs.gitea.com/api).
Full documentation is available on the [Wiki](https://git.mokoconsulting.tech/MokoConsulting/MokoGitea/wiki).
Translations are done through [Crowdin](https://translate.gitea.com). If you want to translate to a new language, ask one of the managers in the Crowdin project to add a new language there.
You can also just create an issue for adding a language or ask on Discord on the #translation channel. If you need context or find some translation issues, you can leave a comment on the string or ask on Discord. For general translation questions there is a section in the docs. Currently a bit empty, but we hope to fill it as questions pop up.
Get more information from [documentation](https://docs.gitea.com/contributing/localization).
## Official and Third-Party Projects
We provide an official [go-sdk](https://gitea.com/gitea/go-sdk), a CLI tool called [tea](https://gitea.com/gitea/tea) and an [action runner](https://gitea.com/gitea/act_runner) for Gitea Action.
We maintain a list of Gitea-related projects at [gitea/awesome-gitea](https://gitea.com/gitea/awesome-gitea), where you can discover more third-party projects, including SDKs, plugins, themes, and more.
## Communication
[](https://discord.gg/Gitea "Join the Discord chat at https://discord.gg/Gitea")
If you have questions that are not covered by the [documentation](https://docs.gitea.com/), you can get in contact with us on our [Discord server](https://discord.gg/Gitea) or create a post in the [discourse forum](https://forum.gitea.com/).
Support this project by becoming a sponsor. Your logo will show up here with a link to your website. [[Become a sponsor](https://opencollective.com/gitea#sponsor)]
Gitea is pronounced [/ɡɪ’ti:/](https://youtu.be/EM71-2uDAoY) as in "gi-tea" with a hard g.
**Why is this not hosted on a Gitea instance?**
We're [working on it](https://github.com/go-gitea/gitea/issues/1029).
**Where can I find the security patches?**
In the [release log](https://github.com/go-gitea/gitea/releases) or the [change log](https://github.com/go-gitea/gitea/blob/main/CHANGELOG.md), search for the keyword `SECURITY` to find the security patches.
See the wiki for development guidelines and contribution instructions.
## License
This project is licensed under the MIT License.
See the [LICENSE](https://github.com/go-gitea/gitea/blob/main/LICENSE) file
for the full license text.
This project is licensed under the GNU General Public License v3.0 or later -- see the [LICENSE](LICENSE) file.
## Further information
---
<details>
<summary>Looking for an overview of the interface? Check it out!</summary>
Some files were not shown because too many files have changed in this diff
Show More
Reference in New Issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.