Skip to content

Commit 58c0c0b

Browse files
committed
Merge remote-tracking branch 'giteaofficial/main'
* giteaofficial/main: Fix schedule actions still running even if workflow disalbed (go-gitea#26939) Fix the missing repo count (go-gitea#26942) Improve SSH Key / GPG Key / Deploy Key UI (go-gitea#26949) [skip ci] Updated translations via Crowdin Update nginx recommendations (go-gitea#26924) docs: Update Profile README information (go-gitea#26947) Fix scoped label layout (go-gitea#26932) Move createrepository from module to service layer (go-gitea#26927) Add a documentation note for Windows Service (go-gitea#26938) allow "latest" to be used in release vTag when downloading file (go-gitea#26748) Extract common code to new template (go-gitea#26933) Show always repo count in header (go-gitea#26842) Show always repo count in header (go-gitea#26842) Artifacts retention and auto clean up (go-gitea#26131) Fix UI anomalies (go-gitea#26929) Fix the display of org level badges (go-gitea#26504)
2 parents dc4aa3f + d1dca38 commit 58c0c0b

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

69 files changed

+962
-603
lines changed

custom/conf/app.example.ini

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2564,6 +2564,8 @@ LEVEL = Info
25642564
;;
25652565
;; Default platform to get action plugins, `github` for `https://github.com`, `self` for the current Gitea instance.
25662566
;DEFAULT_ACTIONS_URL = github
2567+
;; Default artifact retention time in days, default is 90 days
2568+
;ARTIFACT_RETENTION_DAYS = 90
25672569

25682570
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
25692571
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

docs/content/administration/config-cheat-sheet.en-us.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -955,6 +955,12 @@ Default templates for project boards:
955955
- `SCHEDULE`: **@midnight** : Interval as a duration between each synchronization, it will always attempt synchronization when the instance starts.
956956
- `UPDATE_EXISTING`: **true**: Create new users, update existing user data and disable users that are not in external source anymore (default) or only create new users if UPDATE_EXISTING is set to false.
957957

958+
## Cron - Cleanup Expired Actions Assets (`cron.cleanup_actions`)
959+
960+
- `ENABLED`: **true**: Enable cleanup expired actions assets job.
961+
- `RUN_AT_START`: **true**: Run job at start time (if ENABLED).
962+
- `SCHEDULE`: **@midnight** : Cron syntax for the job.
963+
958964
### Extended cron tasks (not enabled by default)
959965

960966
#### Cron - Garbage collect all repositories (`cron.git_gc_repos`)
@@ -1381,6 +1387,7 @@ PROXY_HOSTS = *.github.com
13811387
- `DEFAULT_ACTIONS_URL`: **github**: Default platform to get action plugins, `github` for `https://github.com`, `self` for the current Gitea instance.
13821388
- `STORAGE_TYPE`: **local**: Storage type for actions logs, `local` for local disk or `minio` for s3 compatible object storage service, default is `local` or other name defined with `[storage.xxx]`
13831389
- `MINIO_BASE_PATH`: **actions_log/**: Minio base path on the bucket only available when STORAGE_TYPE is `minio`
1390+
- `ARTIFACT_RETENTION_DAYS`: **90**: Number of days to keep artifacts. Set to 0 to disable artifact retention. Default is 90 days if not set.
13841391

13851392
`DEFAULT_ACTIONS_URL` indicates where the Gitea Actions runners should find the actions with relative path.
13861393
For example, `uses: actions/checkout@v3` means `https://github.com/actions/checkout@v3` since the value of `DEFAULT_ACTIONS_URL` is `github`.

docs/content/administration/reverse-proxies.en-us.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@ server {
2929
location / {
3030
client_max_body_size 512M;
3131
proxy_pass http://localhost:3000;
32+
proxy_set_header Connection $http_connection;
33+
proxy_set_header Upgrade $http_upgrade;
3234
proxy_set_header Host $host;
3335
proxy_set_header X-Real-IP $remote_addr;
3436
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

docs/content/installation/windows-service.en-us.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,15 @@ Open "Windows Services", search for the service named "gitea", right-click it an
5151
"Run". If everything is OK, Gitea will be reachable on `http://localhost:3000` (or the port
5252
that was configured).
5353

54+
## Service startup type
55+
56+
It was observed that on loaded systems during boot Gitea service may fail to start with timeout records in Windows Event Log.
57+
In that case change startup type to `Automatic-Delayed`. This can be done during service creation, or by running config command
58+
59+
```
60+
sc.exe config gitea start= delayed-auto
61+
```
62+
5463
## Adding startup dependencies
5564

5665
To add a startup dependency to the Gitea Windows service (eg Mysql, Mariadb), as an Administrator, then run the following command:

docs/content/usage/profile-readme.en-us.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,6 @@ menu:
1515

1616
# Profile READMEs
1717

18-
To display a markdown file in your Gitea profile page, simply make a repository named ".profile" and edit the README.md file inside. Gitea will automatically pull this file in and display it above your repositories.
18+
To display a Markdown file in your Gitea profile page, simply create a repository named `.profile` and add a new file called `README.md`. Gitea will automatically display the contents of the file on your profile, above your repositories.
1919

20-
Note. You are welcome to make this repository private. Doing so will hide your source files from public viewing and allow you to privitize certain files. However, the README.md file will be the only file present on your profile. If you wish to have an entirely private .profile repository, remove or rename the README.md file.
20+
Making the `.profile` repository private will hide the Profile README.

models/actions/artifact.go

Lines changed: 28 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -9,19 +9,21 @@ package actions
99
import (
1010
"context"
1111
"errors"
12+
"time"
1213

1314
"code.gitea.io/gitea/models/db"
1415
"code.gitea.io/gitea/modules/timeutil"
1516
"code.gitea.io/gitea/modules/util"
1617
)
1718

19+
// ArtifactStatus is the status of an artifact, uploading, expired or need-delete
20+
type ArtifactStatus int64
21+
1822
const (
19-
// ArtifactStatusUploadPending is the status of an artifact upload that is pending
20-
ArtifactStatusUploadPending = 1
21-
// ArtifactStatusUploadConfirmed is the status of an artifact upload that is confirmed
22-
ArtifactStatusUploadConfirmed = 2
23-
// ArtifactStatusUploadError is the status of an artifact upload that is errored
24-
ArtifactStatusUploadError = 3
23+
ArtifactStatusUploadPending ArtifactStatus = iota + 1 // 1, ArtifactStatusUploadPending is the status of an artifact upload that is pending
24+
ArtifactStatusUploadConfirmed // 2, ArtifactStatusUploadConfirmed is the status of an artifact upload that is confirmed
25+
ArtifactStatusUploadError // 3, ArtifactStatusUploadError is the status of an artifact upload that is errored
26+
ArtifactStatusExpired // 4, ArtifactStatusExpired is the status of an artifact that is expired
2527
)
2628

2729
func init() {
@@ -45,9 +47,10 @@ type ActionArtifact struct {
4547
Status int64 `xorm:"index"` // The status of the artifact, uploading, expired or need-delete
4648
CreatedUnix timeutil.TimeStamp `xorm:"created"`
4749
UpdatedUnix timeutil.TimeStamp `xorm:"updated index"`
50+
ExpiredUnix timeutil.TimeStamp `xorm:"index"` // The time when the artifact will be expired
4851
}
4952

50-
func CreateArtifact(ctx context.Context, t *ActionTask, artifactName, artifactPath string) (*ActionArtifact, error) {
53+
func CreateArtifact(ctx context.Context, t *ActionTask, artifactName, artifactPath string, expiredDays int64) (*ActionArtifact, error) {
5154
if err := t.LoadJob(ctx); err != nil {
5255
return nil, err
5356
}
@@ -61,7 +64,8 @@ func CreateArtifact(ctx context.Context, t *ActionTask, artifactName, artifactPa
6164
RepoID: t.RepoID,
6265
OwnerID: t.OwnerID,
6366
CommitSHA: t.CommitSHA,
64-
Status: ArtifactStatusUploadPending,
67+
Status: int64(ArtifactStatusUploadPending),
68+
ExpiredUnix: timeutil.TimeStamp(time.Now().Unix() + 3600*24*expiredDays),
6569
}
6670
if _, err := db.GetEngine(ctx).Insert(artifact); err != nil {
6771
return nil, err
@@ -126,15 +130,16 @@ func ListUploadedArtifactsByRunID(ctx context.Context, runID int64) ([]*ActionAr
126130
type ActionArtifactMeta struct {
127131
ArtifactName string
128132
FileSize int64
133+
Status int64
129134
}
130135

131136
// ListUploadedArtifactsMeta returns all uploaded artifacts meta of a run
132137
func ListUploadedArtifactsMeta(ctx context.Context, runID int64) ([]*ActionArtifactMeta, error) {
133138
arts := make([]*ActionArtifactMeta, 0, 10)
134139
return arts, db.GetEngine(ctx).Table("action_artifact").
135-
Where("run_id=? AND status=?", runID, ArtifactStatusUploadConfirmed).
140+
Where("run_id=? AND (status=? OR status=?)", runID, ArtifactStatusUploadConfirmed, ArtifactStatusExpired).
136141
GroupBy("artifact_name").
137-
Select("artifact_name, sum(file_size) as file_size").
142+
Select("artifact_name, sum(file_size) as file_size, max(status) as status").
138143
Find(&arts)
139144
}
140145

@@ -149,3 +154,16 @@ func ListArtifactsByRunIDAndName(ctx context.Context, runID int64, name string)
149154
arts := make([]*ActionArtifact, 0, 10)
150155
return arts, db.GetEngine(ctx).Where("run_id=? AND artifact_name=?", runID, name).Find(&arts)
151156
}
157+
158+
// ListNeedExpiredArtifacts returns all need expired artifacts but not deleted
159+
func ListNeedExpiredArtifacts(ctx context.Context) ([]*ActionArtifact, error) {
160+
arts := make([]*ActionArtifact, 0, 10)
161+
return arts, db.GetEngine(ctx).
162+
Where("expired_unix < ? AND status = ?", timeutil.TimeStamp(time.Now().Unix()), ArtifactStatusUploadConfirmed).Find(&arts)
163+
}
164+
165+
// SetArtifactExpired sets an artifact to expired
166+
func SetArtifactExpired(ctx context.Context, artifactID int64) error {
167+
_, err := db.GetEngine(ctx).Where("id=? AND status = ?", artifactID, ArtifactStatusUploadConfirmed).Cols("status").Update(&ActionArtifact{Status: int64(ArtifactStatusExpired)})
168+
return err
169+
}

models/migrations/migrations.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -528,6 +528,8 @@ var migrations = []Migration{
528528
NewMigration("Add Version to ActionRun table", v1_21.AddVersionToActionRunTable),
529529
// v273 -> v274
530530
NewMigration("Add Action Schedule Table", v1_21.AddActionScheduleTable),
531+
// v274 -> v275
532+
NewMigration("Add Actions artifacts expiration date", v1_21.AddExpiredUnixColumnInActionArtifactTable),
531533
}
532534

533535
// GetCurrentDBVersion returns the current db version

models/migrations/v1_21/v274.go

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
// Copyright 2023 The Gitea Authors. All rights reserved.
2+
// SPDX-License-Identifier: MIT
3+
4+
package v1_21 //nolint
5+
import (
6+
"time"
7+
8+
"code.gitea.io/gitea/modules/timeutil"
9+
10+
"xorm.io/xorm"
11+
)
12+
13+
func AddExpiredUnixColumnInActionArtifactTable(x *xorm.Engine) error {
14+
type ActionArtifact struct {
15+
ExpiredUnix timeutil.TimeStamp `xorm:"index"` // time when the artifact will be expired
16+
}
17+
if err := x.Sync(new(ActionArtifact)); err != nil {
18+
return err
19+
}
20+
return updateArtifactsExpiredUnixTo90Days(x)
21+
}
22+
23+
func updateArtifactsExpiredUnixTo90Days(x *xorm.Engine) error {
24+
sess := x.NewSession()
25+
defer sess.Close()
26+
27+
if err := sess.Begin(); err != nil {
28+
return err
29+
}
30+
expiredTime := time.Now().AddDate(0, 0, 90).Unix()
31+
if _, err := sess.Exec(`UPDATE action_artifact SET expired_unix=? WHERE status='2' AND expired_unix is NULL`, expiredTime); err != nil {
32+
return err
33+
}
34+
35+
return sess.Commit()
36+
}

modules/context/org.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -250,6 +250,7 @@ func HandleOrgAssignment(ctx *Context, args ...bool) {
250250
return
251251
}
252252
}
253+
ctx.Data["ContextUser"] = ctx.ContextUser
253254

254255
ctx.Data["CanReadProjects"] = ctx.Org.CanReadUnit(ctx, unit.TypeProjects)
255256
ctx.Data["CanReadPackages"] = ctx.Org.CanReadUnit(ctx, unit.TypePackages)

modules/context/repo.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -471,6 +471,7 @@ func RepoAssignment(ctx *Context) context.CancelFunc {
471471
}
472472
ctx.Repo.Owner = owner
473473
ctx.ContextUser = owner
474+
ctx.Data["ContextUser"] = ctx.ContextUser
474475
ctx.Data["Username"] = ctx.Repo.Owner.Name
475476

476477
// redirect link to wiki

modules/repository/create.go

Lines changed: 0 additions & 137 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@ import (
2222
"code.gitea.io/gitea/models/unit"
2323
user_model "code.gitea.io/gitea/models/user"
2424
"code.gitea.io/gitea/models/webhook"
25-
"code.gitea.io/gitea/modules/git"
2625
issue_indexer "code.gitea.io/gitea/modules/indexer/issues"
2726
"code.gitea.io/gitea/modules/log"
2827
"code.gitea.io/gitea/modules/setting"
@@ -156,142 +155,6 @@ func CreateRepositoryByExample(ctx context.Context, doer, u *user_model.User, re
156155
return nil
157156
}
158157

159-
// CreateRepoOptions contains the create repository options
160-
type CreateRepoOptions struct {
161-
Name string
162-
Description string
163-
OriginalURL string
164-
GitServiceType api.GitServiceType
165-
Gitignores string
166-
IssueLabels string
167-
License string
168-
Readme string
169-
DefaultBranch string
170-
IsPrivate bool
171-
IsMirror bool
172-
IsTemplate bool
173-
AutoInit bool
174-
Status repo_model.RepositoryStatus
175-
TrustModel repo_model.TrustModelType
176-
MirrorInterval string
177-
}
178-
179-
// CreateRepository creates a repository for the user/organization.
180-
func CreateRepository(doer, u *user_model.User, opts CreateRepoOptions) (*repo_model.Repository, error) {
181-
if !doer.IsAdmin && !u.CanCreateRepo() {
182-
return nil, repo_model.ErrReachLimitOfRepo{
183-
Limit: u.MaxRepoCreation,
184-
}
185-
}
186-
187-
if len(opts.DefaultBranch) == 0 {
188-
opts.DefaultBranch = setting.Repository.DefaultBranch
189-
}
190-
191-
// Check if label template exist
192-
if len(opts.IssueLabels) > 0 {
193-
if _, err := LoadTemplateLabelsByDisplayName(opts.IssueLabels); err != nil {
194-
return nil, err
195-
}
196-
}
197-
198-
repo := &repo_model.Repository{
199-
OwnerID: u.ID,
200-
Owner: u,
201-
OwnerName: u.Name,
202-
Name: opts.Name,
203-
LowerName: strings.ToLower(opts.Name),
204-
Description: opts.Description,
205-
OriginalURL: opts.OriginalURL,
206-
OriginalServiceType: opts.GitServiceType,
207-
IsPrivate: opts.IsPrivate,
208-
IsFsckEnabled: !opts.IsMirror,
209-
IsTemplate: opts.IsTemplate,
210-
CloseIssuesViaCommitInAnyBranch: setting.Repository.DefaultCloseIssuesViaCommitsInAnyBranch,
211-
Status: opts.Status,
212-
IsEmpty: !opts.AutoInit,
213-
TrustModel: opts.TrustModel,
214-
IsMirror: opts.IsMirror,
215-
DefaultBranch: opts.DefaultBranch,
216-
}
217-
218-
var rollbackRepo *repo_model.Repository
219-
220-
if err := db.WithTx(db.DefaultContext, func(ctx context.Context) error {
221-
if err := CreateRepositoryByExample(ctx, doer, u, repo, false, false); err != nil {
222-
return err
223-
}
224-
225-
// No need for init mirror.
226-
if opts.IsMirror {
227-
return nil
228-
}
229-
230-
repoPath := repo_model.RepoPath(u.Name, repo.Name)
231-
isExist, err := util.IsExist(repoPath)
232-
if err != nil {
233-
log.Error("Unable to check if %s exists. Error: %v", repoPath, err)
234-
return err
235-
}
236-
if isExist {
237-
// repo already exists - We have two or three options.
238-
// 1. We fail stating that the directory exists
239-
// 2. We create the db repository to go with this data and adopt the git repo
240-
// 3. We delete it and start afresh
241-
//
242-
// Previously Gitea would just delete and start afresh - this was naughty.
243-
// So we will now fail and delegate to other functionality to adopt or delete
244-
log.Error("Files already exist in %s and we are not going to adopt or delete.", repoPath)
245-
return repo_model.ErrRepoFilesAlreadyExist{
246-
Uname: u.Name,
247-
Name: repo.Name,
248-
}
249-
}
250-
251-
if err = initRepository(ctx, repoPath, doer, repo, opts); err != nil {
252-
if err2 := util.RemoveAll(repoPath); err2 != nil {
253-
log.Error("initRepository: %v", err)
254-
return fmt.Errorf(
255-
"delete repo directory %s/%s failed(2): %v", u.Name, repo.Name, err2)
256-
}
257-
return fmt.Errorf("initRepository: %w", err)
258-
}
259-
260-
// Initialize Issue Labels if selected
261-
if len(opts.IssueLabels) > 0 {
262-
if err = InitializeLabels(ctx, repo.ID, opts.IssueLabels, false); err != nil {
263-
rollbackRepo = repo
264-
rollbackRepo.OwnerID = u.ID
265-
return fmt.Errorf("InitializeLabels: %w", err)
266-
}
267-
}
268-
269-
if err := CheckDaemonExportOK(ctx, repo); err != nil {
270-
return fmt.Errorf("checkDaemonExportOK: %w", err)
271-
}
272-
273-
if stdout, _, err := git.NewCommand(ctx, "update-server-info").
274-
SetDescription(fmt.Sprintf("CreateRepository(git update-server-info): %s", repoPath)).
275-
RunStdString(&git.RunOpts{Dir: repoPath}); err != nil {
276-
log.Error("CreateRepository(git update-server-info) in %v: Stdout: %s\nError: %v", repo, stdout, err)
277-
rollbackRepo = repo
278-
rollbackRepo.OwnerID = u.ID
279-
return fmt.Errorf("CreateRepository(git update-server-info): %w", err)
280-
}
281-
return nil
282-
}); err != nil {
283-
if rollbackRepo != nil {
284-
if errDelete := models.DeleteRepository(doer, rollbackRepo.OwnerID, rollbackRepo.ID); errDelete != nil {
285-
log.Error("Rollback deleteRepository: %v", errDelete)
286-
}
287-
}
288-
289-
return nil, err
290-
}
291-
292-
return repo, nil
293-
}
294-
295158
const notRegularFileMode = os.ModeSymlink | os.ModeNamedPipe | os.ModeSocket | os.ModeDevice | os.ModeCharDevice | os.ModeIrregular
296159

297160
// getDirectorySize returns the disk consumption for a given path

0 commit comments

Comments
 (0)