Compare commits

...

129 Commits

Author SHA1 Message Date
Copilot
45b4fffae4 refactor: use named Permission field in Repository struct instead of anonymous embedding (#37441)
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>
2026-04-26 20:18:28 +00:00
wxiaoguang
55c9b936cb Refactor pull request view (3) (#37439)
Move some complex logic to backend

Rename `pr.CanAutoMerge` to `pr.IsStatusMergeable`
2026-04-26 19:03:41 +00:00
Nicolas
29c510ef94 Update 1.26.1 changelog in main (#37442)
Signed-off-by: Nicolas <bircni@icloud.com>
Signed-off-by: wxiaoguang <wxiaoguang@gmail.com>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
2026-04-26 20:05:35 +02:00
wxiaoguang
068b59aa97 Make GetPossibleUserByID can handle deleted user (#37430)
Make sure deleted user won't cause 500 error, simplify the caller's code
2026-04-26 16:57:53 +00:00
wxiaoguang
2f42c8cf72 Fix fetch action redirect (#37437)
And add tests for its behavior
2026-04-26 16:37:03 +00:00
Copilot
2671b997f2 Refactor integration test DecodeJSON calls to use generic return value (#37432)
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>
2026-04-26 14:57:07 +00:00
silverwind
99cd4f6b22 Integrate renovate bot for all dependency updates (#37050)
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>
2026-04-26 14:25:22 +00:00
wxiaoguang
b3ed4cde9a Refactor pull request view (2) (#37428)
Follow up #37380

Some code is moved to the place whether it should be.
2026-04-26 13:58:48 +00:00
wxiaoguang
712b3a54b5 Use MarkLongPolling instead of hard-coded route path (#37427) 2026-04-26 11:42:29 +00:00
silverwind
ebf30ac4db Optimize CI caches (#37387)
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>
2026-04-26 10:25:35 +00:00
silverwind
f2a7f6c999 Update AGENTS.md (#37420)
`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>
2026-04-26 12:00:48 +02:00
github-actions[bot]
9e0f692f28 Update Nix flake (#37425)
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>
2026-04-26 11:46:48 +02:00
GiteaBot
d19f653479 [skip ci] Updated translations via Crowdin 2026-04-26 01:04:13 +00:00
TheFox0x7
3e0b99da3b remove excessive quote from terraform instructions (#37424)
fixes: https://github.com/go-gitea/gitea/issues/37423
2026-04-26 00:59:58 +02:00
Copilot
9b9fb95559 Improve testing init, clean up webhook tests (#37412)
Avoid webhook test fixtures affect other tests (be triggered)

Also fixed more testing problems including path init, global config
pollution & conflict

---------

Signed-off-by: silverwind <me@silverwind.io>
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: silverwind <me@silverwind.io>
2026-04-25 18:55:18 +00:00
silverwind
24b60f8ff9 Fix color regressions, add priority color (#37417)
- 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>
2026-04-25 19:08:10 +02:00
GiteaBot
683f8c0014 [skip ci] Updated translations via Crowdin 2026-04-25 00:56:33 +00:00
silverwind
0277e3ebaa Stabilize e2e logout propagation test (#37403)
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>
2026-04-24 15:37:01 +00:00
Copilot
c5c9713ed4 refactor: serve site manifest via /assets/site-manifest.json endpoint (#37405)
Slightly reduce the page size for every request, and don't need to use `href="data:`

Signed-off-by: wxiaoguang <wxiaoguang@gmail.com>
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: silverwind <me@silverwind.io>
Co-authored-by: Claude (Opus 4.7) <noreply@anthropic.com>
2026-04-24 13:00:59 +00:00
Sai Asish Y
6826321570 feat(security): set X-Content-Type-Options: nosniff by default (#37354)
Fixes #37316.

---------

Signed-off-by: SAY-5 <SAY-5@users.noreply.github.com>
Co-authored-by: SAY-5 <SAY-5@users.noreply.github.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>
2026-04-24 11:21:34 +00:00
wxiaoguang
1483291a87 Refactor pull request view (1) (#37380)
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**
2026-04-24 10:24:41 +00:00
silverwind
de99b1fbbf Improve AGENTS.md (#37382)
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>
2026-04-24 09:49:20 +00:00
silverwind
58a1330078 Remove dead CSS (#37376)
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>
2026-04-24 09:45:16 +00:00
silverwind
aa0707c679 Add pr-review e2e test and speed up e2e tests (#37345)
- 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>
2026-04-24 08:19:59 +00:00
silverwind
3816210c05 Drop Fomantic tab, checkbox and form patches (#37377)
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>
2026-04-24 16:02:37 +08:00
Copilot
0817a405af fix: dump with default zip type produces uncompressed zip (#37401)
Fix #37393

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: wxiaoguang <2114189+wxiaoguang@users.noreply.github.com>
2026-04-24 14:35:15 +08:00
Nikita Vakula
3b2fd9791c Allow fast-forward-only merge when signed commits are required (#37335)
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>
2026-04-24 00:04:32 +00:00
Zettat123
899ede1d55 Introduce ActionRunAttempt to represent each execution of a run (#37119)
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>
2026-04-23 23:33:41 +00:00
Lunny Xiao
aedf4e84f5 Move review request functions to a standalone file (#37358)
Assignee functions should be different from review request functions.
2026-04-23 23:01:04 +00:00
wxiaoguang
1af16679c3 Fix repo init README EOL (#37388)
Fix #27120

By the way, refactor ReserveLineBreakForTextarea to NormalizeStringEOL
2026-04-23 18:33:16 +00:00
pisarz77
85192c2e9f Fix org team assignee/reviewer lookups for team member permissions (#37365)
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>
2026-04-23 18:14:29 +02:00
silverwind
7947851e57 Remove external service dependencies in migration tests (#36866)
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>
2026-04-23 15:18:53 +00:00
silverwind
12d83cbfa3 Extend issue context popup beyond markdown content (#36908)
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>
2026-04-23 13:58:31 +00:00
Nicolas
8e85454a50 fix: commit status reporting (#37372)
Fixes the issue that status report always shows waiting to run, when
already running

https://github.com/go-gitea/gitea/issues/36906#issuecomment-4294545813

---------

Co-authored-by: silverwind <me@silverwind.io>
Co-authored-by: Claude (Opus 4.7) <noreply@anthropic.com>
2026-04-22 22:04:51 +00:00
wxiaoguang
83bdfc2a57 Support for Custom URI Schemes in OAuth2 Redirect URIs (#37356)
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
2026-04-22 21:33:27 +00:00
Morgan Peyre
8cfcef32c6 Fix cmd tests by mocking builtin paths (#37369)
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>
2026-04-22 20:58:59 +00:00
Morgan Peyre
9894ebb79c chore: upgrade Go version in devcontainer image to 1.26 (#37374)
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>
2026-04-22 21:47:59 +02:00
bytedream
32fdfb0bd6 Fix button layout shift when collapsing file tree in editor (#37363)
Also fix misc discovered issues.

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>
2026-04-22 18:46:25 +00:00
PineBale
4695110d5f Update Block a user form (#37359)
Use the new "form-fetch-action" for better user experience, and use
JSONError to show error messages.

---------

Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
2026-04-23 02:07:02 +08:00
Copilot
df8aa2f804 Remove IsValidExternalURL/IsAPIURL and use IsValidURL at call sites (#37364)
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>
2026-04-22 09:23:27 -07:00
PineBale
f52b6f3315 Add URL to Learn more about blocking a user (#37355)
Closes #29992
2026-04-22 16:13:45 +08:00
Kalash Thakare ☯︎
c69cbb75bf fix: use TriggerEvent instead of Event in workflow runs API response for scheduled runs (#37288)
## 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>
2026-04-21 21:14:34 +00:00
Lunny Xiao
f1644fc5e2 Add event.schedule context for schedule actions task (#37320)
Fix #35452

---------

Co-authored-by: silverwind <me@silverwind.io>
Co-authored-by: Claude (Opus 4.7) <noreply@anthropic.com>
Co-authored-by: Giteabot <teabot@gitea.io>
2026-04-21 20:30:21 +00:00
Nicolas
732e23258e Fix typos (#37346)
Fixes some typos
2026-04-21 19:56:14 +00:00
Lunny Xiao
b4f48a64fc Fix an issue where changing an organization’s visibility caused problems when users had forked its repositories. (#37324)
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>
2026-04-21 18:47:51 +00:00
silverwind
c489db447d Fail vite build on rolldown warnings via NODE_ENV=test (#37270)
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>
2026-04-21 18:11:07 +00:00
wxiaoguang
38d337c94a Use modern "git update-index --cacheinfo" syntax to support more file names (#37338)
Modern syntax was added in git 2.0

And add more tests
2026-04-21 16:39:01 +00:00
wxiaoguang
aee6628bf5 Fix URL related escaping for oauth2 (#37334)
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.
2026-04-21 23:58:32 +08:00
chethenry
5495b5d126 When the requested arch rpm is missing fall back to noarch (#37236)
This fixes: https://github.com/go-gitea/gitea/issues/37235

It uses the same changeset alpine packages got in:
https://github.com/go-gitea/gitea/issues/26691

---------

Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
2026-04-21 10:52:28 +00:00
silverwind
caff989f34 Fix relative-time error and improve global error handler (#37241)
1. Fixes: #37239
2. Enhance global error message to show stack trace on click

---------

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>
2026-04-21 07:53:19 +00:00
Nicolas
3db3127655 Enhance styling in actions page (#37323)
- Adjust workflow graph for better visualization
- change summary icon to home icon
- use octicon-file-removed for expired artifacts
2026-04-21 15:22:11 +08:00
prettysunflower
63db5972a1 fix(oauth): Error on auth sources with spaces (#37327)
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>
2026-04-21 05:58:04 +00:00
silverwind
f94b476c45 Fix actions concurrency groups cross-branch leak (#37311)
## 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>
2026-04-21 02:25:36 +00:00
Lunny Xiao
12733d3624 Fix bug when accessing user badges (#37321)
Fix #37302

---------

Co-authored-by: silverwind <me@silverwind.io>
2026-04-21 01:18:12 +00:00
Lunny Xiao
85c09b8f45 Fix AppFullLink (#37325)
Fix a bug the checkout command line hint becomes
`git fetch -u https://gitea.combircni/tea`
2026-04-20 23:57:08 +00:00
Sebastian Ertz
3f3bebda0d Update go js dependencies (#37312)
| go | from | to |
| --- | --- | --- |
| github.com/aws/aws-sdk-go-v2/credentials | `1.19.14` | `1.19.15` |
| github.com/aws/aws-sdk-go-v2/service/codecommit | `1.33.12` |
`1.33.13` |
| github.com/dlclark/regexp2 | `1.11.5` | `1.12.0` |
| github.com/go-co-op/gocron/v2 | `2.20.0` | `2.21.0` |
| github.com/go-webauthn/webauthn | `0.16.4` | `0.16.5` |

| js | from | to |
| --- | --- | --- |
| @codemirror/view | `6.41.0` | `6.41.1` |
| @primer/octicons | `19.24.0` | `19.24.1` |
| clippie | `4.1.10` | `4.1.14` |
| postcss | `8.5.9` | `8.5.10` |
| rolldown-license-plugin | `2.2.5` | `3.0.1` |
| swagger-ui-dist | `5.32.2` | `5.32.4` |
| vite | `8.0.8` | `8.0.9` |
| @typescript-eslint/parser | `8.58.2` | `8.59.0` |
| @vitest/eslint-plugin | `1.6.15` | `1.6.16` |
| eslint | `10.2.0` | `10.2.1` |
| eslint-plugin-playwright | `2.10.1` | `2.10.2` |
| eslint-plugin-sonarjs | `4.0.2` | `4.0.3` |
| happy-dom | `20.8.9` | `20.9.0` |
| stylelint | `17.7.0` | `17.8.0` |
| typescript | `6.0.2` | `6.0.3` |
| typescript-eslint | `8.58.2` | `8.59.0` |
| updates | `17.15.3` | `17.15.5` |
| vue-tsc | `3.2.6` | `3.2.7` |

Co-authored-by: Nicolas <bircni@icloud.com>
Co-authored-by: silverwind <me@silverwind.io>
Co-authored-by: silverwind <silv3rwind@gmail.com>
Co-authored-by: Claude (Opus 4.7) <noreply@anthropic.com>
2026-04-20 22:32:45 +00:00
Sebastian Ertz
8068d608d1 Update GitHub Actions to latest major versions (#37313)
|  | from | to |
| --- | --- | --- |
| actions/setup-node | `v5` | `v6` |
| astral-sh/setup-uv | `v8.0.0` | `v8.1.0` |
2026-04-20 20:27:12 +00:00
silverwind
b6ea666fd4 Revert "Add WebKit to e2e test matrix (#37298)" (#37315)
Reverts: #37298
Ref:
https://github.com/go-gitea/gitea/actions/runs/24661464168/job/72108324223?pr=37312

WebKit on Linux has a long history of flakiness in Playwright CI runs,
and the exact "WebKit encountered an internal error" class of failures
has been reported repeatedly and closed without a real fix (typically
stale/no-repro, or worked around by retries):

- https://github.com/microsoft/playwright/issues/34450
- https://github.com/microsoft/playwright/issues/35773
- https://github.com/microsoft/playwright/issues/35870
- https://github.com/microsoft/playwright/issues/35293
- https://github.com/microsoft/playwright/issues/38838

Keeping chromium and firefox in the e2e matrix.

---
This PR was written with the help of Claude Opus 4.7

Co-authored-by: Claude (Opus 4.7) <noreply@anthropic.com>
2026-04-20 19:49:38 +00:00
PineBale
ca44b5fca8 Add form-fetch-action to some forms, fix "fetch action" resp bug (#37305)
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
2026-04-20 18:58:44 +00:00
silverwind
1d25bb22f4 Move heatmap to first-party code (#37262)
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>
2026-04-20 20:15:45 +02:00
techknowlogick
019d85039c Use updated yaml fields for snapcraft (#37318) 2026-04-20 19:02:29 +02:00
silverwind
aba87285f0 Remove dead code identified by deadcode tool (#37271)
Ran [`deadcode`](https://pkg.go.dev/golang.org/x/tools/cmd/deadcode)
(`-test ./...`) to find functions, methods and error types unreachable
from any call path (including tests), and removed the truly-dead ones.

Co-authored-by: Claude (Opus 4.7) <noreply@anthropic.com>
2026-04-20 07:52:48 +00:00
silverwind
f6960096f3 Enable strict TypeScript, add errorMessage helper (#37292)
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>
2026-04-20 07:22:05 +00:00
silverwind
5a3d8d3224 Fix vite manifest update masking build errors (#37279)
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>
2026-04-20 07:10:46 +00:00
techknowlogick
ee253afb86 bump snapcraft base (#37301) 2026-04-20 08:16:48 +02:00
silverwind
6f761219b2 Add WebKit to e2e test matrix (#37298)
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>
2026-04-19 19:09:43 +00:00
Lunny Xiao
a17d5ebe16 Don't add useless labels which will bother changelog generation (#37267)
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.
2026-04-19 11:34:40 -07:00
PineBale
99cd709bd6 Fix Repository transferring page (#37277)
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>
2026-04-19 17:57:51 +00:00
silverwind
b31eef2828 Stabilize issue-project e2e test, increase timeout factor (#37297)
1. stabilize flaky e2e test from
2f5b5a9e9c
2. increase ci timeout factor to 4 as 3 was not enough
3. add a `e2e` category to files-changed so e2e-test-only changes
trigger ci

---
This PR was written with the help of Claude Opus 4.7

---------

Co-authored-by: Claude (Opus 4.7) <noreply@anthropic.com>
2026-04-19 17:27:23 +00:00
Nicolas
284298f2a9 Fix Mermaid diagrams failing when node labels contain line breaks (#37296)
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
2026-04-19 17:39:40 +02:00
Myers Carpenter
2f5b5a9e9c Add project column picker to issue and pull request sidebar (#37037)
Why? You are working on a ticket, it's ready to be moved to the QA
column in your project. Currently you have to go to the project, find
the issue card, then move it. With this change you can move the issue's
column on the issue page.

When an issue or pull request belongs to a project board, a dropdown
appears in the sidebar to move it between columns without opening the
board view. Read-only users see the current column name instead.

* Fix #13520
* Replace #30617

This was written using Claude Code and Opus. 

Closed:

<img width="1346" height="507" alt="image"
src="https://github.com/user-attachments/assets/7c1ea7ee-b71c-40af-bb14-aeb1d2beff73"
/>

Open:
<img width="1315" height="577" alt="image"
src="https://github.com/user-attachments/assets/4d64b065-44c2-42c7-8d20-84b5caea589a"
/>

---------

Signed-off-by: silverwind <me@silverwind.io>
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: Nicolas <bircni@icloud.com>
Co-authored-by: Cursor <cursor@cursor.com>
2026-04-19 12:53:02 +00:00
wxiaoguang
6ed861589a Fix container auth for public instance (#37290)
Fix #37289
2026-04-19 11:52:47 +00:00
Copilot
30be22f30f Refactor frontend tw-justify-between layouts to flex-left-right (#37291)
This PR standardizes left/right two-child frontend layouts on
`flex-left-right` and removes ad-hoc `tw-justify-between` combinations.
The goal is consistent wrapping + spacing behavior under narrow widths
with less utility-class churn.

Also: remove useless "flex-center-wrap", slightly improve some templates
(no visual change, tested)

---------

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>
2026-04-19 18:57:48 +08:00
github-actions[bot]
c98134033a Update Nix flake (#37284)
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>
2026-04-19 12:20:49 +02:00
Nicolas
16bdae53c8 Workflow Artifact Info Hover (#37100)
Add expiry metadata to action artifacts in the run view and show it on hover.

---------

Signed-off-by: Nicolas <bircni@icloud.com>
Co-authored-by: silverwind <me@silverwind.io>
Co-authored-by: Claude (Opus 4.6) <noreply@anthropic.com>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
2026-04-19 07:37:50 +00:00
GiteaBot
0bc2a2836f [skip ci] Updated translations via Crowdin 2026-04-19 01:01:55 +00:00
Lunny Xiao
ea6280da75 release notes for 1.26.0 (#37282)
Frontend from #37266
2026-04-18 13:39:25 -07:00
Nicolas
f247d7d4e5 Enhance GetActionWorkflow to support fallback references (#37189)
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>
2026-04-18 20:21:21 +00:00
wxiaoguang
af31b9d433 Refactor LDAP tests (#37274)
Not really fix #37263, just make things better, and easy to catch more
clues if it would fail again.
2026-04-18 19:32:49 +00:00
silverwind
0824610e39 Remove SubmitEvent polyfill (#37276)
Remove this obsolete polyfill as per
https://github.com/go-gitea/gitea/pull/37270#issuecomment-4273399551.

Co-authored-by: Claude (Opus 4.7) <noreply@anthropic.com>
2026-04-18 20:55:01 +02:00
silverwind
98202110be Upgrade go-git to v5.18.0 (#37268)
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>
2026-04-18 08:49:40 +00:00
wxiaoguang
cf3f8e807a Avoid top-level await (#37272) 2026-04-18 16:01:58 +08:00
silverwind
d5831b9385 Frontend iframe renderer framework: 3D models, OpenAPI (#37233)
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>
2026-04-17 22:30:17 +00:00
JoeGruffins
0161f3019b pull: Fix CODEOWNERS absolute path matching. (#37244)
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>
2026-04-17 23:54:49 +02:00
Copilot
e43422b042 Swift registry metadata: preserve more JSON fields and accept empty metadata (#37254) 2026-04-18 04:16:26 +08:00
silverwind
a9108ab6aa Replace custom Go formatter with golangci-lint fmt (#37194)
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>
2026-04-17 17:45:22 +00:00
wxiaoguang
279bf84066 Fix user ssh key exporting and tests (#37256)
1. Make sure OmitEmail won't panic
2. SSH principal keys are not for signing or authentication
2026-04-17 16:57:20 +00:00
PineBale
18064f772d Add pagination and search box to org teams list (#37245)
- Add pagination and keyword search to the teams list page
- 5 teams shown at most in the overview page

Fixes: #34482
Fixes: #36602
Fixes: #37084
Signed-off-by: silverwind <me@silverwind.io>
Co-authored-by: Animesh Kumar <83393501+kmranimesh@users.noreply.github.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>
2026-04-17 17:29:11 +02:00
Copilot
eb334e3738 tests/integration: simplify code (#37249)
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: silverwind <me@silverwind.io>
Co-authored-by: Claude (Opus 4.7) <noreply@anthropic.com>
2026-04-17 20:33:49 +08:00
silverwind
dc974715e9 Fix commit title rendering in action run and blame (#37243)
Fixes #37242

Co-authored-by: Claude (Opus 4.7) <noreply@anthropic.com>
2026-04-17 09:18:33 +00:00
PineBale
2bfaa33347 Replace dropzone with @deltablot/dropzone (#37237)
Fix #37228. 

Using NicolasCARPi/dropzone as short-term solution
2026-04-17 08:16:42 +00:00
Zettat123
b1bfca39f1 Add ExternalIDClaim option for OAuth2 OIDC auth source (#37229)
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.
2026-04-16 17:30:46 +00:00
Copilot
4a2bba9aed Remove error returns from crypto random helpers and callers (#37240)
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: silverwind <115237+silverwind@users.noreply.github.com>
2026-04-17 00:59:26 +08:00
wxiaoguang
82bfde2a37 Use Content-Security-Policy: script nonce (#37232)
Fix #305
2026-04-15 20:07:57 +00:00
wxiaoguang
2644bb8490 Remove htmx (#37224)
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>
2026-04-15 17:26:26 +00:00
wxiaoguang
17f62bfec5 Refactor "htmx" to "fetch action" (#37208)
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)
2026-04-14 18:38:07 +00:00
wxiaoguang
893df6b265 Fix UI regression (#37218)
Fix  #37213

Also fix the misaligned tags, remove unused classes, etc.
2026-04-14 23:24:44 +08:00
wxiaoguang
b9961e193d Fix corrupted JSON caused by goccy library (#37214)
Fix #37211
2026-04-14 14:00:20 +00:00
wxiaoguang
699eb41e7c Add test for "fetch redirect", add CSS value validation for external render (#37207)
By the way, fix the checkAppUrl message for #37212
2026-04-14 13:11:08 +00:00
Zettat123
9327b1808e Fix incorrect concurrency check (#37205)
This bug was identified in
https://github.com/go-gitea/gitea/pull/37119/changes#diff-37655a02d5a44d5c0e3e19c75fb58adb47a8e7835cbd619345d5b556292935a7L180

Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
Co-authored-by: Giteabot <teabot@gitea.io>
2026-04-14 12:34:41 +00:00
Copilot
84d5c99e64 refactor: simplify ParseCatFileTreeLine and catBatchParseTreeEntries (#37210)
Simplify ParseCatFileTreeLine: it is faster without the preset buffers,
and easier to read and maintain.

---------

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>
2026-04-14 12:03:26 +00:00
Sebastian Ertz
b55528b1a2 Update go js py dependencies (#37204)
| go | from | to |
| --- | --- | --- |
| github.com/go-webauthn/webauthn | `0.16.3` | `0.16.4` |
| github.com/meilisearch/meilisearch-go | `0.36.1` | `0.36.2` |
| golang.org/x/crypto | `0.49.0` | `0.50.0` |
| golang.org/x/image | `0.38.0` | `0.39.0` |
| golang.org/x/net | `0.52.0` | `0.53.0` |
| golang.org/x/text | `0.35.0` | `0.36.0` |

| js | from | to |
| --- | --- | --- |
| @primer/octicons | `19.23.1` | `19.24.0` |
| @vitejs/plugin-vue | `6.0.5` | `6.0.6` |
| rolldown-license-plugin | `2.2.0` | `2.2.5` |
| vite | `8.0.7` | `8.0.8` |
| @types/node | `25.5.2` | `25.6.0` |
| @typescript-eslint/parser | `8.58.1` | `8.58.2` |
| @vitest/eslint-plugin | `1.6.14` | `1.6.15` |
| globals | `17.4.0` | `17.5.0` |
| stylelint | `17.6.0` | `17.7.0` |
| typescript-eslint | `8.58.1` | `8.58.2` |
| updates | `17.13.5` | `17.15.3` |
| vitest | `4.1.3` | `4.1.4` |

| py | from | to |
| --- | --- | --- |
| click | `8.3.1` | `8.3.2` |
| json5 | `0.13.0` | `0.14.0` |
| regex | `2026.2.19` | `2026.4.4` |
| tomli | `2.4.0` | `2.4.1` |
2026-04-14 12:45:54 +02:00
wxiaoguang
0593b58ff7 Add comment for the design of "user activity time" (#37195) 2026-04-13 20:01:29 +00:00
Mohit Swarnkar
37396fff13 fix(api): handle missing base branch in PR commits API (#37193)
Closes #36366

---------

Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
2026-04-13 19:30:41 +00:00
wxiaoguang
6bcb666a9d Refactor htmx and fetch-action related code (#37186)
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.
2026-04-13 18:53:55 +00:00
Nicolas
6eae04241d Fix encoding for Matrix Webhooks (#37190)
`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>
2026-04-13 18:10:43 +00:00
Xing Hong
fa8f7f15ef Always show owner/repo name in compare page dropdowns (#37172)
Fixes: https://github.com/go-gitea/gitea/issues/36677

---------

Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
2026-04-14 01:25:58 +08:00
Mohit Swarnkar
80585adab4 fix(api): handle fork-only commits in compare API (#37185)
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>
2026-04-12 18:52:46 -07:00
Nicolas
47fdf3e284 Improve Contributing docs and set a release schedule (#37109)
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>
2026-04-12 11:26:02 -07:00
github-actions[bot]
355aafd1f9 Update Nix flake (#37183) 2026-04-12 16:51:54 +00:00
wxiaoguang
c2fa157731 Remove outdated RunUser logic (#37180)
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.
2026-04-12 02:52:12 +00:00
wxiaoguang
8fcbdf05b0 Refactor flash message and remove SanitizeHTML template func (#37179)
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
2026-04-12 10:17:25 +08:00
silverwind
ba9258c478 Indicate form field readonly via background (#37175)
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>
2026-04-11 14:38:56 +00:00
silverwind
d913fae237 Remove dead CSS rules (#37173)
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>
2026-04-11 10:41:56 +00:00
silverwind
09c2677b21 Fix flaky TestCatFileBatch/QueryTerminated test (#37159)
`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
Co-authored-by: Claude (Opus 4.6) <noreply@anthropic.com>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
2026-04-10 17:34:12 +00:00
Elisei Roca
16d7817338 Implement logout redirection for reverse proxy auth setups (#36085)
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>
2026-04-10 13:02:35 +00:00
silverwind
681c4074e5 Add missing //nolint:depguard (#37162)
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>
2026-04-10 10:39:28 +00:00
wxiaoguang
45c80bfec1 Make Markdown fenced code block work with more syntaxes (#37154) 2026-04-09 23:54:39 +00:00
wxiaoguang
c10a5b908a Remove unneeded doctor sub-commands (#37156)
Co-authored-by: Giteabot <teabot@gitea.io>
2026-04-09 22:22:17 +02:00
Nicolas
980a8995bc Report structurally invalid workflows to users (#37116)
`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>
2026-04-09 15:03:32 +02:00
silverwind
04fb6f1c0b Replace rollup-plugin-license with rolldown-license-plugin (#37130)
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>
2026-04-09 09:31:05 +00:00
silverwind
0914a44a9b Clean up and improve non-gitea js error filter (#37148)
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>
2026-04-09 08:36:08 +00:00
Copilot
6f9fa55785 models/fixtures: add "DO NOT add more test data" comment to all yml fixture files (#37150)
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: wxiaoguang <2114189+wxiaoguang@users.noreply.github.com>
2026-04-09 13:26:21 +08:00
Lunny Xiao
8bf3c8b79d Frontport changelog of v1.26.0-rc0 (#37138) 2026-04-08 22:43:28 +02:00
Sebastian Ertz
dfd495f823 Update go dependencies (#37141)
|     | from | to  |
| --- | ---- | --- |
| github.com/aws/aws-sdk-go-v2/credentials | `v1.19.13` | `v1.19.14` |
| github.com/go-co-op/gocron/v2 | `v2.19.1` | `v2.20.0` |
| github.com/go-enry/go-enry/v2 | `v2.9.5` | `v2.9.6` |
| github.com/go-webauthn/webauthn | `v0.16.1` | `v0.16.3` |
| github.com/google/pprof | `v0.0.0-20260302011040-a15ffb7f9dcc` |
`v0.0.0-20260402051712-545e8a4df936` |
| github.com/lib/pq | `v1.12.1` | `v1.12.3` |
| github.com/mattn/go-isatty | `v0.0.20` | `v0.0.21` |
| github.com/mattn/go-sqlite3 | `v1.14.38` | `v1.14.42` |
| github.com/minio/minio-go/v7 | `v7.0.99` | `v7.0.100` |
| golang.org/x/sys | `v0.42.0` | `v0.43.0` |
| google.golang.org/grpc | `v1.79.3` | `v1.80.0` |
2026-04-08 19:07:17 +00:00
Sebastian Ertz
714f4207d9 Update javascript dependencies (#37142)
---

|     | from | to  |
| --- | ---- | --- |
| esbuild | `0.27.4` | `0.28.0` |
| katex | `0.16.44` | `0.16.45` |
| postcss | `8.5.8` | `8.5.9` |
| swagger-ui-dist | `5.32.1` | `5.32.2` |
| vite | `8.0.5` | `8.0.7` |
| vue | `3.5.31` | `3.5.32` |
2026-04-08 16:45:02 +00:00
silverwind
d600968aaf Bump min go version to 1.26.2 (#37139)
Update Go from 1.26.1 to 1.26.2 to fix 6 stdlib vulnerabilities:
- GO-2026-4947: `crypto/x509` chain building
- GO-2026-4946: `crypto/x509` policy validation
- GO-2026-4870: `crypto/tls` KeyUpdate DoS
- GO-2026-4869: `archive/tar` unbounded allocation
- GO-2026-4866: `crypto/x509` name constraints bypass
- GO-2026-4865: `html/template` XSS

Co-authored-by: Claude (Opus 4.6) <noreply@anthropic.com>
2026-04-08 17:56:06 +02:00
Karthik Bhandary
fc178e3203 Add bulk repository deletion for organizations (#36763)
Fixes #36512

This PR adds a new API endpoint to delete all repositories within an
organization in a single operation, improving efficiency for
organization cleanup and management tasks.

---------

Signed-off-by: Karthik Bhandary <34509856+karthikbhandary2@users.noreply.github.com>
Co-authored-by: karthik.bhandary <karthik.bhandary@kfintech.com>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
2026-04-08 04:32:22 +00:00
GiteaBot
03205d94da [skip ci] Updated translations via Crowdin 2026-04-08 00:55:16 +00:00
1026 changed files with 18742 additions and 12988 deletions

View File

@@ -37,10 +37,7 @@ groups:
name: BUGFIXES name: BUGFIXES
labels: labels:
- type/bug - type/bug
-
name: API
labels:
- modifies/api
- -
name: TESTING name: TESTING
labels: labels:

View File

@@ -1,6 +1,6 @@
{ {
"name": "Gitea DevContainer", "name": "Gitea DevContainer",
"image": "mcr.microsoft.com/devcontainers/go:1.25-trixie", "image": "mcr.microsoft.com/devcontainers/go:1.26-trixie",
"containerEnv": { "containerEnv": {
// override "local" from packaged version // override "local" from packaged version
"GOTOOLCHAIN": "auto" "GOTOOLCHAIN": "auto"

47
.github/actions/go-cache/action.yml vendored Normal file
View File

@@ -0,0 +1,47 @@
name: go-caches
description: Restore and save go module, build, and golangci-lint caches
inputs:
cache-name:
description: Short identifier used in the per-caller build cache key
required: true
build-cache:
description: Whether to include ~/.cache/go-build
default: "true"
build-cache-rotate:
description: Whether to rotate the build cache key per run so Go's test result cache can accumulate across runs
default: "false"
lint-cache:
description: Whether to include ~/.cache/golangci-lint
default: "false"
runs:
using: composite
steps:
- uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
with:
path: ~/go/pkg/mod
key: gomod-${{ runner.os }}-${{ runner.arch }}-${{ hashFiles('go.sum') }}
restore-keys: gomod-${{ runner.os }}-${{ runner.arch }}
- if: ${{ inputs.build-cache == 'true' && inputs.build-cache-rotate == 'true' }}
uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
with:
path: ~/.cache/go-build
key: gobuild-${{ runner.os }}-${{ runner.arch }}-${{ inputs.cache-name }}-${{ hashFiles('go.sum') }}-${{ github.run_id }}
restore-keys: |
gobuild-${{ runner.os }}-${{ runner.arch }}-${{ inputs.cache-name }}-${{ hashFiles('go.sum') }}
gobuild-${{ runner.os }}-${{ runner.arch }}-${{ inputs.cache-name }}
gobuild-${{ runner.os }}-${{ runner.arch }}-${{ hashFiles('go.sum') }}
gobuild-${{ runner.os }}-${{ runner.arch }}
- if: ${{ inputs.build-cache == 'true' && inputs.build-cache-rotate != 'true' }}
uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
with:
path: ~/.cache/go-build
key: gobuild-${{ runner.os }}-${{ runner.arch }}-${{ hashFiles('go.sum') }}
restore-keys: gobuild-${{ runner.os }}-${{ runner.arch }}
- if: ${{ inputs.lint-cache == 'true' }}
uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
with:
path: ~/.cache/golangci-lint
key: golangci-${{ runner.os }}-${{ runner.arch }}-${{ inputs.cache-name }}-${{ hashFiles('go.sum', '.golangci.yml') }}
restore-keys: golangci-${{ runner.os }}-${{ runner.arch }}-${{ inputs.cache-name }}

View File

@@ -1,10 +0,0 @@
version: 2
updates:
- package-ecosystem: github-actions
labels: [modifies/dependencies]
directory: /
schedule:
interval: daily
cooldown:
default-days: 5

77
.github/labeler.yml vendored
View File

@@ -1,80 +1,3 @@
modifies/docs:
- changed-files:
- any-glob-to-any-file:
- "**/*.md"
- "docs/**"
modifies/templates:
- changed-files:
- all-globs-to-any-file:
- "templates/**"
- "!templates/swagger/v1_json.tmpl"
modifies/api:
- changed-files:
- any-glob-to-any-file:
- "routers/api/**"
- "templates/swagger/v1_json.tmpl"
modifies/cli:
- changed-files:
- any-glob-to-any-file:
- "cmd/**"
modifies/translation:
- changed-files:
- any-glob-to-any-file:
- "options/locale/*.ini"
modifies/migrations:
- changed-files:
- any-glob-to-any-file:
- "models/migrations/**"
modifies/internal:
- changed-files:
- any-glob-to-any-file:
- ".air.toml"
- "Makefile"
- "Dockerfile"
- "Dockerfile.rootless"
- ".dockerignore"
- "docker/**"
- ".editorconfig"
- ".eslintrc.cjs"
- ".golangci.yml"
- ".markdownlint.yaml"
- ".spectral.yaml"
- "stylelint.config.*"
- ".yamllint.yaml"
- ".github/**"
- ".gitea/**"
- ".devcontainer/**"
- "build/**"
- "contrib/**"
modifies/dependencies:
- changed-files:
- any-glob-to-any-file:
- "package.json"
- "pnpm-lock.yaml"
- "pyproject.toml"
- "uv.lock"
- "go.mod"
- "go.sum"
modifies/go:
- changed-files:
- any-glob-to-any-file:
- "**/*.go"
modifies/frontend:
- changed-files:
- any-glob-to-any-file:
- "*.js"
- "*.ts"
- "web_src/**"
docs-update-needed: docs-update-needed:
- changed-files: - changed-files:
- any-glob-to-any-file: - any-glob-to-any-file:

75
.github/workflows/cache-seeder.yml vendored Normal file
View File

@@ -0,0 +1,75 @@
# Populates the go module, build, and golangci-lint caches under the default
# branch's cache scope so that PR runs have a warm fallback to restore from.
#
# GitHub Actions caches are scoped per ref: a PR run can only write to its own
# branch's scope, but can read from the base branch's scope as a fallback.
# PRs therefore cannot seed main's scope themselves. Running the same cache
# steps on push-to-main is the only opportunity to populate that fallback
# scope so fresh PR branches start with a useful cache on first run.
# A PR job's exact key lives in its own PR-scope (empty on first run, filled
# by later runs of the same PR); on miss, actions/cache's restore-keys fall
# back to prefix matches against entries this seeder saves in main's scope.
name: cache-seeder
on:
push:
branches:
- main
paths:
- "go.sum"
- ".golangci.yml"
- ".github/actions/go-cache/action.yml"
- ".github/workflows/cache-seeder.yml"
concurrency:
group: cache-seeder
cancel-in-progress: true
jobs:
gobuild:
runs-on: ubuntu-latest
permissions:
contents: read
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0
with:
go-version-file: go.mod
check-latest: true
cache: false
- uses: ./.github/actions/go-cache
with:
cache-name: seed
- run: make deps-backend
- run: TAGS="bindata" make backend
- run: TAGS="bindata sqlite sqlite_unlock_notify" make backend
- run: TAGS="bindata gogit sqlite sqlite_unlock_notify" GOEXPERIMENT="" make backend
lint:
runs-on: ubuntu-latest
permissions:
contents: read
strategy:
fail-fast: false
matrix:
include:
- { job: lint-backend, tags: "bindata sqlite sqlite_unlock_notify", target: "lint-backend" }
- { job: lint-go-windows, tags: "bindata sqlite sqlite_unlock_notify", target: "lint-go-windows" }
- { job: lint-go-gogit, tags: "bindata sqlite sqlite_unlock_notify gogit", target: "lint-go" }
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0
with:
go-version-file: go.mod
check-latest: true
cache: false
- uses: ./.github/actions/go-cache
with:
cache-name: ${{ matrix.job }}
lint-cache: "true"
- run: make deps-backend deps-tools
- run: make ${{ matrix.target }}
env:
TAGS: ${{ matrix.tags }}

View File

@@ -1,22 +0,0 @@
name: cron-flake-updater
on:
workflow_dispatch:
schedule:
- cron: '0 0 * * 0' # runs weekly on Sunday at 00:00
jobs:
nix-flake-update:
permissions:
contents: write
issues: write
pull-requests: write
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- uses: DeterminateSystems/determinate-nix-action@v3
- uses: DeterminateSystems/update-flake-lock@main
with:
pr-title: "Update Nix flake"
pr-labels: |
dependencies

View File

@@ -12,15 +12,15 @@ jobs:
permissions: permissions:
contents: write contents: write
steps: steps:
- uses: actions/checkout@v6 - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- uses: actions/setup-go@v6 - uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0
with: with:
go-version-file: go.mod go-version-file: go.mod
check-latest: true check-latest: true
- run: make generate-gitignore - run: make generate-gitignore
timeout-minutes: 40 timeout-minutes: 40
- name: push translations to repo - name: push translations to repo
uses: appleboy/git-push-action@v1.2.0 uses: appleboy/git-push-action@3b2c8661652360dbf1afe1b319a49dbb739c39f1 # v1.2.0
with: with:
author_email: "teabot@gitea.io" author_email: "teabot@gitea.io"
author_name: GiteaBot author_name: GiteaBot

31
.github/workflows/cron-renovate.yml vendored Normal file
View File

@@ -0,0 +1,31 @@
name: cron-renovate
on:
schedule:
- cron: "0 1 * * *" # daily at 01:00 UTC
workflow_dispatch:
concurrency:
group: cron-renovate
env:
RENOVATE_VERSION: 43.141.5 # renovate: datasource=docker depName=ghcr.io/renovatebot/renovate
jobs:
cron-renovate:
runs-on: ubuntu-latest
if: github.repository == 'go-gitea/gitea' # prevent running on forks
timeout-minutes: 30
permissions:
contents: read
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- uses: renovatebot/github-action@83ec54fee49ab67d9cd201084c1ff325b4b462e4 # v46.1.10
with:
renovate-version: ${{ env.RENOVATE_VERSION }}
configurationFile: renovate.json5
token: ${{ secrets.RENOVATE_TOKEN }}
env:
RENOVATE_BINARY_SOURCE: install # auto-install go/node toolchains needed by post-upgrade tasks.
RENOVATE_ALLOWED_POST_UPGRADE_COMMANDS: '["^make (tidy|svg)$"]'
RENOVATE_REPOSITORIES: '["go-gitea/gitea"]'

View File

@@ -12,8 +12,8 @@ jobs:
permissions: permissions:
contents: write contents: write
steps: steps:
- uses: actions/checkout@v6 - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- uses: crowdin/github-action@v2 - uses: crowdin/github-action@8868a33591d21088edfc398968173a3b98d51706 # v2.16.2
with: with:
upload_sources: true upload_sources: true
upload_translations: false upload_translations: false
@@ -29,7 +29,7 @@ jobs:
- name: update locales - name: update locales
run: ./build/update-locales.sh run: ./build/update-locales.sh
- name: push translations to repo - name: push translations to repo
uses: appleboy/git-push-action@v1.2.0 uses: appleboy/git-push-action@3b2c8661652360dbf1afe1b319a49dbb739c39f1 # v1.2.0
with: with:
author_email: "teabot@gitea.io" author_email: "teabot@gitea.io"
author_name: GiteaBot author_name: GiteaBot

View File

@@ -21,6 +21,8 @@ on:
value: ${{ jobs.detect.outputs.yaml }} value: ${{ jobs.detect.outputs.yaml }}
json: json:
value: ${{ jobs.detect.outputs.json }} value: ${{ jobs.detect.outputs.json }}
e2e:
value: ${{ jobs.detect.outputs.e2e }}
jobs: jobs:
detect: detect:
@@ -38,9 +40,10 @@ jobs:
swagger: ${{ steps.changes.outputs.swagger }} swagger: ${{ steps.changes.outputs.swagger }}
yaml: ${{ steps.changes.outputs.yaml }} yaml: ${{ steps.changes.outputs.yaml }}
json: ${{ steps.changes.outputs.json }} json: ${{ steps.changes.outputs.json }}
e2e: ${{ steps.changes.outputs.e2e }}
steps: steps:
- uses: actions/checkout@v6 - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- uses: dorny/paths-filter@v4 - uses: dorny/paths-filter@fbd0ab8f3e69293af611ebaee6363fc25e6d187d # v4.0.1
id: changes id: changes
with: with:
filters: | filters: |
@@ -107,3 +110,8 @@ jobs:
json: json:
- "**/*.json" - "**/*.json"
e2e:
- "tests/e2e/**"
- "tools/test-e2e.sh"
- "playwright.config.ts"

View File

@@ -20,11 +20,16 @@ jobs:
permissions: permissions:
contents: read contents: read
steps: steps:
- uses: actions/checkout@v6 - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- uses: actions/setup-go@v6 - uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0
with: with:
go-version-file: go.mod go-version-file: go.mod
check-latest: true check-latest: true
cache: false
- uses: ./.github/actions/go-cache
with:
cache-name: lint-backend
lint-cache: "true"
- run: make deps-backend deps-tools - run: make deps-backend deps-tools
- run: make lint-backend - run: make lint-backend
env: env:
@@ -37,11 +42,11 @@ jobs:
permissions: permissions:
contents: read contents: read
steps: steps:
- uses: actions/checkout@v6 - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- uses: astral-sh/setup-uv@v8.0.0 - uses: astral-sh/setup-uv@08807647e7069bb48b6ef5acd8ec9567f424441b # v8.1.0
- run: uv python install 3.14 - run: uv python install 3.14
- uses: pnpm/action-setup@v5 - uses: pnpm/action-setup@fc06bc1257f339d1d5d8b3a19a8cae5388b55320 # v5.0.0
- uses: actions/setup-node@v6 - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
with: with:
node-version: 24 node-version: 24
cache: pnpm cache: pnpm
@@ -57,8 +62,8 @@ jobs:
permissions: permissions:
contents: read contents: read
steps: steps:
- uses: actions/checkout@v6 - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- uses: astral-sh/setup-uv@v8.0.0 - uses: astral-sh/setup-uv@08807647e7069bb48b6ef5acd8ec9567f424441b # v8.1.0
- run: uv python install 3.14 - run: uv python install 3.14
- run: make deps-py - run: make deps-py
- run: make lint-yaml - run: make lint-yaml
@@ -70,11 +75,13 @@ jobs:
permissions: permissions:
contents: read contents: read
steps: steps:
- uses: actions/checkout@v6 - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- uses: pnpm/action-setup@v5 - uses: pnpm/action-setup@fc06bc1257f339d1d5d8b3a19a8cae5388b55320 # v5.0.0
- uses: actions/setup-node@v5 - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
with: with:
node-version: 24 node-version: 24
cache: pnpm
cache-dependency-path: pnpm-lock.yaml
- run: make deps-frontend - run: make deps-frontend
- run: make lint-json - run: make lint-json
@@ -85,9 +92,9 @@ jobs:
permissions: permissions:
contents: read contents: read
steps: steps:
- uses: actions/checkout@v6 - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- uses: pnpm/action-setup@v5 - uses: pnpm/action-setup@fc06bc1257f339d1d5d8b3a19a8cae5388b55320 # v5.0.0
- uses: actions/setup-node@v6 - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
with: with:
node-version: 24 node-version: 24
cache: pnpm cache: pnpm
@@ -102,8 +109,8 @@ jobs:
permissions: permissions:
contents: read contents: read
steps: steps:
- uses: actions/checkout@v6 - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- uses: actions/setup-go@v6 - uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0
with: with:
go-version-file: go.mod go-version-file: go.mod
check-latest: true check-latest: true
@@ -116,13 +123,18 @@ jobs:
permissions: permissions:
contents: read contents: read
steps: steps:
- uses: actions/checkout@v6 - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- uses: actions/setup-go@v6 - uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0
with: with:
go-version-file: go.mod go-version-file: go.mod
check-latest: true check-latest: true
cache: false
- uses: ./.github/actions/go-cache
with:
cache-name: lint-go-windows
lint-cache: "true"
- run: make deps-backend deps-tools - run: make deps-backend deps-tools
- run: make lint-go-windows lint-go-gitea-vet - run: make lint-go-windows
env: env:
TAGS: bindata sqlite sqlite_unlock_notify TAGS: bindata sqlite sqlite_unlock_notify
GOOS: windows GOOS: windows
@@ -135,11 +147,16 @@ jobs:
permissions: permissions:
contents: read contents: read
steps: steps:
- uses: actions/checkout@v6 - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- uses: actions/setup-go@v6 - uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0
with: with:
go-version-file: go.mod go-version-file: go.mod
check-latest: true check-latest: true
cache: false
- uses: ./.github/actions/go-cache
with:
cache-name: lint-go-gogit
lint-cache: "true"
- run: make deps-backend deps-tools - run: make deps-backend deps-tools
- run: make lint-go - run: make lint-go
env: env:
@@ -152,11 +169,16 @@ jobs:
permissions: permissions:
contents: read contents: read
steps: steps:
- uses: actions/checkout@v6 - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- uses: actions/setup-go@v6 - uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0
with: with:
go-version-file: go.mod go-version-file: go.mod
check-latest: true check-latest: true
cache: false
- uses: ./.github/actions/go-cache
with:
cache-name: checks-backend
build-cache: "false"
- run: make deps-backend deps-tools - run: make deps-backend deps-tools
- run: make --always-make checks-backend # ensure the "go-licenses" make target runs - run: make --always-make checks-backend # ensure the "go-licenses" make target runs
@@ -167,9 +189,9 @@ jobs:
permissions: permissions:
contents: read contents: read
steps: steps:
- uses: actions/checkout@v6 - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- uses: pnpm/action-setup@v5 - uses: pnpm/action-setup@fc06bc1257f339d1d5d8b3a19a8cae5388b55320 # v5.0.0
- uses: actions/setup-node@v6 - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
with: with:
node-version: 24 node-version: 24
cache: pnpm cache: pnpm
@@ -187,11 +209,15 @@ jobs:
permissions: permissions:
contents: read contents: read
steps: steps:
- uses: actions/checkout@v6 - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- uses: actions/setup-go@v6 - uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0
with: with:
go-version-file: go.mod go-version-file: go.mod
check-latest: true check-latest: true
cache: false
- uses: ./.github/actions/go-cache
with:
cache-name: backend
# no frontend build here as backend should be able to build # no frontend build here as backend should be able to build
# even without any frontend files # even without any frontend files
- run: make deps-backend - run: make deps-backend
@@ -221,9 +247,9 @@ jobs:
permissions: permissions:
contents: read contents: read
steps: steps:
- uses: actions/checkout@v6 - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- uses: pnpm/action-setup@v5 - uses: pnpm/action-setup@fc06bc1257f339d1d5d8b3a19a8cae5388b55320 # v5.0.0
- uses: actions/setup-node@v6 - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
with: with:
node-version: 24 node-version: 24
cache: pnpm cache: pnpm
@@ -238,8 +264,8 @@ jobs:
permissions: permissions:
contents: read contents: read
steps: steps:
- uses: actions/checkout@v6 - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- uses: actions/setup-go@v6 - uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0
with: with:
go-version-file: go.mod go-version-file: go.mod
check-latest: true check-latest: true

View File

@@ -42,11 +42,15 @@ jobs:
ports: ports:
- "9000:9000" - "9000:9000"
steps: steps:
- uses: actions/checkout@v6 - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- uses: actions/setup-go@v6 - uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0
with: with:
go-version-file: go.mod go-version-file: go.mod
check-latest: true check-latest: true
cache: false
- uses: ./.github/actions/go-cache
with:
cache-name: pgsql
- name: Add hosts to /etc/hosts - name: Add hosts to /etc/hosts
run: '[ -e "/.dockerenv" ] || [ -e "/run/.containerenv" ] || echo "127.0.0.1 pgsql ldap minio" | sudo tee -a /etc/hosts' run: '[ -e "/.dockerenv" ] || [ -e "/run/.containerenv" ] || echo "127.0.0.1 pgsql ldap minio" | sudo tee -a /etc/hosts'
- run: make deps-backend - run: make deps-backend
@@ -60,7 +64,6 @@ jobs:
timeout-minutes: 50 timeout-minutes: 50
env: env:
TAGS: bindata gogit TAGS: bindata gogit
RACE_ENABLED: true
TEST_TAGS: gogit TEST_TAGS: gogit
TEST_LDAP: 1 TEST_LDAP: 1
@@ -71,11 +74,15 @@ jobs:
permissions: permissions:
contents: read contents: read
steps: steps:
- uses: actions/checkout@v6 - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- uses: actions/setup-go@v6 - uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0
with: with:
go-version-file: go.mod go-version-file: go.mod
check-latest: true check-latest: true
cache: false
- uses: ./.github/actions/go-cache
with:
cache-name: sqlite
- run: make deps-backend - run: make deps-backend
- run: GOEXPERIMENT='' make backend - run: GOEXPERIMENT='' make backend
env: env:
@@ -130,11 +137,16 @@ jobs:
ports: ports:
- 10000:10000 - 10000:10000
steps: steps:
- uses: actions/checkout@v6 - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- uses: actions/setup-go@v6 - uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0
with: with:
go-version-file: go.mod go-version-file: go.mod
check-latest: true check-latest: true
cache: false
- uses: ./.github/actions/go-cache
with:
cache-name: unit
build-cache-rotate: "true"
- name: Add hosts to /etc/hosts - name: Add hosts to /etc/hosts
run: '[ -e "/.dockerenv" ] || [ -e "/run/.containerenv" ] || echo "127.0.0.1 minio devstoreaccount1.azurite.local mysql elasticsearch meilisearch smtpimap" | sudo tee -a /etc/hosts' run: '[ -e "/.dockerenv" ] || [ -e "/run/.containerenv" ] || echo "127.0.0.1 minio devstoreaccount1.azurite.local mysql elasticsearch meilisearch smtpimap" | sudo tee -a /etc/hosts'
- run: make deps-backend - run: make deps-backend
@@ -142,16 +154,18 @@ jobs:
env: env:
TAGS: bindata TAGS: bindata
- name: unit-tests - name: unit-tests
run: make unit-test-coverage test-check run: make test-backend test-check
env: env:
TAGS: bindata TAGS: bindata
RACE_ENABLED: true RACE_ENABLED: true
GOTESTFLAGS: -timeout=20m
GITHUB_READ_TOKEN: ${{ secrets.GITHUB_READ_TOKEN }} GITHUB_READ_TOKEN: ${{ secrets.GITHUB_READ_TOKEN }}
- name: unit-tests-gogit - name: unit-tests-gogit
run: GOEXPERIMENT='' make unit-test-coverage test-check run: GOEXPERIMENT='' make test-backend test-check
env: env:
TAGS: bindata gogit TAGS: bindata gogit
RACE_ENABLED: true RACE_ENABLED: true
GOTESTFLAGS: -timeout=20m
GITHUB_READ_TOKEN: ${{ secrets.GITHUB_READ_TOKEN }} GITHUB_READ_TOKEN: ${{ secrets.GITHUB_READ_TOKEN }}
test-mysql: test-mysql:
@@ -185,11 +199,15 @@ jobs:
- "587:587" - "587:587"
- "993:993" - "993:993"
steps: steps:
- uses: actions/checkout@v6 - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- uses: actions/setup-go@v6 - uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0
with: with:
go-version-file: go.mod go-version-file: go.mod
check-latest: true check-latest: true
cache: false
- uses: ./.github/actions/go-cache
with:
cache-name: mysql
- name: Add hosts to /etc/hosts - name: Add hosts to /etc/hosts
run: '[ -e "/.dockerenv" ] || [ -e "/run/.containerenv" ] || echo "127.0.0.1 mysql elasticsearch smtpimap" | sudo tee -a /etc/hosts' run: '[ -e "/.dockerenv" ] || [ -e "/run/.containerenv" ] || echo "127.0.0.1 mysql elasticsearch smtpimap" | sudo tee -a /etc/hosts'
- run: make deps-backend - run: make deps-backend
@@ -203,7 +221,6 @@ jobs:
run: make test-mysql run: make test-mysql
env: env:
TAGS: bindata TAGS: bindata
RACE_ENABLED: true
TEST_INDEXER_CODE_ES_URL: "http://elastic:changeme@elasticsearch:9200" TEST_INDEXER_CODE_ES_URL: "http://elastic:changeme@elasticsearch:9200"
test-mssql: test-mssql:
@@ -226,11 +243,15 @@ jobs:
ports: ports:
- 10000:10000 - 10000:10000
steps: steps:
- uses: actions/checkout@v6 - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- uses: actions/setup-go@v6 - uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0
with: with:
go-version-file: go.mod go-version-file: go.mod
check-latest: true check-latest: true
cache: false
- uses: ./.github/actions/go-cache
with:
cache-name: mssql
- name: Add hosts to /etc/hosts - name: Add hosts to /etc/hosts
run: '[ -e "/.dockerenv" ] || [ -e "/run/.containerenv" ] || echo "127.0.0.1 mssql devstoreaccount1.azurite.local" | sudo tee -a /etc/hosts' run: '[ -e "/.dockerenv" ] || [ -e "/run/.containerenv" ] || echo "127.0.0.1 mssql devstoreaccount1.azurite.local" | sudo tee -a /etc/hosts'
- run: make deps-backend - run: make deps-backend

View File

@@ -20,18 +20,18 @@ jobs:
permissions: permissions:
contents: read contents: read
steps: steps:
- uses: actions/checkout@v6 - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- uses: docker/setup-qemu-action@v4 - uses: docker/setup-qemu-action@ce360397dd3f832beb865e1373c09c0e9f86d70a # v4.0.0
- uses: docker/setup-buildx-action@v4 - uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # v4.0.0
- name: Build regular container image - name: Build regular container image
uses: docker/build-push-action@v7 uses: docker/build-push-action@bcafcacb16a39f128d818304e6c9c0c18556b85f # v7.1.0
with: with:
context: . context: .
platforms: linux/amd64,linux/arm64,linux/riscv64 platforms: linux/amd64,linux/arm64,linux/riscv64
push: false push: false
cache-from: type=registry,ref=ghcr.io/go-gitea/gitea:buildcache-rootful cache-from: type=registry,ref=ghcr.io/go-gitea/gitea:buildcache-rootful
- name: Build rootless container image - name: Build rootless container image
uses: docker/build-push-action@v7 uses: docker/build-push-action@bcafcacb16a39f128d818304e6c9c0c18556b85f # v7.1.0
with: with:
context: . context: .
push: false push: false

View File

@@ -14,19 +14,24 @@ jobs:
contents: read contents: read
test-e2e: test-e2e:
if: needs.files-changed.outputs.backend == 'true' || needs.files-changed.outputs.frontend == 'true' if: needs.files-changed.outputs.backend == 'true' || needs.files-changed.outputs.frontend == 'true' || needs.files-changed.outputs.e2e == 'true'
needs: files-changed needs: files-changed
runs-on: ubuntu-latest runs-on: ubuntu-latest
permissions: permissions:
contents: read contents: read
steps: steps:
- uses: actions/checkout@v6 - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- uses: actions/setup-go@v6 - uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0
with: with:
go-version-file: go.mod go-version-file: go.mod
check-latest: true check-latest: true
- uses: pnpm/action-setup@v5 cache: false
- uses: actions/setup-node@v6 - uses: ./.github/actions/go-cache
with:
cache-name: e2e
build-cache: "false"
- uses: pnpm/action-setup@fc06bc1257f339d1d5d8b3a19a8cae5388b55320 # v5.0.0
- uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
with: with:
node-version: 24 node-version: 24
cache: pnpm cache: pnpm

View File

@@ -15,6 +15,6 @@ jobs:
contents: read contents: read
pull-requests: write pull-requests: write
steps: steps:
- uses: actions/labeler@v6 - uses: actions/labeler@634933edcd8ababfe52f92936142cc22ac488b1b # v6.0.1
with: with:
sync-labels: true sync-labels: true

View File

@@ -14,16 +14,16 @@ jobs:
permissions: permissions:
contents: read contents: read
steps: steps:
- uses: actions/checkout@v6 - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
# fetch all commits instead of only the last as some branches are long lived and could have many between versions # fetch all commits instead of only the last as some branches are long lived and could have many between versions
# fetch all tags to ensure that "git describe" reports expected Gitea version, eg. v1.21.0-dev-1-g1234567 # fetch all tags to ensure that "git describe" reports expected Gitea version, eg. v1.21.0-dev-1-g1234567
- run: git fetch --unshallow --quiet --tags --force - run: git fetch --unshallow --quiet --tags --force
- uses: actions/setup-go@v6 - uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0
with: with:
go-version-file: go.mod go-version-file: go.mod
check-latest: true check-latest: true
- uses: pnpm/action-setup@v5 - uses: pnpm/action-setup@fc06bc1257f339d1d5d8b3a19a8cae5388b55320 # v5.0.0
- uses: actions/setup-node@v6 - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
with: with:
node-version: 24 node-version: 24
cache: pnpm cache: pnpm
@@ -35,7 +35,7 @@ jobs:
TAGS: bindata sqlite sqlite_unlock_notify TAGS: bindata sqlite sqlite_unlock_notify
- name: import gpg key - name: import gpg key
id: import_gpg id: import_gpg
uses: crazy-max/ghaction-import-gpg@v7 uses: crazy-max/ghaction-import-gpg@2dc316deee8e90f13e1a351ab510b4d5bc0c82cd # v7.0.0
with: with:
gpg_private_key: ${{ secrets.GPGSIGN_KEY }} gpg_private_key: ${{ secrets.GPGSIGN_KEY }}
passphrase: ${{ secrets.GPGSIGN_PASSPHRASE }} passphrase: ${{ secrets.GPGSIGN_PASSPHRASE }}
@@ -52,7 +52,7 @@ jobs:
echo "Cleaned name is ${REF_NAME}" echo "Cleaned name is ${REF_NAME}"
echo "branch=${REF_NAME}-nightly" >> "$GITHUB_OUTPUT" echo "branch=${REF_NAME}-nightly" >> "$GITHUB_OUTPUT"
- name: configure aws - name: configure aws
uses: aws-actions/configure-aws-credentials@v6 uses: aws-actions/configure-aws-credentials@ec61189d14ec14c8efccab744f656cffd0e33f37 # v6.1.0
with: with:
aws-region: ${{ secrets.AWS_REGION }} aws-region: ${{ secrets.AWS_REGION }}
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }} aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
@@ -67,18 +67,18 @@ jobs:
contents: read contents: read
packages: write # to publish to ghcr.io packages: write # to publish to ghcr.io
steps: steps:
- uses: actions/checkout@v6 - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
# fetch all commits instead of only the last as some branches are long lived and could have many between versions # fetch all commits instead of only the last as some branches are long lived and could have many between versions
# fetch all tags to ensure that "git describe" reports expected Gitea version, eg. v1.21.0-dev-1-g1234567 # fetch all tags to ensure that "git describe" reports expected Gitea version, eg. v1.21.0-dev-1-g1234567
- run: git fetch --unshallow --quiet --tags --force - run: git fetch --unshallow --quiet --tags --force
- uses: docker/setup-qemu-action@v4 - uses: docker/setup-qemu-action@ce360397dd3f832beb865e1373c09c0e9f86d70a # v4.0.0
- uses: docker/setup-buildx-action@v4 - uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # v4.0.0
- name: Get cleaned branch name - name: Get cleaned branch name
id: clean_name id: clean_name
run: | run: |
REF_NAME=$(echo "${{ github.ref }}" | sed -e 's/refs\/heads\///' -e 's/refs\/tags\///' -e 's/release\/v//') REF_NAME=$(echo "${{ github.ref }}" | sed -e 's/refs\/heads\///' -e 's/refs\/tags\///' -e 's/release\/v//')
echo "branch=${REF_NAME}-nightly" >> "$GITHUB_OUTPUT" echo "branch=${REF_NAME}-nightly" >> "$GITHUB_OUTPUT"
- uses: docker/metadata-action@v6 - uses: docker/metadata-action@030e881283bb7a6894de51c315a6bfe6a94e05cf # v6.0.0
id: meta id: meta
with: with:
images: |- images: |-
@@ -88,7 +88,7 @@ jobs:
type=raw,value=${{ steps.clean_name.outputs.branch }} type=raw,value=${{ steps.clean_name.outputs.branch }}
annotations: | annotations: |
org.opencontainers.image.authors="maintainers@gitea.io" org.opencontainers.image.authors="maintainers@gitea.io"
- uses: docker/metadata-action@v6 - uses: docker/metadata-action@030e881283bb7a6894de51c315a6bfe6a94e05cf # v6.0.0
id: meta_rootless id: meta_rootless
with: with:
images: |- images: |-
@@ -102,18 +102,18 @@ jobs:
annotations: | annotations: |
org.opencontainers.image.authors="maintainers@gitea.io" org.opencontainers.image.authors="maintainers@gitea.io"
- name: Login to Docker Hub - name: Login to Docker Hub
uses: docker/login-action@v4 uses: docker/login-action@4907a6ddec9925e35a0a9e82d7399ccc52663121 # v4.1.0
with: with:
username: ${{ secrets.DOCKERHUB_USERNAME }} username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }} password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Login to GHCR using PAT - name: Login to GHCR using PAT
uses: docker/login-action@v4 uses: docker/login-action@4907a6ddec9925e35a0a9e82d7399ccc52663121 # v4.1.0
with: with:
registry: ghcr.io registry: ghcr.io
username: ${{ github.repository_owner }} username: ${{ github.repository_owner }}
password: ${{ secrets.GITHUB_TOKEN }} password: ${{ secrets.GITHUB_TOKEN }}
- name: build regular docker image - name: build regular docker image
uses: docker/build-push-action@v7 uses: docker/build-push-action@bcafcacb16a39f128d818304e6c9c0c18556b85f # v7.1.0
with: with:
context: . context: .
platforms: linux/amd64,linux/arm64,linux/riscv64 platforms: linux/amd64,linux/arm64,linux/riscv64
@@ -123,7 +123,7 @@ jobs:
cache-from: type=registry,ref=ghcr.io/go-gitea/gitea:buildcache-rootful cache-from: type=registry,ref=ghcr.io/go-gitea/gitea:buildcache-rootful
cache-to: type=registry,ref=ghcr.io/go-gitea/gitea:buildcache-rootful,mode=max cache-to: type=registry,ref=ghcr.io/go-gitea/gitea:buildcache-rootful,mode=max
- name: build rootless docker image - name: build rootless docker image
uses: docker/build-push-action@v7 uses: docker/build-push-action@bcafcacb16a39f128d818304e6c9c0c18556b85f # v7.1.0
with: with:
context: . context: .
platforms: linux/amd64,linux/arm64,linux/riscv64 platforms: linux/amd64,linux/arm64,linux/riscv64

View File

@@ -15,16 +15,16 @@ jobs:
permissions: permissions:
contents: read contents: read
steps: steps:
- uses: actions/checkout@v6 - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
# fetch all commits instead of only the last as some branches are long lived and could have many between versions # fetch all commits instead of only the last as some branches are long lived and could have many between versions
# fetch all tags to ensure that "git describe" reports expected Gitea version, eg. v1.21.0-dev-1-g1234567 # fetch all tags to ensure that "git describe" reports expected Gitea version, eg. v1.21.0-dev-1-g1234567
- run: git fetch --unshallow --quiet --tags --force - run: git fetch --unshallow --quiet --tags --force
- uses: actions/setup-go@v6 - uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0
with: with:
go-version-file: go.mod go-version-file: go.mod
check-latest: true check-latest: true
- uses: pnpm/action-setup@v5 - uses: pnpm/action-setup@fc06bc1257f339d1d5d8b3a19a8cae5388b55320 # v5.0.0
- uses: actions/setup-node@v6 - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
with: with:
node-version: 24 node-version: 24
cache: pnpm cache: pnpm
@@ -36,7 +36,7 @@ jobs:
TAGS: bindata sqlite sqlite_unlock_notify TAGS: bindata sqlite sqlite_unlock_notify
- name: import gpg key - name: import gpg key
id: import_gpg id: import_gpg
uses: crazy-max/ghaction-import-gpg@v7 uses: crazy-max/ghaction-import-gpg@2dc316deee8e90f13e1a351ab510b4d5bc0c82cd # v7.0.0
with: with:
gpg_private_key: ${{ secrets.GPGSIGN_KEY }} gpg_private_key: ${{ secrets.GPGSIGN_KEY }}
passphrase: ${{ secrets.GPGSIGN_PASSPHRASE }} passphrase: ${{ secrets.GPGSIGN_PASSPHRASE }}
@@ -53,7 +53,7 @@ jobs:
echo "Cleaned name is ${REF_NAME}" echo "Cleaned name is ${REF_NAME}"
echo "branch=${REF_NAME}" >> "$GITHUB_OUTPUT" echo "branch=${REF_NAME}" >> "$GITHUB_OUTPUT"
- name: configure aws - name: configure aws
uses: aws-actions/configure-aws-credentials@v6 uses: aws-actions/configure-aws-credentials@ec61189d14ec14c8efccab744f656cffd0e33f37 # v6.1.0
with: with:
aws-region: ${{ secrets.AWS_REGION }} aws-region: ${{ secrets.AWS_REGION }}
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }} aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
@@ -62,7 +62,7 @@ jobs:
run: | run: |
aws s3 sync dist/release s3://${{ secrets.AWS_S3_BUCKET }}/gitea/${{ steps.clean_name.outputs.branch }} --no-progress aws s3 sync dist/release s3://${{ secrets.AWS_S3_BUCKET }}/gitea/${{ steps.clean_name.outputs.branch }} --no-progress
- name: Install GH CLI - name: Install GH CLI
uses: dev-hanz-ops/install-gh-cli-action@v0.2.1 uses: dev-hanz-ops/install-gh-cli-action@af38ce09b1ec248aeb08eea2b16bbecea9e059f8 # v0.2.1
with: with:
gh-cli-version: 2.39.1 gh-cli-version: 2.39.1
- name: create github release - name: create github release
@@ -77,13 +77,13 @@ jobs:
contents: read contents: read
packages: write # to publish to ghcr.io packages: write # to publish to ghcr.io
steps: steps:
- uses: actions/checkout@v6 - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
# fetch all commits instead of only the last as some branches are long lived and could have many between versions # fetch all commits instead of only the last as some branches are long lived and could have many between versions
# fetch all tags to ensure that "git describe" reports expected Gitea version, eg. v1.21.0-dev-1-g1234567 # fetch all tags to ensure that "git describe" reports expected Gitea version, eg. v1.21.0-dev-1-g1234567
- run: git fetch --unshallow --quiet --tags --force - run: git fetch --unshallow --quiet --tags --force
- uses: docker/setup-qemu-action@v4 - uses: docker/setup-qemu-action@ce360397dd3f832beb865e1373c09c0e9f86d70a # v4.0.0
- uses: docker/setup-buildx-action@v4 - uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # v4.0.0
- uses: docker/metadata-action@v6 - uses: docker/metadata-action@030e881283bb7a6894de51c315a6bfe6a94e05cf # v6.0.0
id: meta id: meta
with: with:
images: |- images: |-
@@ -96,7 +96,7 @@ jobs:
type=semver,pattern={{version}} type=semver,pattern={{version}}
annotations: | annotations: |
org.opencontainers.image.authors="maintainers@gitea.io" org.opencontainers.image.authors="maintainers@gitea.io"
- uses: docker/metadata-action@v6 - uses: docker/metadata-action@030e881283bb7a6894de51c315a6bfe6a94e05cf # v6.0.0
id: meta_rootless id: meta_rootless
with: with:
images: |- images: |-
@@ -112,18 +112,18 @@ jobs:
annotations: | annotations: |
org.opencontainers.image.authors="maintainers@gitea.io" org.opencontainers.image.authors="maintainers@gitea.io"
- name: Login to Docker Hub - name: Login to Docker Hub
uses: docker/login-action@v4 uses: docker/login-action@4907a6ddec9925e35a0a9e82d7399ccc52663121 # v4.1.0
with: with:
username: ${{ secrets.DOCKERHUB_USERNAME }} username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }} password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Login to GHCR using PAT - name: Login to GHCR using PAT
uses: docker/login-action@v4 uses: docker/login-action@4907a6ddec9925e35a0a9e82d7399ccc52663121 # v4.1.0
with: with:
registry: ghcr.io registry: ghcr.io
username: ${{ github.repository_owner }} username: ${{ github.repository_owner }}
password: ${{ secrets.GITHUB_TOKEN }} password: ${{ secrets.GITHUB_TOKEN }}
- name: build regular container image - name: build regular container image
uses: docker/build-push-action@v7 uses: docker/build-push-action@bcafcacb16a39f128d818304e6c9c0c18556b85f # v7.1.0
with: with:
context: . context: .
platforms: linux/amd64,linux/arm64,linux/riscv64 platforms: linux/amd64,linux/arm64,linux/riscv64
@@ -131,7 +131,7 @@ jobs:
tags: ${{ steps.meta.outputs.tags }} tags: ${{ steps.meta.outputs.tags }}
annotations: ${{ steps.meta.outputs.annotations }} annotations: ${{ steps.meta.outputs.annotations }}
- name: build rootless container image - name: build rootless container image
uses: docker/build-push-action@v7 uses: docker/build-push-action@bcafcacb16a39f128d818304e6c9c0c18556b85f # v7.1.0
with: with:
context: . context: .
platforms: linux/amd64,linux/arm64,linux/riscv64 platforms: linux/amd64,linux/arm64,linux/riscv64

View File

@@ -18,16 +18,16 @@ jobs:
contents: read contents: read
packages: write # to publish to ghcr.io packages: write # to publish to ghcr.io
steps: steps:
- uses: actions/checkout@v6 - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
# fetch all commits instead of only the last as some branches are long lived and could have many between versions # fetch all commits instead of only the last as some branches are long lived and could have many between versions
# fetch all tags to ensure that "git describe" reports expected Gitea version, eg. v1.21.0-dev-1-g1234567 # fetch all tags to ensure that "git describe" reports expected Gitea version, eg. v1.21.0-dev-1-g1234567
- run: git fetch --unshallow --quiet --tags --force - run: git fetch --unshallow --quiet --tags --force
- uses: actions/setup-go@v6 - uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0
with: with:
go-version-file: go.mod go-version-file: go.mod
check-latest: true check-latest: true
- uses: pnpm/action-setup@v5 - uses: pnpm/action-setup@fc06bc1257f339d1d5d8b3a19a8cae5388b55320 # v5.0.0
- uses: actions/setup-node@v6 - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
with: with:
node-version: 24 node-version: 24
cache: pnpm cache: pnpm
@@ -39,7 +39,7 @@ jobs:
TAGS: bindata sqlite sqlite_unlock_notify TAGS: bindata sqlite sqlite_unlock_notify
- name: import gpg key - name: import gpg key
id: import_gpg id: import_gpg
uses: crazy-max/ghaction-import-gpg@v7 uses: crazy-max/ghaction-import-gpg@2dc316deee8e90f13e1a351ab510b4d5bc0c82cd # v7.0.0
with: with:
gpg_private_key: ${{ secrets.GPGSIGN_KEY }} gpg_private_key: ${{ secrets.GPGSIGN_KEY }}
passphrase: ${{ secrets.GPGSIGN_PASSPHRASE }} passphrase: ${{ secrets.GPGSIGN_PASSPHRASE }}
@@ -56,7 +56,7 @@ jobs:
echo "Cleaned name is ${REF_NAME}" echo "Cleaned name is ${REF_NAME}"
echo "branch=${REF_NAME}" >> "$GITHUB_OUTPUT" echo "branch=${REF_NAME}" >> "$GITHUB_OUTPUT"
- name: configure aws - name: configure aws
uses: aws-actions/configure-aws-credentials@v6 uses: aws-actions/configure-aws-credentials@ec61189d14ec14c8efccab744f656cffd0e33f37 # v6.1.0
with: with:
aws-region: ${{ secrets.AWS_REGION }} aws-region: ${{ secrets.AWS_REGION }}
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }} aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
@@ -65,7 +65,7 @@ jobs:
run: | run: |
aws s3 sync dist/release s3://${{ secrets.AWS_S3_BUCKET }}/gitea/${{ steps.clean_name.outputs.branch }} --no-progress aws s3 sync dist/release s3://${{ secrets.AWS_S3_BUCKET }}/gitea/${{ steps.clean_name.outputs.branch }} --no-progress
- name: Install GH CLI - name: Install GH CLI
uses: dev-hanz-ops/install-gh-cli-action@v0.2.1 uses: dev-hanz-ops/install-gh-cli-action@af38ce09b1ec248aeb08eea2b16bbecea9e059f8 # v0.2.1
with: with:
gh-cli-version: 2.39.1 gh-cli-version: 2.39.1
- name: create github release - name: create github release
@@ -80,13 +80,13 @@ jobs:
contents: read contents: read
packages: write # to publish to ghcr.io packages: write # to publish to ghcr.io
steps: steps:
- uses: actions/checkout@v6 - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
# fetch all commits instead of only the last as some branches are long lived and could have many between versions # fetch all commits instead of only the last as some branches are long lived and could have many between versions
# fetch all tags to ensure that "git describe" reports expected Gitea version, eg. v1.21.0-dev-1-g1234567 # fetch all tags to ensure that "git describe" reports expected Gitea version, eg. v1.21.0-dev-1-g1234567
- run: git fetch --unshallow --quiet --tags --force - run: git fetch --unshallow --quiet --tags --force
- uses: docker/setup-qemu-action@v4 - uses: docker/setup-qemu-action@ce360397dd3f832beb865e1373c09c0e9f86d70a # v4.0.0
- uses: docker/setup-buildx-action@v4 - uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # v4.0.0
- uses: docker/metadata-action@v6 - uses: docker/metadata-action@030e881283bb7a6894de51c315a6bfe6a94e05cf # v6.0.0
id: meta id: meta
with: with:
images: |- images: |-
@@ -103,7 +103,7 @@ jobs:
type=semver,pattern={{major}}.{{minor}} type=semver,pattern={{major}}.{{minor}}
annotations: | annotations: |
org.opencontainers.image.authors="maintainers@gitea.io" org.opencontainers.image.authors="maintainers@gitea.io"
- uses: docker/metadata-action@v6 - uses: docker/metadata-action@030e881283bb7a6894de51c315a6bfe6a94e05cf # v6.0.0
id: meta_rootless id: meta_rootless
with: with:
images: |- images: |-
@@ -124,18 +124,18 @@ jobs:
annotations: | annotations: |
org.opencontainers.image.authors="maintainers@gitea.io" org.opencontainers.image.authors="maintainers@gitea.io"
- name: Login to Docker Hub - name: Login to Docker Hub
uses: docker/login-action@v4 uses: docker/login-action@4907a6ddec9925e35a0a9e82d7399ccc52663121 # v4.1.0
with: with:
username: ${{ secrets.DOCKERHUB_USERNAME }} username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }} password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Login to GHCR using PAT - name: Login to GHCR using PAT
uses: docker/login-action@v4 uses: docker/login-action@4907a6ddec9925e35a0a9e82d7399ccc52663121 # v4.1.0
with: with:
registry: ghcr.io registry: ghcr.io
username: ${{ github.repository_owner }} username: ${{ github.repository_owner }}
password: ${{ secrets.GITHUB_TOKEN }} password: ${{ secrets.GITHUB_TOKEN }}
- name: build regular container image - name: build regular container image
uses: docker/build-push-action@v7 uses: docker/build-push-action@bcafcacb16a39f128d818304e6c9c0c18556b85f # v7.1.0
with: with:
context: . context: .
platforms: linux/amd64,linux/arm64,linux/riscv64 platforms: linux/amd64,linux/arm64,linux/riscv64
@@ -143,7 +143,7 @@ jobs:
tags: ${{ steps.meta.outputs.tags }} tags: ${{ steps.meta.outputs.tags }}
annotations: ${{ steps.meta.outputs.annotations }} annotations: ${{ steps.meta.outputs.annotations }}
- name: build rootless container image - name: build rootless container image
uses: docker/build-push-action@v7 uses: docker/build-push-action@bcafcacb16a39f128d818304e6c9c0c18556b85f # v7.1.0
with: with:
context: . context: .
platforms: linux/amd64,linux/arm64,linux/riscv64 platforms: linux/amd64,linux/arm64,linux/riscv64

View File

@@ -13,6 +13,7 @@ linters:
- forbidigo - forbidigo
- gocheckcompilerdirectives - gocheckcompilerdirectives
- gocritic - gocritic
- goheader
- govet - govet
- ineffassign - ineffassign
- mirror - mirror
@@ -51,6 +52,14 @@ linters:
desc: do not use the go-chi cache package, use gitea's cache system desc: do not use the go-chi cache package, use gitea's cache system
- pkg: github.com/pkg/errors - pkg: github.com/pkg/errors
desc: use builtin errors package instead desc: use builtin errors package instead
migrations:
files:
- '**/models/migrations/**/*.go'
deny:
- pkg: code.gitea.io/gitea/models$
desc: migrations must not depend on the models package
- pkg: code.gitea.io/gitea/modules/structs
desc: migrations must not depend on modules/structs (API structures change over time)
nolintlint: nolintlint:
allow-unused: false allow-unused: false
require-explanation: true require-explanation: true
@@ -109,6 +118,11 @@ linters:
enable: enable:
- nilness - nilness
- unusedwrite - 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.-]+'
template: '{{ HEADER }}'
exclusions: exclusions:
generated: lax generated: lax
presets: presets:
@@ -158,9 +172,16 @@ issues:
max-same-issues: 0 max-same-issues: 0
formatters: formatters:
enable: enable:
- gofmt - gci
- gofumpt - gofumpt
settings: settings:
gci:
custom-order: true
sections:
- standard
- prefix(code.gitea.io/gitea)
- blank
- default
gofumpt: gofumpt:
extra-rules: true extra-rules: true
exclusions: exclusions:
@@ -170,9 +191,6 @@ formatters:
- .venv - .venv
- public - public
- web_src - web_src
- third_party$
- builtin$
- examples$
run: run:
timeout: 10m timeout: 10m

View File

@@ -2,10 +2,14 @@
- Run `make fmt` to format `.go` files, and run `make lint-go` to lint them - 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 lint-js` to lint `.ts` files
- Run `make tidy` after any `go.mod` changes - Run `make tidy` after any `go.mod` changes
- Run single go tests with `go test -tags 'sqlite sqlite_unlock_notify' -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 - Add the current year into the copyright header of new `.go` files
- Ensure no trailing whitespace in edited files - Ensure no trailing whitespace in edited files
- Never force-push, amend, or squash unless asked. Use new commits and normal push for pull request updates - 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 - 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 - 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 - Include authorship attribution in issue and pull request comments
- Add `Co-Authored-By` lines to all commits, indicating name and model used - Add `Co-Authored-By` lines to all commits, indicating name and model used

View File

@@ -4,6 +4,428 @@ This changelog goes through the changes that have been made in each release
without substantial changes to our git log; to see the highlights of what has without substantial changes to our git log; to see the highlights of what has
been added to each release, please refer to the [blog](https://blog.gitea.com). been added to each release, please refer to the [blog](https://blog.gitea.com).
## [1.26.1](https://github.com/go-gitea/gitea/releases/tag/v1.26.1) - 2026-04-21
* BUGFIXES
* Add event.schedule context for schedule actions task (#37320) (#37348)
* Fix an issue where changing an organization's visibility caused problems when users had forked its repositories. (#37324) (#37344)
* Use modern "git update-index --cacheinfo" syntax to support more file names (#37338) (#37343)
* Fix URL related escaping for oauth2 (#37334) (#37340)
* When the requested arch rpm is missing fall back to noarch (#37236) (#37339)
* Fix actions concurrency groups cross-branch leak (#37311) (#37331)
* Fix bug when accessing user badges (#37321) (#37329)
* Fix AppFullLink (#37325) (#37328)
* Fix container auth for public instance (#37290) (#37294)
* Enhance GetActionWorkflow to support fallback references (#37189) (#37283)
* Fix vite manifest update masking build errors (#37279) (#37310)
* Fix Mermaid diagrams failing when node labels contain line breaks (#37296) (#37299)
* Use TriggerEvent instead of Event in workflow runs API response for scheduled runs (#37288) #37360
* Add URL to Learn more about blocking a user. (#37355) #37367
* Fix button layout shift when collapsing file tree in editor (#37363) #37375
* Fix org team assignee/reviewer lookups for team member permissions (#37365) #37391
* Fix repo init README EOL (#37388) #37399
* Fix: dump with default zip type produces uncompressed zip (#37401) #37402
## [1.26.0](https://github.com/go-gitea/gitea/releases/tag/v1.26.0) - 2026-04-17
* BREAKING
* Correct swagger annotations for enums, status codes, and notification state (#37030)
* Remove GET API registration-token (#36801)
* Support Actions `concurrency` syntax (#32751)
* Make PUBLIC_URL_DETECTION default to "auto" (#36955)
* SECURITY
* Bound PageSize in `ListUnadoptedRepositories` (#36884)
* FEATURES
* Support Actions `concurrency` syntax (#32751)
* Add terraform state registry (#36710)
* Instance-wide (global) info banner and maintenance mode (#36571)
* Support rendering OpenAPI spec (#36449)
* Add keyboard shortcuts for repository file and code search (#36416)
* Add support for archive-upload rpc (#36391)
* Add ability to download subpath archive (#36371)
* Add workflow dependencies visualization (#26062) (#36248) & Restyle Workflow Graph (#36912)
* Automatic generation of release notes (#35977)
* Add "Go to file", "Delete Directory" to repo file list page (#35911)
* Introduce "config edit-ini" sub command to help maintaining INI config file (#35735)
* Add button to re-run failed jobs in Actions (#36924)
* Support actions and reusable workflows from private repos (#32562)
* Add summary to action runs view (#36883)
* Add user badges (#36752)
* Add configurable permissions for Actions automatic tokens (#36173)
* Add per-runner "Disable/Pause" (#36776)
* Feature non-zipped actions artifacts (action v7 / nodejs / npm v6.2.0) (#36786)
* PERFORMANCE
* WorkflowDispatch API optionally return runid (#36706)
* Add render cache for SVG icons (#36863)
* Load `mentionValues` asynchronously (#36739)
* Lazy-load some Vue components, fix heatmap chunk loading on every page (#36719)
* Load heatmap data asynchronously (#36622)
* Use prev/next pagination for user profile activities page to speed up (#36642)
* Refactor cat-file batch operations and support `--batch-command` approach (#35775)
* Use merge tree to detect conflicts when possible (#36400)
* ENHANCEMENTS
* Implement logout redirection for reverse proxy auth setups (#36085) (#37171)
* Adds option to force update new branch in contents routes (#35592)
* Add viewer controller for mermaid (zoom, drag) (#36557)
* Add code editor setting dropdowns (#36534)
* Add `elk` layout support to mermaid (#36486)
* Add resolve/unresolve review comment API endpoints (#36441)
* Allow configuring default PR base branch (fixes #36412) (#36425)
* Add support for RPM Errata (updateinfo.xml) (#37125)
* Require additional user confirmation for making repo private (#36959)
* Add `actions.WORKFLOW_DIRS` setting (#36619)
* Avoid opening new tab when downloading actions logs (#36740)
* Implements OIDC RP-Initiated Logout (#36724)
* Show workflow link (#37070)
* Desaturate dark theme background colors (#37056)
* Refactor "org teams" page and help new users to "add member" to an org (#37051)
* Add webhook name field to improve webhook identification (#37025) (#37040)
* Make task list checkboxes clickable in the preview tab (#37010)
* Improve severity labels in Actions logs and tweak colors (#36993)
* Linkify URLs in Actions workflow logs (#36986)
* Allow text selection on checkbox labels (#36970)
* Support dark/light theme images in markdown (#36922)
* Enable native dark mode for swagger-ui (#36899)
* Rework checkbox styling, remove `input` border hover effect (#36870)
* Refactor storage content-type handling of ServeDirectURL (#36804)
* Use "Enable Gravatar" but not "Disable" (#36771)
* Use case-insensitive matching for Git error "Not a valid object name" (#36728)
* Add "Copy Source" to markup comment menu (#36726)
* Change image transparency grid to CSS (#36711)
* Add "Run" prefix for unnamed action steps (#36624)
* Persist actions log time display settings in `localStorage` (#36623)
* Use first commit title for multi-commit PRs and fix auto-focus title field (#36606)
* Improve BuildCaseInsensitiveLike with lowercase (#36598)
* Improve diff highlighting (#36583)
* Exclude cancelled runs from failure-only email notifications (#36569)
* Use full-file highlighting for diff sections (#36561)
* Color command/error logs in Actions log (#36538)
* Add paging headers (#36521)
* Improve timeline entries for WIP prefix changes in pull requests (#36518)
* Add FOLDER_ICON_THEME configuration option (#36496)
* Normalize guessed languages for code highlighting (#36450)
* Add chunked transfer encoding support for LFS uploads (#36380)
* Indicate when only optional checks failed (#36367)
* Add 'allow_maintainer_edit' API option for creating a pull request (#36283)
* Support closing keywords with URL references (#36221)
* Improve diff file headers (#36215)
* Fix and enhance comment editor monospace toggle (#36181)
* Add git.DIFF_RENAME_SIMILARITY_THRESHOLD option (#36164)
* Add matching pair insertion to markdown textarea (#36121)
* Add sorting/filtering to admin user search API endpoint (#36112)
* Allow action user have read permission in public repo like other user (#36095)
* Disable matchBrackets in monaco (#36089)
* Use GitHub-style commit message for squash merge (#35987)
* Make composer registry support tar.gz and tar.bz2 and fix bugs (#35958)
* Add GITEA_PR_INDEX env variable to githooks (#35938)
* Add proper error message if session provider can not be created (#35520)
* Add button to copy file name in PR files (#35509)
* Move `X_FRAME_OPTIONS` setting from `cors` to `security` section (#30256)
* Add placeholder content for empty content page (#37114)
* Add `DEFAULT_DELETE_BRANCH_AFTER_MERGE` setting (#36917)
* Redirect to the only OAuth2 provider when no other login methods and fix various problems (#36901)
* Add admin badge to navbar avatar (#36790)
* Add `never` option to `PUBLIC_URL_DETECTION` configuration (#36785)
* Add background and run count to actions list page (#36707)
* Add icon to buttons "Close with Comment", "Close Pull Request", "Close Issue" (#36654)
* Add support for in_progress event in workflow_run webhook (#36979)
* Report commit status for pull_request_review events (#36589)
* Render merged pull request title as such in dashboard feed (#36479)
* Feature to be able to filter project boards by milestones (#36321)
* Use user id in noreply emails (#36550)
* Enable pagination on GiteaDownloader.getIssueReactions() (#36549)
* Remove striped tables in UI (#36509)
* Improve control char rendering and escape button styling (#37094)
* Support legacy run/job index-based URLs and refactor migration 326 (#37008)
* Add date to "No Contributions" tooltip (#36190)
* Show edit page confirmation dialog on tree view file change (#36130)
* Mention proc-receive in text for dashboard.resync_all_hooks func (#35991)
* Reuse selectable style for wiki (#35990)
* Support blue yellow colorblind theme (#35910)
* Support selecting theme on the footer (#35741)
* Improve online runner check (#35722)
* Add quick approve button on PR page (#35678)
* Enable commenting on expanded lines in PR diffs (#35662)
* Print PR-Title into tooltip for actions (#35579)
* Use explicit, stronger defaults for newly generated repo signing keys for Debian (#36236)
* Improve the compare page (#36261)
* Unify repo names in system notices (#36491)
* Move package settings to package instead of being tied to version (#37026)
* Add Actions API rerun endpoints for runs and jobs (#36768)
* Add branch_count to repository API (#35351) (#36743)
* Add created_by filter to SearchIssues (#36670)
* Allow admins to rename non-local users (#35970)
* Support updating branch via API (#35951)
* Add an option to automatically verify SSH keys from LDAP (#35927)
* Make "update file" API can create a new file when SHA is not set (#35738)
* Update issue.go with labels documentation (labels content, not ids) (#35522)
* Expose content_version for optimistic locking on issue and PR edits (#37035)
* Pass ServeHeaderOptions by value instead of pointer, fine tune httplib tests (#36982)
* BUGFIXES
* Frontend iframe renderer framework: 3D models, OpenAPI (#37233) (#37273)
* Fix CODEOWNERS absolute path matching. (#37244) (#37264)
* Swift registry metadata: preserve more JSON fields and accept empty metadata (#37254) (#37261)
* Fix user ssh key exporting and tests (#37256) (#37258)
* Fix team member avatar size and add tooltip (#37253)
* Fix commit title rendering in action run and blame (#37243) (#37251)
* Fix corrupted JSON caused by goccy library (#37214) (#37220)
* Add test for "fetch redirect", add CSS value validation for external render (#37207) (#37216)
* Fix incorrect concurrency check (#37205) (#37215)
* Fix handle missing base branch in PR commits API (#37193) (#37203)
* Fix encoding for Matrix Webhooks (#37190) (#37201)
* Fix handle fork-only commits in compare API (#37185) (#37199)
* Indicate form field readonly via background, fix RunUser config (#37175, #37180) (#37178)
* Report structurally invalid workflows to users (#37116) (#37164)
* Fix API not persisting pull request unit config when has_pull_requests is not set (#36718)
* Rename CSS variables and improve colorblind themes (#36353)
* Hide `add-matcher` and `remove-matcher` from actions job logs (#36520)
* Prevent navigation keys from triggering actions during IME composition (#36540)
* Fix vertical alignment of `.commit-sign-badge` children (#36570)
* Fix duplicate startup warnings in admin panel (#36641)
* Fix CODEOWNERS review request attribution using comment metadata (#36348)
* Fix HTML tags appearing in wiki table of contents (#36284)
* Fix various bugs (#37096)
* Fix various legacy problems (#37092)
* Fix RPM Registry 404 when package name contains 'package' (#37087)
* Merge some standalone Vite entries into index.js (#37085)
* Fix various problems (#37077)
* Fix issue label deletion with Actions tokens (#37013)
* Hide delete branch or tag buttons in mirror or archived repositories. (#37006)
* Fix org contact email not clearable once set (#36975)
* Fix a bug when forking a repository in an organization (#36950)
* Preserve sort order of exclusive labels from template repo (#36931)
* Make container registry support Apple Container (basic auth) (#36920)
* Fix the wrong push commits in the pull request when force push (#36914)
* Add class "list-header-filters" to the div for projects (#36889)
* Fix dbfs error handling (#36844)
* Fix incorrect viewed files counter if reverted change was viewed (#36819)
* Refactor avatar package, support default avatar fallback (#36788)
* Fix README symlink resolution in subdirectories like .github (#36775)
* Fix CSS stacking context issue in actions log (#36749)
* Add gpg signing for merge rebase and update by rebase (#36701)
* Delete non-exist branch should return 404 (#36694)
* Fix `TestActionsCollaborativeOwner` (#36657)
* Fix multi-arch Docker build SIGILL by splitting frontend stage (#36646)
* Fix linguist-detectable attribute being ignored for configuration files (#36640)
* Fix state desync in ComboMarkdownEditor (#36625)
* Unify DEFAULT_SHOW_FULL_NAME output in templates and dropdown (#36597)
* Pull Request Pusher should be the author of the merge (#36581)
* Fix various version parsing problems (#36553)
* Fix highlight diff result (#36539)
* Fix mirror sync parser and fix mirror messages (#36504)
* Fix bug when list pull request commits (#36485)
* Fix various bugs (#36446)
* Fix issue filter menu layout (#36426)
* Restrict branch naming when new change matches with protection rules (#36405)
* Fix link/origin referrer and login redirect (#36279)
* Generate IDs for HTML headings without id attribute (#36233)
* Use a migration test instead of a wrong test which populated the meta test repositories and fix a migration bug (#36160)
* Fix issue close timeline icon (#36138)
* Fix diff blob excerpt expansion (#35922)
* Fix external render (#35727)
* Fix review request webhook bug (#35339) (#35723)
* Fix shutdown waitgroup panic (#35676)
* Cleanup ActionRun creation (#35624)
* Fix possible bug when migrating issues/pull requests (#33487)
* Various fixes (#36697)
* Apply notify/register mail flags during install load (#37120)
* Repair duration display for bad stopped timestamps (#37121)
* Fix(upgrade.sh): use HTTPS for GPG key import and restore SELinux context after upgrade (#36930)
* Fix various trivial problems (#36921)
* Fix various trivial problems (#36953)
* Fix NuGet package upload error handling (#37074)
* Fix CodeQL code scanning alerts (#36858)
* Refactor issue sidebar and fix various problems (#37045)
* Fix various problems (#37029)
* Fix relative-time RangeError (#37021)
* Fix chroma lexer mapping (#36629)
* Fix typos and grammar in English locale (#36751)
* Fix milestone/project text overflow in issue sidebar (#36741)
* Fix `no-content` message not rendering after comment edit (#36733)
* Fix theme loading in development (#36605)
* Fix workflow run jobs API returning null steps (#36603)
* Fix timeline event layout overflow with long content (#36595)
* Fix minor UI issues in runner edit page (#36590)
* Fix incorrect vendored detections (#36508)
* Fix editorconfig not respected in PR Conversation view (#36492)
* Don't create self-references in merged PRs (#36490)
* Fix potential incorrect runID in run status update (#36437)
* Fix file-tree ui error when adding files to repo without commits (#36312)
* Improve image captcha contrast for dark mode (#36265)
* Fix panic in blame view when a file has only a single commit (#36230)
* Fix spelling error in migrate-storage cmd utility (#36226)
* Fix code highlighting on blame page (#36157)
* Fix nilnil in onedev downloader (#36154)
* Fix actions lint (#36029)
* Fix oauth2 session gob register (#36017)
* Fix Arch repo pacman.conf snippet (#35825)
* Fix a number of `strictNullChecks`-related issues (#35795)
* Fix URLJoin, markup render link reoslving, sign-in/up/linkaccount page common data (#36861)
* Hide delete directory button for mirror or archive repository and disable the menu item if user have no permission (#36384)
* Update message severity colors, fix navbar double border (#37019)
* Inline and lazy-load EasyMDE CSS, fix border colors (#36714)
* Closed milestones with no issues now show as 100% completed (#36220)
* Add test for ExtendCommentTreePathLength migration and fix bugs (#35791)
* Only turn links to current instance into hash links (#36237)
* Fix typos in code comments: doesnt, dont, wont (#36890)
* REFACTOR
* Clean up and improve non-gitea js error filter (#37148) (#37155)
* Always show owner/repo name in compare page dropdowns (#37172) (#37200)
* Remove dead CSS rules (#37173) (#37177)
* Replace Monaco with CodeMirror (#36764)
* Replace CSRF cookie with `CrossOriginProtection` (#36183)
* Replace index with id in actions routes (#36842)
* Remove unnecessary function parameter (#35765)
* Move jobparser from act repository to Gitea (#36699)
* Refactor compare router param parse (#36105)
* Optimize 'refreshAccesses' to perform update without removing then adding (#35702)
* Clean up checkbox cursor styles (#37016)
* Remove undocumented support of signing key in the repository git configuration file (#36143)
* Switch `cmd/` to use constructor functions. (#36962)
* Use `relative-time` to render absolute dates (#36238)
* Some refactors about GetMergeBase (#36186)
* Some small refactors (#36163)
* Use gitRepo as parameter instead of repopath when invoking sign functions (#36162)
* Move blame to gitrepo (#36161)
* Move some functions to gitrepo package to reduce RepoPath reference directly (#36126)
* Use gitrepo's clone and push when possible (#36093)
* Remove mermaid margin workaround (#35732)
* Move some functions to gitrepo package (#35543)
* Move GetDiverging functions to gitrepo (#35524)
* Use global lock instead of status pool for cron lock (#35507)
* Use explicit mux instead of DefaultServeMux (#36276)
* Use gitrepo's push function (#36245)
* Pass request context to generateAdditionalHeadersForIssue (#36274)
* Move assign project when creating pull request to the same database transaction (#36244)
* Move catfile batch to a sub package of git module (#36232)
* Use gitrepo.Repository instead of wikipath (#35398)
* Use experimental go json v2 library (#35392)
* Refactor template render (#36438)
* Refactor GetRepoRawDiffForFile to avoid unnecessary pipe or goroutine (#36434)
* Refactor text utility classes to Tailwind CSS (#36703)
* Refactor git command stdio pipe (#36422)
* Refactor git command context & pipeline (#36406)
* Refactor git command stdio pipe (#36393)
* Remove unused functions (#36672)
* Refactor Actions Token Access (#35688)
* Move commit related functions to gitrepo package (#35600)
* Move archive function to repo_model and gitrepo (#35514)
* Move some functions to gitrepo package (#35503)
* Use git model to detect whether branch exist instead of gitrepo method (#35459)
* Some refactor for repo path (#36251)
* Extract helper functions from SearchIssues (#36158)
* Refactor merge conan and container auth preserve actions taskID (#36560)
* Refactor Nuget Auth to reuse Basic Auth Token Validation (#36558)
* Refactor ActionsTaskID (#36503)
* Refactor auth middleware (#36848)
* Refactor code render and render control chars (#37078)
* Clean up AppURL, remove legacy origin-url webcomponent (#37090)
* Remove `util.URLJoin` and replace all callers with direct path concatenation (#36867)
* Replace legacy tw-flex utility classes with flex-text-block/inline (#36778)
* Mark unused&immature activitypub as "not implemented" (#36789)
* TESTING
* Add e2e tests for server push events (#36879)
* Rework e2e tests (#36634)
* Add e2e reaction test, improve accessibility, enable parallel testing (#37081)
* Increase e2e test timeouts on CI to fix flaky tests (#37053)
* BUILD
* Upgrade go-git to v5.18.0 (#37269)
* Replace rollup-plugin-license with rolldown-license-plugin (#37130) (#37158)
* Bump min go version to 1.26.2 (#37139) (#37143)
* Convert locale files from ini to json format (#35489)
* Bump golangci-lint to 2.7.2, enable modernize stringsbuilder (#36180)
* Port away from `flake-utils` (#35675)
* Remove nolint (#36252)
* Update the Unlicense copy to latest version (#36636)
* Update to go 1.26.0 and golangci-lint 2.9.0 (#36588)
* Replace `google/go-licenses` with custom generation (#36575)
* Update go dependencies (#36548)
* Bump appleboy/git-push-action from 1.0.0 to 1.2.0 (#36306)
* Remove fomantic form module (#36222)
* Bump setup-node to v6, re-enable cache (#36207)
* Bump crowdin/github-action from 1 to 2 (#36204)
* Revert "Bump alpine to 3.23 (#36185)" (#36202)
* Update chroma to v2.21.1 (#36201)
* Bump astral-sh/setup-uv from 6 to 7 (#36198)
* Bump docker/build-push-action from 5 to 6 (#36197)
* Bump aws-actions/configure-aws-credentials from 4 to 5 (#36196)
* Bump dev-hanz-ops/install-gh-cli-action from 0.1.0 to 0.2.1 (#36195)
* Add JSON linting (#36192)
* Enable dependabot for actions (#36191)
* Bump alpine to 3.23 (#36185)
* Update chroma to v2.21.0 (#36171)
* Update JS deps and eslint enhancements (#36147)
* Update JS deps (#36091)
* update golangci-lint to v2.7.0 (#36079)
* Update JS deps, fix deprecations (#36040)
* Update JS deps (#35978)
* Add toolchain directive to go.mod (#35901)
* Move `gitea-vet` to use `go tool` (#35878)
* Update to go 1.25.4 (#35877)
* Enable TypeScript `strictNullChecks` (#35843)
* Enable `vue/require-typed-ref` eslint rule (#35764)
* Update JS dependencies (#35759)
* Move `codeformat` folder to tools (#35758)
* Update dependencies (#35733)
* Bump happy-dom from 20.0.0 to 20.0.2 (#35677)
* Bump setup-go to v6 (#35660)
* Update JS deps, misc tweaks (#35643)
* Bump happy-dom from 19.0.2 to 20.0.0 (#35625)
* Use bundled version of spectral (#35573)
* Update JS and PY deps (#35565)
* Bump github.com/wneessen/go-mail from 0.6.2 to 0.7.1 (#35557)
* Migrate from webpack to vite (#37002)
* Update JS dependencies and misc tweaks (#37064)
* Update to eslint 10 (#36925)
* Optimize Docker build with dependency layer caching (#36864)
* Update JS deps (#36850)
* Update tool dependencies and fix new lint issues (#36702)
* Remove redundant linter rules (#36658)
* Move Fomantic dropdown CSS to custom module (#36530)
* Remove and forbid `@ts-expect-error` (#36513)
* Refactor git command stderr handling (#36402)
* Enable gocheckcompilerdirectives linter (#36156)
* Replace `lint-go-gopls` with additional `govet` linters (#36028)
* Update golangci-lint to v2.6.0 (#35801)
* Misc tool tweaks (#35734)
* Add cache to container build (#35697)
* Upgrade vite (#37126)
* Update `setup-uv` to v8.0.0 (#37101)
* Upgrade `go-git` to v5.17.2 and related dependencies (#37060)
* Raise minimum Node.js version to 22.18.0 (#37058)
* Upgrade `golang.org/x/image` to v0.38.0 (#37054)
* Update minimum go version to 1.26.1, golangci-lint to 2.11.2, fix test style (#36876)
* Enable eslint concurrency (#36878)
* Vendor relative-time-element as local web component (#36853)
* Update material-icon-theme v5.32.0 (#36832)
* Update Go dependencies (#36781)
* Upgrade minimatch (#36760)
* Remove i18n backport tool at the moment because of translation format changed (#36643)
* Update emoji data for Unicode 16 (#36596)
* Update JS dependencies, adjust webpack config, misc fixes (#36431)
* Update material-icon-theme to v5.31.0 (#36427)
* Update JS and PY deps (#36383)
* Bump alpine to 3.23, add platforms to `docker-dryrun` (#36379)
* Update JS deps (#36354)
* Update goldmark to v1.7.16 (#36343)
* Update chroma to v2.22.0 (#36342)
* DOCS
* Update AI Contribution Policy (#37022)
* Update AGENTS.md with additional guidelines (#37018)
* Add missing cron tasks to example ini (#37012)
* Add AI Contribution Policy to CONTRIBUTING.md (#36651)
* Minor punctuation improvement in CONTRIBUTING.md (#36291)
* Add documentation for markdown anchor post-processing (#36443)
* MISC
* Correct spelling (#36783)
* Update Nix flake (#37110)
* Update Nix flake (#37024)
* Add valid github scopes (#36977)
* Update Nix flake (#36943)
* Update Nix flake (#36902)
* Update Nix flake (#36857)
* Update Nix flake (#36787)
## [1.25.5](https://github.com/go-gitea/gitea/releases/tag/v1.25.5) - 2026-03-10 ## [1.25.5](https://github.com/go-gitea/gitea/releases/tag/v1.25.5) - 2026-03-10
* SECURITY * SECURITY

View File

@@ -1,5 +1,14 @@
# Contribution Guidelines # Contribution Guidelines
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) |
| Frontend (npm, UI guidelines) | [docs/guideline-frontend.md](docs/guideline-frontend.md) |
| Maintainers, TOC, labels, merge queue, commit format for mergers | [docs/community-governance.md](docs/community-governance.md) |
| Release cycle, backports, tagging releases | [docs/release-management.md](docs/release-management.md) |
<details><summary>Table of Contents</summary> <details><summary>Table of Contents</summary>
- [Contribution Guidelines](#contribution-guidelines) - [Contribution Guidelines](#contribution-guidelines)
@@ -11,10 +20,6 @@
- [Discuss your design before the implementation](#discuss-your-design-before-the-implementation) - [Discuss your design before the implementation](#discuss-your-design-before-the-implementation)
- [Issue locking](#issue-locking) - [Issue locking](#issue-locking)
- [Building Gitea](#building-gitea) - [Building Gitea](#building-gitea)
- [Dependencies](#dependencies)
- [Backend](#backend)
- [Frontend](#frontend)
- [Design guideline](#design-guideline)
- [Styleguide](#styleguide) - [Styleguide](#styleguide)
- [Copyright](#copyright) - [Copyright](#copyright)
- [Testing](#testing) - [Testing](#testing)
@@ -22,47 +27,19 @@
- [Code review](#code-review) - [Code review](#code-review)
- [Pull request format](#pull-request-format) - [Pull request format](#pull-request-format)
- [PR title and summary](#pr-title-and-summary) - [PR title and summary](#pr-title-and-summary)
- [Milestone](#milestone)
- [Labels](#labels)
- [Breaking PRs](#breaking-prs) - [Breaking PRs](#breaking-prs)
- [What is a breaking PR?](#what-is-a-breaking-pr) - [What is a breaking PR?](#what-is-a-breaking-pr)
- [How to handle breaking PRs?](#how-to-handle-breaking-prs) - [How to handle breaking PRs?](#how-to-handle-breaking-prs)
- [Maintaining open PRs](#maintaining-open-prs) - [Maintaining open PRs](#maintaining-open-prs)
- [Getting PRs merged](#getting-prs-merged) - [Reviewing PRs](#reviewing-prs)
- [Final call](#final-call) - [For PR authors](#for-pr-authors)
- [Commit messages](#commit-messages)
- [PR Co-authors](#pr-co-authors)
- [PRs targeting `main`](#prs-targeting-main)
- [Backport PRs](#backport-prs)
- [Documentation](#documentation) - [Documentation](#documentation)
- [API v1](#api-v1)
- [GitHub API compatibility](#github-api-compatibility)
- [Adding/Maintaining API routes](#addingmaintaining-api-routes)
- [When to use what HTTP method](#when-to-use-what-http-method)
- [Requirements for API routes](#requirements-for-api-routes)
- [Backports and Frontports](#backports-and-frontports)
- [What is backported?](#what-is-backported)
- [How to backport?](#how-to-backport)
- [Format of backport PRs](#format-of-backport-prs)
- [Frontports](#frontports)
- [Developer Certificate of Origin (DCO)](#developer-certificate-of-origin-dco) - [Developer Certificate of Origin (DCO)](#developer-certificate-of-origin-dco)
- [Release Cycle](#release-cycle)
- [Maintainers](#maintainers)
- [Technical Oversight Committee (TOC)](#technical-oversight-committee-toc)
- [TOC election process](#toc-election-process)
- [Current TOC members](#current-toc-members)
- [Previous TOC/owners members](#previous-tocowners-members)
- [Governance Compensation](#governance-compensation)
- [TOC \& Working groups](#toc--working-groups)
- [Roadmap](#roadmap)
- [Versions](#versions)
- [Releasing Gitea](#releasing-gitea)
</details> </details>
## Introduction ## Introduction
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). \ 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). 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). 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)
- [refactoring guideline](https://docs.gitea.com/contributing/guidelines-refactoring)
## Styleguide ## Styleguide
You should always run `make fmt` before committing to conform to Gitea's styleguide. You should always run `make fmt` before committing to conform to Gitea's styleguide.
@@ -202,7 +151,7 @@ Here's how to run the test suite:
| :-------------------------------- | :---------------------------------------------------------- | | :-------------------------------- | :---------------------------------------------------------- |
| ``GITEA_TEST_E2E_DEBUG`` | When set, show Gitea server output | | ``GITEA_TEST_E2E_DEBUG`` | When set, show Gitea server output |
| ``GITEA_TEST_E2E_FLAGS`` | Additional flags passed to Playwright, for example ``--ui`` | | ``GITEA_TEST_E2E_FLAGS`` | Additional flags passed to Playwright, for example ``--ui`` |
| ``GITEA_TEST_E2E_TIMEOUT_FACTOR`` | Timeout multiplier (default: 3 on CI, 1 locally) | | ``GITEA_TEST_E2E_TIMEOUT_FACTOR`` | Timeout multiplier (default: 4 on CI, 1 locally) |
## Translation ## Translation
@@ -216,6 +165,8 @@ The tool `go run build/backport-locale.go` can be used to backport locales from
## Code review ## Code review
How labels, milestones, and the merge queue work is documented in [docs/community-governance.md](docs/community-governance.md).
### Pull request format ### Pull request format
Please try to make your pull request easy to review for us. \ Please try to make your pull request easy to review for us. \
@@ -260,29 +211,6 @@ Fixes/Closes/Resolves #<ISSUE_NR_Y>.
to your summary. \ to your summary. \
Each issue that will be closed must stand on a separate line. 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 ### Breaking PRs
#### What is a breaking PR? #### What is a breaking PR?
@@ -311,165 +239,29 @@ Breaking PRs will not be merged as long as not both of these requirements are me
### Maintaining open PRs ### 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. \ 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.
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.
### 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 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.
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.
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. \ ### Reviewing PRs
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:
<https://github.com/go-gitea/gitea/pulls?q=is%3Apr+label%3Areviewed%2Fwait-merge+sort%3Acreated-asc+is%3Aopen> 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. \ #### For PR authors
This tool does the things listed below automatically:
- create a backport PR if needed once the initial PR was merged - **Response**: When answering reviewer questions, use real-world cases or examples and avoid speculation.
- remove the PR from the merge queue after the PR merged - **Discussion**: A discussion is always welcome and should be used to clarify the changes and the intent of the PR.
- keep the oldest branch in the merge queue up to date with merges - **Help**: If you need help with the PR or comments are unclear, ask for clarification.
### Final call Guidance for reviewers, the merge queue, and the squash commit message format is in [docs/community-governance.md](docs/community-governance.md).
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
```bash
$PR_TITLE ($PR_INDEX)
$REWRITTEN_PR_SUMMARY
```
#### Backport PRs
The commit message of backport PRs is always
```bash
$PR_TITLE ($INITIAL_PR_INDEX) ($BACKPORT_PR_INDEX)
$REWRITTEN_PR_SUMMARY
```
## Documentation ## 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). 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.** **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) ## 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). \ 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 +275,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`. 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. 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
if possible provide GPG signed commits.
https://help.github.com/articles/securing-your-account-with-two-factor-authentication-2fa/
https://help.github.com/articles/signing-commits-with-gpg/
Furthermore, any account with write access (like bots and TOC members) **must** use 2FA.
https://help.github.com/articles/securing-your-account-with-two-factor-authentication-2fa/
## Technical Oversight Committee (TOC)
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.
### Current TOC members
- 2024-01-01 ~ 2024-12-31
- Company
- [Jason Song](https://gitea.com/wolfogre) <i@wolfogre.com>
- [Lunny Xiao](https://gitea.com/lunny) <xiaolunwen@gmail.com>
- [Matti Ranta](https://gitea.com/techknowlogick) <techknowlogick@gitea.com>
- Community
- [6543](https://gitea.com/6543) <6543@obermui.de>
- [delvh](https://gitea.com/delvh) <dev.lh@web.de>
- [John Olheiser](https://gitea.com/jolheiser) <john.olheiser@gmail.com>
### Previous TOC/owners members
Here's the history of the owners and the time they served:
- [Lunny Xiao](https://gitea.com/lunny) - 2016, 2017, [2018](https://github.com/go-gitea/gitea/issues/3255), [2019](https://github.com/go-gitea/gitea/issues/5572), [2020](https://github.com/go-gitea/gitea/issues/9230), [2021](https://github.com/go-gitea/gitea/issues/13801), [2022](https://github.com/go-gitea/gitea/issues/17872), 2023
- [Kim Carlbäcker](https://github.com/bkcsoft) - 2016, 2017
- [Thomas Boerger](https://gitea.com/tboerger) - 2016, 2017
- [Lauris Bukšis-Haberkorns](https://gitea.com/lafriks) - [2018](https://github.com/go-gitea/gitea/issues/3255), [2019](https://github.com/go-gitea/gitea/issues/5572), [2020](https://github.com/go-gitea/gitea/issues/9230), [2021](https://github.com/go-gitea/gitea/issues/13801)
- [Matti Ranta](https://gitea.com/techknowlogick) - [2019](https://github.com/go-gitea/gitea/issues/5572), [2020](https://github.com/go-gitea/gitea/issues/9230), [2021](https://github.com/go-gitea/gitea/issues/13801), [2022](https://github.com/go-gitea/gitea/issues/17872), 2023
- [Andrew Thornton](https://gitea.com/zeripath) - [2020](https://github.com/go-gitea/gitea/issues/9230), [2021](https://github.com/go-gitea/gitea/issues/13801), [2022](https://github.com/go-gitea/gitea/issues/17872), 2023
- [6543](https://gitea.com/6543) - 2023
- [John Olheiser](https://gitea.com/jolheiser) - 2023
- [Jason Song](https://gitea.com/wolfogre) - 2023
## Governance Compensation
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`

View File

@@ -12,16 +12,15 @@ COMMA := ,
XGO_VERSION := go-1.25.x XGO_VERSION := go-1.25.x
AIR_PACKAGE ?= github.com/air-verse/air@v1 AIR_PACKAGE ?= github.com/air-verse/air@v1 # renovate: datasource=go
EDITORCONFIG_CHECKER_PACKAGE ?= github.com/editorconfig-checker/editorconfig-checker/v3/cmd/editorconfig-checker@v3 EDITORCONFIG_CHECKER_PACKAGE ?= github.com/editorconfig-checker/editorconfig-checker/v3/cmd/editorconfig-checker@v3 # renovate: datasource=go
GOFUMPT_PACKAGE ?= mvdan.cc/gofumpt@v0.9.2 GOLANGCI_LINT_PACKAGE ?= github.com/golangci/golangci-lint/v2/cmd/golangci-lint@v2.11.4 # renovate: datasource=go
GOLANGCI_LINT_PACKAGE ?= github.com/golangci/golangci-lint/v2/cmd/golangci-lint@v2.11.4 GXZ_PACKAGE ?= github.com/ulikunitz/xz/cmd/gxz@v0.5.15 # renovate: datasource=go
GXZ_PACKAGE ?= github.com/ulikunitz/xz/cmd/gxz@v0.5.15 MISSPELL_PACKAGE ?= github.com/golangci/misspell/cmd/misspell@v0.8.0 # renovate: datasource=go
MISSPELL_PACKAGE ?= github.com/golangci/misspell/cmd/misspell@v0.8.0 SWAGGER_PACKAGE ?= github.com/go-swagger/go-swagger/cmd/swagger@v0.33.1 # renovate: datasource=go
SWAGGER_PACKAGE ?= github.com/go-swagger/go-swagger/cmd/swagger@v0.33.1
XGO_PACKAGE ?= src.techknowlogick.com/xgo@latest XGO_PACKAGE ?= src.techknowlogick.com/xgo@latest
GOVULNCHECK_PACKAGE ?= golang.org/x/vuln/cmd/govulncheck@v1 GOVULNCHECK_PACKAGE ?= golang.org/x/vuln/cmd/govulncheck@v1 # renovate: datasource=go
ACTIONLINT_PACKAGE ?= github.com/rhysd/actionlint/cmd/actionlint@v1.7.11 ACTIONLINT_PACKAGE ?= github.com/rhysd/actionlint/cmd/actionlint@v1.7.11 # renovate: datasource=go
DOCKER_IMAGE ?= gitea/gitea DOCKER_IMAGE ?= gitea/gitea
DOCKER_TAG ?= latest DOCKER_TAG ?= latest
@@ -206,7 +205,7 @@ clean: ## delete backend and integration files
.PHONY: fmt .PHONY: fmt
fmt: ## format the Go and template code fmt: ## format the Go and template code
@GOFUMPT_PACKAGE=$(GOFUMPT_PACKAGE) $(GO) run tools/code-batch-process.go gitea-fmt -w '{file-list}' $(GO) run $(GOLANGCI_LINT_PACKAGE) fmt
$(eval TEMPLATES := $(shell find templates -type f -name '*.tmpl')) $(eval TEMPLATES := $(shell find templates -type f -name '*.tmpl'))
@# strip whitespace after '{{' or '(' and before '}}' or ')' unless there is only @# strip whitespace after '{{' or '(' and before '}}' or ')' unless there is only
@# whitespace before it @# whitespace before it
@@ -278,10 +277,10 @@ lint-frontend: lint-js lint-css ## lint frontend files
lint-frontend-fix: lint-js-fix lint-css-fix ## lint frontend files and fix issues lint-frontend-fix: lint-js-fix lint-css-fix ## lint frontend files and fix issues
.PHONY: lint-backend .PHONY: lint-backend
lint-backend: lint-go lint-go-gitea-vet lint-editorconfig ## lint backend files lint-backend: lint-go lint-editorconfig ## lint backend files
.PHONY: lint-backend-fix .PHONY: lint-backend-fix
lint-backend-fix: lint-go-fix lint-go-gitea-vet lint-editorconfig ## lint backend files and fix issues lint-backend-fix: lint-go-fix lint-editorconfig ## lint backend files and fix issues
.PHONY: lint-js .PHONY: lint-js
lint-js: node_modules ## lint js and ts files lint-js: node_modules ## lint js and ts files
@@ -336,11 +335,6 @@ lint-go-windows:
@GOOS= GOARCH= $(GO) install $(GOLANGCI_LINT_PACKAGE) @GOOS= GOARCH= $(GO) install $(GOLANGCI_LINT_PACKAGE)
golangci-lint run golangci-lint run
.PHONY: lint-go-gitea-vet
lint-go-gitea-vet: ## lint go files with gitea-vet
@echo "Running gitea-vet..."
@$(GO) vet -vettool="$(shell GOOS= GOARCH= go tool -n gitea-vet)" ./...
.PHONY: lint-editorconfig .PHONY: lint-editorconfig
lint-editorconfig: lint-editorconfig:
@echo "Running editorconfig check..." @echo "Running editorconfig check..."
@@ -730,7 +724,6 @@ deps-backend: ## install backend dependencies
deps-tools: ## install tool dependencies deps-tools: ## install tool dependencies
$(GO) install $(AIR_PACKAGE) & \ $(GO) install $(AIR_PACKAGE) & \
$(GO) install $(EDITORCONFIG_CHECKER_PACKAGE) & \ $(GO) install $(EDITORCONFIG_CHECKER_PACKAGE) & \
$(GO) install $(GOFUMPT_PACKAGE) & \
$(GO) install $(GOLANGCI_LINT_PACKAGE) & \ $(GO) install $(GOLANGCI_LINT_PACKAGE) & \
$(GO) install $(GXZ_PACKAGE) & \ $(GO) install $(GXZ_PACKAGE) & \
$(GO) install $(MISSPELL_PACKAGE) & \ $(GO) install $(MISSPELL_PACKAGE) & \

View File

@@ -19,6 +19,7 @@ import (
// regexp is based on go-license, excluding README and NOTICE // regexp is based on go-license, excluding README and NOTICE
// https://github.com/google/go-licenses/blob/master/licenses/find.go // https://github.com/google/go-licenses/blob/master/licenses/find.go
// also defined in vite.config.ts
var licenseRe = regexp.MustCompile(`^(?i)((UN)?LICEN(S|C)E|COPYING).*$`) var licenseRe = regexp.MustCompile(`^(?i)((UN)?LICEN(S|C)E|COPYING).*$`)
// primaryLicenseRe matches exact primary license filenames without suffixes. // primaryLicenseRe matches exact primary license filenames without suffixes.

View File

@@ -4,6 +4,7 @@
package cmd package cmd
import ( import (
"io"
"testing" "testing"
"code.gitea.io/gitea/models/db" "code.gitea.io/gitea/models/db"
@@ -82,7 +83,9 @@ func TestChangePasswordCommand(t *testing.T) {
for _, tc := range testCases { for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) { t.Run(tc.name, func(t *testing.T) {
err := microcmdUserChangePassword().Run(ctx, tc.args) cmd := microcmdUserChangePassword()
cmd.Writer, cmd.ErrWriter = io.Discard, io.Discard
err := cmd.Run(ctx, tc.args)
require.Error(t, err) require.Error(t, err)
require.Contains(t, err.Error(), tc.expectedErr) require.Contains(t, err.Error(), tc.expectedErr)
}) })

View File

@@ -4,6 +4,7 @@
package cmd package cmd
import ( import (
"io"
"path/filepath" "path/filepath"
"testing" "testing"
@@ -107,6 +108,7 @@ func TestCertCommandFailures(t *testing.T) {
for _, c := range cases { for _, c := range cases {
t.Run(c.name, func(t *testing.T) { t.Run(c.name, func(t *testing.T) {
app := cmdCert() app := cmdCert()
app.Writer, app.ErrWriter = io.Discard, io.Discard
tempDir := t.TempDir() tempDir := t.TempDir()
certFile := filepath.Join(tempDir, "cert.pem") certFile := filepath.Join(tempDir, "cert.pem")

View File

@@ -1,38 +0,0 @@
// Copyright 2025 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package cmd
import (
"context"
"testing"
"github.com/stretchr/testify/assert"
"github.com/urfave/cli/v3"
)
func TestDefaultCommand(t *testing.T) {
test := func(t *testing.T, args []string, expectedRetName string, expectedRetValid bool) {
called := false
cmd := &cli.Command{
DefaultCommand: "test",
Commands: []*cli.Command{
{
Name: "test",
Action: func(ctx context.Context, command *cli.Command) error {
retName, retValid := isValidDefaultSubCommand(command)
assert.Equal(t, expectedRetName, retName)
assert.Equal(t, expectedRetValid, retValid)
called = true
return nil
},
},
},
}
assert.NoError(t, cmd.Run(t.Context(), args))
assert.True(t, called)
}
test(t, []string{"./gitea"}, "", true)
test(t, []string{"./gitea", "test"}, "", true)
test(t, []string{"./gitea", "other"}, "other", false)
}

237
cmd/cmdtest/cmd_test.go Normal file
View File

@@ -0,0 +1,237 @@
// Copyright 2026 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
// Tests here reload the config system multiple times with uncontrollable details.
// So they must be in a separate package, to avoid affecting other tests
package cmdtest
import (
"context"
"errors"
"fmt"
"io"
"path/filepath"
"strings"
"testing"
"code.gitea.io/gitea/cmd"
"code.gitea.io/gitea/models/unittest"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/test"
"code.gitea.io/gitea/modules/util"
"github.com/stretchr/testify/assert"
"github.com/urfave/cli/v3"
)
func TestMain(m *testing.M) {
unittest.MainTest(m)
}
func makePathOutput(workPath, customPath, customConf string) string {
return fmt.Sprintf("WorkPath=%s\nCustomPath=%s\nCustomConf=%s", workPath, customPath, customConf)
}
func newTestApp(testCmd cli.Command) *cli.Command {
app := cmd.NewMainApp(cmd.AppVersion{})
testCmd.Name = util.IfZero(testCmd.Name, "test-cmd")
cmd.PrepareSubcommandWithGlobalFlags(&testCmd)
app.Commands = append(app.Commands, &testCmd)
app.DefaultCommand = testCmd.Name
return app
}
type runResult struct {
Stdout string
Stderr string
ExitCode int
}
func runTestApp(app *cli.Command, args ...string) (runResult, error) {
outBuf := new(strings.Builder)
errBuf := new(strings.Builder)
app.Writer = outBuf
app.ErrWriter = errBuf
exitCode := -1
defer test.MockVariableValue(&cli.ErrWriter, app.ErrWriter)()
defer test.MockVariableValue(&cli.OsExiter, func(code int) {
if exitCode == -1 {
exitCode = code // save the exit code once and then reset the writer (to simulate the exit)
app.Writer, app.ErrWriter, cli.ErrWriter = io.Discard, io.Discard, io.Discard
}
})()
err := cmd.RunMainApp(app, args...)
return runResult{outBuf.String(), errBuf.String(), exitCode}, err
}
func TestCliCmd(t *testing.T) {
defaultWorkPath := filepath.FromSlash("/tmp/mocked-work-path")
defaultCustomPath := filepath.Join(defaultWorkPath, "custom")
defaultCustomConf := filepath.Join(defaultCustomPath, "conf/app.ini")
defer setting.MockBuiltinPaths(defaultWorkPath, "", "")()
cli.CommandHelpTemplate = "(command help template)"
cli.RootCommandHelpTemplate = "(app help template)"
cli.SubcommandHelpTemplate = "(subcommand help template)"
cases := []struct {
env map[string]string
cmd string
exp string
}{
// help commands
{
cmd: "./gitea -h",
exp: "DEFAULT CONFIGURATION:",
},
{
cmd: "./gitea help",
exp: "DEFAULT CONFIGURATION:",
},
{
cmd: "./gitea -c /dev/null -h",
exp: "ConfigFile: /dev/null",
},
{
cmd: "./gitea -c /dev/null help",
exp: "ConfigFile: /dev/null",
},
{
cmd: "./gitea help -c /dev/null",
exp: "ConfigFile: /dev/null",
},
{
cmd: "./gitea -c /dev/null test-cmd -h",
exp: "ConfigFile: /dev/null",
},
{
cmd: "./gitea test-cmd -c /dev/null -h",
exp: "ConfigFile: /dev/null",
},
{
cmd: "./gitea test-cmd -h -c /dev/null",
exp: "ConfigFile: /dev/null",
},
{
cmd: "./gitea -c /dev/null test-cmd help",
exp: "ConfigFile: /dev/null",
},
{
cmd: "./gitea test-cmd -c /dev/null help",
exp: "ConfigFile: /dev/null",
},
{
cmd: "./gitea test-cmd help -c /dev/null",
exp: "ConfigFile: /dev/null",
},
// parse paths
{
cmd: "./gitea test-cmd",
exp: makePathOutput(defaultWorkPath, defaultCustomPath, defaultCustomConf),
},
{
cmd: "./gitea -c /tmp/app.ini test-cmd",
exp: makePathOutput(defaultWorkPath, defaultCustomPath, "/tmp/app.ini"),
},
{
cmd: "./gitea test-cmd -c /tmp/app.ini",
exp: makePathOutput(defaultWorkPath, defaultCustomPath, "/tmp/app.ini"),
},
{
env: map[string]string{"GITEA_WORK_DIR": "/tmp"},
cmd: "./gitea test-cmd",
exp: makePathOutput("/tmp", "/tmp/custom", "/tmp/custom/conf/app.ini"),
},
{
env: map[string]string{"GITEA_WORK_DIR": "/tmp"},
cmd: "./gitea test-cmd --work-path /tmp/other",
exp: makePathOutput("/tmp/other", "/tmp/other/custom", "/tmp/other/custom/conf/app.ini"),
},
{
env: map[string]string{"GITEA_WORK_DIR": "/tmp"},
cmd: "./gitea test-cmd --config /tmp/app-other.ini",
exp: makePathOutput("/tmp", "/tmp/custom", "/tmp/app-other.ini"),
},
}
for _, c := range cases {
t.Run(c.cmd, func(t *testing.T) {
app := newTestApp(cli.Command{
Action: func(ctx context.Context, cmd *cli.Command) error {
_, _ = fmt.Fprint(cmd.Root().Writer, makePathOutput(setting.AppWorkPath, setting.CustomPath, setting.CustomConf))
return nil
},
})
for k, v := range c.env {
t.Setenv(k, v)
}
args := strings.Split(c.cmd, " ") // for test only, "split" is good enough
r, err := runTestApp(app, args...)
assert.NoError(t, err, c.cmd)
assert.NotEmpty(t, c.exp, c.cmd)
if !assert.Contains(t, r.Stdout, c.exp, c.cmd) {
t.Log("Full output:\n" + r.Stdout)
t.Log("Expected:\n" + c.exp)
}
})
}
}
func TestCliCmdError(t *testing.T) {
app := newTestApp(cli.Command{Action: func(ctx context.Context, cmd *cli.Command) error { return errors.New("normal error") }})
r, err := runTestApp(app, "./gitea", "test-cmd")
assert.Error(t, err)
assert.Equal(t, 1, r.ExitCode)
assert.Empty(t, r.Stdout)
assert.Equal(t, "Command error: normal error\n", r.Stderr)
app = newTestApp(cli.Command{Action: func(ctx context.Context, cmd *cli.Command) error { return cli.Exit("exit error", 2) }})
r, err = runTestApp(app, "./gitea", "test-cmd")
assert.Error(t, err)
assert.Equal(t, 2, r.ExitCode)
assert.Empty(t, r.Stdout)
assert.Equal(t, "exit error\n", r.Stderr)
app = newTestApp(cli.Command{Action: func(ctx context.Context, cmd *cli.Command) error { return nil }})
r, err = runTestApp(app, "./gitea", "test-cmd", "--no-such")
assert.Error(t, err)
assert.Equal(t, 1, r.ExitCode)
assert.Empty(t, r.Stdout)
assert.Equal(t, "Incorrect Usage: flag provided but not defined: -no-such\n\n", r.Stderr)
app = newTestApp(cli.Command{Action: func(ctx context.Context, cmd *cli.Command) error { return nil }})
r, err = runTestApp(app, "./gitea", "test-cmd")
assert.NoError(t, err)
assert.Equal(t, -1, r.ExitCode) // the cli.OsExiter is not called
assert.Empty(t, r.Stdout)
assert.Empty(t, r.Stderr)
}
func TestCliCmdBefore(t *testing.T) {
ctxNew := context.WithValue(context.Background(), any("key"), "value")
configValues := map[string]string{}
setting.CustomConf = "/tmp/any.ini"
var actionCtx context.Context
app := newTestApp(cli.Command{
Before: func(context.Context, *cli.Command) (context.Context, error) {
configValues["before"] = setting.CustomConf
return ctxNew, nil
},
Action: func(ctx context.Context, cmd *cli.Command) error {
configValues["action"] = setting.CustomConf
actionCtx = ctx
return nil
},
})
_, err := runTestApp(app, "./gitea", "--config", "/dev/null", "test-cmd")
assert.NoError(t, err)
assert.Equal(t, ctxNew, actionCtx)
assert.Equal(t, "/tmp/any.ini", configValues["before"], "BeforeFunc must be called before preparing config")
assert.Equal(t, "/dev/null", configValues["action"])
}

View File

@@ -124,7 +124,7 @@ func PrepareConsoleLoggerLevel(defaultLevel log.Level) func(context.Context, *cl
if setting.InstallLock { if setting.InstallLock {
// During config loading, there might also be logs (for example: deprecation warnings). // During config loading, there might also be logs (for example: deprecation warnings).
// It must make sure that console logger is set up before config is loaded. // It must make sure that console logger is set up before config is loaded.
log.Error("Config is loaded before console logger is setup, it will cause bugs. Please fix it.") log.Error("Config is loaded before console logger is setup, it will cause bugs. Please fix it. CustomConf=%s", setting.CustomConf)
return nil, errors.New("console logger must be setup before config is loaded") return nil, errors.New("console logger must be setup before config is loaded")
} }
level := defaultLevel level := defaultLevel

View File

@@ -48,7 +48,7 @@ DEFAULT CONFIGURATION:
} }
} }
func prepareSubcommandWithGlobalFlags(originCmd *cli.Command) { func PrepareSubcommandWithGlobalFlags(originCmd *cli.Command) {
originBefore := originCmd.Before originBefore := originCmd.Before
originCmd.Before = func(ctxOrig context.Context, cmd *cli.Command) (ctx context.Context, err error) { originCmd.Before = func(ctxOrig context.Context, cmd *cli.Command) (ctx context.Context, err error) {
ctx = ctxOrig ctx = ctxOrig
@@ -145,7 +145,7 @@ func NewMainApp(appVer AppVersion) *cli.Command {
app.Before = PrepareConsoleLoggerLevel(log.INFO) app.Before = PrepareConsoleLoggerLevel(log.INFO)
for i := range subCmdWithConfig { for i := range subCmdWithConfig {
prepareSubcommandWithGlobalFlags(subCmdWithConfig[i]) PrepareSubcommandWithGlobalFlags(subCmdWithConfig[i])
} }
app.Commands = append(app.Commands, subCmdWithConfig...) app.Commands = append(app.Commands, subCmdWithConfig...)
app.Commands = append(app.Commands, subCmdStandalone...) app.Commands = append(app.Commands, subCmdStandalone...)

View File

@@ -5,17 +5,9 @@ package cmd
import ( import (
"context" "context"
"errors"
"fmt"
"io"
"path/filepath"
"strings"
"testing" "testing"
"code.gitea.io/gitea/models/unittest" "code.gitea.io/gitea/models/unittest"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/test"
"code.gitea.io/gitea/modules/util"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/urfave/cli/v3" "github.com/urfave/cli/v3"
@@ -25,209 +17,28 @@ func TestMain(m *testing.M) {
unittest.MainTest(m) unittest.MainTest(m)
} }
func makePathOutput(workPath, customPath, customConf string) string { func TestDefaultCommand(t *testing.T) {
return fmt.Sprintf("WorkPath=%s\nCustomPath=%s\nCustomConf=%s", workPath, customPath, customConf) test := func(t *testing.T, args []string, expectedRetName string, expectedRetValid bool) {
} called := false
cmd := &cli.Command{
func newTestApp(testCmd cli.Command) *cli.Command { DefaultCommand: "test",
app := NewMainApp(AppVersion{}) Commands: []*cli.Command{
testCmd.Name = util.IfZero(testCmd.Name, "test-cmd") {
prepareSubcommandWithGlobalFlags(&testCmd) Name: "test",
app.Commands = append(app.Commands, &testCmd) Action: func(ctx context.Context, command *cli.Command) error {
app.DefaultCommand = testCmd.Name retName, retValid := isValidDefaultSubCommand(command)
return app assert.Equal(t, expectedRetName, retName)
} assert.Equal(t, expectedRetValid, retValid)
called = true
type runResult struct { return nil
Stdout string },
Stderr string
ExitCode int
}
func runTestApp(app *cli.Command, args ...string) (runResult, error) {
outBuf := new(strings.Builder)
errBuf := new(strings.Builder)
app.Writer = outBuf
app.ErrWriter = errBuf
exitCode := -1
defer test.MockVariableValue(&cli.ErrWriter, app.ErrWriter)()
defer test.MockVariableValue(&cli.OsExiter, func(code int) {
if exitCode == -1 {
exitCode = code // save the exit code once and then reset the writer (to simulate the exit)
app.Writer, app.ErrWriter, cli.ErrWriter = io.Discard, io.Discard, io.Discard
}
})()
err := RunMainApp(app, args...)
return runResult{outBuf.String(), errBuf.String(), exitCode}, err
}
func TestCliCmd(t *testing.T) {
defaultWorkPath := filepath.Dir(setting.AppPath)
defaultCustomPath := filepath.Join(defaultWorkPath, "custom")
defaultCustomConf := filepath.Join(defaultCustomPath, "conf/app.ini")
cli.CommandHelpTemplate = "(command help template)"
cli.RootCommandHelpTemplate = "(app help template)"
cli.SubcommandHelpTemplate = "(subcommand help template)"
cases := []struct {
env map[string]string
cmd string
exp string
}{
// help commands
{
cmd: "./gitea -h",
exp: "DEFAULT CONFIGURATION:",
},
{
cmd: "./gitea help",
exp: "DEFAULT CONFIGURATION:",
},
{
cmd: "./gitea -c /dev/null -h",
exp: "ConfigFile: /dev/null",
},
{
cmd: "./gitea -c /dev/null help",
exp: "ConfigFile: /dev/null",
},
{
cmd: "./gitea help -c /dev/null",
exp: "ConfigFile: /dev/null",
},
{
cmd: "./gitea -c /dev/null test-cmd -h",
exp: "ConfigFile: /dev/null",
},
{
cmd: "./gitea test-cmd -c /dev/null -h",
exp: "ConfigFile: /dev/null",
},
{
cmd: "./gitea test-cmd -h -c /dev/null",
exp: "ConfigFile: /dev/null",
},
{
cmd: "./gitea -c /dev/null test-cmd help",
exp: "ConfigFile: /dev/null",
},
{
cmd: "./gitea test-cmd -c /dev/null help",
exp: "ConfigFile: /dev/null",
},
{
cmd: "./gitea test-cmd help -c /dev/null",
exp: "ConfigFile: /dev/null",
},
// parse paths
{
cmd: "./gitea test-cmd",
exp: makePathOutput(defaultWorkPath, defaultCustomPath, defaultCustomConf),
},
{
cmd: "./gitea -c /tmp/app.ini test-cmd",
exp: makePathOutput(defaultWorkPath, defaultCustomPath, "/tmp/app.ini"),
},
{
cmd: "./gitea test-cmd -c /tmp/app.ini",
exp: makePathOutput(defaultWorkPath, defaultCustomPath, "/tmp/app.ini"),
},
{
env: map[string]string{"GITEA_WORK_DIR": "/tmp"},
cmd: "./gitea test-cmd",
exp: makePathOutput("/tmp", "/tmp/custom", "/tmp/custom/conf/app.ini"),
},
{
env: map[string]string{"GITEA_WORK_DIR": "/tmp"},
cmd: "./gitea test-cmd --work-path /tmp/other",
exp: makePathOutput("/tmp/other", "/tmp/other/custom", "/tmp/other/custom/conf/app.ini"),
},
{
env: map[string]string{"GITEA_WORK_DIR": "/tmp"},
cmd: "./gitea test-cmd --config /tmp/app-other.ini",
exp: makePathOutput("/tmp", "/tmp/custom", "/tmp/app-other.ini"),
},
}
for _, c := range cases {
t.Run(c.cmd, func(t *testing.T) {
defer test.MockVariableValue(&setting.InstallLock, false)()
app := newTestApp(cli.Command{
Action: func(ctx context.Context, cmd *cli.Command) error {
_, _ = fmt.Fprint(cmd.Root().Writer, makePathOutput(setting.AppWorkPath, setting.CustomPath, setting.CustomConf))
return nil
}, },
}) },
for k, v := range c.env { }
t.Setenv(k, v) assert.NoError(t, cmd.Run(t.Context(), args))
} assert.True(t, called)
args := strings.Split(c.cmd, " ") // for test only, "split" is good enough
r, err := runTestApp(app, args...)
assert.NoError(t, err, c.cmd)
assert.NotEmpty(t, c.exp, c.cmd)
if !assert.Contains(t, r.Stdout, c.exp, c.cmd) {
t.Log("Full output:\n" + r.Stdout)
t.Log("Expected:\n" + c.exp)
}
})
} }
} test(t, []string{"./gitea"}, "", true)
test(t, []string{"./gitea", "test"}, "", true)
func TestCliCmdError(t *testing.T) { test(t, []string{"./gitea", "other"}, "other", false)
app := newTestApp(cli.Command{Action: func(ctx context.Context, cmd *cli.Command) error { return errors.New("normal error") }})
r, err := runTestApp(app, "./gitea", "test-cmd")
assert.Error(t, err)
assert.Equal(t, 1, r.ExitCode)
assert.Empty(t, r.Stdout)
assert.Equal(t, "Command error: normal error\n", r.Stderr)
app = newTestApp(cli.Command{Action: func(ctx context.Context, cmd *cli.Command) error { return cli.Exit("exit error", 2) }})
r, err = runTestApp(app, "./gitea", "test-cmd")
assert.Error(t, err)
assert.Equal(t, 2, r.ExitCode)
assert.Empty(t, r.Stdout)
assert.Equal(t, "exit error\n", r.Stderr)
app = newTestApp(cli.Command{Action: func(ctx context.Context, cmd *cli.Command) error { return nil }})
r, err = runTestApp(app, "./gitea", "test-cmd", "--no-such")
assert.Error(t, err)
assert.Equal(t, 1, r.ExitCode)
assert.Empty(t, r.Stdout)
assert.Equal(t, "Incorrect Usage: flag provided but not defined: -no-such\n\n", r.Stderr)
app = newTestApp(cli.Command{Action: func(ctx context.Context, cmd *cli.Command) error { return nil }})
r, err = runTestApp(app, "./gitea", "test-cmd")
assert.NoError(t, err)
assert.Equal(t, -1, r.ExitCode) // the cli.OsExiter is not called
assert.Empty(t, r.Stdout)
assert.Empty(t, r.Stderr)
}
func TestCliCmdBefore(t *testing.T) {
ctxNew := context.WithValue(context.Background(), any("key"), "value")
configValues := map[string]string{}
setting.CustomConf = "/tmp/any.ini"
var actionCtx context.Context
app := newTestApp(cli.Command{
Before: func(context.Context, *cli.Command) (context.Context, error) {
configValues["before"] = setting.CustomConf
return ctxNew, nil
},
Action: func(ctx context.Context, cmd *cli.Command) error {
configValues["action"] = setting.CustomConf
actionCtx = ctx
return nil
},
})
_, err := runTestApp(app, "./gitea", "--config", "/dev/null", "test-cmd")
assert.NoError(t, err)
assert.Equal(t, ctxNew, actionCtx)
assert.Equal(t, "/tmp/any.ini", configValues["before"], "BeforeFunc must be called before preparing config")
assert.Equal(t, "/dev/null", configValues["action"])
} }

View File

@@ -41,10 +41,10 @@
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; ;;
;; App name that shows in every page title ;; App name that shows in every page title
APP_NAME = ; Gitea: Git with a cup of tea ;APP_NAME = Gitea: Git with a cup of tea
;; ;;
;; RUN_USER will automatically detect the current user - but you can set it here change it if you run locally ;; RUN_USER will automatically detect the current user - but you can set it here change it if you run locally
RUN_USER = ; git ;RUN_USER =
;; ;;
;; Application run mode, affects performance and debugging: "dev" or "prod", default is "prod" ;; Application run mode, affects performance and debugging: "dev" or "prod", default is "prod"
;; Mode "dev" makes Gitea easier to develop and debug, values other than "dev" are treated as "prod" which is for production use. ;; Mode "dev" makes Gitea easier to develop and debug, values other than "dev" are treated as "prod" which is for production use.
@@ -461,6 +461,11 @@ INTERNAL_TOKEN =
;; Name of cookie used to store authentication information. ;; Name of cookie used to store authentication information.
;COOKIE_REMEMBER_NAME = gitea_incredible ;COOKIE_REMEMBER_NAME = gitea_incredible
;; ;;
;; URL or path that Gitea should redirect users to *after* performing its own logout.
;; Use this, if needed, when authentication is handled by a reverse proxy or SSO.
;; For example: "/my-sso/logout?return=/my-sso/home"
;REVERSE_PROXY_LOGOUT_REDIRECT =
;;
;; Reverse proxy authentication header name of user name, email, and full name ;; Reverse proxy authentication header name of user name, email, and full name
;REVERSE_PROXY_AUTHENTICATION_USER = X-WEBAUTH-USER ;REVERSE_PROXY_AUTHENTICATION_USER = X-WEBAUTH-USER
;REVERSE_PROXY_AUTHENTICATION_EMAIL = X-WEBAUTH-EMAIL ;REVERSE_PROXY_AUTHENTICATION_EMAIL = X-WEBAUTH-EMAIL
@@ -520,8 +525,11 @@ INTERNAL_TOKEN =
;; Set to "enforced", to force users to enroll into Two-Factor Authentication, users without 2FA have no access to repositories via API or web. ;; Set to "enforced", to force users to enroll into Two-Factor Authentication, users without 2FA have no access to repositories via API or web.
;TWO_FACTOR_AUTH = ;TWO_FACTOR_AUTH =
;; ;;
;; The value of the X-Frame-Options HTTP header for HTML responses. Use "unset" to remove the header. ;; The value of the X-Frame-Options HTTP header for all responses. Use "unset" to remove the header.
;X_FRAME_OPTIONS = SAMEORIGIN ;X_FRAME_OPTIONS = SAMEORIGIN
;;
;; The value of the X-Content-Type-Options HTTP header for all responses. Use "unset" to remove the header.
;X_CONTENT_TYPE_OPTIONS = nosniff
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
@@ -587,6 +595,11 @@ ENABLED = true
;; * https://github.com/git-ecosystem/git-credential-manager ;; * https://github.com/git-ecosystem/git-credential-manager
;; * https://gitea.com/gitea/tea ;; * https://gitea.com/gitea/tea
;DEFAULT_APPLICATIONS = git-credential-oauth, git-credential-manager, tea ;DEFAULT_APPLICATIONS = git-credential-oauth, git-credential-manager, tea
;;
;; By default, OAuth2 applications can only use "http" and "https" as their redirect URI schemes.
;; If you need to use other schemes (e.g. for desktop applications), you can specify them here as a comma-separated list.
;; For example: set "my-scheme, com.example.app" to support "my-scheme://..." and "com.example.app://..." redirect URIs.
;CUSTOM_SCHEMES =
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
@@ -2963,6 +2976,8 @@ LEVEL = Info
;; Comma-separated list of workflow directories, the first one to exist ;; Comma-separated list of workflow directories, the first one to exist
;; in a repo is used to find Actions workflow files ;; in a repo is used to find Actions workflow files
;WORKFLOW_DIRS = .gitea/workflows,.github/workflows ;WORKFLOW_DIRS = .gitea/workflows,.github/workflows
;; Maximum number of attempts a single workflow run can have. Default value is 50.
;MAX_RERUN_ATTEMPTS = 50
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

View File

@@ -0,0 +1,198 @@
# Community governance and review process
This document describes maintainer expectations, project governance, and the detailed pull request review workflow (labels, merge queue, commit message format for mergers). For what contributors should do when opening and updating a PR, see [CONTRIBUTING.md](../CONTRIBUTING.md).
## Code review
### Milestone
A PR should only be assigned to a milestone if it will likely be merged into the given version. \
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/…` / `lgtm/…`: 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 `lgtm/need 2`
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
### Reviewing PRs
Maintainers are encouraged to review pull requests in areas where they have expertise or particular interest.
#### For reviewers
- **Verification**: Verify that the PR accurately reflects the changes, and verify that the tests and documentation are complete and aligned with the implementation.
- **Actionable feedback**: Say what should change and why, and distinguish required changes from optional suggestions.
- **Feedback**: Focus feedback on the issue itself and avoid comments about the contributor's abilities.
- **Request changes**: If you request changes (i.e., block a PR), give a clear rationale and, whenever possible, a concrete path to resolution.
- **Approval**: Only approve a PR when you are fully satisfied with its current state - "rubber-stamp" approvals need to be highlighted as such.
### Getting PRs merged
Changes to Gitea must be reviewed before they are accepted, including changes from owners and maintainers. The exception is critical bugs that prevent Gitea from compiling or starting.
We require two maintainer approvals for every PR. When that is satisfied, your PR gets the `lgtm/done` label. After that, you mainly fix merge conflicts and respond to or implement maintainer requests; maintainers drive getting the PR merged.
If a PR has `lgtm/done`, no open discussions, and no merge conflicts, any maintainer may add `reviewed/wait-merge`. That puts the PR in the merge queue. PRs are merged from the queue in the order of this list:
<https://github.com/go-gitea/gitea/pulls?q=is%3Apr+label%3Areviewed%2Fwait-merge+sort%3Acreated-asc+is%3Aopen>
Gitea uses its own tool, <https://github.com/GiteaBot/gitea-backporter>, to automate parts of the review process. The backporter:
- Creates a backport PR when needed after the initial PR merges.
- Removes the PR from the merge queue after it merges.
- Keeps the oldest branch in the merge queue up to date with merges.
### 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 required to rewrite the PR title and the first comment (the summary) when necessary so the squash commit message is clear.
The final commit message should not hedge: replace phrases like `hopefully, <x> won't happen anymore` with definite wording.
#### PR Co-authors
A person counts as a PR co-author once they (co-)authored a commit that is not simply a `Merge base branch into branch` commit. Mergers must remove such false-positive co-authors when writing the squash message. Every true co-author must remain in the commit message.
#### PRs targeting `main`
The commit message of PRs targeting `main` is always
```bash
$PR_TITLE ($PR_INDEX)
$REWRITTEN_PR_SUMMARY
```
#### Backport PRs
The commit message of backport PRs is always
```bash
$PR_TITLE ($INITIAL_PR_INDEX) ($BACKPORT_PR_INDEX)
$REWRITTEN_PR_SUMMARY
```
## Maintainers
We list [maintainers](../MAINTAINERS) so every PR gets proper review.
#### Review expectations
Every PR **must** be reviewed by at least two maintainers (or owners) before merge. **Exception:** after one week, refactoring PRs and documentation-only PRs need only one maintainer approval.
Maintainers are expected to spend time on code reviews.
#### Becoming a maintainer
A maintainer should already be a Gitea contributor with at least four merged PRs. To apply, use the [Discord](https://discord.gg/Gitea) `#develop` channel. Maintainer teams may also invite contributors.
#### Stepping down, advisors, and inactivity
If you cannot keep reviewing, apply to leave the maintainers team. You can join the [advisors team](https://github.com/orgs/go-gitea/teams/advisors); advisors who want to review again are welcome back as maintainers.
If a maintainer is inactive for more than three months and has not left the team, owners may move them to the advisors team.
#### Account security
For security, maintainers should enable 2FA and sign commits with GPG when possible:
- [Two-factor authentication](https://docs.github.com/en/authentication/securing-your-account-with-two-factor-authentication-2fa/configuring-two-factor-authentication)
- [Signing commits with GPG](https://docs.github.com/en/authentication/managing-commit-signature-verification/signing-commits)
Any account with write access (including bots and TOC members) **must** use [2FA](https://docs.github.com/en/authentication/securing-your-account-with-two-factor-authentication-2fa/configuring-two-factor-authentication).
## Technical Oversight Committee (TOC)
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.
### Current TOC members
- 2024-01-01 ~ 2024-12-31
- Company
- [Jason Song](https://gitea.com/wolfogre) <i@wolfogre.com>
- [Lunny Xiao](https://gitea.com/lunny) <xiaolunwen@gmail.com>
- [Matti Ranta](https://gitea.com/techknowlogick) <techknowlogick@gitea.com>
- Community
- [6543](https://gitea.com/6543) <6543@obermui.de>
- [delvh](https://gitea.com/delvh) <dev.lh@web.de>
- [John Olheiser](https://gitea.com/jolheiser) <john.olheiser@gmail.com>
### Previous TOC/owners members
Here's the history of the owners and the time they served:
- [Lunny Xiao](https://gitea.com/lunny) - 2016, 2017, [2018](https://github.com/go-gitea/gitea/issues/3255), [2019](https://github.com/go-gitea/gitea/issues/5572), [2020](https://github.com/go-gitea/gitea/issues/9230), [2021](https://github.com/go-gitea/gitea/issues/13801), [2022](https://github.com/go-gitea/gitea/issues/17872), 2023
- [Kim Carlbäcker](https://github.com/bkcsoft) - 2016, 2017
- [Thomas Boerger](https://gitea.com/tboerger) - 2016, 2017
- [Lauris Bukšis-Haberkorns](https://gitea.com/lafriks) - [2018](https://github.com/go-gitea/gitea/issues/3255), [2019](https://github.com/go-gitea/gitea/issues/5572), [2020](https://github.com/go-gitea/gitea/issues/9230), [2021](https://github.com/go-gitea/gitea/issues/13801)
- [Matti Ranta](https://gitea.com/techknowlogick) - [2019](https://github.com/go-gitea/gitea/issues/5572), [2020](https://github.com/go-gitea/gitea/issues/9230), [2021](https://github.com/go-gitea/gitea/issues/13801), [2022](https://github.com/go-gitea/gitea/issues/17872), 2023
- [Andrew Thornton](https://gitea.com/zeripath) - [2020](https://github.com/go-gitea/gitea/issues/9230), [2021](https://github.com/go-gitea/gitea/issues/13801), [2022](https://github.com/go-gitea/gitea/issues/17872), 2023
- [6543](https://gitea.com/6543) - 2023
- [John Olheiser](https://gitea.com/jolheiser) - 2023
- [Jason Song](https://gitea.com/wolfogre) - 2023
## Governance Compensation
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.

58
docs/guideline-backend.md Normal file
View File

@@ -0,0 +1,58 @@
# Backend development
This document covers backend-specific contribution expectations. For general contribution workflow, see [CONTRIBUTING.md](../CONTRIBUTING.md).
For coding style and architecture, see also the [backend development guideline](https://docs.gitea.com/contributing/guidelines-backend) on the documentation site.
## Dependencies
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.
## 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))

View File

@@ -0,0 +1,17 @@
# Frontend development
This document covers frontend-specific contribution expectations. For general contribution workflow, see [CONTRIBUTING.md](../CONTRIBUTING.md).
## Dependencies
For the frontend, we use [npm](https://www.npmjs.com/).
The same restrictions apply for frontend dependencies as for [backend dependencies](guideline-backend.md#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)
- [refactoring guideline](https://docs.gitea.com/contributing/guidelines-refactoring)

115
docs/release-management.md Normal file
View File

@@ -0,0 +1,115 @@
# Release management
This document describes the release cycle, backports, versioning, and the release manager checklist. For everyday contribution workflow, see [CONTRIBUTING.md](../CONTRIBUTING.md).
## 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.
## Release Cycle
We use a release schedule so work, stabilization, and releases stay predictable.
### Cadence
- Aim for a major release about every three or four months.
- Roughly two or three months of general development, then about one month of testing and polish called the **release freeze**.
- *Starting with v1.26 the release cycle will be more predictable and follow a more regular schedule.*
### Release schedule
We will try to publish a new major version every three months:
- v1.26.0 in April 2026
- v1.27.0 in June 2026
- v1.28.0 in September 2026
- v1.29.0 in December 2026
#### How is the release handled?
- The release manager will tag the release candidate (e.g. `v1.26.0-rc0`) and publish it for testing in the **first week of the release month**.
- If there are no major issues, the release manager will check with the other maintainers and then tag the final release (e.g. `v1.26.0`) in the **one or two weeks following the release candidate**.
### Feature freeze
- Merge feature PRs before the freeze when you can.
- Feature PRs still open at the freeze move to the next milestone. Watch Discord for the freeze announcement.
- During the freeze, a **release branch** takes fixes backported from `main`. Release candidates ship for testing; the final release for that line is maintained from that branch.
### Patch releases
During a cycle we may ship patch releases for an older line. For example, if the latest release is v1.2, we can still publish v1.1.1 after v1.1.0.
### End of life (EOL)
We support per standard the last major release. For example, if the latest release is v1.26, we support v1.26 and v1.25, but not v1.24 anymore. We will only publish security fixes for the last major release, so if you are using an older release, please upgrade to a supported release as soon as possible.
Also we always try to support the latest on main branch, so if you are using the latest on main, you should be fine.
## 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 MAJOR, MINOR and PATCH be Major, Minor and Patch version numbers, PATCH should be rc1, rc2, 0, 1, ...... MAJOR.MINOR 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 vMAJOR.MINOR.0-dev` and push the tag as `git push origin vMAJOR.MINOR.0-dev`.
- When CI has finished building tag then you have to create a new branch named `release/vMAJOR.MINOR`
- If it is bugfix version create PR for changelog on branch `release/vMAJOR.MINOR` and wait till it is reviewed and merged.
- Add a tag as `git tag -s -F release.notes vMAJOR.MINOR.PATCH`, 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 vMAJOR.MINOR.$`. 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`

View File

@@ -574,8 +574,6 @@ export default defineConfig([
'no-restricted-properties': [2, ...restrictedProperties], 'no-restricted-properties': [2, ...restrictedProperties],
'no-restricted-imports': [2, {paths: [ 'no-restricted-imports': [2, {paths: [
{name: 'jquery', message: 'Use the global $ instead', allowTypeImports: true}, {name: 'jquery', message: 'Use the global $ instead', allowTypeImports: true},
{name: 'htmx.org', message: 'Use the global htmx instead', allowTypeImports: true},
{name: 'idiomorph/htmx', message: 'Loaded in globals.ts', allowTypeImports: true},
]}], ]}],
'no-restricted-syntax': [2, 'WithStatement', 'ForInStatement', 'LabeledStatement', 'SequenceExpression'], 'no-restricted-syntax': [2, 'WithStatement', 'ForInStatement', 'LabeledStatement', 'SequenceExpression'],
'no-return-assign': [0], 'no-return-assign': [0],
@@ -926,6 +924,7 @@ export default defineConfig([
{ {
...playwright.configs['flat/recommended'], ...playwright.configs['flat/recommended'],
files: ['tests/e2e/**/*.test.ts'], files: ['tests/e2e/**/*.test.ts'],
languageOptions: {globals: {...globals.nodeBuiltin, ...globals.browser}},
rules: { rules: {
...playwright.configs['flat/recommended'].rules, ...playwright.configs['flat/recommended'].rules,
'playwright/expect-expect': [0], 'playwright/expect-expect': [0],
@@ -1022,6 +1021,6 @@ export default defineConfig([
}, },
{ {
files: ['web_src/**/*'], files: ['web_src/**/*'],
languageOptions: {globals: {...globals.browser, ...globals.jquery, htmx: false}}, languageOptions: {globals: {...globals.browser, ...globals.jquery}},
}, },
]); ]);

6
flake.lock generated
View File

@@ -2,11 +2,11 @@
"nodes": { "nodes": {
"nixpkgs": { "nixpkgs": {
"locked": { "locked": {
"lastModified": 1775036866, "lastModified": 1776877367,
"narHash": "sha256-ZojAnPuCdy657PbTq5V0Y+AHKhZAIwSIT2cb8UgAz/U=", "narHash": "sha256-EHq1/OX139R1RvBzOJ0aMRT3xnWyqtHBRUBuO1gFzjI=",
"owner": "nixos", "owner": "nixos",
"repo": "nixpkgs", "repo": "nixpkgs",
"rev": "6201e203d09599479a3b3450ed24fa81537ebc4e", "rev": "0726a0ecb6d4e08f6adced58726b95db924cef57",
"type": "github" "type": "github"
}, },
"original": { "original": {

59
go.mod
View File

@@ -1,6 +1,6 @@
module code.gitea.io/gitea module code.gitea.io/gitea
go 1.26.1 go 1.26.2
// rfc5280 said: "The serial number is an integer assigned by the CA to each certificate." // rfc5280 said: "The serial number is an integer assigned by the CA to each certificate."
// But some CAs use negative serial number, just relax the check. related: // But some CAs use negative serial number, just relax the check. related:
@@ -12,7 +12,7 @@ require (
code.gitea.io/sdk/gitea v0.24.1 code.gitea.io/sdk/gitea v0.24.1
codeberg.org/gusted/mcaptcha v0.0.0-20220723083913-4f3072e1d570 codeberg.org/gusted/mcaptcha v0.0.0-20220723083913-4f3072e1d570
connectrpc.com/connect v1.19.1 connectrpc.com/connect v1.19.1
gitea.com/go-chi/binding v0.0.0-20240430071103-39a851e106ed gitea.com/go-chi/binding v0.0.0-20260414111559-654cea7ac60a
gitea.com/go-chi/cache v0.2.1 gitea.com/go-chi/cache v0.2.1
gitea.com/go-chi/captcha v0.0.0-20240315150714-fb487f629098 gitea.com/go-chi/captcha v0.0.0-20240315150714-fb487f629098
gitea.com/go-chi/session v0.0.0-20251124165456-68e0254e989e gitea.com/go-chi/session v0.0.0-20251124165456-68e0254e989e
@@ -27,8 +27,8 @@ require (
github.com/PuerkitoBio/goquery v1.12.0 github.com/PuerkitoBio/goquery v1.12.0
github.com/SaveTheRbtz/zstd-seekable-format-go/pkg v0.8.0 github.com/SaveTheRbtz/zstd-seekable-format-go/pkg v0.8.0
github.com/alecthomas/chroma/v2 v2.23.1 github.com/alecthomas/chroma/v2 v2.23.1
github.com/aws/aws-sdk-go-v2/credentials v1.19.13 github.com/aws/aws-sdk-go-v2/credentials v1.19.15
github.com/aws/aws-sdk-go-v2/service/codecommit v1.33.12 github.com/aws/aws-sdk-go-v2/service/codecommit v1.33.13
github.com/blakesmith/ar v0.0.0-20190502131153-809d4375e1fb github.com/blakesmith/ar v0.0.0-20190502131153-809d4375e1fb
github.com/blevesearch/bleve/v2 v2.5.7 github.com/blevesearch/bleve/v2 v2.5.7
github.com/bohde/codel v0.2.0 github.com/bohde/codel v0.2.0
@@ -37,7 +37,7 @@ require (
github.com/charmbracelet/git-lfs-transfer v0.1.1-0.20251013092601-6327009efd21 github.com/charmbracelet/git-lfs-transfer v0.1.1-0.20251013092601-6327009efd21
github.com/chi-middleware/proxy v1.1.1 github.com/chi-middleware/proxy v1.1.1
github.com/dimiro1/reply v0.0.0-20200315094148-d0136a4c9e21 github.com/dimiro1/reply v0.0.0-20200315094148-d0136a4c9e21
github.com/dlclark/regexp2 v1.11.5 github.com/dlclark/regexp2 v1.12.0
github.com/dsnet/compress v0.0.2-0.20230904184137-39efe44ab707 github.com/dsnet/compress v0.0.2-0.20230904184137-39efe44ab707
github.com/dustin/go-humanize v1.0.1 github.com/dustin/go-humanize v1.0.1
github.com/editorconfig/editorconfig-core-go/v2 v2.6.4 github.com/editorconfig/editorconfig-core-go/v2 v2.6.4
@@ -49,21 +49,20 @@ require (
github.com/gliderlabs/ssh v0.3.8 github.com/gliderlabs/ssh v0.3.8
github.com/go-chi/chi/v5 v5.2.5 github.com/go-chi/chi/v5 v5.2.5
github.com/go-chi/cors v1.2.2 github.com/go-chi/cors v1.2.2
github.com/go-co-op/gocron/v2 v2.19.1 github.com/go-co-op/gocron/v2 v2.21.0
github.com/go-enry/go-enry/v2 v2.9.5 github.com/go-enry/go-enry/v2 v2.9.6
github.com/go-git/go-billy/v5 v5.8.0 github.com/go-git/go-billy/v5 v5.8.0
github.com/go-git/go-git/v5 v5.17.2 github.com/go-git/go-git/v5 v5.18.0
github.com/go-ldap/ldap/v3 v3.4.13 github.com/go-ldap/ldap/v3 v3.4.13
github.com/go-redsync/redsync/v4 v4.16.0 github.com/go-redsync/redsync/v4 v4.16.0
github.com/go-sql-driver/mysql v1.9.3 github.com/go-sql-driver/mysql v1.9.3
github.com/go-webauthn/webauthn v0.16.1 github.com/go-webauthn/webauthn v0.16.5
github.com/goccy/go-json v0.10.6
github.com/gogs/chardet v0.0.0-20211120154057-b7413eaefb8f github.com/gogs/chardet v0.0.0-20211120154057-b7413eaefb8f
github.com/gogs/go-gogs-client v0.0.0-20210131175652-1d7215cd8d85 github.com/gogs/go-gogs-client v0.0.0-20210131175652-1d7215cd8d85
github.com/golang-jwt/jwt/v5 v5.3.1 github.com/golang-jwt/jwt/v5 v5.3.1
github.com/google/go-github/v84 v84.0.0 github.com/google/go-github/v84 v84.0.0
github.com/google/licenseclassifier/v2 v2.0.0 github.com/google/licenseclassifier/v2 v2.0.0
github.com/google/pprof v0.0.0-20260302011040-a15ffb7f9dcc github.com/google/pprof v0.0.0-20260402051712-545e8a4df936
github.com/google/uuid v1.6.0 github.com/google/uuid v1.6.0
github.com/gorilla/feeds v1.2.0 github.com/gorilla/feeds v1.2.0
github.com/gorilla/sessions v1.4.0 github.com/gorilla/sessions v1.4.0
@@ -75,15 +74,15 @@ require (
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51
github.com/klauspost/compress v1.18.5 github.com/klauspost/compress v1.18.5
github.com/klauspost/cpuid/v2 v2.3.0 github.com/klauspost/cpuid/v2 v2.3.0
github.com/lib/pq v1.12.1 github.com/lib/pq v1.12.3
github.com/markbates/goth v1.82.0 github.com/markbates/goth v1.82.0
github.com/mattn/go-isatty v0.0.20 github.com/mattn/go-isatty v0.0.21
github.com/mattn/go-sqlite3 v1.14.38 github.com/mattn/go-sqlite3 v1.14.42
github.com/meilisearch/meilisearch-go v0.36.1 github.com/meilisearch/meilisearch-go v0.36.2
github.com/mholt/archives v0.1.5 github.com/mholt/archives v0.1.5
github.com/microcosm-cc/bluemonday v1.0.27 github.com/microcosm-cc/bluemonday v1.0.27
github.com/microsoft/go-mssqldb v1.9.6 github.com/microsoft/go-mssqldb v1.9.6
github.com/minio/minio-go/v7 v7.0.99 github.com/minio/minio-go/v7 v7.0.100
github.com/msteinert/pam/v2 v2.1.0 github.com/msteinert/pam/v2 v2.1.0
github.com/nektos/act v0.2.63 github.com/nektos/act v0.2.63
github.com/niklasfasching/go-org v1.9.1 github.com/niklasfasching/go-org v1.9.1
@@ -111,14 +110,14 @@ require (
github.com/yuin/goldmark-highlighting/v2 v2.0.0-20230729083705-37449abec8cc github.com/yuin/goldmark-highlighting/v2 v2.0.0-20230729083705-37449abec8cc
gitlab.com/gitlab-org/api/client-go v1.46.0 gitlab.com/gitlab-org/api/client-go v1.46.0
go.yaml.in/yaml/v4 v4.0.0-rc.3 go.yaml.in/yaml/v4 v4.0.0-rc.3
golang.org/x/crypto v0.49.0 golang.org/x/crypto v0.50.0
golang.org/x/image v0.38.0 golang.org/x/image v0.39.0
golang.org/x/net v0.52.0 golang.org/x/net v0.53.0
golang.org/x/oauth2 v0.36.0 golang.org/x/oauth2 v0.36.0
golang.org/x/sync v0.20.0 golang.org/x/sync v0.20.0
golang.org/x/sys v0.42.0 golang.org/x/sys v0.43.0
golang.org/x/text v0.35.0 golang.org/x/text v0.36.0
google.golang.org/grpc v1.79.3 google.golang.org/grpc v1.80.0
google.golang.org/protobuf v1.36.11 google.golang.org/protobuf v1.36.11
gopkg.in/ini.v1 v1.67.1 gopkg.in/ini.v1 v1.67.1
gopkg.in/yaml.v3 v3.0.1 gopkg.in/yaml.v3 v3.0.1
@@ -130,7 +129,6 @@ require (
require ( require (
cloud.google.com/go/compute/metadata v0.9.0 // indirect cloud.google.com/go/compute/metadata v0.9.0 // indirect
code.gitea.io/gitea-vet v0.2.3 // indirect
dario.cat/mergo v1.0.2 // indirect dario.cat/mergo v1.0.2 // indirect
filippo.io/edwards25519 v1.2.0 // indirect filippo.io/edwards25519 v1.2.0 // indirect
github.com/Azure/azure-sdk-for-go/sdk/internal v1.11.2 // indirect github.com/Azure/azure-sdk-for-go/sdk/internal v1.11.2 // indirect
@@ -141,10 +139,10 @@ require (
github.com/andybalholm/brotli v1.2.1 // indirect github.com/andybalholm/brotli v1.2.1 // indirect
github.com/andybalholm/cascadia v1.3.3 // indirect github.com/andybalholm/cascadia v1.3.3 // indirect
github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be // indirect github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be // indirect
github.com/aws/aws-sdk-go-v2 v1.41.5 // indirect github.com/aws/aws-sdk-go-v2 v1.41.6 // indirect
github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.21 // indirect github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.22 // indirect
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.21 // indirect github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.22 // indirect
github.com/aws/smithy-go v1.24.2 // indirect github.com/aws/smithy-go v1.25.0 // indirect
github.com/aymerick/douceur v0.2.0 // indirect github.com/aymerick/douceur v0.2.0 // indirect
github.com/beorn7/perks v1.0.1 // indirect github.com/beorn7/perks v1.0.1 // indirect
github.com/bits-and-blooms/bitset v1.24.4 // indirect github.com/bits-and-blooms/bitset v1.24.4 // indirect
@@ -195,7 +193,8 @@ require (
github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 // indirect github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 // indirect
github.com/go-ini/ini v1.67.0 // indirect github.com/go-ini/ini v1.67.0 // indirect
github.com/go-viper/mapstructure/v2 v2.5.0 // indirect github.com/go-viper/mapstructure/v2 v2.5.0 // indirect
github.com/go-webauthn/x v0.2.2 // indirect github.com/go-webauthn/x v0.2.3 // indirect
github.com/goccy/go-json v0.10.6 // indirect
github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9 // indirect github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9 // indirect
github.com/golang-sql/sqlexp v0.1.0 // indirect github.com/golang-sql/sqlexp v0.1.0 // indirect
github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 // indirect github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 // indirect
@@ -259,7 +258,7 @@ require (
github.com/sorairolake/lzip-go v0.3.8 // indirect github.com/sorairolake/lzip-go v0.3.8 // indirect
github.com/spf13/afero v1.15.0 // indirect github.com/spf13/afero v1.15.0 // indirect
github.com/ssor/bom v0.0.0-20170718123548-6386211fdfcf // indirect github.com/ssor/bom v0.0.0-20170718123548-6386211fdfcf // indirect
github.com/tinylib/msgp v1.6.3 // indirect github.com/tinylib/msgp v1.6.4 // indirect
github.com/unknwon/com v1.0.1 // indirect github.com/unknwon/com v1.0.1 // indirect
github.com/x448/float16 v0.8.4 // indirect github.com/x448/float16 v0.8.4 // indirect
github.com/xanzy/ssh-agent v0.3.3 // indirect github.com/xanzy/ssh-agent v0.3.3 // indirect
@@ -306,5 +305,3 @@ replace github.com/Azure/azure-sdk-for-go/sdk/azcore => github.com/Azure/azure-s
replace github.com/Azure/azure-sdk-for-go/sdk/storage/azblob => github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.6.2 // v1.6.4+ uses API version unsupported by Azurite in CI replace github.com/Azure/azure-sdk-for-go/sdk/storage/azblob => github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.6.2 // v1.6.4+ uses API version unsupported by Azurite in CI
replace github.com/microsoft/go-mssqldb => github.com/microsoft/go-mssqldb v1.9.7 // downgraded with Azure SDK replace github.com/microsoft/go-mssqldb => github.com/microsoft/go-mssqldb v1.9.7 // downgraded with Azure SDK
tool code.gitea.io/gitea-vet

115
go.sum
View File

@@ -2,8 +2,6 @@ cloud.google.com/go/compute/metadata v0.9.0 h1:pDUj4QMoPejqq20dK0Pg2N4yG9zIkYGdB
cloud.google.com/go/compute/metadata v0.9.0/go.mod h1:E0bWwX5wTnLPedCKqk3pJmVgCBSM6qQI1yTBdEb3C10= cloud.google.com/go/compute/metadata v0.9.0/go.mod h1:E0bWwX5wTnLPedCKqk3pJmVgCBSM6qQI1yTBdEb3C10=
code.gitea.io/actions-proto-go v0.4.1 h1:l0EYhjsgpUe/1VABo2eK7zcoNX2W44WOnb0MSLrKfls= code.gitea.io/actions-proto-go v0.4.1 h1:l0EYhjsgpUe/1VABo2eK7zcoNX2W44WOnb0MSLrKfls=
code.gitea.io/actions-proto-go v0.4.1/go.mod h1:mn7Wkqz6JbnTOHQpot3yDeHx+O5C9EGhMEE+htvHBas= code.gitea.io/actions-proto-go v0.4.1/go.mod h1:mn7Wkqz6JbnTOHQpot3yDeHx+O5C9EGhMEE+htvHBas=
code.gitea.io/gitea-vet v0.2.3 h1:gdFmm6WOTM65rE8FUBTRzeQZYzXePKSSB1+r574hWwI=
code.gitea.io/gitea-vet v0.2.3/go.mod h1:zcNbT/aJEmivCAhfmkHOlT645KNOf9W2KnkLgFjGGfE=
code.gitea.io/sdk/gitea v0.24.1 h1:hpaqcdGcBmfMpV7JSbBJVwE99qo+WqGreJYKrDKEyW8= code.gitea.io/sdk/gitea v0.24.1 h1:hpaqcdGcBmfMpV7JSbBJVwE99qo+WqGreJYKrDKEyW8=
code.gitea.io/sdk/gitea v0.24.1/go.mod h1:5/77BL3sHneCMEiZaMT9lfTvnnibsYxyO48mceCF3qA= code.gitea.io/sdk/gitea v0.24.1/go.mod h1:5/77BL3sHneCMEiZaMT9lfTvnnibsYxyO48mceCF3qA=
code.pfad.fr/check v1.1.0 h1:GWvjdzhSEgHvEHe2uJujDcpmZoySKuHQNrZMfzfO0bE= code.pfad.fr/check v1.1.0 h1:GWvjdzhSEgHvEHe2uJujDcpmZoySKuHQNrZMfzfO0bE=
@@ -18,8 +16,8 @@ filippo.io/edwards25519 v1.2.0 h1:crnVqOiS4jqYleHd9vaKZ+HKtHfllngJIiOpNpoJsjo=
filippo.io/edwards25519 v1.2.0/go.mod h1:xzAOLCNug/yB62zG1bQ8uziwrIqIuxhctzJT18Q77mc= filippo.io/edwards25519 v1.2.0/go.mod h1:xzAOLCNug/yB62zG1bQ8uziwrIqIuxhctzJT18Q77mc=
gitea.com/gitea/act v0.261.10 h1:ndwbtuMXXz1dpYF2iwY1/PkgKNETo4jmPXfinTZt8cs= gitea.com/gitea/act v0.261.10 h1:ndwbtuMXXz1dpYF2iwY1/PkgKNETo4jmPXfinTZt8cs=
gitea.com/gitea/act v0.261.10/go.mod h1:oIkqQHvU0lfuIWwcpqa4FmU+t3prA89tgkuHUTsrI2c= gitea.com/gitea/act v0.261.10/go.mod h1:oIkqQHvU0lfuIWwcpqa4FmU+t3prA89tgkuHUTsrI2c=
gitea.com/go-chi/binding v0.0.0-20240430071103-39a851e106ed h1:EZZBtilMLSZNWtHHcgq2mt6NSGhJSZBuduAlinMEmso= gitea.com/go-chi/binding v0.0.0-20260414111559-654cea7ac60a h1:JHoBrfuTSF9Ke9aNfSYj1XRPBHjKPgCApVprnt2Am0M=
gitea.com/go-chi/binding v0.0.0-20240430071103-39a851e106ed/go.mod h1:E3i3cgB04dDx0v3CytCgRTTn9Z/9x891aet3r456RVw= gitea.com/go-chi/binding v0.0.0-20260414111559-654cea7ac60a/go.mod h1:FOsLJIMdpiHzBp3Vby6Wfkdw2ppGscrjgU1IC7E4/zQ=
gitea.com/go-chi/cache v0.2.1 h1:bfAPkvXlbcZxPCpcmDVCWoHgiBSBmZN/QosnZvEC0+g= gitea.com/go-chi/cache v0.2.1 h1:bfAPkvXlbcZxPCpcmDVCWoHgiBSBmZN/QosnZvEC0+g=
gitea.com/go-chi/cache v0.2.1/go.mod h1:Qic0HZ8hOHW62ETGbonpwz8WYypj9NieU9659wFUJ8Q= gitea.com/go-chi/cache v0.2.1/go.mod h1:Qic0HZ8hOHW62ETGbonpwz8WYypj9NieU9659wFUJ8Q=
gitea.com/go-chi/captcha v0.0.0-20240315150714-fb487f629098 h1:p2ki+WK0cIeNQuqjR98IP2KZQKRzJJiV7aTeMAFwaWo= gitea.com/go-chi/captcha v0.0.0-20240315150714-fb487f629098 h1:p2ki+WK0cIeNQuqjR98IP2KZQKRzJJiV7aTeMAFwaWo=
@@ -94,18 +92,18 @@ github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be/go.mod h1:ySMOLuW
github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio= github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio=
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs= github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs=
github.com/aws/aws-sdk-go-v2 v1.41.5 h1:dj5kopbwUsVUVFgO4Fi5BIT3t4WyqIDjGKCangnV/yY= github.com/aws/aws-sdk-go-v2 v1.41.6 h1:1AX0AthnBQzMx1vbmir3Y4WsnJgiydmnJjiLu+LvXOg=
github.com/aws/aws-sdk-go-v2 v1.41.5/go.mod h1:mwsPRE8ceUUpiTgF7QmQIJ7lgsKUPQOUl3o72QBrE1o= github.com/aws/aws-sdk-go-v2 v1.41.6/go.mod h1:dy0UzBIfwSeot4grGvY1AqFWN5zgziMmWGzysDnHFcQ=
github.com/aws/aws-sdk-go-v2/credentials v1.19.13 h1:mA59E3fokBvyEGHKFdnpNNrvaR351cqiHgRg+JzOSRI= github.com/aws/aws-sdk-go-v2/credentials v1.19.15 h1:fyvgWTszojq8hEnMi8PPBTvZdTtEVmAVyo+NFLHBhH4=
github.com/aws/aws-sdk-go-v2/credentials v1.19.13/go.mod h1:yoTXOQKea18nrM69wGF9jBdG4WocSZA1h38A+t/MAsk= github.com/aws/aws-sdk-go-v2/credentials v1.19.15/go.mod h1:gJiYyMOjNg8OEdRWOf3CrFQxM2a98qmrtjx1zuiQfB8=
github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.21 h1:Rgg6wvjjtX8bNHcvi9OnXWwcE0a2vGpbwmtICOsvcf4= github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.22 h1:GmLa5Kw1ESqtFpXsx5MmC84QWa/ZrLZvlJGa2y+4kcQ=
github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.21/go.mod h1:A/kJFst/nm//cyqonihbdpQZwiUhhzpqTsdbhDdRF9c= github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.22/go.mod h1:6sW9iWm9DK9YRpRGga/qzrzNLgKpT2cIxb7Vo2eNOp0=
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.21 h1:PEgGVtPoB6NTpPrBgqSE5hE/o47Ij9qk/SEZFbUOe9A= github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.22 h1:dY4kWZiSaXIzxnKlj17nHnBcXXBfac6UlsAx2qL6XrU=
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.21/go.mod h1:p+hz+PRAYlY3zcpJhPwXlLC4C+kqn70WIHwnzAfs6ps= github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.22/go.mod h1:KIpEUx0JuRZLO7U6cbV204cWAEco2iC3l061IxlwLtI=
github.com/aws/aws-sdk-go-v2/service/codecommit v1.33.12 h1:yv3mfWt/eiDTTry6fkN5hh8wHJfU5ygnw+DJp10C0/c= github.com/aws/aws-sdk-go-v2/service/codecommit v1.33.13 h1:IIW5QmNI9PrnDTBCPa75HcD0g+hoD/a+d388dbIAkEM=
github.com/aws/aws-sdk-go-v2/service/codecommit v1.33.12/go.mod h1:voO3LP/dZ4CTERiNWCz3DFLbK/8hbfeC1OJkLW+sang= github.com/aws/aws-sdk-go-v2/service/codecommit v1.33.13/go.mod h1:B1FUSufCQp3d8VUzob1EY+AdSo2OuEWNEY6GQff7EHA=
github.com/aws/smithy-go v1.24.2 h1:FzA3bu/nt/vDvmnkg+R8Xl46gmzEDam6mZ1hzmwXFng= github.com/aws/smithy-go v1.25.0 h1:Sz/XJ64rwuiKtB6j98nDIPyYrV1nVNJ4YU74gttcl5U=
github.com/aws/smithy-go v1.24.2/go.mod h1:YE2RhdIuDbA5E5bTdciG9KrW3+TiEONeUWCqxX9i1Fc= github.com/aws/smithy-go v1.25.0/go.mod h1:YE2RhdIuDbA5E5bTdciG9KrW3+TiEONeUWCqxX9i1Fc=
github.com/aymerick/douceur v0.2.0 h1:Mv+mAeH1Q+n9Fr+oyamOlAkUNPWPlA8PPGR0QAaYuPk= github.com/aymerick/douceur v0.2.0 h1:Mv+mAeH1Q+n9Fr+oyamOlAkUNPWPlA8PPGR0QAaYuPk=
github.com/aymerick/douceur v0.2.0/go.mod h1:wlT5vV2O3h55X9m7iVYN0TBM0NH/MmbLnd30/FjWUq4= github.com/aymerick/douceur v0.2.0/go.mod h1:wlT5vV2O3h55X9m7iVYN0TBM0NH/MmbLnd30/FjWUq4=
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
@@ -241,8 +239,8 @@ github.com/dimiro1/reply v0.0.0-20200315094148-d0136a4c9e21/go.mod h1:xJvkyD6Y2r
github.com/dlclark/regexp2 v1.2.0/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc= github.com/dlclark/regexp2 v1.2.0/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc=
github.com/dlclark/regexp2 v1.4.0/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc= github.com/dlclark/regexp2 v1.4.0/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc=
github.com/dlclark/regexp2 v1.7.0/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8= github.com/dlclark/regexp2 v1.7.0/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8=
github.com/dlclark/regexp2 v1.11.5 h1:Q/sSnsKerHeCkc/jSTNq1oCm7KiVgUMZRDUoRu0JQZQ= github.com/dlclark/regexp2 v1.12.0 h1:0j4c5qQmnC6XOWNjP3PIXURXN2gWx76rd3KvgdPkCz8=
github.com/dlclark/regexp2 v1.11.5/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8= github.com/dlclark/regexp2 v1.12.0/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8=
github.com/dsnet/compress v0.0.2-0.20230904184137-39efe44ab707 h1:2tV76y6Q9BB+NEBasnqvs7e49aEBFI8ejC89PSnWH+4= github.com/dsnet/compress v0.0.2-0.20230904184137-39efe44ab707 h1:2tV76y6Q9BB+NEBasnqvs7e49aEBFI8ejC89PSnWH+4=
github.com/dsnet/compress v0.0.2-0.20230904184137-39efe44ab707/go.mod h1:qssHWj60/X5sZFNxpG4HBPDHVqxNm4DfnCKgrbZOT+s= github.com/dsnet/compress v0.0.2-0.20230904184137-39efe44ab707/go.mod h1:qssHWj60/X5sZFNxpG4HBPDHVqxNm4DfnCKgrbZOT+s=
github.com/dsnet/golib v0.0.0-20171103203638-1ea166775780/go.mod h1:Lj+Z9rebOhdfkVLjJ8T6VcRQv3SXugXy999NBtR9aFY= github.com/dsnet/golib v0.0.0-20171103203638-1ea166775780/go.mod h1:Lj+Z9rebOhdfkVLjJ8T6VcRQv3SXugXy999NBtR9aFY=
@@ -290,10 +288,10 @@ github.com/go-chi/chi/v5 v5.2.5 h1:Eg4myHZBjyvJmAFjFvWgrqDTXFyOzjj7YIm3L3mu6Ug=
github.com/go-chi/chi/v5 v5.2.5/go.mod h1:X7Gx4mteadT3eDOMTsXzmI4/rwUpOwBHLpAfupzFJP0= github.com/go-chi/chi/v5 v5.2.5/go.mod h1:X7Gx4mteadT3eDOMTsXzmI4/rwUpOwBHLpAfupzFJP0=
github.com/go-chi/cors v1.2.2 h1:Jmey33TE+b+rB7fT8MUy1u0I4L+NARQlK6LhzKPSyQE= github.com/go-chi/cors v1.2.2 h1:Jmey33TE+b+rB7fT8MUy1u0I4L+NARQlK6LhzKPSyQE=
github.com/go-chi/cors v1.2.2/go.mod h1:sSbTewc+6wYHBBCW7ytsFSn836hqM7JxpglAy2Vzc58= github.com/go-chi/cors v1.2.2/go.mod h1:sSbTewc+6wYHBBCW7ytsFSn836hqM7JxpglAy2Vzc58=
github.com/go-co-op/gocron/v2 v2.19.1 h1:B4iLeA0NB/2iO3EKQ7NfKn5KsQgZfjb2fkvoZJU3yBI= github.com/go-co-op/gocron/v2 v2.21.0 h1:e1nt9AEFglarRH9/9y9q0V5sblwxlknpHPjttEajrwQ=
github.com/go-co-op/gocron/v2 v2.19.1/go.mod h1:5lEiCKk1oVJV39Zg7/YG10OnaVrDAV5GGR6O0663k6U= github.com/go-co-op/gocron/v2 v2.21.0/go.mod h1:5lEiCKk1oVJV39Zg7/YG10OnaVrDAV5GGR6O0663k6U=
github.com/go-enry/go-enry/v2 v2.9.5 h1:HPhAQQHYwJgihL2PxBZiUMFWiROsGwOBdB6/D8zCUhY= github.com/go-enry/go-enry/v2 v2.9.6 h1:np63eOtMV56zfYDHnFVgpEVOk8fr2kmylcMnAZUDbSs=
github.com/go-enry/go-enry/v2 v2.9.5/go.mod h1:9yrj4ES1YrbNb1Wb7/PWYr2bpaCXUGRt0uafN0ISyG8= github.com/go-enry/go-enry/v2 v2.9.6/go.mod h1:9yrj4ES1YrbNb1Wb7/PWYr2bpaCXUGRt0uafN0ISyG8=
github.com/go-enry/go-oniguruma v1.2.1 h1:k8aAMuJfMrqm/56SG2lV9Cfti6tC4x8673aHCcBk+eo= github.com/go-enry/go-oniguruma v1.2.1 h1:k8aAMuJfMrqm/56SG2lV9Cfti6tC4x8673aHCcBk+eo=
github.com/go-enry/go-oniguruma v1.2.1/go.mod h1:bWDhYP+S6xZQgiRL7wlTScFYBe023B6ilRZbCAD5Hf4= github.com/go-enry/go-oniguruma v1.2.1/go.mod h1:bWDhYP+S6xZQgiRL7wlTScFYBe023B6ilRZbCAD5Hf4=
github.com/go-fed/httpsig v1.1.1-0.20201223112313-55836744818e h1:oRq/fiirun5HqlEWMLIcDmLpIELlG4iGbd0s8iqgPi8= github.com/go-fed/httpsig v1.1.1-0.20201223112313-55836744818e h1:oRq/fiirun5HqlEWMLIcDmLpIELlG4iGbd0s8iqgPi8=
@@ -304,8 +302,8 @@ github.com/go-git/go-billy/v5 v5.8.0 h1:I8hjc3LbBlXTtVuFNJuwYuMiHvQJDq1AT6u4DwDz
github.com/go-git/go-billy/v5 v5.8.0/go.mod h1:RpvI/rw4Vr5QA+Z60c6d6LXH0rYJo0uD5SqfmrrheCY= github.com/go-git/go-billy/v5 v5.8.0/go.mod h1:RpvI/rw4Vr5QA+Z60c6d6LXH0rYJo0uD5SqfmrrheCY=
github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399 h1:eMje31YglSBqCdIqdhKBW8lokaMrL3uTkpGYlE2OOT4= github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399 h1:eMje31YglSBqCdIqdhKBW8lokaMrL3uTkpGYlE2OOT4=
github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399/go.mod h1:1OCfN199q1Jm3HZlxleg+Dw/mwps2Wbk9frAWm+4FII= github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399/go.mod h1:1OCfN199q1Jm3HZlxleg+Dw/mwps2Wbk9frAWm+4FII=
github.com/go-git/go-git/v5 v5.17.2 h1:B+nkdlxdYrvyFK4GPXVU8w1U+YkbsgciIR7f2sZJ104= github.com/go-git/go-git/v5 v5.18.0 h1:O831KI+0PR51hM2kep6T8k+w0/LIAD490gvqMCvL5hM=
github.com/go-git/go-git/v5 v5.17.2/go.mod h1:pW/VmeqkanRFqR6AljLcs7EA7FbZaN5MQqO7oZADXpo= github.com/go-git/go-git/v5 v5.18.0/go.mod h1:pW/VmeqkanRFqR6AljLcs7EA7FbZaN5MQqO7oZADXpo=
github.com/go-ini/ini v1.67.0 h1:z6ZrTEZqSWOTyH2FlglNbNgARyHG8oLW9gMELqKr06A= github.com/go-ini/ini v1.67.0 h1:z6ZrTEZqSWOTyH2FlglNbNgARyHG8oLW9gMELqKr06A=
github.com/go-ini/ini v1.67.0/go.mod h1:ByCAeIL28uOIIG0E3PJtZPDL8WnHpFKFOtgjp+3Ies8= github.com/go-ini/ini v1.67.0/go.mod h1:ByCAeIL28uOIIG0E3PJtZPDL8WnHpFKFOtgjp+3Ies8=
github.com/go-jose/go-jose/v4 v4.1.3 h1:CVLmWDhDVRa6Mi/IgCgaopNosCaHz7zrMeF9MlZRkrs= github.com/go-jose/go-jose/v4 v4.1.3 h1:CVLmWDhDVRa6Mi/IgCgaopNosCaHz7zrMeF9MlZRkrs=
@@ -327,10 +325,10 @@ github.com/go-test/deep v1.1.1 h1:0r/53hagsehfO4bzD2Pgr/+RgHqhmf+k1Bpse2cTu1U=
github.com/go-test/deep v1.1.1/go.mod h1:5C2ZWiW0ErCdrYzpqxLbTX7MG14M9iiw8DgHncVwcsE= github.com/go-test/deep v1.1.1/go.mod h1:5C2ZWiW0ErCdrYzpqxLbTX7MG14M9iiw8DgHncVwcsE=
github.com/go-viper/mapstructure/v2 v2.5.0 h1:vM5IJoUAy3d7zRSVtIwQgBj7BiWtMPfmPEgAXnvj1Ro= github.com/go-viper/mapstructure/v2 v2.5.0 h1:vM5IJoUAy3d7zRSVtIwQgBj7BiWtMPfmPEgAXnvj1Ro=
github.com/go-viper/mapstructure/v2 v2.5.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= github.com/go-viper/mapstructure/v2 v2.5.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM=
github.com/go-webauthn/webauthn v0.16.1 h1:x5/SSki5/aIfogaRukqvbg/RXa3Sgxy/9vU7UfFPHKU= github.com/go-webauthn/webauthn v0.16.5 h1:x+vADHlaiIjta23kGhtwyCIlB5mayKx6SBlpwQ5NF9A=
github.com/go-webauthn/webauthn v0.16.1/go.mod h1:RBS+rtQJMkE5VfMQ4diDA2VNrEL8OeUhp4Srz37FHbQ= github.com/go-webauthn/webauthn v0.16.5/go.mod h1:mQC6L0lZ5Kiu35G70zeB2WnrW4+vbHjR8Koq4HdVaMg=
github.com/go-webauthn/x v0.2.2 h1:zIiipvMbr48CXi5RG0XdBJR94kd8I5LfzHPb/q+YYmk= github.com/go-webauthn/x v0.2.3 h1:8oArS+Rc1SWFLXhE17KZNx258Z4kUSyaDgsSncCO5RA=
github.com/go-webauthn/x v0.2.2/go.mod h1:IpJ5qyWB9NRhLX3C7gIfjTU7RZLXEP6kzFkoVSE7Fz4= github.com/go-webauthn/x v0.2.3/go.mod h1:tM04GF3V6VYq79AZMl7vbj4q6pz9r7L2criWRzbWhPk=
github.com/gobwas/httphead v0.1.0/go.mod h1:O/RXo79gxV8G+RqlR/otEwx4Q36zl9rqC5u12GKvMCM= github.com/gobwas/httphead v0.1.0/go.mod h1:O/RXo79gxV8G+RqlR/otEwx4Q36zl9rqC5u12GKvMCM=
github.com/gobwas/pool v0.2.1/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw= github.com/gobwas/pool v0.2.1/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw=
github.com/gobwas/ws v1.2.1/go.mod h1:hRKAFb8wOxFROYNsT1bqfWnhX+b5MFeJM9r2ZSwg/KY= github.com/gobwas/ws v1.2.1/go.mod h1:hRKAFb8wOxFROYNsT1bqfWnhX+b5MFeJM9r2ZSwg/KY=
@@ -391,8 +389,8 @@ github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/
github.com/google/licenseclassifier/v2 v2.0.0 h1:1Y57HHILNf4m0ABuMVb6xk4vAJYEUO0gDxNpog0pyeA= github.com/google/licenseclassifier/v2 v2.0.0 h1:1Y57HHILNf4m0ABuMVb6xk4vAJYEUO0gDxNpog0pyeA=
github.com/google/licenseclassifier/v2 v2.0.0/go.mod h1:cOjbdH0kyC9R22sdQbYsFkto4NGCAc+ZSwbeThazEtM= github.com/google/licenseclassifier/v2 v2.0.0/go.mod h1:cOjbdH0kyC9R22sdQbYsFkto4NGCAc+ZSwbeThazEtM=
github.com/google/pprof v0.0.0-20240227163752-401108e1b7e7/go.mod h1:czg5+yv1E0ZGTi6S6vVK1mke0fV+FaUhNGcd6VRS9Ik= github.com/google/pprof v0.0.0-20240227163752-401108e1b7e7/go.mod h1:czg5+yv1E0ZGTi6S6vVK1mke0fV+FaUhNGcd6VRS9Ik=
github.com/google/pprof v0.0.0-20260302011040-a15ffb7f9dcc h1:VBbFa1lDYWEeV5FZKUiYKYT0VxCp9twUmmaq9eb8sXw= github.com/google/pprof v0.0.0-20260402051712-545e8a4df936 h1:EwtI+Al+DeppwYX2oXJCETMO23COyaKGP6fHVpkpWpg=
github.com/google/pprof v0.0.0-20260302011040-a15ffb7f9dcc/go.mod h1:MxpfABSjhmINe3F1It9d+8exIHFvUqtLIRCdOGNXqiI= github.com/google/pprof v0.0.0-20260402051712-545e8a4df936/go.mod h1:MxpfABSjhmINe3F1It9d+8exIHFvUqtLIRCdOGNXqiI=
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/gopherjs/gopherjs v0.0.0-20181103185306-d547d1d9531e/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gopherjs/gopherjs v0.0.0-20181103185306-d547d1d9531e/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
@@ -498,8 +496,8 @@ github.com/letsencrypt/challtestsrv v1.4.2 h1:0ON3ldMhZyWlfVNYYpFuWRTmZNnyfiL9Hh
github.com/letsencrypt/challtestsrv v1.4.2/go.mod h1:GhqMqcSoeGpYd5zX5TgwA6er/1MbWzx/o7yuuVya+Wk= github.com/letsencrypt/challtestsrv v1.4.2/go.mod h1:GhqMqcSoeGpYd5zX5TgwA6er/1MbWzx/o7yuuVya+Wk=
github.com/letsencrypt/pebble/v2 v2.10.0 h1:Wq6gYXlsY6ubqI3hhxsTzdyotvfdjFBxuwYqCLCnj/U= github.com/letsencrypt/pebble/v2 v2.10.0 h1:Wq6gYXlsY6ubqI3hhxsTzdyotvfdjFBxuwYqCLCnj/U=
github.com/letsencrypt/pebble/v2 v2.10.0/go.mod h1:Sk8cmUIPcIdv2nINo+9PB4L+ZBhzY+F9A1a/h/xmWiQ= github.com/letsencrypt/pebble/v2 v2.10.0/go.mod h1:Sk8cmUIPcIdv2nINo+9PB4L+ZBhzY+F9A1a/h/xmWiQ=
github.com/lib/pq v1.12.1 h1:x1nbl/338GLqeDJ/FAiILallhAsqubLzEZu/pXtHUow= github.com/lib/pq v1.12.3 h1:tTWxr2YLKwIvK90ZXEw8GP7UFHtcbTtty8zsI+YjrfQ=
github.com/lib/pq v1.12.1/go.mod h1:/p+8NSbOcwzAEI7wiMXFlgydTwcgTr3OSKMsD2BitpA= github.com/lib/pq v1.12.3/go.mod h1:/p+8NSbOcwzAEI7wiMXFlgydTwcgTr3OSKMsD2BitpA=
github.com/libdns/libdns v1.1.1 h1:wPrHrXILoSHKWJKGd0EiAVmiJbFShguILTg9leS/P/U= github.com/libdns/libdns v1.1.1 h1:wPrHrXILoSHKWJKGd0EiAVmiJbFShguILTg9leS/P/U=
github.com/libdns/libdns v1.1.1/go.mod h1:4Bj9+5CQiNMVGf87wjX4CY3HQJypUHRuLvlsfsZqLWQ= github.com/libdns/libdns v1.1.1/go.mod h1:4Bj9+5CQiNMVGf87wjX4CY3HQJypUHRuLvlsfsZqLWQ=
github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
@@ -512,16 +510,16 @@ github.com/markbates/goth v1.82.0 h1:8j/c34AjBSTNzO7zTsOyP5IYCQCMBTRBHAbBt/PI0bQ
github.com/markbates/goth v1.82.0/go.mod h1:/DRlcq0pyqkKToyZjsL2KgiA1zbF1HIjE7u2uC79rUk= github.com/markbates/goth v1.82.0/go.mod h1:/DRlcq0pyqkKToyZjsL2KgiA1zbF1HIjE7u2uC79rUk=
github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE= github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE=
github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8= github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8=
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= github.com/mattn/go-isatty v0.0.21 h1:xYae+lCNBP7QuW4PUnNG61ffM4hVIfm+zUzDuSzYLGs=
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/mattn/go-isatty v0.0.21/go.mod h1:ZXfXG4SQHsB/w3ZeOYbR0PrPwLy+n6xiMrJlRFqopa4=
github.com/mattn/go-runewidth v0.0.21 h1:jJKAZiQH+2mIinzCJIaIG9Be1+0NR+5sz/lYEEjdM8w= github.com/mattn/go-runewidth v0.0.21 h1:jJKAZiQH+2mIinzCJIaIG9Be1+0NR+5sz/lYEEjdM8w=
github.com/mattn/go-runewidth v0.0.21/go.mod h1:XBkDxAl56ILZc9knddidhrOlY5R/pDhgLpndooCuJAs= github.com/mattn/go-runewidth v0.0.21/go.mod h1:XBkDxAl56ILZc9knddidhrOlY5R/pDhgLpndooCuJAs=
github.com/mattn/go-shellwords v1.0.12 h1:M2zGm7EW6UQJvDeQxo4T51eKPurbeFbe8WtebGE2xrk= github.com/mattn/go-shellwords v1.0.12 h1:M2zGm7EW6UQJvDeQxo4T51eKPurbeFbe8WtebGE2xrk=
github.com/mattn/go-shellwords v1.0.12/go.mod h1:EZzvwXDESEeg03EKmM+RmDnNOPKG4lLtQsUlTZDWQ8Y= github.com/mattn/go-shellwords v1.0.12/go.mod h1:EZzvwXDESEeg03EKmM+RmDnNOPKG4lLtQsUlTZDWQ8Y=
github.com/mattn/go-sqlite3 v1.14.38 h1:tDUzL85kMvOrvpCt8P64SbGgVFtJB11GPi2AdmITgb4= github.com/mattn/go-sqlite3 v1.14.42 h1:MigqEP4ZmHw3aIdIT7T+9TLa90Z6smwcthx+Azv4Cgo=
github.com/mattn/go-sqlite3 v1.14.38/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y= github.com/mattn/go-sqlite3 v1.14.42/go.mod h1:pjEuOr8IwzLJP2MfGeTb0A35jauH+C2kbHKBr7yXKVQ=
github.com/meilisearch/meilisearch-go v0.36.1 h1:mJTCJE5g7tRvaqKco6DfqOuJEjX+rRltDEnkEC02Y0M= github.com/meilisearch/meilisearch-go v0.36.2 h1:MYaMPCpdLh2aYPt+zK+19mLoA4dfBY3S1L7T0FADCjU=
github.com/meilisearch/meilisearch-go v0.36.1/go.mod h1:hWcR0MuWLSzHfbz9GGzIr3s9rnXLm1jqkmHkJPbUSvM= github.com/meilisearch/meilisearch-go v0.36.2/go.mod h1:hWcR0MuWLSzHfbz9GGzIr3s9rnXLm1jqkmHkJPbUSvM=
github.com/mholt/acmez/v3 v3.1.6 h1:eGVQNObP0pBN4sxqrXeg7MYqTOWyoiYpQqITVWlrevk= github.com/mholt/acmez/v3 v3.1.6 h1:eGVQNObP0pBN4sxqrXeg7MYqTOWyoiYpQqITVWlrevk=
github.com/mholt/acmez/v3 v3.1.6/go.mod h1:5nTPosTGosLxF3+LU4ygbgMRFDhbAVpqMI4+a4aHLBY= github.com/mholt/acmez/v3 v3.1.6/go.mod h1:5nTPosTGosLxF3+LU4ygbgMRFDhbAVpqMI4+a4aHLBY=
github.com/mholt/archives v0.1.5 h1:Fh2hl1j7VEhc6DZs2DLMgiBNChUux154a1G+2esNvzQ= github.com/mholt/archives v0.1.5 h1:Fh2hl1j7VEhc6DZs2DLMgiBNChUux154a1G+2esNvzQ=
@@ -538,8 +536,8 @@ github.com/minio/crc64nvme v1.1.1 h1:8dwx/Pz49suywbO+auHCBpCtlW1OfpcLN7wYgVR6wAI
github.com/minio/crc64nvme v1.1.1/go.mod h1:eVfm2fAzLlxMdUGc0EEBGSMmPwmXD5XiNRpnu9J3bvg= github.com/minio/crc64nvme v1.1.1/go.mod h1:eVfm2fAzLlxMdUGc0EEBGSMmPwmXD5XiNRpnu9J3bvg=
github.com/minio/md5-simd v1.1.2 h1:Gdi1DZK69+ZVMoNHRXJyNcxrMA4dSxoYHZSQbirFg34= github.com/minio/md5-simd v1.1.2 h1:Gdi1DZK69+ZVMoNHRXJyNcxrMA4dSxoYHZSQbirFg34=
github.com/minio/md5-simd v1.1.2/go.mod h1:MzdKDxYpY2BT9XQFocsiZf/NKVtR7nkE4RoEpN+20RM= github.com/minio/md5-simd v1.1.2/go.mod h1:MzdKDxYpY2BT9XQFocsiZf/NKVtR7nkE4RoEpN+20RM=
github.com/minio/minio-go/v7 v7.0.99 h1:2vH/byrwUkIpFQFOilvTfaUpvAX3fEFhEzO+DR3DlCE= github.com/minio/minio-go/v7 v7.0.100 h1:ShkWi8Tyj9RtU57OQB2HIXKz4bFgtVib0bbT1sbtLI8=
github.com/minio/minio-go/v7 v7.0.99/go.mod h1:EtGNKtlX20iL2yaYnxEigaIvj0G0GwSDnifnG8ClIdw= github.com/minio/minio-go/v7 v7.0.100/go.mod h1:EtGNKtlX20iL2yaYnxEigaIvj0G0GwSDnifnG8ClIdw=
github.com/minio/minlz v1.1.0 h1:rUOGu3EP4EqJC5k3qCsIwEnZiJULKqtRyDdqbhlvMmQ= github.com/minio/minlz v1.1.0 h1:rUOGu3EP4EqJC5k3qCsIwEnZiJULKqtRyDdqbhlvMmQ=
github.com/minio/minlz v1.1.0/go.mod h1:qT0aEB35q79LLornSzeDH75LBf3aH1MV+jB5w9Wasec= github.com/minio/minlz v1.1.0/go.mod h1:qT0aEB35q79LLornSzeDH75LBf3aH1MV+jB5w9Wasec=
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
@@ -697,8 +695,8 @@ github.com/stvp/tempredis v0.0.0-20181119212430-b82af8480203/go.mod h1:oqN97ltKN
github.com/syndtr/goleveldb v1.0.0 h1:fBdIW9lB4Iz0n9khmH8w27SJ3QEJ7+IgjPEwGSZiFdE= github.com/syndtr/goleveldb v1.0.0 h1:fBdIW9lB4Iz0n9khmH8w27SJ3QEJ7+IgjPEwGSZiFdE=
github.com/syndtr/goleveldb v1.0.0/go.mod h1:ZVVdQEZoIme9iO1Ch2Jdy24qqXrMMOU6lpPAyBWyWuQ= github.com/syndtr/goleveldb v1.0.0/go.mod h1:ZVVdQEZoIme9iO1Ch2Jdy24qqXrMMOU6lpPAyBWyWuQ=
github.com/tinylib/msgp v1.1.0/go.mod h1:+d+yLhGm8mzTaHzB+wgMYrodPfmZrzkirds8fDWklFE= github.com/tinylib/msgp v1.1.0/go.mod h1:+d+yLhGm8mzTaHzB+wgMYrodPfmZrzkirds8fDWklFE=
github.com/tinylib/msgp v1.6.3 h1:bCSxiTz386UTgyT1i0MSCvdbWjVW+8sG3PjkGsZQt4s= github.com/tinylib/msgp v1.6.4 h1:mOwYbyYDLPj35mkA2BjjYejgJk9BuHxDdvRnb6v2ZcQ=
github.com/tinylib/msgp v1.6.3/go.mod h1:RSp0LW9oSxFut3KzESt5Voq4GVWyS+PSulT77roAqEA= github.com/tinylib/msgp v1.6.4/go.mod h1:RSp0LW9oSxFut3KzESt5Voq4GVWyS+PSulT77roAqEA=
github.com/tstranex/u2f v1.0.0 h1:HhJkSzDDlVSVIVt7pDJwCHQj67k7A5EeBgPmeD+pVsQ= github.com/tstranex/u2f v1.0.0 h1:HhJkSzDDlVSVIVt7pDJwCHQj67k7A5EeBgPmeD+pVsQ=
github.com/tstranex/u2f v1.0.0/go.mod h1:eahSLaqAS0zsIEv80+vXT7WanXs7MQQDg3j3wGBSayo= github.com/tstranex/u2f v1.0.0/go.mod h1:eahSLaqAS0zsIEv80+vXT7WanXs7MQQDg3j3wGBSayo=
github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0=
@@ -732,7 +730,6 @@ github.com/xyproto/randomstring v1.0.5 h1:YtlWPoRdgMu3NZtP45drfy1GKoojuR7hmRcnhZ
github.com/xyproto/randomstring v1.0.5/go.mod h1:rgmS5DeNXLivK7YprL0pY+lTuhNQW3iGxZ18UQApw/E= github.com/xyproto/randomstring v1.0.5/go.mod h1:rgmS5DeNXLivK7YprL0pY+lTuhNQW3iGxZ18UQApw/E=
github.com/yohcop/openid-go v1.0.1 h1:DPRd3iPO5F6O5zX2e62XpVAbPT6wV51cuucH0z9g3js= github.com/yohcop/openid-go v1.0.1 h1:DPRd3iPO5F6O5zX2e62XpVAbPT6wV51cuucH0z9g3js=
github.com/yohcop/openid-go v1.0.1/go.mod h1:b/AvD03P0KHj4yuihb+VtLD6bYYgsy0zqBzPCRjkCNs= github.com/yohcop/openid-go v1.0.1/go.mod h1:b/AvD03P0KHj4yuihb+VtLD6bYYgsy0zqBzPCRjkCNs=
github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
github.com/yuin/goldmark v1.4.15/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= github.com/yuin/goldmark v1.4.15/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
@@ -785,15 +782,14 @@ golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDf
golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8= golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk= golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk=
golang.org/x/crypto v0.32.0/go.mod h1:ZnnJkOaASj8g0AjIduWNlq2NRxL0PlBrbKVyZ6V/Ugc= golang.org/x/crypto v0.32.0/go.mod h1:ZnnJkOaASj8g0AjIduWNlq2NRxL0PlBrbKVyZ6V/Ugc=
golang.org/x/crypto v0.49.0 h1:+Ng2ULVvLHnJ/ZFEq4KdcDd/cfjrrjjNSXNzxg0Y4U4= golang.org/x/crypto v0.50.0 h1:zO47/JPrL6vsNkINmLoo/PH1gcxpls50DNogFvB5ZGI=
golang.org/x/crypto v0.49.0/go.mod h1:ErX4dUh2UM+CFYiXZRTcMpEcN8b/1gxEuv3nODoYtCA= golang.org/x/crypto v0.50.0/go.mod h1:3muZ7vA7PBCE6xgPX7nkzzjiUq87kRItoJQM1Yo8S+Q=
golang.org/x/exp v0.0.0-20250819193227-8b4c13bb791b h1:DXr+pvt3nC887026GRP39Ej11UATqWDmWuS99x26cD0= golang.org/x/exp v0.0.0-20250819193227-8b4c13bb791b h1:DXr+pvt3nC887026GRP39Ej11UATqWDmWuS99x26cD0=
golang.org/x/exp v0.0.0-20250819193227-8b4c13bb791b/go.mod h1:4QTo5u+SEIbbKW1RacMZq1YEfOBqeXa19JeshGi+zc4= golang.org/x/exp v0.0.0-20250819193227-8b4c13bb791b/go.mod h1:4QTo5u+SEIbbKW1RacMZq1YEfOBqeXa19JeshGi+zc4=
golang.org/x/image v0.38.0 h1:5l+q+Y9JDC7mBOMjo4/aPhMDcxEptsX+Tt3GgRQRPuE= golang.org/x/image v0.39.0 h1:skVYidAEVKgn8lZ602XO75asgXBgLj9G/FE3RbuPFww=
golang.org/x/image v0.38.0/go.mod h1:/3f6vaXC+6CEanU4KJxbcUZyEePbyKbaLoDOe4ehFYY= golang.org/x/image v0.39.0/go.mod h1:sIbmppfU+xFLPIG0FoVUTvyBMmgng1/XAMhQ2ft0hpA=
golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
@@ -805,7 +801,6 @@ golang.org/x/mod v0.34.0/go.mod h1:ykgH52iCZe79kzLLMhyCUzhMci+nQj+0XkbXpNYtVjY=
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
@@ -819,13 +814,12 @@ golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk=
golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44= golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM= golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4= golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4=
golang.org/x/net v0.52.0 h1:He/TN1l0e4mmR3QqHMT2Xab3Aj3L9qjbhRm78/6jrW0= golang.org/x/net v0.53.0 h1:d+qAbo5L0orcWAr0a9JweQpjXF19LMXJE8Ey7hwOdUA=
golang.org/x/net v0.52.0/go.mod h1:R1MAz7uMZxVMualyPXb+VaqGSa3LIaUqk0eEt3w36Sw= golang.org/x/net v0.53.0/go.mod h1:JvMuJH7rrdiCfbeHoo3fCQU24Lf5JJwT9W3sJFulfgs=
golang.org/x/oauth2 v0.36.0 h1:peZ/1z27fi9hUOFCAZaHyrpWG5lwe0RJEEEeH0ThlIs= golang.org/x/oauth2 v0.36.0 h1:peZ/1z27fi9hUOFCAZaHyrpWG5lwe0RJEEEeH0ThlIs=
golang.org/x/oauth2 v0.36.0/go.mod h1:YDBUJMTkDnJS+A4BP4eZBjCqtokkg1hODuPjwiGPO7Q= golang.org/x/oauth2 v0.36.0/go.mod h1:YDBUJMTkDnJS+A4BP4eZBjCqtokkg1hODuPjwiGPO7Q=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
@@ -868,8 +862,8 @@ golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.29.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.29.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.42.0 h1:omrd2nAlyT5ESRdCLYdm3+fMfNFE/+Rf4bDIQImRJeo= golang.org/x/sys v0.43.0 h1:Rlag2XtaFTxp19wS8MXlJwTvoh8ArU6ezoyFsMyCTNI=
golang.org/x/sys v0.42.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw= golang.org/x/sys v0.43.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
golang.org/x/telemetry v0.0.0-20240228155512-f48c80bd79b2/go.mod h1:TeRTkGYfJXctD9OcfyVLyj2J3IxLnKwHJR8f4D8a3YE= golang.org/x/telemetry v0.0.0-20240228155512-f48c80bd79b2/go.mod h1:TeRTkGYfJXctD9OcfyVLyj2J3IxLnKwHJR8f4D8a3YE=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
@@ -880,8 +874,8 @@ golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk=
golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY= golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY=
golang.org/x/term v0.27.0/go.mod h1:iMsnZpn0cago0GOrHO2+Y7u7JPn5AylBrcoWkElMTSM= golang.org/x/term v0.27.0/go.mod h1:iMsnZpn0cago0GOrHO2+Y7u7JPn5AylBrcoWkElMTSM=
golang.org/x/term v0.28.0/go.mod h1:Sw/lC2IAUZ92udQNf3WodGtn4k/XoLyZoh8v/8uiwek= golang.org/x/term v0.28.0/go.mod h1:Sw/lC2IAUZ92udQNf3WodGtn4k/XoLyZoh8v/8uiwek=
golang.org/x/term v0.41.0 h1:QCgPso/Q3RTJx2Th4bDLqML4W6iJiaXFq2/ftQF13YU= golang.org/x/term v0.42.0 h1:UiKe+zDFmJobeJ5ggPwOshJIVt6/Ft0rcfrXZDLWAWY=
golang.org/x/term v0.41.0/go.mod h1:3pfBgksrReYfZ5lvYM0kSO0LIkAl4Yl2bXOkKP7Ec2A= golang.org/x/term v0.42.0/go.mod h1:Dq/D+snpsbazcBG5+F9Q1n2rXV8Ma+71xEjTRufARgY=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
@@ -892,14 +886,13 @@ golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ= golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
golang.org/x/text v0.35.0 h1:JOVx6vVDFokkpaq1AEptVzLTpDe9KGpj5tR4/X+ybL8= golang.org/x/text v0.36.0 h1:JfKh3XmcRPqZPKevfXVpI1wXPTqbkE5f7JA92a55Yxg=
golang.org/x/text v0.35.0/go.mod h1:khi/HExzZJ2pGnjenulevKNX1W67CUy0AsXcNubPGCA= golang.org/x/text v0.36.0/go.mod h1:NIdBknypM8iqVmPiuco0Dh6P5Jcdk8lJL0CUebqK164=
golang.org/x/time v0.15.0 h1:bbrp8t3bGUeFOx08pvsMYRTCVSMk89u4tKbNOZbp88U= golang.org/x/time v0.15.0 h1:bbrp8t3bGUeFOx08pvsMYRTCVSMk89u4tKbNOZbp88U=
golang.org/x/time v0.15.0/go.mod h1:Y4YMaQmXwGQZoFaVFk4YpCt4FLQMYKZe9oeV/f4MSno= golang.org/x/time v0.15.0/go.mod h1:Y4YMaQmXwGQZoFaVFk4YpCt4FLQMYKZe9oeV/f4MSno=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200325010219-a49f79bcc224/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8=
golang.org/x/tools v0.0.0-20200928182047-19e03678916f/go.mod h1:z6u4i615ZeAfBE4XtMziQW1fSVJXACjjbWkB/mvPzlU= golang.org/x/tools v0.0.0-20200928182047-19e03678916f/go.mod h1:z6u4i615ZeAfBE4XtMziQW1fSVJXACjjbWkB/mvPzlU=
golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
@@ -914,8 +907,8 @@ golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8T
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/genproto/googleapis/rpc v0.0.0-20260401020348-3a24fdc17823 h1:YedBIttDguBl/zy2wJauEUm+DZZg4UXseWj0g/3N+yo= google.golang.org/genproto/googleapis/rpc v0.0.0-20260401020348-3a24fdc17823 h1:YedBIttDguBl/zy2wJauEUm+DZZg4UXseWj0g/3N+yo=
google.golang.org/genproto/googleapis/rpc v0.0.0-20260401020348-3a24fdc17823/go.mod h1:4Hqkh8ycfw05ld/3BWL7rJOSfebL2Q+DVDeRgYgxUU8= google.golang.org/genproto/googleapis/rpc v0.0.0-20260401020348-3a24fdc17823/go.mod h1:4Hqkh8ycfw05ld/3BWL7rJOSfebL2Q+DVDeRgYgxUU8=
google.golang.org/grpc v1.79.3 h1:sybAEdRIEtvcD68Gx7dmnwjZKlyfuc61Dyo9pGXXkKE= google.golang.org/grpc v1.80.0 h1:Xr6m2WmWZLETvUNvIUmeD5OAagMw3FiKmMlTdViWsHM=
google.golang.org/grpc v1.79.3/go.mod h1:KmT0Kjez+0dde/v2j9vzwoAScgEPx/Bw1CYChhHLrHQ= google.golang.org/grpc v1.80.0/go.mod h1:ho/dLnxwi3EDJA4Zghp7k2Ec1+c2jqup0bFkw07bwF4=
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=

View File

@@ -12,6 +12,7 @@ import (
"time" "time"
"code.gitea.io/gitea/models/db" "code.gitea.io/gitea/models/db"
"code.gitea.io/gitea/modules/optional"
"code.gitea.io/gitea/modules/timeutil" "code.gitea.io/gitea/modules/timeutil"
"code.gitea.io/gitea/modules/util" "code.gitea.io/gitea/modules/util"
@@ -61,7 +62,8 @@ const (
// ActionArtifact is a file that is stored in the artifact storage. // ActionArtifact is a file that is stored in the artifact storage.
type ActionArtifact struct { type ActionArtifact struct {
ID int64 `xorm:"pk autoincr"` ID int64 `xorm:"pk autoincr"`
RunID int64 `xorm:"index unique(runid_name_path)"` // The run id of the artifact RunID int64 `xorm:"index unique(runid_attempt_name_path)"` // The run id of the artifact
RunAttemptID int64 `xorm:"index unique(runid_attempt_name_path) NOT NULL DEFAULT 0"`
RunnerID int64 RunnerID int64
RepoID int64 `xorm:"index"` RepoID int64 `xorm:"index"`
OwnerID int64 OwnerID int64
@@ -80,9 +82,9 @@ type ActionArtifact struct {
// * "application/pdf", "text/html", etc.: real content type of the artifact // * "application/pdf", "text/html", etc.: real content type of the artifact
ContentEncodingOrType string `xorm:"content_encoding"` ContentEncodingOrType string `xorm:"content_encoding"`
ArtifactPath string `xorm:"index unique(runid_name_path)"` // The path to the artifact when runner uploads it ArtifactPath string `xorm:"index unique(runid_attempt_name_path)"` // The path to the artifact when runner uploads it
ArtifactName string `xorm:"index unique(runid_name_path)"` // The name of the artifact when runner uploads it ArtifactName string `xorm:"index unique(runid_attempt_name_path)"` // The name of the artifact when runner uploads it
Status ArtifactStatus `xorm:"index"` // The status of the artifact, uploading, expired or need-delete Status ArtifactStatus `xorm:"index"` // The status of the artifact, uploading, expired or need-delete
CreatedUnix timeutil.TimeStamp `xorm:"created"` CreatedUnix timeutil.TimeStamp `xorm:"created"`
UpdatedUnix timeutil.TimeStamp `xorm:"updated index"` UpdatedUnix timeutil.TimeStamp `xorm:"updated index"`
ExpiredUnix timeutil.TimeStamp `xorm:"index"` // The time when the artifact will be expired ExpiredUnix timeutil.TimeStamp `xorm:"index"` // The time when the artifact will be expired
@@ -92,12 +94,13 @@ func CreateArtifact(ctx context.Context, t *ActionTask, artifactName, artifactPa
if err := t.LoadJob(ctx); err != nil { if err := t.LoadJob(ctx); err != nil {
return nil, err return nil, err
} }
artifact, err := getArtifactByNameAndPath(ctx, t.Job.RunID, artifactName, artifactPath) artifact, err := getArtifactByNameAndPath(ctx, t.Job.RunID, t.Job.RunAttemptID, artifactName, artifactPath)
if errors.Is(err, util.ErrNotExist) { if errors.Is(err, util.ErrNotExist) {
artifact := &ActionArtifact{ artifact := &ActionArtifact{
ArtifactName: artifactName, ArtifactName: artifactName,
ArtifactPath: artifactPath, ArtifactPath: artifactPath,
RunID: t.Job.RunID, RunID: t.Job.RunID,
RunAttemptID: t.Job.RunAttemptID,
RunnerID: t.RunnerID, RunnerID: t.RunnerID,
RepoID: t.RepoID, RepoID: t.RepoID,
OwnerID: t.OwnerID, OwnerID: t.OwnerID,
@@ -122,9 +125,9 @@ func CreateArtifact(ctx context.Context, t *ActionTask, artifactName, artifactPa
return artifact, nil return artifact, nil
} }
func getArtifactByNameAndPath(ctx context.Context, runID int64, name, fpath string) (*ActionArtifact, error) { func getArtifactByNameAndPath(ctx context.Context, runID, runAttemptID int64, name, fpath string) (*ActionArtifact, error) {
var art ActionArtifact var art ActionArtifact
has, err := db.GetEngine(ctx).Where("run_id = ? AND artifact_name = ? AND artifact_path = ?", runID, name, fpath).Get(&art) has, err := db.GetEngine(ctx).Where("run_id = ? AND run_attempt_id = ? AND artifact_name = ? AND artifact_path = ?", runID, runAttemptID, name, fpath).Get(&art)
if err != nil { if err != nil {
return nil, err return nil, err
} else if !has { } else if !has {
@@ -144,6 +147,7 @@ type FindArtifactsOptions struct {
db.ListOptions db.ListOptions
RepoID int64 RepoID int64
RunID int64 RunID int64
RunAttemptID optional.Option[int64] // use optional to allow filtering by zero (legacy artifacts have run_attempt_id=0)
ArtifactName string ArtifactName string
Status int Status int
FinalizedArtifactsV4 bool FinalizedArtifactsV4 bool
@@ -163,6 +167,9 @@ func (opts FindArtifactsOptions) ToConds() builder.Cond {
if opts.RunID > 0 { if opts.RunID > 0 {
cond = cond.And(builder.Eq{"run_id": opts.RunID}) cond = cond.And(builder.Eq{"run_id": opts.RunID})
} }
if opts.RunAttemptID.Has() {
cond = cond.And(builder.Eq{"run_attempt_id": opts.RunAttemptID.Value()})
}
if opts.ArtifactName != "" { if opts.ArtifactName != "" {
cond = cond.And(builder.Eq{"artifact_name": opts.ArtifactName}) cond = cond.And(builder.Eq{"artifact_name": opts.ArtifactName})
} }
@@ -183,15 +190,17 @@ type ActionArtifactMeta struct {
ArtifactName string ArtifactName string
FileSize int64 FileSize int64
Status ArtifactStatus Status ArtifactStatus
ExpiredUnix timeutil.TimeStamp
} }
// ListUploadedArtifactsMeta returns all uploaded artifacts meta of a run // ListUploadedArtifactsMetaByRunAttempt returns uploaded artifacts meta scoped to a specific run and attempt.
func ListUploadedArtifactsMeta(ctx context.Context, repoID, runID int64) ([]*ActionArtifactMeta, error) { // Pass runAttemptID=0 to target legacy artifacts (pre-v331) belonging to the run.
func ListUploadedArtifactsMetaByRunAttempt(ctx context.Context, repoID, runID, runAttemptID int64) ([]*ActionArtifactMeta, error) {
arts := make([]*ActionArtifactMeta, 0, 10) arts := make([]*ActionArtifactMeta, 0, 10)
return arts, db.GetEngine(ctx).Table("action_artifact"). return arts, db.GetEngine(ctx).Table("action_artifact").
Where("repo_id=? AND run_id=? AND (status=? OR status=?)", repoID, runID, ArtifactStatusUploadConfirmed, ArtifactStatusExpired). Where("repo_id=? AND run_id=? AND run_attempt_id=? AND (status=? OR status=?)", repoID, runID, runAttemptID, ArtifactStatusUploadConfirmed, ArtifactStatusExpired).
GroupBy("artifact_name"). GroupBy("artifact_name").
Select("artifact_name, sum(file_size) as file_size, max(status) as status"). Select("artifact_name, sum(file_size) as file_size, max(status) as status, max(expired_unix) as expired_unix").
Find(&arts) Find(&arts)
} }
@@ -216,12 +225,29 @@ func SetArtifactExpired(ctx context.Context, artifactID int64) error {
return err return err
} }
// SetArtifactNeedDelete sets an artifact to need-delete, cron job will delete it // SetArtifactNeedDeleteByID sets an artifact to need-delete by ID, cron job will delete it.
func SetArtifactNeedDelete(ctx context.Context, runID int64, name string) error { func SetArtifactNeedDeleteByID(ctx context.Context, artifactID int64) error {
_, err := db.GetEngine(ctx).Where("run_id=? AND artifact_name=? AND status = ?", runID, name, ArtifactStatusUploadConfirmed).Cols("status").Update(&ActionArtifact{Status: ArtifactStatusPendingDeletion}) _, err := db.GetEngine(ctx).Where("id=? AND status = ?", artifactID, ArtifactStatusUploadConfirmed).Cols("status").Update(&ActionArtifact{Status: ArtifactStatusPendingDeletion})
return err return err
} }
// SetArtifactNeedDeleteByRunAttempt sets an artifact to need-delete in a run attempt, cron job will delete it.
// runAttemptID may be 0 for legacy artifacts created before ActionRunAttempt existed.
func SetArtifactNeedDeleteByRunAttempt(ctx context.Context, runID, runAttemptID int64, name string) error {
_, err := db.GetEngine(ctx).Where("run_id=? AND run_attempt_id=? AND artifact_name=? AND status = ?", runID, runAttemptID, name, ArtifactStatusUploadConfirmed).Cols("status").Update(&ActionArtifact{Status: ArtifactStatusPendingDeletion})
return err
}
// GetArtifactsByRunAttemptAndName returns all artifacts with the given name in the specified run attempt.
// This supports both attempt-scoped data and legacy artifacts with run_attempt_id=0.
func GetArtifactsByRunAttemptAndName(ctx context.Context, runID, runAttemptID int64, artifactName string) ([]*ActionArtifact, error) {
arts := make([]*ActionArtifact, 0)
return arts, db.GetEngine(ctx).
Where("run_id = ? AND run_attempt_id = ? AND artifact_name = ?", runID, runAttemptID, artifactName).
OrderBy("id").
Find(&arts)
}
// SetArtifactDeleted sets an artifact to deleted // SetArtifactDeleted sets an artifact to deleted
func SetArtifactDeleted(ctx context.Context, artifactID int64) error { func SetArtifactDeleted(ctx context.Context, artifactID int64) error {
_, err := db.GetEngine(ctx).ID(artifactID).Cols("status").Update(&ActionArtifact{Status: ArtifactStatusDeleted}) _, err := db.GetEngine(ctx).ID(artifactID).Cols("status").Update(&ActionArtifact{Status: ArtifactStatusDeleted})

View File

@@ -30,7 +30,7 @@ import (
type ActionRun struct { type ActionRun struct {
ID int64 ID int64
Title string Title string
RepoID int64 `xorm:"unique(repo_index) index(repo_concurrency)"` RepoID int64 `xorm:"unique(repo_index)"`
Repo *repo_model.Repository `xorm:"-"` Repo *repo_model.Repository `xorm:"-"`
OwnerID int64 `xorm:"index"` OwnerID int64 `xorm:"index"`
WorkflowID string `xorm:"index"` // the name of workflow file WorkflowID string `xorm:"index"` // the name of workflow file
@@ -50,15 +50,20 @@ type ActionRun struct {
Status Status `xorm:"index"` Status Status `xorm:"index"`
Version int `xorm:"version default 0"` // Status could be updated concomitantly, so an optimistic lock is needed Version int `xorm:"version default 0"` // Status could be updated concomitantly, so an optimistic lock is needed
RawConcurrency string // raw concurrency RawConcurrency string // raw concurrency
ConcurrencyGroup string `xorm:"index(repo_concurrency) NOT NULL DEFAULT ''"`
ConcurrencyCancel bool `xorm:"NOT NULL DEFAULT FALSE"` // Started and Stopped are identical to the latest attempt after ActionRunAttempt was introduced.
// Started and Stopped is used for recording last run time, if rerun happened, they will be reset to 0 // When a rerun creates a new latest attempt, they are reset until the new attempt starts and stops.
Started timeutil.TimeStamp Started timeutil.TimeStamp
Stopped timeutil.TimeStamp Stopped timeutil.TimeStamp
// PreviousDuration is used for recording previous duration
// PreviousDuration is kept only for legacy runs created before ActionRunAttempt existed.
// New runs and reruns no longer update this field and use attempt-scoped durations instead.
PreviousDuration time.Duration PreviousDuration time.Duration
Created timeutil.TimeStamp `xorm:"created"`
Updated timeutil.TimeStamp `xorm:"updated"` LatestAttemptID int64 `xorm:"index NOT NULL DEFAULT 0"`
Created timeutil.TimeStamp `xorm:"created"`
Updated timeutil.TimeStamp `xorm:"updated"`
} }
func init() { func init() {
@@ -115,7 +120,7 @@ func (run *ActionRun) RefTooltip() string {
} }
// LoadAttributes load Repo TriggerUser if not loaded // LoadAttributes load Repo TriggerUser if not loaded
func (run *ActionRun) LoadAttributes(ctx context.Context) error { func (run *ActionRun) LoadAttributes(ctx context.Context) (err error) {
if run == nil { if run == nil {
return nil return nil
} }
@@ -129,11 +134,10 @@ func (run *ActionRun) LoadAttributes(ctx context.Context) error {
} }
if run.TriggerUser == nil { if run.TriggerUser == nil {
u, err := user_model.GetPossibleUserByID(ctx, run.TriggerUserID) run.TriggerUserID, run.TriggerUser, err = user_model.GetPossibleUserByID(ctx, run.TriggerUserID)
if err != nil { if err != nil {
return err return err
} }
run.TriggerUser = u
} }
return nil return nil
@@ -160,6 +164,31 @@ func (run *ActionRun) Duration() time.Duration {
return d return d
} }
// GetLatestAttempt returns
// - the latest attempt of the run
// - (nil, false, nil) for legacy runs that have no attempt records
func (run *ActionRun) GetLatestAttempt(ctx context.Context) (*ActionRunAttempt, bool, error) {
if run.LatestAttemptID == 0 {
return nil, false, nil
}
attempt, err := GetRunAttemptByRepoAndID(ctx, run.RepoID, run.LatestAttemptID)
if err != nil {
return nil, false, err
}
return attempt, true, nil
}
func (run *ActionRun) GetEffectiveConcurrency(ctx context.Context) (string, bool, error) {
attempt, has, err := run.GetLatestAttempt(ctx)
if err != nil {
return "", false, err
}
if has {
return attempt.ConcurrencyGroup, attempt.ConcurrencyCancel, nil
}
return "", false, nil
}
func (run *ActionRun) GetPushEventPayload() (*api.PushPayload, error) { func (run *ActionRun) GetPushEventPayload() (*api.PushPayload, error) {
if run.Event == webhook_module.HookEventPush { if run.Event == webhook_module.HookEventPush {
var payload api.PushPayload var payload api.PushPayload
@@ -406,14 +435,11 @@ func UpdateRun(ctx context.Context, run *ActionRun, cols ...string) error {
type ActionRunIndex db.ResourceIndex type ActionRunIndex db.ResourceIndex
func GetConcurrentRunsAndJobs(ctx context.Context, repoID int64, concurrencyGroup string, status []Status) ([]*ActionRun, []*ActionRunJob, error) { // GetConcurrentRunAttemptsAndJobs returns run attempts and jobs in the same concurrency group by statuses.
runs, err := db.Find[ActionRun](ctx, &FindRunOptions{ func GetConcurrentRunAttemptsAndJobs(ctx context.Context, repoID int64, concurrencyGroup string, status []Status) ([]*ActionRunAttempt, []*ActionRunJob, error) {
RepoID: repoID, attempts, err := FindConcurrentRunAttempts(ctx, repoID, concurrencyGroup, status)
ConcurrencyGroup: concurrencyGroup,
Status: status,
})
if err != nil { if err != nil {
return nil, nil, fmt.Errorf("find runs: %w", err) return nil, nil, fmt.Errorf("find run attempts: %w", err)
} }
jobs, err := db.Find[ActionRunJob](ctx, &FindRunJobOptions{ jobs, err := db.Find[ActionRunJob](ctx, &FindRunJobOptions{
@@ -425,36 +451,34 @@ func GetConcurrentRunsAndJobs(ctx context.Context, repoID int64, concurrencyGrou
return nil, nil, fmt.Errorf("find jobs: %w", err) return nil, nil, fmt.Errorf("find jobs: %w", err)
} }
return runs, jobs, nil return attempts, jobs, nil
} }
func CancelPreviousJobsByRunConcurrency(ctx context.Context, actionRun *ActionRun) ([]*ActionRunJob, error) { func CancelPreviousJobsByRunConcurrency(ctx context.Context, attempt *ActionRunAttempt) ([]*ActionRunJob, error) {
if actionRun.ConcurrencyGroup == "" { if attempt.ConcurrencyGroup == "" {
return nil, nil return nil, nil
} }
var jobsToCancel []*ActionRunJob var jobsToCancel []*ActionRunJob
statusFindOption := []Status{StatusWaiting, StatusBlocked} statusFindOption := []Status{StatusWaiting, StatusBlocked}
if actionRun.ConcurrencyCancel { if attempt.ConcurrencyCancel {
statusFindOption = append(statusFindOption, StatusRunning) statusFindOption = append(statusFindOption, StatusRunning)
} }
runs, jobs, err := GetConcurrentRunsAndJobs(ctx, actionRun.RepoID, actionRun.ConcurrencyGroup, statusFindOption) attempts, jobs, err := GetConcurrentRunAttemptsAndJobs(ctx, attempt.RepoID, attempt.ConcurrencyGroup, statusFindOption)
if err != nil { if err != nil {
return nil, fmt.Errorf("find concurrent runs and jobs: %w", err) return nil, fmt.Errorf("find concurrent runs and jobs: %w", err)
} }
jobsToCancel = append(jobsToCancel, jobs...) jobsToCancel = append(jobsToCancel, jobs...)
// cancel runs in the same concurrency group // cancel runs in the same concurrency group
for _, run := range runs { for _, concurrentAttempt := range attempts {
if run.ID == actionRun.ID { if concurrentAttempt.RunID == attempt.RunID {
continue continue
} }
jobs, err := db.Find[ActionRunJob](ctx, FindRunJobOptions{ jobs, err := GetRunJobsByRunAndAttemptID(ctx, concurrentAttempt.RunID, concurrentAttempt.ID)
RunID: run.ID,
})
if err != nil { if err != nil {
return nil, fmt.Errorf("find run %d jobs: %w", run.ID, err) return nil, fmt.Errorf("find run %d attempt %d jobs: %w", concurrentAttempt.RunID, concurrentAttempt.ID, err)
} }
jobsToCancel = append(jobsToCancel, jobs...) jobsToCancel = append(jobsToCancel, jobs...)
} }

View File

@@ -0,0 +1,144 @@
// Copyright 2026 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package actions
import (
"context"
"fmt"
"slices"
"time"
"code.gitea.io/gitea/models/db"
user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/timeutil"
"code.gitea.io/gitea/modules/util"
)
// ActionRunAttempt represents a single execution attempt of an ActionRun.
type ActionRunAttempt struct {
ID int64
RepoID int64 `xorm:"index(repo_concurrency_status)"`
RunID int64 `xorm:"UNIQUE(run_attempt)"`
Run *ActionRun `xorm:"-"`
Attempt int64 `xorm:"UNIQUE(run_attempt)"`
TriggerUserID int64
TriggerUser *user_model.User `xorm:"-"`
ConcurrencyGroup string `xorm:"index(repo_concurrency_status) NOT NULL DEFAULT ''"`
ConcurrencyCancel bool `xorm:"NOT NULL DEFAULT FALSE"`
Status Status `xorm:"index(repo_concurrency_status)"`
Started timeutil.TimeStamp
Stopped timeutil.TimeStamp
Created timeutil.TimeStamp `xorm:"created"`
Updated timeutil.TimeStamp `xorm:"updated"`
}
func (*ActionRunAttempt) TableName() string {
return "action_run_attempt"
}
func init() {
db.RegisterModel(new(ActionRunAttempt))
}
func (attempt *ActionRunAttempt) Duration() time.Duration {
return calculateDuration(attempt.Started, attempt.Stopped, attempt.Status, attempt.Updated)
}
func (attempt *ActionRunAttempt) LoadAttributes(ctx context.Context) (err error) {
if attempt == nil {
return nil
}
if attempt.Run == nil {
run, err := GetRunByRepoAndID(ctx, attempt.RepoID, attempt.RunID)
if err != nil {
return err
}
if err := run.LoadAttributes(ctx); err != nil {
return err
}
attempt.Run = run
}
if attempt.TriggerUser == nil {
attempt.TriggerUserID, attempt.TriggerUser, err = user_model.GetPossibleUserByID(ctx, attempt.TriggerUserID)
if err != nil {
return err
}
}
return nil
}
func GetRunAttemptByRepoAndID(ctx context.Context, repoID, attemptID int64) (*ActionRunAttempt, error) {
var attempt ActionRunAttempt
has, err := db.GetEngine(ctx).Where("repo_id=? AND id=?", repoID, attemptID).Get(&attempt)
if err != nil {
return nil, err
} else if !has {
return nil, fmt.Errorf("run attempt %d in repo %d: %w", attemptID, repoID, util.ErrNotExist)
}
return &attempt, nil
}
func GetRunAttemptByRunIDAndAttemptNum(ctx context.Context, runID, attemptNum int64) (*ActionRunAttempt, error) {
var attempt ActionRunAttempt
has, err := db.GetEngine(ctx).Where("run_id=? AND attempt=?", runID, attemptNum).Get(&attempt)
if err != nil {
return nil, err
} else if !has {
return nil, fmt.Errorf("run attempt %d for run %d: %w", attemptNum, runID, util.ErrNotExist)
}
return &attempt, nil
}
// FindConcurrentRunAttempts returns attempts in the given concurrency group and status set.
// Results are unordered; callers must not depend on any particular row order.
func FindConcurrentRunAttempts(ctx context.Context, repoID int64, concurrencyGroup string, statuses []Status) ([]*ActionRunAttempt, error) {
attempts := make([]*ActionRunAttempt, 0)
sess := db.GetEngine(ctx).Where("repo_id=? AND concurrency_group=?", repoID, concurrencyGroup)
if len(statuses) > 0 {
sess = sess.In("status", statuses)
}
return attempts, sess.Find(&attempts)
}
func UpdateRunAttempt(ctx context.Context, attempt *ActionRunAttempt, cols ...string) error {
if slices.Contains(cols, "status") && attempt.Started.IsZero() && attempt.Status.IsRunning() {
attempt.Started = timeutil.TimeStampNow()
cols = append(cols, "started")
}
sess := db.GetEngine(ctx).ID(attempt.ID)
if len(cols) > 0 {
sess.Cols(cols...)
}
if _, err := sess.Update(attempt); err != nil {
return err
}
// Only status/timing changes on an attempt need to update the latest run.
if len(cols) > 0 && !slices.Contains(cols, "status") && !slices.Contains(cols, "started") && !slices.Contains(cols, "stopped") {
return nil
}
run, err := GetRunByRepoAndID(ctx, attempt.RepoID, attempt.RunID)
if err != nil {
return err
}
if run.LatestAttemptID != attempt.ID {
log.Warn("run %d cannot be updated by an old attempt %d", run.LatestAttemptID, attempt.ID)
return nil
}
run.Status = attempt.Status
run.Started = attempt.Started
run.Stopped = attempt.Stopped
return UpdateRun(ctx, run, "status", "started", "stopped")
}

View File

@@ -0,0 +1,46 @@
// Copyright 2026 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package actions
import (
"context"
"code.gitea.io/gitea/models/db"
user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/container"
)
type ActionRunAttemptList []*ActionRunAttempt
// GetUserIDs returns a slice of user's id
func (attempts ActionRunAttemptList) GetUserIDs() []int64 {
return container.FilterSlice(attempts, func(attempt *ActionRunAttempt) (int64, bool) {
return attempt.TriggerUserID, true
})
}
func (attempts ActionRunAttemptList) LoadTriggerUser(ctx context.Context) error {
userIDs := attempts.GetUserIDs()
users := make(map[int64]*user_model.User, len(userIDs))
if err := db.GetEngine(ctx).In("id", userIDs).Find(&users); err != nil {
return err
}
for _, attempt := range attempts {
if attempt.TriggerUserID == user_model.ActionsUserID {
attempt.TriggerUser = user_model.NewActionsUser()
} else {
attempt.TriggerUser = users[attempt.TriggerUserID]
if attempt.TriggerUser == nil {
attempt.TriggerUser = user_model.NewGhostUser()
}
}
}
return nil
}
// ListRunAttemptsByRunID returns all attempts of a run, ordered by attempt number DESC (newest first).
func ListRunAttemptsByRunID(ctx context.Context, runID int64) (ActionRunAttemptList, error) {
var attempts ActionRunAttemptList
return attempts, db.GetEngine(ctx).Where("run_id=?", runID).OrderBy("attempt DESC").Find(&attempts)
}

View File

@@ -34,7 +34,10 @@ type ActionRunJob struct {
CommitSHA string `xorm:"index"` CommitSHA string `xorm:"index"`
IsForkPullRequest bool IsForkPullRequest bool
Name string `xorm:"VARCHAR(255)"` Name string `xorm:"VARCHAR(255)"`
Attempt int64
// for legacy jobs, this counts how many times the job has run;
// otherwise it matches the Attempt of the ActionRunAttempt identified by job.RunAttemptID
Attempt int64
// WorkflowPayload is act/jobparser.SingleWorkflow for act/jobparser.Parse // WorkflowPayload is act/jobparser.SingleWorkflow for act/jobparser.Parse
// it should contain exactly one job with global workflow fields for this model // it should contain exactly one job with global workflow fields for this model
@@ -43,8 +46,11 @@ type ActionRunJob struct {
JobID string `xorm:"VARCHAR(255)"` // job id in workflow, not job's id JobID string `xorm:"VARCHAR(255)"` // job id in workflow, not job's id
Needs []string `xorm:"JSON TEXT"` Needs []string `xorm:"JSON TEXT"`
RunsOn []string `xorm:"JSON TEXT"` RunsOn []string `xorm:"JSON TEXT"`
TaskID int64 // the latest task of the job
Status Status `xorm:"index"` TaskID int64 // the task created by this job in its own attempt
SourceTaskID int64 `xorm:"NOT NULL DEFAULT 0"` // SourceTaskID points to a historical task when this job reuses an earlier attempt's result.
Status Status `xorm:"index"`
RawConcurrency string // raw concurrency from job YAML's "concurrency" section RawConcurrency string // raw concurrency from job YAML's "concurrency" section
@@ -61,6 +67,14 @@ type ActionRunJob struct {
// It is JSON-encoded repo_model.ActionsTokenPermissions and may be empty if not specified. // It is JSON-encoded repo_model.ActionsTokenPermissions and may be empty if not specified.
TokenPermissions *repo_model.ActionsTokenPermissions `xorm:"JSON TEXT"` TokenPermissions *repo_model.ActionsTokenPermissions `xorm:"JSON TEXT"`
// RunAttemptID identifies the ActionRunAttempt this job belongs to.
// A value of 0 indicates a legacy job created before ActionRunAttempt existed.
RunAttemptID int64 `xorm:"index NOT NULL DEFAULT 0"`
// AttemptJobID is unique within a single attempt.
// For jobs created after ActionRunAttempt was introduced, the same logical job is expected to keep the same AttemptJobID across attempts.
// A value of 0 indicates a legacy job created before ActionRunAttempt existed.
AttemptJobID int64 `xorm:"index NOT NULL DEFAULT 0"`
Started timeutil.TimeStamp Started timeutil.TimeStamp
Stopped timeutil.TimeStamp Stopped timeutil.TimeStamp
Created timeutil.TimeStamp `xorm:"created"` Created timeutil.TimeStamp `xorm:"created"`
@@ -75,6 +89,13 @@ func (job *ActionRunJob) Duration() time.Duration {
return calculateDuration(job.Started, job.Stopped, job.Status, job.Updated) return calculateDuration(job.Started, job.Stopped, job.Status, job.Updated)
} }
func (job *ActionRunJob) EffectiveTaskID() int64 {
if job.TaskID > 0 {
return job.TaskID
}
return job.SourceTaskID
}
func (job *ActionRunJob) LoadRun(ctx context.Context) error { func (job *ActionRunJob) LoadRun(ctx context.Context) error {
if job.Run == nil { if job.Run == nil {
run, err := GetRunByRepoAndID(ctx, job.RepoID, job.RunID) run, err := GetRunByRepoAndID(ctx, job.RepoID, job.RunID)
@@ -152,9 +173,50 @@ func GetRunJobByRunAndID(ctx context.Context, runID, jobID int64) (*ActionRunJob
return &job, nil return &job, nil
} }
func GetRunJobsByRunID(ctx context.Context, runID int64) (ActionJobList, error) { func GetRunJobByAttemptJobID(ctx context.Context, runID, attemptID, attemptJobID int64) (*ActionRunJob, error) {
var job ActionRunJob
has, err := db.GetEngine(ctx).Where("run_id=? AND run_attempt_id=? AND attempt_job_id=?", runID, attemptID, attemptJobID).Get(&job)
if err != nil {
return nil, err
} else if !has {
return nil, fmt.Errorf("run job with attempt_job_id %d in run %d attempt %d: %w", attemptJobID, runID, attemptID, util.ErrNotExist)
}
return &job, nil
}
// GetLatestAttemptJobsByRepoAndRunID returns the jobs of the latest attempt for a run.
// It prefers the latest attempt when one exists, and falls back to legacy jobs with run_attempt_id=0 for runs created before ActionRunAttempt existed.
func GetLatestAttemptJobsByRepoAndRunID(ctx context.Context, repoID, runID int64) (ActionJobList, error) {
run, err := GetRunByRepoAndID(ctx, repoID, runID)
if err != nil {
return nil, err
}
if run.LatestAttemptID > 0 {
return GetRunJobsByRunAndAttemptID(ctx, runID, run.LatestAttemptID)
}
var jobs []*ActionRunJob var jobs []*ActionRunJob
if err := db.GetEngine(ctx).Where("run_id=?", runID).OrderBy("id").Find(&jobs); err != nil { if err := db.GetEngine(ctx).Where("repo_id=? AND run_id=? AND run_attempt_id=0", repoID, runID).OrderBy("id").Find(&jobs); err != nil {
return nil, err
}
return jobs, nil
}
// GetAllRunJobsByRepoAndRunID returns all jobs for a run across all attempts.
func GetAllRunJobsByRepoAndRunID(ctx context.Context, repoID, runID int64) (ActionJobList, error) {
var jobs []*ActionRunJob
if err := db.GetEngine(ctx).Where("repo_id=? AND run_id=?", repoID, runID).OrderBy("id").Find(&jobs); err != nil {
return nil, err
}
return jobs, nil
}
// GetRunJobsByRunAndAttemptID returns jobs for a run within a specific attempt.
// runAttemptID may be 0 to address legacy jobs that were created before ActionRunAttempt existed and therefore have no attempt association.
func GetRunJobsByRunAndAttemptID(ctx context.Context, runID, runAttemptID int64) (ActionJobList, error) {
var jobs []*ActionRunJob
if err := db.GetEngine(ctx).Where("run_id=? AND run_attempt_id=?", runID, runAttemptID).OrderBy("id").Find(&jobs); err != nil {
return nil, err return nil, err
} }
return jobs, nil return jobs, nil
@@ -196,25 +258,51 @@ func UpdateRunJob(ctx context.Context, job *ActionRunJob, cond builder.Cond, col
} }
{ {
// Other goroutines may aggregate the status of the run and update it too. // Other goroutines may aggregate the status of the attempt/run and update it too.
// So we need load the run and its jobs before updating the run. // So we need to load the current jobs before updating the aggregate state.
run, err := GetRunByRepoAndID(ctx, job.RepoID, job.RunID) if job.RunAttemptID > 0 {
if err != nil { attempt, err := GetRunAttemptByRepoAndID(ctx, job.RepoID, job.RunAttemptID)
return 0, err if err != nil {
} return 0, err
jobs, err := GetRunJobsByRunID(ctx, job.RunID) }
if err != nil { jobs, err := GetRunJobsByRunAndAttemptID(ctx, job.RunID, job.RunAttemptID)
return 0, err if err != nil {
} return 0, err
run.Status = AggregateJobStatus(jobs) }
if run.Started.IsZero() && run.Status.IsRunning() { attempt.Status = AggregateJobStatus(jobs)
run.Started = timeutil.TimeStampNow() if attempt.Started.IsZero() && attempt.Status.IsRunning() {
} attempt.Started = timeutil.TimeStampNow()
if run.Stopped.IsZero() && run.Status.IsDone() { }
run.Stopped = timeutil.TimeStampNow() if attempt.Stopped.IsZero() && attempt.Status.IsDone() {
} attempt.Stopped = timeutil.TimeStampNow()
if err := UpdateRun(ctx, run, "status", "started", "stopped"); err != nil { }
return 0, fmt.Errorf("update run %d: %w", run.ID, err) if err := UpdateRunAttempt(ctx, attempt, "status", "started", "stopped"); err != nil {
return 0, fmt.Errorf("update run attempt %d: %w", attempt.ID, err)
}
} else {
// TODO: Remove this fallback in the future.
// Legacy fallback: jobs created before migration v331 have RunAttemptID=0 and are NOT backfilled.
// This path keeps those runs' status consistent when their jobs finish, including:
// - jobs created before migration v331 and complete on the new version starts
// - zombie/abandoned cleanup cron tasks that call UpdateRunJob on legacy jobs
run, err := GetRunByRepoAndID(ctx, job.RepoID, job.RunID)
if err != nil {
return 0, err
}
jobs, err := GetLatestAttemptJobsByRepoAndRunID(ctx, job.RepoID, job.RunID)
if err != nil {
return 0, err
}
run.Status = AggregateJobStatus(jobs)
if run.Started.IsZero() && run.Status.IsRunning() {
run.Started = timeutil.TimeStampNow()
}
if run.Stopped.IsZero() && run.Status.IsDone() {
run.Stopped = timeutil.TimeStampNow()
}
if err := UpdateRun(ctx, run, "status", "started", "stopped"); err != nil {
return 0, fmt.Errorf("update run %d: %w", run.ID, err)
}
} }
} }
@@ -269,7 +357,7 @@ func CancelPreviousJobsByJobConcurrency(ctx context.Context, job *ActionRunJob)
if job.ConcurrencyCancel { if job.ConcurrencyCancel {
statusFindOption = append(statusFindOption, StatusRunning) statusFindOption = append(statusFindOption, StatusRunning)
} }
runs, jobs, err := GetConcurrentRunsAndJobs(ctx, job.RepoID, job.ConcurrencyGroup, statusFindOption) attempts, jobs, err := GetConcurrentRunAttemptsAndJobs(ctx, job.RepoID, job.ConcurrencyGroup, statusFindOption)
if err != nil { if err != nil {
return nil, fmt.Errorf("find concurrent runs and jobs: %w", err) return nil, fmt.Errorf("find concurrent runs and jobs: %w", err)
} }
@@ -277,12 +365,13 @@ func CancelPreviousJobsByJobConcurrency(ctx context.Context, job *ActionRunJob)
jobsToCancel = append(jobsToCancel, jobs...) jobsToCancel = append(jobsToCancel, jobs...)
// cancel runs in the same concurrency group // cancel runs in the same concurrency group
for _, run := range runs { for _, attempt := range attempts {
jobs, err := db.Find[ActionRunJob](ctx, FindRunJobOptions{ if attempt.ID == job.RunAttemptID {
RunID: run.ID, continue
}) }
jobs, err := GetRunJobsByRunAndAttemptID(ctx, attempt.RunID, attempt.ID)
if err != nil { if err != nil {
return nil, fmt.Errorf("find run %d jobs: %w", run.ID, err) return nil, fmt.Errorf("find run %d attempt %d jobs: %w", attempt.RunID, attempt.ID, err)
} }
jobsToCancel = append(jobsToCancel, jobs...) jobsToCancel = append(jobsToCancel, jobs...)
} }

View File

@@ -9,6 +9,7 @@ import (
"code.gitea.io/gitea/models/db" "code.gitea.io/gitea/models/db"
repo_model "code.gitea.io/gitea/models/repo" repo_model "code.gitea.io/gitea/models/repo"
"code.gitea.io/gitea/modules/container" "code.gitea.io/gitea/modules/container"
"code.gitea.io/gitea/modules/optional"
"code.gitea.io/gitea/modules/timeutil" "code.gitea.io/gitea/modules/timeutil"
"xorm.io/builder" "xorm.io/builder"
@@ -70,6 +71,7 @@ func (jobs ActionJobList) LoadAttributes(ctx context.Context, withRepo bool) err
type FindRunJobOptions struct { type FindRunJobOptions struct {
db.ListOptions db.ListOptions
RunID int64 RunID int64
RunAttemptID optional.Option[int64] // use optional to allow filtering by zero (legacy jobs have run_attempt_id=0)
RepoID int64 RepoID int64
OwnerID int64 OwnerID int64
CommitSHA string CommitSHA string
@@ -83,6 +85,9 @@ func (opts FindRunJobOptions) ToConds() builder.Cond {
if opts.RunID > 0 { if opts.RunID > 0 {
cond = cond.And(builder.Eq{"`action_run_job`.run_id": opts.RunID}) cond = cond.And(builder.Eq{"`action_run_job`.run_id": opts.RunID})
} }
if opts.RunAttemptID.Has() {
cond = cond.And(builder.Eq{"`action_run_job`.run_attempt_id": opts.RunAttemptID.Value()})
}
if opts.RepoID > 0 { if opts.RepoID > 0 {
cond = cond.And(builder.Eq{"`action_run_job`.repo_id": opts.RepoID}) cond = cond.And(builder.Eq{"`action_run_job`.repo_id": opts.RepoID})
} }

View File

@@ -7,7 +7,6 @@ import (
"context" "context"
"code.gitea.io/gitea/models/db" "code.gitea.io/gitea/models/db"
repo_model "code.gitea.io/gitea/models/repo"
user_model "code.gitea.io/gitea/models/user" user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/container" "code.gitea.io/gitea/modules/container"
"code.gitea.io/gitea/modules/translation" "code.gitea.io/gitea/modules/translation"
@@ -25,12 +24,6 @@ func (runs RunList) GetUserIDs() []int64 {
}) })
} }
func (runs RunList) GetRepoIDs() []int64 {
return container.FilterSlice(runs, func(run *ActionRun) (int64, bool) {
return run.RepoID, true
})
}
func (runs RunList) LoadTriggerUser(ctx context.Context) error { func (runs RunList) LoadTriggerUser(ctx context.Context) error {
userIDs := runs.GetUserIDs() userIDs := runs.GetUserIDs()
users := make(map[int64]*user_model.User, len(userIDs)) users := make(map[int64]*user_model.User, len(userIDs))
@@ -50,18 +43,6 @@ func (runs RunList) LoadTriggerUser(ctx context.Context) error {
return nil return nil
} }
func (runs RunList) LoadRepos(ctx context.Context) error {
repoIDs := runs.GetRepoIDs()
repos, err := repo_model.GetRepositoriesMapByIDs(ctx, repoIDs)
if err != nil {
return err
}
for _, run := range runs {
run.Repo = repos[run.RepoID]
}
return nil
}
type FindRunOptions struct { type FindRunOptions struct {
db.ListOptions db.ListOptions
RepoID int64 RepoID int64
@@ -102,12 +83,6 @@ func (opts FindRunOptions) ToConds() builder.Cond {
if opts.CommitSHA != "" { if opts.CommitSHA != "" {
cond = cond.And(builder.Eq{"`action_run`.commit_sha": opts.CommitSHA}) cond = cond.And(builder.Eq{"`action_run`.commit_sha": opts.CommitSHA})
} }
if len(opts.ConcurrencyGroup) > 0 {
if opts.RepoID == 0 {
panic("Invalid FindRunOptions: repo_id is required")
}
cond = cond.And(builder.Eq{"`action_run`.concurrency_group": opts.ConcurrencyGroup})
}
return cond return cond
} }

View File

@@ -32,7 +32,7 @@ func TestUpdateRepoRunsNumbers(t *testing.T) {
err = UpdateRepoRunsNumbers(t.Context(), repo) err = UpdateRepoRunsNumbers(t.Context(), repo)
assert.NoError(t, err) assert.NoError(t, err)
repo = unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 4}) repo = unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 4})
assert.Equal(t, 5, repo.NumActionRuns) assert.Equal(t, 4, repo.NumActionRuns)
assert.Equal(t, 3, repo.NumClosedActionRuns) assert.Equal(t, 3, repo.NumClosedActionRuns)
} }

View File

@@ -171,9 +171,8 @@ func (r *ActionRunner) LoadAttributes(ctx context.Context) error {
return nil return nil
} }
func (r *ActionRunner) GenerateToken() (err error) { func (r *ActionRunner) GenerateAndFillToken() {
r.Token, r.TokenSalt, r.TokenHash, _, err = generateSaltedToken() r.Token, r.TokenSalt, r.TokenHash, _ = generateSaltedToken()
return err
} }
// CanMatchLabels checks whether the runner's labels can match a job's "runs-on" // CanMatchLabels checks whether the runner's labels can match a job's "runs-on"

View File

@@ -97,10 +97,7 @@ func NewRunnerTokenWithValue(ctx context.Context, ownerID, repoID int64, token s
} }
func NewRunnerToken(ctx context.Context, ownerID, repoID int64) (*ActionRunnerToken, error) { func NewRunnerToken(ctx context.Context, ownerID, repoID int64) (*ActionRunnerToken, error) {
token, err := util.CryptoRandomString(40) token := util.CryptoRandomString(40)
if err != nil {
return nil, err
}
return NewRunnerTokenWithValue(ctx, ownerID, repoID, token) return NewRunnerTokenWithValue(ctx, ownerID, repoID, token)
} }

View File

@@ -4,62 +4,13 @@
package actions package actions
import ( import (
"context"
"code.gitea.io/gitea/models/db" "code.gitea.io/gitea/models/db"
repo_model "code.gitea.io/gitea/models/repo"
user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/container"
"xorm.io/builder" "xorm.io/builder"
) )
type ScheduleList []*ActionSchedule type ScheduleList []*ActionSchedule
// GetUserIDs returns a slice of user's id
func (schedules ScheduleList) GetUserIDs() []int64 {
return container.FilterSlice(schedules, func(schedule *ActionSchedule) (int64, bool) {
return schedule.TriggerUserID, true
})
}
func (schedules ScheduleList) GetRepoIDs() []int64 {
return container.FilterSlice(schedules, func(schedule *ActionSchedule) (int64, bool) {
return schedule.RepoID, true
})
}
func (schedules ScheduleList) LoadTriggerUser(ctx context.Context) error {
userIDs := schedules.GetUserIDs()
users := make(map[int64]*user_model.User, len(userIDs))
if err := db.GetEngine(ctx).In("id", userIDs).Find(&users); err != nil {
return err
}
for _, schedule := range schedules {
if schedule.TriggerUserID == user_model.ActionsUserID {
schedule.TriggerUser = user_model.NewActionsUser()
} else {
schedule.TriggerUser = users[schedule.TriggerUserID]
if schedule.TriggerUser == nil {
schedule.TriggerUser = user_model.NewGhostUser()
}
}
}
return nil
}
func (schedules ScheduleList) LoadRepos(ctx context.Context) error {
repoIDs := schedules.GetRepoIDs()
repos, err := repo_model.GetRepositoriesMapByIDs(ctx, repoIDs)
if err != nil {
return err
}
for _, schedule := range schedules {
schedule.Repo = repos[schedule.RepoID]
}
return nil
}
type FindScheduleOptions struct { type FindScheduleOptions struct {
db.ListOptions db.ListOptions
RepoID int64 RepoID int64

View File

@@ -147,9 +147,8 @@ func (task *ActionTask) LoadAttributes(ctx context.Context) error {
return nil return nil
} }
func (task *ActionTask) GenerateToken() (err error) { func (task *ActionTask) GenerateAndFillToken() {
task.Token, task.TokenSalt, task.TokenHash, task.TokenLastEight, err = generateSaltedToken() task.Token, task.TokenSalt, task.TokenHash, task.TokenLastEight = generateSaltedToken()
return err
} }
func GetTaskByID(ctx context.Context, id int64) (*ActionTask, error) { func GetTaskByID(ctx context.Context, id int64) (*ActionTask, error) {
@@ -273,7 +272,6 @@ func CreateTaskForRunner(ctx context.Context, runner *ActionRunner) (*ActionTask
} }
now := timeutil.TimeStampNow() now := timeutil.TimeStampNow()
job.Attempt++
job.Started = now job.Started = now
job.Status = StatusRunning job.Status = StatusRunning
@@ -288,9 +286,7 @@ func CreateTaskForRunner(ctx context.Context, runner *ActionRunner) (*ActionTask
CommitSHA: job.CommitSHA, CommitSHA: job.CommitSHA,
IsForkPullRequest: job.IsForkPullRequest, IsForkPullRequest: job.IsForkPullRequest,
} }
if err := task.GenerateToken(); err != nil { task.GenerateAndFillToken()
return nil, false, err
}
workflowJob, err := job.ParseJob() workflowJob, err := job.ParseJob()
if err != nil { if err != nil {

View File

@@ -18,18 +18,12 @@ import (
"code.gitea.io/gitea/modules/util" "code.gitea.io/gitea/modules/util"
) )
func generateSaltedToken() (string, string, string, string, error) { func generateSaltedToken() (string, string, string, string) {
salt, err := util.CryptoRandomString(10) salt := util.CryptoRandomString(10)
if err != nil { buf := util.CryptoRandomBytes(20)
return "", "", "", "", err
}
buf, err := util.CryptoRandomBytes(20)
if err != nil {
return "", "", "", "", err
}
token := hex.EncodeToString(buf) token := hex.EncodeToString(buf)
hash := auth_model.HashToken(token, salt) hash := auth_model.HashToken(token, salt)
return token, salt, hash, token[len(token)-8:], nil return token, salt, hash, token[len(token)-8:]
} }
/* /*

View File

@@ -186,15 +186,7 @@ func (a *Action) LoadActUser(ctx context.Context) {
if a.ActUser != nil { if a.ActUser != nil {
return return
} }
var err error a.ActUserID, a.ActUser, _ = user_model.GetPossibleUserByID(ctx, a.ActUserID)
a.ActUser, err = user_model.GetPossibleUserByID(ctx, a.ActUserID)
if err == nil {
return
} else if user_model.IsErrUserNotExist(err) {
a.ActUser = user_model.NewGhostUser()
} else {
log.Error("GetUserByID(%d): %v", a.ActUserID, err)
}
} }
func (a *Action) LoadRepo(ctx context.Context) error { func (a *Action) LoadRepo(ctx context.Context) error {

View File

@@ -282,9 +282,3 @@ func GetFeeds(ctx context.Context, opts GetFeedsOptions) (ActionList, int64, err
return actions, count, nil return actions, count, nil
} }
func CountUserFeeds(ctx context.Context, userID int64) (int64, error) {
return db.GetEngine(ctx).Where("user_id = ?", userID).
And("is_deleted = ?", false).
Count(&Action{})
}

View File

@@ -62,6 +62,7 @@ func getUserHeatmapData(ctx context.Context, user *user_model.User, team *organi
return nil, err return nil, err
} }
// HINT: USER-ACTIVITY-PUSH-COMMITS: it only uses the doer's action time, it doesn't use git commit's time
return hdata, db.GetEngine(ctx). return hdata, db.GetEngine(ctx).
Select(groupBy+" AS timestamp, count(user_id) as contributions"). Select(groupBy+" AS timestamp, count(user_id) as contributions").
Table("action"). Table("action").

View File

@@ -192,28 +192,6 @@ func (err ErrGPGKeyIDAlreadyUsed) Unwrap() error {
return util.ErrAlreadyExist return util.ErrAlreadyExist
} }
// ErrGPGKeyAccessDenied represents a "GPGKeyAccessDenied" kind of Error.
type ErrGPGKeyAccessDenied struct {
UserID int64
KeyID int64
}
// IsErrGPGKeyAccessDenied checks if an error is a ErrGPGKeyAccessDenied.
func IsErrGPGKeyAccessDenied(err error) bool {
_, ok := err.(ErrGPGKeyAccessDenied)
return ok
}
// Error pretty-prints an error of type ErrGPGKeyAccessDenied.
func (err ErrGPGKeyAccessDenied) Error() string {
return fmt.Sprintf("user does not have access to the key [user_id: %d, key_id: %d]",
err.UserID, err.KeyID)
}
func (err ErrGPGKeyAccessDenied) Unwrap() error {
return util.ErrPermissionDenied
}
// ErrKeyAccessDenied represents a "KeyAccessDenied" kind of error. // ErrKeyAccessDenied represents a "KeyAccessDenied" kind of error.
type ErrKeyAccessDenied struct { type ErrKeyAccessDenied struct {
UserID int64 UserID int64

View File

@@ -15,6 +15,7 @@ import (
"code.gitea.io/gitea/models/perm" "code.gitea.io/gitea/models/perm"
user_model "code.gitea.io/gitea/models/user" user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/timeutil" "code.gitea.io/gitea/modules/timeutil"
"code.gitea.io/gitea/modules/util" "code.gitea.io/gitea/modules/util"
@@ -64,7 +65,12 @@ func (key *PublicKey) AfterLoad() {
// OmitEmail returns content of public key without email address. // OmitEmail returns content of public key without email address.
func (key *PublicKey) OmitEmail() string { func (key *PublicKey) OmitEmail() string {
return strings.Join(strings.Split(key.Content, " ")[:2], " ") fields := strings.Split(key.Content, " ") // format: ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC... comment
if len(fields) < 2 {
setting.PanicInDevOrTesting("invalid public key %d content: %s", key.ID, key.Content)
return "" // not a valid public key, it shouldn't really happen, the value is managed internally
}
return strings.Join(fields[:2], " ")
} }
func addKey(ctx context.Context, key *PublicKey) (err error) { func addKey(ctx context.Context, key *PublicKey) (err error) {

View File

@@ -105,14 +105,6 @@ func addDeployKey(ctx context.Context, keyID, repoID int64, name, fingerprint st
return key, db.Insert(ctx, key) return key, db.Insert(ctx, key)
} }
// HasDeployKey returns true if public key is a deploy key of given repository.
func HasDeployKey(ctx context.Context, keyID, repoID int64) bool {
has, _ := db.GetEngine(ctx).
Where("key_id = ? AND repo_id = ?", keyID, repoID).
Get(new(DeployKey))
return has
}
// AddDeployKey add new deploy key to database and authorized_keys file. // AddDeployKey add new deploy key to database and authorized_keys file.
func AddDeployKey(ctx context.Context, repoID int64, name, content string, readOnly bool) (*DeployKey, error) { func AddDeployKey(ctx context.Context, repoID int64, name, content string, readOnly bool) (*DeployKey, error) {
fingerprint, err := CalcFingerprint(content) fingerprint, err := CalcFingerprint(content)

View File

@@ -98,19 +98,13 @@ func init() {
// NewAccessToken creates new access token. // NewAccessToken creates new access token.
func NewAccessToken(ctx context.Context, t *AccessToken) error { func NewAccessToken(ctx context.Context, t *AccessToken) error {
salt, err := util.CryptoRandomString(10) salt := util.CryptoRandomString(10)
if err != nil { token := util.CryptoRandomBytes(20)
return err
}
token, err := util.CryptoRandomBytes(20)
if err != nil {
return err
}
t.TokenSalt = salt t.TokenSalt = salt
t.Token = hex.EncodeToString(token) t.Token = hex.EncodeToString(token)
t.TokenHash = HashToken(t.Token, t.TokenSalt) t.TokenHash = HashToken(t.Token, t.TokenSalt)
t.TokenLastEight = t.Token[len(t.Token)-8:] t.TokenLastEight = t.Token[len(t.Token)-8:]
_, err = db.GetEngine(ctx).Insert(t) _, err := db.GetEngine(ctx).Insert(t)
return err return err
} }

View File

@@ -185,10 +185,7 @@ var base32Lower = base32.NewEncoding(lowerBase32Chars).WithPadding(base32.NoPadd
// GenerateClientSecret will generate the client secret and returns the plaintext and saves the hash at the database // GenerateClientSecret will generate the client secret and returns the plaintext and saves the hash at the database
func (app *OAuth2Application) GenerateClientSecret(ctx context.Context) (string, error) { func (app *OAuth2Application) GenerateClientSecret(ctx context.Context) (string, error) {
rBytes, err := util.CryptoRandomBytes(32) rBytes := util.CryptoRandomBytes(32)
if err != nil {
return "", err
}
// Add a prefix to the base32, this is in order to make it easier // Add a prefix to the base32, this is in order to make it easier
// for code scanners to grab sensitive tokens. // for code scanners to grab sensitive tokens.
clientSecret := "gto_" + base32Lower.EncodeToString(rBytes) clientSecret := "gto_" + base32Lower.EncodeToString(rBytes)
@@ -220,7 +217,7 @@ func (app *OAuth2Application) GetGrantByUserID(ctx context.Context, userID int64
return grant, nil return grant, nil
} }
// CreateGrant generates a grant for an user // CreateGrant generates a grant for a user
func (app *OAuth2Application) CreateGrant(ctx context.Context, userID int64, scope string) (*OAuth2Grant, error) { func (app *OAuth2Application) CreateGrant(ctx context.Context, userID int64, scope string) (*OAuth2Grant, error) {
grant := &OAuth2Grant{ grant := &OAuth2Grant{
ApplicationID: app.ID, ApplicationID: app.ID,
@@ -464,7 +461,7 @@ func GetOAuth2AuthorizationByCode(ctx context.Context, code string) (auth *OAuth
////////////////////////////////////////////////////// //////////////////////////////////////////////////////
// OAuth2Grant represents the permission of an user for a specific application to access resources // OAuth2Grant represents the permission of a user for a specific application to access resources
type OAuth2Grant struct { type OAuth2Grant struct {
ID int64 `xorm:"pk autoincr"` ID int64 `xorm:"pk autoincr"`
UserID int64 `xorm:"INDEX unique(user_application)"` UserID int64 `xorm:"INDEX unique(user_application)"`
@@ -484,10 +481,7 @@ func (grant *OAuth2Grant) TableName() string {
// GenerateNewAuthorizationCode generates a new authorization code for a grant and saves it to the database // GenerateNewAuthorizationCode generates a new authorization code for a grant and saves it to the database
func (grant *OAuth2Grant) GenerateNewAuthorizationCode(ctx context.Context, redirectURI, codeChallenge, codeChallengeMethod string) (code *OAuth2AuthorizationCode, err error) { func (grant *OAuth2Grant) GenerateNewAuthorizationCode(ctx context.Context, redirectURI, codeChallenge, codeChallengeMethod string) (code *OAuth2AuthorizationCode, err error) {
rBytes, err := util.CryptoRandomBytes(32) rBytes := util.CryptoRandomBytes(32)
if err != nil {
return &OAuth2AuthorizationCode{}, err
}
// Add a prefix to the base32, this is in order to make it easier // Add a prefix to the base32, this is in order to make it easier
// for code scanners to grab sensitive tokens. // for code scanners to grab sensitive tokens.
codeSecret := "gta_" + base32Lower.EncodeToString(rBytes) codeSecret := "gta_" + base32Lower.EncodeToString(rBytes)
@@ -633,7 +627,7 @@ func GetActiveOAuth2SourceByAuthName(ctx context.Context, name string) (*Source,
} }
if !has { if !has {
return nil, fmt.Errorf("oauth2 source not found, name: %q", name) return nil, util.NewNotExistErrorf("oauth2 source not found, name: %q", name)
} }
return authSource, nil return authSource, nil

View File

@@ -12,19 +12,30 @@ import (
"code.gitea.io/gitea/modules/timeutil" "code.gitea.io/gitea/modules/timeutil"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
) )
func TestOAuth2AuthorizationCodeValidity(t *testing.T) { func TestOAuth2AuthorizationCode(t *testing.T) {
assert.NoError(t, unittest.PrepareTestDatabase()) require.NoError(t, unittest.PrepareTestDatabase())
t.Run("GenerateSetsValidUntil", func(t *testing.T) { t.Run("GenerateSetsValidUntil", func(t *testing.T) {
grant := unittest.AssertExistsAndLoadBean(t, &auth_model.OAuth2Grant{ID: 1}) grant := unittest.AssertExistsAndLoadBean(t, &auth_model.OAuth2Grant{ID: 1})
expectedValidUntil := timeutil.TimeStamp(time.Now().Unix() + 600) expectedValidUntil := timeutil.TimeStamp(time.Now().Unix() + 600)
code, err := grant.GenerateNewAuthorizationCode(t.Context(), "http://127.0.0.1/", "", "") code, err := grant.GenerateNewAuthorizationCode(t.Context(), "http://127.0.0.1/", "", "")
assert.NoError(t, err) require.NoError(t, err)
assert.Equal(t, expectedValidUntil, code.ValidUntil) assert.Equal(t, expectedValidUntil, code.ValidUntil)
assert.False(t, code.IsExpired()) assert.False(t, code.IsExpired())
assert.Equal(t, int64(1), code.ID)
code2, err := auth_model.GetOAuth2AuthorizationByCode(t.Context(), code.Code)
require.NoError(t, err)
assert.Equal(t, code.Code, code2.Code)
assert.NoError(t, code.Invalidate(t.Context())) assert.NoError(t, code.Invalidate(t.Context()))
code, err = auth_model.GetOAuth2AuthorizationByCode(t.Context(), "does not exist")
require.NoError(t, err)
require.Nil(t, code)
}) })
t.Run("Expired", func(t *testing.T) { t.Run("Expired", func(t *testing.T) {
@@ -34,13 +45,14 @@ func TestOAuth2AuthorizationCodeValidity(t *testing.T) {
assert.True(t, code.IsExpired()) assert.True(t, code.IsExpired())
}) })
t.Run("InvalidateTwice", func(t *testing.T) { t.Run("Invalidate", func(t *testing.T) {
code, err := auth_model.GetOAuth2AuthorizationByCode(t.Context(), "authcode") grant := unittest.AssertExistsAndLoadBean(t, &auth_model.OAuth2Grant{ID: 1})
assert.NoError(t, err) code, err := grant.GenerateNewAuthorizationCode(t.Context(), "http://127.0.0.1/", "", "")
if assert.NotNil(t, code) { require.NoError(t, err)
assert.NoError(t, code.Invalidate(t.Context())) require.NotNil(t, code)
assert.ErrorIs(t, code.Invalidate(t.Context()), auth_model.ErrOAuth2AuthorizationCodeInvalidated) require.NoError(t, code.Invalidate(t.Context()))
} unittest.AssertNotExistsBean(t, &auth_model.OAuth2AuthorizationCode{Code: code.Code})
assert.ErrorIs(t, code.Invalidate(t.Context()), auth_model.ErrOAuth2AuthorizationCodeInvalidated)
}) })
} }
@@ -224,19 +236,6 @@ func TestRevokeOAuth2Grant(t *testing.T) {
//////////////////// Authorization Code //////////////////// Authorization Code
func TestGetOAuth2AuthorizationByCode(t *testing.T) {
assert.NoError(t, unittest.PrepareTestDatabase())
code, err := auth_model.GetOAuth2AuthorizationByCode(t.Context(), "authcode")
assert.NoError(t, err)
assert.NotNil(t, code)
assert.Equal(t, "authcode", code.Code)
assert.Equal(t, int64(1), code.ID)
code, err = auth_model.GetOAuth2AuthorizationByCode(t.Context(), "does not exist")
assert.NoError(t, err)
assert.Nil(t, code)
}
func TestOAuth2AuthorizationCode_ValidateCodeChallenge(t *testing.T) { func TestOAuth2AuthorizationCode_ValidateCodeChallenge(t *testing.T) {
// test plain // test plain
code := &auth_model.OAuth2AuthorizationCode{ code := &auth_model.OAuth2AuthorizationCode{
@@ -284,13 +283,6 @@ func TestOAuth2AuthorizationCode_GenerateRedirectURI(t *testing.T) {
assert.Equal(t, "https://example.com/callback?code=thecode", redirect.String()) assert.Equal(t, "https://example.com/callback?code=thecode", redirect.String())
} }
func TestOAuth2AuthorizationCode_Invalidate(t *testing.T) {
assert.NoError(t, unittest.PrepareTestDatabase())
code := unittest.AssertExistsAndLoadBean(t, &auth_model.OAuth2AuthorizationCode{Code: "authcode"})
assert.NoError(t, code.Invalidate(t.Context()))
unittest.AssertNotExistsBean(t, &auth_model.OAuth2AuthorizationCode{Code: "authcode"})
}
func TestOAuth2AuthorizationCode_TableName(t *testing.T) { func TestOAuth2AuthorizationCode_TableName(t *testing.T) {
assert.Equal(t, "oauth2_authorization_code", new(auth_model.OAuth2AuthorizationCode).TableName()) assert.Equal(t, "oauth2_authorization_code", new(auth_model.OAuth2AuthorizationCode).TableName())
} }

View File

@@ -65,14 +65,11 @@ func init() {
// GenerateScratchToken recreates the scratch token the user is using. // GenerateScratchToken recreates the scratch token the user is using.
func (t *TwoFactor) GenerateScratchToken() (string, error) { func (t *TwoFactor) GenerateScratchToken() (string, error) {
tokenBytes, err := util.CryptoRandomBytes(6) tokenBytes := util.CryptoRandomBytes(6)
if err != nil {
return "", err
}
// these chars are specially chosen, avoid ambiguous chars like `0`, `O`, `1`, `I`. // these chars are specially chosen, avoid ambiguous chars like `0`, `O`, `1`, `I`.
const base32Chars = "ABCDEFGHJKLMNPQRSTUVWXYZ23456789" const base32Chars = "ABCDEFGHJKLMNPQRSTUVWXYZ23456789"
token := base32.NewEncoding(base32Chars).WithPadding(base32.NoPadding).EncodeToString(tokenBytes) token := base32.NewEncoding(base32Chars).WithPadding(base32.NoPadding).EncodeToString(tokenBytes)
t.ScratchSalt, _ = util.CryptoRandomString(10) t.ScratchSalt = util.CryptoRandomString(10)
t.ScratchHash = HashToken(token, t.ScratchSalt) t.ScratchHash = HashToken(token, t.ScratchSalt)
return token, nil return token, nil
} }

View File

@@ -200,13 +200,3 @@ func DeleteCredential(ctx context.Context, id, userID int64) (bool, error) {
had, err := db.GetEngine(ctx).ID(id).Where("user_id = ?", userID).Delete(&WebAuthnCredential{}) had, err := db.GetEngine(ctx).ID(id).Where("user_id = ?", userID).Delete(&WebAuthnCredential{})
return had > 0, err return had > 0, err
} }
// WebAuthnCredentials implements the webauthn.User interface
func WebAuthnCredentials(ctx context.Context, userID int64) ([]webauthn.Credential, error) {
dbCreds, err := GetWebAuthnCredentialsByUID(ctx, userID)
if err != nil {
return nil, err
}
return dbCreds.ToCredentials(), nil
}

View File

@@ -11,11 +11,11 @@ import (
"reflect" "reflect"
"strings" "strings"
"xorm.io/xorm"
_ "github.com/go-sql-driver/mysql" // Needed for the MySQL driver _ "github.com/go-sql-driver/mysql" // Needed for the MySQL driver
_ "github.com/lib/pq" // Needed for the Postgresql driver _ "github.com/lib/pq" // Needed for the Postgresql driver
_ "github.com/microsoft/go-mssqldb" // Needed for the MSSQL driver _ "github.com/microsoft/go-mssqldb" // Needed for the MSSQL driver
"xorm.io/xorm"
) )
var ( var (

View File

@@ -177,3 +177,5 @@
user_id: 40 user_id: 40
repo_id: 1 repo_id: 1
mode: 2 mode: 2
# DO NOT add more test data in the fixtures, test case should prepare their own test data separately and clearly

View File

@@ -31,3 +31,5 @@
created_unix: 946687980 created_unix: 946687980
updated_unix: 946687980 updated_unix: 946687980
# commented out tokens so you can see what they are in plaintext # commented out tokens so you can see what they are in plaintext
# DO NOT add more test data in the fixtures, test case should prepare their own test data separately and clearly

View File

@@ -73,3 +73,5 @@
is_private: false is_private: false
created_unix: 1680454039 created_unix: 1680454039
content: '4|' # issueId 5 content: '4|' # issueId 5
# DO NOT add more test data in the fixtures, test case should prepare their own test data separately and clearly

View File

@@ -177,3 +177,5 @@
created_unix: 1730330775 created_unix: 1730330775
updated_unix: 1730330775 updated_unix: 1730330775
expired_unix: 1738106775 expired_unix: 1738106775
# DO NOT add more test data in the fixtures, test case should prepare their own test data separately and clearly

View File

@@ -89,7 +89,7 @@
ref: "refs/heads/test" ref: "refs/heads/test"
commit_sha: "c2d72f548424103f01ee1dc02889c1e2bff816b0" commit_sha: "c2d72f548424103f01ee1dc02889c1e2bff816b0"
event: "push" event: "push"
trigger_event: "push" trigger_event: "schedule"
is_fork_pull_request: 0 is_fork_pull_request: 0
status: 1 status: 1
started: 1683636528 started: 1683636528
@@ -140,23 +140,4 @@
need_approval: 0 need_approval: 0
approved_by: 0 approved_by: 0
- # DO NOT add more test data in the fixtures, test case should prepare their own test data separately and clearly
id: 805
title: "update actions"
repo_id: 4
owner_id: 1
workflow_id: "artifact.yaml"
index: 191
trigger_user_id: 1
ref: "refs/heads/master"
commit_sha: "c2d72f548424103f01ee1dc02889c1e2bff816b0"
event: "push"
trigger_event: "push"
is_fork_pull_request: 0
status: 5
started: 1683636528
stopped: 1683636626
created: 1683636108
updated: 1683636626
need_approval: 0
approved_by: 0

View File

@@ -130,17 +130,4 @@
started: 1683636528 started: 1683636528
stopped: 1683636626 stopped: 1683636626
- # DO NOT add more test data in the fixtures, test case should prepare their own test data separately and clearly
id: 206
run_id: 805
repo_id: 4
owner_id: 1
commit_sha: c2d72f548424103f01ee1dc02889c1e2bff816b0
is_fork_pull_request: 0
name: job_2
attempt: 1
job_id: job_2
task_id: 56
status: 3
started: 1683636528
stopped: 1683636626

View File

@@ -49,3 +49,5 @@
repo_id: 0 repo_id: 0
description: "This runner is going to be deleted" description: "This runner is going to be deleted"
agent_labels: '["runner_to_be_deleted","linux"]' agent_labels: '["runner_to_be_deleted","linux"]'
# DO NOT add more test data in the fixtures, test case should prepare their own test data separately and clearly

View File

@@ -33,3 +33,5 @@
is_active: 1 is_active: 1
created: 1695617751 created: 1695617751
updated: 1695617751 updated: 1695617751
# DO NOT add more test data in the fixtures, test case should prepare their own test data separately and clearly

View File

@@ -178,22 +178,4 @@
log_size: 0 log_size: 0
log_expired: 0 log_expired: 0
- # DO NOT add more test data in the fixtures, test case should prepare their own test data separately and clearly
id: 56
attempt: 1
runner_id: 1
status: 3 # 3 is the status code for "cancelled"
started: 1683636528
stopped: 1683636626
repo_id: 4
owner_id: 1
commit_sha: c2d72f548424103f01ee1dc02889c1e2bff816b0
is_fork_pull_request: 0
token_hash: 6d8ef48297195edcc8e22c70b3020eaa06c52976db67d39b4240c64a69a2cc1508825121b7b8394e48e00b1bf3718b2aaaab
token_salt: eeeeeeee
token_last_eight: eeeeeeee
log_filename: artifact-test2/2f/47.log
log_in_storage: 1
log_length: 707
log_size: 90179
log_expired: 0

View File

@@ -18,3 +18,5 @@
task_id: 50 task_id: 50
output_key: output_b output_key: output_b
output_value: bbb output_value: bbb
# DO NOT add more test data in the fixtures, test case should prepare their own test data separately and clearly

View File

@@ -166,3 +166,5 @@
download_count: 0 download_count: 0
size: 0 size: 0
created_unix: 946684800 created_unix: 946684800
# DO NOT add more test data in the fixtures, test case should prepare their own test data separately and clearly

View File

@@ -3,3 +3,5 @@
slug: badge1 slug: badge1
description: just a test badge description: just a test badge
image_url: badge1.png image_url: badge1.png
# DO NOT add more test data in the fixtures, test case should prepare their own test data separately and clearly

View File

@@ -249,3 +249,5 @@
is_deleted: false is_deleted: false
deleted_by_id: 0 deleted_by_id: 0
deleted_unix: 0 deleted_unix: 0
# DO NOT add more test data in the fixtures, test case should prepare their own test data separately and clearly

View File

@@ -63,3 +63,5 @@
repo_id: 32 repo_id: 32
user_id: 10 user_id: 10
mode: 2 # write mode: 2 # write
# DO NOT add more test data in the fixtures, test case should prepare their own test data separately and clearly

View File

@@ -102,3 +102,5 @@
review_id: 22 review_id: 22
assignee_id: 5 assignee_id: 5
created_unix: 946684817 created_unix: 946684817
# DO NOT add more test data in the fixtures, test case should prepare their own test data separately and clearly

View File

@@ -57,3 +57,5 @@
context: deploy/awesomeness context: deploy/awesomeness
context_hash: ae9547713a6665fc4261d0756904932085a41cf2 context_hash: ae9547713a6665fc4261d0756904932085a41cf2
creator_id: 2 creator_id: 2
# DO NOT add more test data in the fixtures, test case should prepare their own test data separately and clearly

View File

@@ -3,3 +3,5 @@
repo_id: 1 repo_id: 1
sha: "1234123412341234123412341234123412341234" sha: "1234123412341234123412341234123412341234"
max_index: 5 max_index: 5
# DO NOT add more test data in the fixtures, test case should prepare their own test data separately and clearly

View File

@@ -1 +1,3 @@
[] # empty [] # empty
# DO NOT add more test data in the fixtures, test case should prepare their own test data separately and clearly

View File

@@ -317,3 +317,5 @@
lower_email: user40@example.com lower_email: user40@example.com
is_activated: true is_activated: true
is_primary: true is_primary: true
# DO NOT add more test data in the fixtures, test case should prepare their own test data separately and clearly

View File

@@ -1 +1,3 @@
[] # empty [] # empty
# DO NOT add more test data in the fixtures, test case should prepare their own test data separately and clearly

View File

@@ -17,3 +17,5 @@
id: 4 id: 4
user_id: 31 user_id: 31
follow_id: 33 follow_id: 33
# DO NOT add more test data in the fixtures, test case should prepare their own test data separately and clearly

View File

@@ -21,3 +21,5 @@
can_encrypt_comms: true can_encrypt_comms: true
can_encrypt_storage: true can_encrypt_storage: true
can_certify: true can_certify: true
# DO NOT add more test data in the fixtures, test case should prepare their own test data separately and clearly

View File

@@ -1 +1,3 @@
[] # empty [] # empty
# DO NOT add more test data in the fixtures, test case should prepare their own test data separately and clearly

View File

@@ -1,37 +1,2 @@
- []
id: 1 # DO NOT add more test data in the fixtures, test case should prepare their own test data separately and clearly
hook_id: 1
uuid: uuid1
is_delivered: true
is_succeed: false
request_content: >
{
"url": "/matrix-delivered",
"http_method":"PUT",
"headers": {
"X-Head": "42"
},
"body": "{}"
}
-
id: 2
hook_id: 1
uuid: uuid2
is_delivered: true
-
id: 3
hook_id: 1
uuid: uuid3
is_delivered: true
is_succeed: true
payload_content: '{"key":"value"}' # legacy task, payload saved in payload_content (and not in request_content)
request_content: >
{
"url": "/matrix-success",
"http_method":"PUT",
"headers": {
"X-Head": "42"
}
}

View File

@@ -372,3 +372,5 @@
created_unix: 1707270422 created_unix: 1707270422
updated_unix: 1707270422 updated_unix: 1707270422
is_locked: false is_locked: false
# DO NOT add more test data in the fixtures, test case should prepare their own test data separately and clearly

View File

@@ -18,3 +18,5 @@
id: 5 id: 5
assignee_id: 10 assignee_id: 10
issue_id: 6 issue_id: 6
# DO NOT add more test data in the fixtures, test case should prepare their own test data separately and clearly

View File

@@ -33,3 +33,5 @@
- -
group_id: 51 group_id: 51
max_index: 1 max_index: 1
# DO NOT add more test data in the fixtures, test case should prepare their own test data separately and clearly

View File

@@ -17,3 +17,5 @@
id: 4 id: 4
issue_id: 2 issue_id: 2
label_id: 4 label_id: 4
# DO NOT add more test data in the fixtures, test case should prepare their own test data separately and clearly

View File

@@ -4,3 +4,5 @@
issue_id: 4 issue_id: 4
is_pull: false is_pull: false
pin_order: 1 pin_order: 1
# DO NOT add more test data in the fixtures, test case should prepare their own test data separately and clearly

View File

@@ -18,3 +18,5 @@
issue_id: 1 issue_id: 1
is_read: false is_read: false
is_mentioned: true is_mentioned: true
# DO NOT add more test data in the fixtures, test case should prepare their own test data separately and clearly

View File

@@ -29,3 +29,5 @@
is_watching: false is_watching: false
created_unix: 946684800 created_unix: 946684800
updated_unix: 946684800 updated_unix: 946684800
# DO NOT add more test data in the fixtures, test case should prepare their own test data separately and clearly

View File

@@ -107,3 +107,5 @@
num_issues: 0 num_issues: 0
num_closed_issues: 0 num_closed_issues: 0
archived_unix: 0 archived_unix: 0
# DO NOT add more test data in the fixtures, test case should prepare their own test data separately and clearly

View File

@@ -30,3 +30,5 @@
size: 25 size: 25
repository_id: 54 repository_id: 54
created_unix: 1671607299 created_unix: 1671607299
# DO NOT add more test data in the fixtures, test case should prepare their own test data separately and clearly

View File

@@ -1 +1,3 @@
[] # empty [] # empty
# DO NOT add more test data in the fixtures, test case should prepare their own test data separately and clearly

Some files were not shown because too many files have changed in this diff Show More