This PR introduces project workflows, allowing users to configure
event-based automations directly from the UI.
Users can define filters and actions for each workflow event, and
duplicate existing events when needed.
### Concepts
Every workflow is composed of `event`, `filters`, and `actions`.
- **Event** - An Event defines when a workflow should be triggered. It
represents specific activities such as an issue being added to the
project, a pull request being merged, or a project column being changed.
- **Filter** - A Filter refines when an event should take effect. It
allows users to specify conditions like issue type, labels, or project
columns to ensure actions only run in targeted scenarios.
- **Action** - An Action defines what happens when the event and filters
match. It performs operations such as adding labels, moving issues
between columns, or changing the issue or pull request state.
### Available Events
Currently, the following eight events are supported:
- On issues/pull requests closed
- On issues/pull requests reopened
- On issues/pull requests was added to the project, including when
created in it
- On issues/pull requests was removed from the project
- On issues/pull requests' column was changed
- On code changes requested
- On code review approved
- On pull request merged
Each event type supports its own set of filters and actions.
### Available Filters
There are four types of filters that can be configured for an event:
- **Apply to** - Specify the target type: `issues only`, `pull requests
only`, or `issues and pull requests`.
- **Labels** - Trigger the event only if the issue or pull request
contains one or more specified labels.
- **Move from column** - Filter events based on the original project
column.
- **Move to column** - Filter events based on the destination project
column.
### Available Actions
There are four types of actions that can be executed when an event is
triggered:
- **Add labels** - Automatically add one or more labels to the issue or
pull request.
- **Remove labels** - Remove one or more specified labels.
- **Move to column** - Move the issue or pull request to a designated
project column.
- **Issue state** - Close or reopen the issue. Pull requests can only be
closed.
### Enable/Disable an event workflow
Each event workflow can be individually enabled or disabled. When
disabled, the workflow will be ignored even if the event occurs. This
feature is useful when you want to temporarily stop certain automated
actions without deleting the workflow configuration. Workflows of closed
projects don't run either.
### Clone an event workflow
When you need multiple workflows for the same event, you can clone an
existing event to create a new one with different filters and actions.
This allows you to customize how the same event behaves under different
conditions, making workflows more flexible and powerful.
### Permissions
Permissions are checked when workflows are managed, not when they run:
- Viewing a project's workflows needs read access to the project
- Managing them needs write access to the project plus write access to
both issues and pull requests of a repository project's repository,
being an owner of an organization project's organization or a site
administrator, or being the user of a user project. Tokens limited to
public repositories can't manage owner-level projects' workflows
- A workflow runs when its event happens to an item of an open project
that can hold the item's repository, unless that repository is archived,
no matter who caused the event, and applies its actions without further
permission checks. Pull requests are never reopened
- Changes show as made by "Project workflow" on behalf of the user who
triggered the event and don't trigger other workflows
- Only users who can read an item can put it on a board or move its card
The management rule is also documented on `CanManageWorkflows` in
`services/projects/workflow.go`.
Fixes: #14359Fixes: #26704Fixes: #27990
Replaces: #28745
Documentation PR: https://gitea.com/gitea/docs/pulls/308
Co-authored-by: bircni <bircni@icloud.com>
Co-authored-by: silverwind <me@silverwind.io>
Co-authored-by: Giteabot <teabot@gitea.io>
Adds a repository setting for the default squash merge commit message
body with GitHub's options `PR_BODY`, `COMMIT_MESSAGES` and `BLANK`,
also settable via `squash_merge_commit_message` in the API. The commit
title stays the pull request title.
1. Breaking: API squash merges without `merge_message_field` now get the
same default message as the web merge box instead of a title-only
commit, which affects clients sending only `Do` like Renovate. An empty
value keeps title-only.
2. Breaking: `[repository.pull-request] DEFAULT_SQUASH_MERGE_MESSAGE`
replaces `POPULATE_SQUASH_COMMENT_WITH_COMMIT_MESSAGES`, which still
works as a deprecated fallback. Repositories store the default when
created or next saved.
3. Deprecated app.ini keys now migrate through one table instead of
per-loader fallbacks, which also fixes the ignored `[mailer] CERT_FILE`
and `KEY_FILE` fallbacks. Deprecation warnings no longer claim a removal
version.
<img width="1891" height="571" alt="grafik"
src="https://github.com/user-attachments/assets/0fdcde13-1f11-4156-b598-d80eb0d04cbe"
/>
---------
Co-authored-by: silverwind <me@silverwind.io>
Fixes#39598
The AGit update path in `services/agit` moved `refs/pull/N/head` without
recomputing commits_behind.
The AGit update path now calls `syncCommitDivergence` in
`UpdateRefForAgit`, the same as AGit PR creation (`NewPullRequest`)
already does.
---------
Signed-off-by: dziulatex <paweldziurasoftware@yahoo.com>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
Creating a PR fetches the head commit into the base repo, then pushes
the same objects into `refs/pull/N/head`. Since git 2.54, background
repacks race that push:
1. The push can be rejected with "unable to migrate objects to permanent
storage", see
https://github.com/go-gitea/gitea/actions/runs/37171442185/job/111345034829.
2. For heads with 100+ new objects, the repack can delete the reused
pack, leaving the PR ref pointing at missing objects.
Fetching the head commit with `FetchRemoteTempCommit` and setting the PR
ref with `UpdateRef` avoids both, as the fetch transfers nothing when
the objects exist. Fork PR refs are now updated like AGit PR refs
already are, without going through receive hooks.
Also syncs the PR ref when a PR is reopened again.
https://github.com/go-gitea/gitea/pull/37077 inverted that condition, so
a reopened PR kept a stale ref.
---------
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
Co-authored-by: bircni <bircni@icloud.com>
Various pages did not display the correct action run list tooltips. Fix
those tooltips like here on the `/pulls` page:
`ctx.Repo.Permission` is the zero value outside a repository route, so
on `/pulls`, `/issues`, `/notifications/subscriptions` and the dashboard
repo list the commit status "Details" link was always stripped. The live
job status is looked up from that target URL, so running checks also
rendered as a static pending dot instead of a spinner.
Resolve the Actions unit permission per repository instead.
Also drops the releases page's gate on *loading* statuses, which hid
external CI results from anyone without Actions read; it now loads them
and hides only the URL, like every other page.
Co-authored-by: bircni <bircni@icloud.com>
Admin and write team authorize now grant that mode on every unit,
including units added later, instead of only rows present in
`team_unit`. Granular teams keep `authorize=none` and explicit unit
rows.
Closes the `TEAM-UNIT-PERMISSION` design gap from
https://github.com/go-gitea/gitea/pull/34128.
Maybe also fix#15962 (actually maybe it had been fixed before, the root
cause is out-of-sync "access" table)
## Screenshots
only writing selected:
<img width="1399" height="1007" alt="image"
src="https://github.com/user-attachments/assets/1d1b4c49-a59a-47b6-998f-0464a067395b"
/>
_Created with the help of AI_
---------
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
Enable [`forcetypeassert`](https://github.com/gostaticanalysis/forcetypeassert)
linter to prevent unchecked type assertions. ~650 issues fixed, most
fixes were clean, some use `setting.PanicInDevOrTesting`.
The only behaviour changes are where code would previously send a 500 error
or panic, a 4xx error is now emitted.
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
Unfortunately, we can't completely remove the ctx from git.Repository,
because the CatFileBatch still heavily depends on a parent context.
If we remove the Repository ctx, the CatFileBatch will become a mess and
create a lot of unnecessary git processes.
http://localhost:3000/-/admin/monitor/perftrace
* Before: open a repo home, dozens of git processes (duplicate cat-file)
* After: only a few (no duplicate cat-file)
by the way, remove some unnecessary "models" imports from model
migration package, fix migration test model init bug
(modelmigration/migrationtest/tests.go)
before: gitrepo vs git packages
after: git package fully handle all git operations
by the way, use `WithRepo(repo)` instead of `WithDir(repo.Path)` to hide
path details.
benefits:
1. remove all unnecessary wrappers, developers no need to struggle with
"which package should be used"
2. simplify code, RepositoryFacade can (will) be used everywhere, all
"path" details are (will be) hidden
Removed `gitrepo.RunCmd*` functions, because gitcmd.Command works with
Repository directly.
Move some "local filesystem" related function into "localfs.go"
1. Storing "ctx" in a long-living object is wrong
2. Make the commit & tree cacheable (for the future performance
optimization)
3. Also fix some bad designs like `// FIXME: bad design, this field can
be nil if the commit is from "last commit cache"`
ref:
* #33893
The `official` flag of a pull request review is computed against the
target branch's protection rules at submit time and stored on the review
record. `ChangeTargetBranch` updated the base branch but never
re-evaluated it, so an `official` approval obtained against an
unprotected branch could be retargeted onto a protected branch and
satisfy its required approvals, bypassing the branch protection.
This re-evaluates the `official` flag of the latest approve/reject
reviews against the new base branch whenever the target branch changes.
Parse `Co-authored-by:` trailers from commit messages and surface
contributors as an avatar stack across the commit page, commits list, PR
commits tab, latest-commit row, blame, graph, and dashboard feed.
- Up to 10 visible 20px avatars, GitHub-style overlap (6px first stride,
4px between subsequent), `+N` chip for the rest.
- Label: 1 → name; 2 → `<a> and <b>`; 3+ → `<N> people` opens a Tippy
popup with all participants.
- Names and avatars link to the repo's commits-by-author search; fall
back to profile or `mailto:`.
- Trailer parsing uses `net/mail.ParseAddress`, scans only the trailing
paragraph, filters out the commit's own author/committer.
- Drops the non-standard `Co-committed-by:` emission on squash merge and
web edits.
Devtest: `/devtest/coauthor-avatars`.
Fixes#25521
----
<img width="353" height="277" alt="image"
src="https://github.com/user-attachments/assets/72092ceb-97ca-4b09-9557-0b72d3c5458e"
/>
<img width="533" height="328"
src="https://github.com/user-attachments/assets/11d0c8f8-8b3f-4f2e-9993-879f1c06bcc5"
/>
---------
Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
Co-authored-by: silverwind <me@silverwind.io>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
Co-authored-by: Giteabot <teabot@gitea.io>
## Summary
- Add `before` and `after` fields to `PullRequestPayload` for
`synchronize` events
- Thread push old/new commit SHAs through the PR synchronize notifier
path (regular and Agit flows)
- Populate the fields in webhook and Actions event payloads so workflows
can access them via `github.event.before` and `github.event.after`
Fixes#33395
---------
Co-authored-by: Cursor <cursoragent@cursor.com>
1. Pin all makefile go deps to exact version, renovate will bump them in the future
2. Bump all deps and golangci-lint and fix all new issues, most are from modernize
Signed-off-by: silverwind <me@silverwind.io>
Co-authored-by: Claude (Opus 4.7) <noreply@anthropic.com>
Fix#36905
The changes focus on force-push PR timeline handling and commit range
calculation:
- Reworked pull-request push comment creation to use a new
`gitrepo.GetCommitIDsBetweenReverse` helper, with special handling for
force pushes (merge-base based range, tolerate missing/invalid old
commits, and keep force-push timeline entries).
- Added `Comment.GetPushActionContent` to parse push comment payloads
and used it to delete only non-force-push push comments during force
pushes.
- Removed the old `Repository.CommitsBetweenNotBase` helper from
`modules/git/repo_commit.go` in favor of the new commit ID range helper.
- Added tests for `GetCommitIDsBetweenReverse` (normal range, `notRef`
filtering, fallback branch usage) and expanded pull comment tests to
cover force-push edge cases.
<img width="989" height="563" alt="image"
src="https://github.com/user-attachments/assets/a01e1bc2-fa8a-4028-8a35-d484e601ff3b"
/>
---------
Signed-off-by: Lunny Xiao <xiaolunwen@gmail.com>
Signed-off-by: wxiaoguang <wxiaoguang@gmail.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
Use shared repo permission resolution for Actions task users in issue
label remove and clear paths, and add a regression test for deleting
issue labels with a Gitea Actions token.
This fixes issue label deletion when the request is authenticated with a
Gitea Actions token.
Fixes#37011
The bug was that the delete path re-resolved repository permissions
using the normal user permission helper, which does not handle Actions
task users. As a result, `DELETE
/api/v1/repos/{owner}/{repo}/issues/{index}/labels/{id}` could return
`500` for Actions tokens even though label listing and label addition
worked.
---------
Co-authored-by: Codex <codex@openai.com>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com>
Co-authored-by: Giteabot <teabot@gitea.io>
In Git 2.38, the `merge-tree` command introduced the `--write-tree`
option, which works directly on bare repositories. In Git 2.40, a new parameter `--merge-base` introduced so we require Git 2.40 to use the merge tree feature.
This option produces the merged tree object ID, allowing us to perform
diffs between commits without creating a temporary repository. By
avoiding the overhead of setting up and tearing down temporary repos,
this approach delivers a notable performance improvement.
It also fixes a possible situation that conflict files might be empty
but it's a conflict status according to
https://git-scm.com/docs/git-merge-tree#_mistakes_to_avoid
Replace #35542
---------
Signed-off-by: Lunny Xiao <xiaolunwen@gmail.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
Most potential deadlock problems should have been fixed, and new code is
unlikely to cause new problems with the new design.
Also raise the minimum Git version required to 2.6.0 (released in 2015)
Maybe fix#32018
- Use `gitrepo.GetMergeBase` method instead of other two
implementations.
- Add `FetchRemoteCommit` so that we don't need to add many `remote` to
the git repository to avoid possible git lock conflicts. A lock will
start when invoke the function, it will be invoked when cross-repository
comparing. The head repository will fetch the base repository's base
commit id. In most situations, it should lock the fork repositories so
that it should not become a bottleneck.
- Improve `GetCompareInfo` to remove unnecessarily adding remote.
- Remove unnecessary parameters of `SignMerge`.
1 Move `IsRepositoryModelOrDirExist` and `CheckCreateRepository` to
service layer
2 Use `gitrepo.Pushxxx` instead of `git.Push` when possible
3 use `gitrepo.Clonexxx` instead of `gitrepo.Clone` when possible
Partially fix#34710
The bug described in #34710 can be divided into two parts: `push.paths`
and `pull_request.paths`. This PR fixes the issue related to
`pull_request.paths`. The root cause is that the check for whether the
workflow can be triggered happens **before** updating the PR’s merge
base. This causes the file-change detection to use the old merge base.
Therefore, we need to update the merge base first and then check whether
the workflow can be triggered.
This PR moved the creation of pushing comments before pull request
mergeable checking. So that when the pull request status changed, the
comments should have been created.
---------
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
Refactor Git command functions to use WithXXX methods instead of
exposing RunOpts.
This change simplifies reuse across gitrepo and improves consistency,
encapsulation, and maintainability of command options.
---------
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
Partially fix#32018
`git config` and `git remote` write operations create a temporary file
named `config.lock`. Since these operations are not atomic, they must
not be run in parallel. If two requests attempt to modify the same
repository concurrently—such as during a compare operation—one may fail
due to the presence of an existing `config.lock` file.
In cases where `config.lock` is left behind due to an unexpected program
exit, a global lock mechanism could allow us to safely remove the stale
lock file when a related error is detected. While this behavior is not
yet implemented in this PR, it is planned for a future enhancement.
---------
Signed-off-by: wxiaoguang <wxiaoguang@gmail.com>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>