Skip to content

Commit

Permalink
Merge remote-tracking branch 'giteaofficial/main'
Browse files Browse the repository at this point in the history
* 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)
  • Loading branch information
zjjhot committed Sep 7, 2023
2 parents dc4aa3f + d1dca38 commit 58c0c0b
Show file tree
Hide file tree
Showing 69 changed files with 962 additions and 603 deletions.
2 changes: 2 additions & 0 deletions custom/conf/app.example.ini
Expand Up @@ -2564,6 +2564,8 @@ LEVEL = Info
;;
;; Default platform to get action plugins, `github` for `https://github.com`, `self` for the current Gitea instance.
;DEFAULT_ACTIONS_URL = github
;; Default artifact retention time in days, default is 90 days
;ARTIFACT_RETENTION_DAYS = 90

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
Expand Down
7 changes: 7 additions & 0 deletions docs/content/administration/config-cheat-sheet.en-us.md
Expand Up @@ -955,6 +955,12 @@ Default templates for project boards:
- `SCHEDULE`: **@midnight** : Interval as a duration between each synchronization, it will always attempt synchronization when the instance starts.
- `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.

## Cron - Cleanup Expired Actions Assets (`cron.cleanup_actions`)

- `ENABLED`: **true**: Enable cleanup expired actions assets job.
- `RUN_AT_START`: **true**: Run job at start time (if ENABLED).
- `SCHEDULE`: **@midnight** : Cron syntax for the job.

### Extended cron tasks (not enabled by default)

#### Cron - Garbage collect all repositories (`cron.git_gc_repos`)
Expand Down Expand Up @@ -1381,6 +1387,7 @@ PROXY_HOSTS = *.github.com
- `DEFAULT_ACTIONS_URL`: **github**: Default platform to get action plugins, `github` for `https://github.com`, `self` for the current Gitea instance.
- `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]`
- `MINIO_BASE_PATH`: **actions_log/**: Minio base path on the bucket only available when STORAGE_TYPE is `minio`
- `ARTIFACT_RETENTION_DAYS`: **90**: Number of days to keep artifacts. Set to 0 to disable artifact retention. Default is 90 days if not set.

`DEFAULT_ACTIONS_URL` indicates where the Gitea Actions runners should find the actions with relative path.
For example, `uses: actions/checkout@v3` means `https://github.com/actions/checkout@v3` since the value of `DEFAULT_ACTIONS_URL` is `github`.
Expand Down
2 changes: 2 additions & 0 deletions docs/content/administration/reverse-proxies.en-us.md
Expand Up @@ -29,6 +29,8 @@ server {
location / {
client_max_body_size 512M;
proxy_pass http://localhost:3000;
proxy_set_header Connection $http_connection;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
Expand Down
9 changes: 9 additions & 0 deletions docs/content/installation/windows-service.en-us.md
Expand Up @@ -51,6 +51,15 @@ Open "Windows Services", search for the service named "gitea", right-click it an
"Run". If everything is OK, Gitea will be reachable on `http://localhost:3000` (or the port
that was configured).

## Service startup type

It was observed that on loaded systems during boot Gitea service may fail to start with timeout records in Windows Event Log.
In that case change startup type to `Automatic-Delayed`. This can be done during service creation, or by running config command

```
sc.exe config gitea start= delayed-auto
```

## Adding startup dependencies

To add a startup dependency to the Gitea Windows service (eg Mysql, Mariadb), as an Administrator, then run the following command:
Expand Down
4 changes: 2 additions & 2 deletions docs/content/usage/profile-readme.en-us.md
Expand Up @@ -15,6 +15,6 @@ menu:

# Profile READMEs

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.
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.

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.
Making the `.profile` repository private will hide the Profile README.
38 changes: 28 additions & 10 deletions models/actions/artifact.go
Expand Up @@ -9,19 +9,21 @@ package actions
import (
"context"
"errors"
"time"

"code.gitea.io/gitea/models/db"
"code.gitea.io/gitea/modules/timeutil"
"code.gitea.io/gitea/modules/util"
)

// ArtifactStatus is the status of an artifact, uploading, expired or need-delete
type ArtifactStatus int64

const (
// ArtifactStatusUploadPending is the status of an artifact upload that is pending
ArtifactStatusUploadPending = 1
// ArtifactStatusUploadConfirmed is the status of an artifact upload that is confirmed
ArtifactStatusUploadConfirmed = 2
// ArtifactStatusUploadError is the status of an artifact upload that is errored
ArtifactStatusUploadError = 3
ArtifactStatusUploadPending ArtifactStatus = iota + 1 // 1, ArtifactStatusUploadPending is the status of an artifact upload that is pending
ArtifactStatusUploadConfirmed // 2, ArtifactStatusUploadConfirmed is the status of an artifact upload that is confirmed
ArtifactStatusUploadError // 3, ArtifactStatusUploadError is the status of an artifact upload that is errored
ArtifactStatusExpired // 4, ArtifactStatusExpired is the status of an artifact that is expired
)

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

func CreateArtifact(ctx context.Context, t *ActionTask, artifactName, artifactPath string) (*ActionArtifact, error) {
func CreateArtifact(ctx context.Context, t *ActionTask, artifactName, artifactPath string, expiredDays int64) (*ActionArtifact, error) {
if err := t.LoadJob(ctx); err != nil {
return nil, err
}
Expand All @@ -61,7 +64,8 @@ func CreateArtifact(ctx context.Context, t *ActionTask, artifactName, artifactPa
RepoID: t.RepoID,
OwnerID: t.OwnerID,
CommitSHA: t.CommitSHA,
Status: ArtifactStatusUploadPending,
Status: int64(ArtifactStatusUploadPending),
ExpiredUnix: timeutil.TimeStamp(time.Now().Unix() + 3600*24*expiredDays),
}
if _, err := db.GetEngine(ctx).Insert(artifact); err != nil {
return nil, err
Expand Down Expand Up @@ -126,15 +130,16 @@ func ListUploadedArtifactsByRunID(ctx context.Context, runID int64) ([]*ActionAr
type ActionArtifactMeta struct {
ArtifactName string
FileSize int64
Status int64
}

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

Expand All @@ -149,3 +154,16 @@ func ListArtifactsByRunIDAndName(ctx context.Context, runID int64, name string)
arts := make([]*ActionArtifact, 0, 10)
return arts, db.GetEngine(ctx).Where("run_id=? AND artifact_name=?", runID, name).Find(&arts)
}

// ListNeedExpiredArtifacts returns all need expired artifacts but not deleted
func ListNeedExpiredArtifacts(ctx context.Context) ([]*ActionArtifact, error) {
arts := make([]*ActionArtifact, 0, 10)
return arts, db.GetEngine(ctx).
Where("expired_unix < ? AND status = ?", timeutil.TimeStamp(time.Now().Unix()), ArtifactStatusUploadConfirmed).Find(&arts)
}

// SetArtifactExpired sets an artifact to expired
func SetArtifactExpired(ctx context.Context, artifactID int64) error {
_, err := db.GetEngine(ctx).Where("id=? AND status = ?", artifactID, ArtifactStatusUploadConfirmed).Cols("status").Update(&ActionArtifact{Status: int64(ArtifactStatusExpired)})
return err
}
2 changes: 2 additions & 0 deletions models/migrations/migrations.go
Expand Up @@ -528,6 +528,8 @@ var migrations = []Migration{
NewMigration("Add Version to ActionRun table", v1_21.AddVersionToActionRunTable),
// v273 -> v274
NewMigration("Add Action Schedule Table", v1_21.AddActionScheduleTable),
// v274 -> v275
NewMigration("Add Actions artifacts expiration date", v1_21.AddExpiredUnixColumnInActionArtifactTable),
}

// GetCurrentDBVersion returns the current db version
Expand Down
36 changes: 36 additions & 0 deletions models/migrations/v1_21/v274.go
@@ -0,0 +1,36 @@
// Copyright 2023 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT

package v1_21 //nolint
import (
"time"

"code.gitea.io/gitea/modules/timeutil"

"xorm.io/xorm"
)

func AddExpiredUnixColumnInActionArtifactTable(x *xorm.Engine) error {
type ActionArtifact struct {
ExpiredUnix timeutil.TimeStamp `xorm:"index"` // time when the artifact will be expired
}
if err := x.Sync(new(ActionArtifact)); err != nil {
return err
}
return updateArtifactsExpiredUnixTo90Days(x)
}

func updateArtifactsExpiredUnixTo90Days(x *xorm.Engine) error {
sess := x.NewSession()
defer sess.Close()

if err := sess.Begin(); err != nil {
return err
}
expiredTime := time.Now().AddDate(0, 0, 90).Unix()
if _, err := sess.Exec(`UPDATE action_artifact SET expired_unix=? WHERE status='2' AND expired_unix is NULL`, expiredTime); err != nil {
return err
}

return sess.Commit()
}
1 change: 1 addition & 0 deletions modules/context/org.go
Expand Up @@ -250,6 +250,7 @@ func HandleOrgAssignment(ctx *Context, args ...bool) {
return
}
}
ctx.Data["ContextUser"] = ctx.ContextUser

ctx.Data["CanReadProjects"] = ctx.Org.CanReadUnit(ctx, unit.TypeProjects)
ctx.Data["CanReadPackages"] = ctx.Org.CanReadUnit(ctx, unit.TypePackages)
Expand Down
1 change: 1 addition & 0 deletions modules/context/repo.go
Expand Up @@ -471,6 +471,7 @@ func RepoAssignment(ctx *Context) context.CancelFunc {
}
ctx.Repo.Owner = owner
ctx.ContextUser = owner
ctx.Data["ContextUser"] = ctx.ContextUser
ctx.Data["Username"] = ctx.Repo.Owner.Name

// redirect link to wiki
Expand Down
137 changes: 0 additions & 137 deletions modules/repository/create.go
Expand Up @@ -22,7 +22,6 @@ import (
"code.gitea.io/gitea/models/unit"
user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/models/webhook"
"code.gitea.io/gitea/modules/git"
issue_indexer "code.gitea.io/gitea/modules/indexer/issues"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/setting"
Expand Down Expand Up @@ -156,142 +155,6 @@ func CreateRepositoryByExample(ctx context.Context, doer, u *user_model.User, re
return nil
}

// CreateRepoOptions contains the create repository options
type CreateRepoOptions struct {
Name string
Description string
OriginalURL string
GitServiceType api.GitServiceType
Gitignores string
IssueLabels string
License string
Readme string
DefaultBranch string
IsPrivate bool
IsMirror bool
IsTemplate bool
AutoInit bool
Status repo_model.RepositoryStatus
TrustModel repo_model.TrustModelType
MirrorInterval string
}

// CreateRepository creates a repository for the user/organization.
func CreateRepository(doer, u *user_model.User, opts CreateRepoOptions) (*repo_model.Repository, error) {
if !doer.IsAdmin && !u.CanCreateRepo() {
return nil, repo_model.ErrReachLimitOfRepo{
Limit: u.MaxRepoCreation,
}
}

if len(opts.DefaultBranch) == 0 {
opts.DefaultBranch = setting.Repository.DefaultBranch
}

// Check if label template exist
if len(opts.IssueLabels) > 0 {
if _, err := LoadTemplateLabelsByDisplayName(opts.IssueLabels); err != nil {
return nil, err
}
}

repo := &repo_model.Repository{
OwnerID: u.ID,
Owner: u,
OwnerName: u.Name,
Name: opts.Name,
LowerName: strings.ToLower(opts.Name),
Description: opts.Description,
OriginalURL: opts.OriginalURL,
OriginalServiceType: opts.GitServiceType,
IsPrivate: opts.IsPrivate,
IsFsckEnabled: !opts.IsMirror,
IsTemplate: opts.IsTemplate,
CloseIssuesViaCommitInAnyBranch: setting.Repository.DefaultCloseIssuesViaCommitsInAnyBranch,
Status: opts.Status,
IsEmpty: !opts.AutoInit,
TrustModel: opts.TrustModel,
IsMirror: opts.IsMirror,
DefaultBranch: opts.DefaultBranch,
}

var rollbackRepo *repo_model.Repository

if err := db.WithTx(db.DefaultContext, func(ctx context.Context) error {
if err := CreateRepositoryByExample(ctx, doer, u, repo, false, false); err != nil {
return err
}

// No need for init mirror.
if opts.IsMirror {
return nil
}

repoPath := repo_model.RepoPath(u.Name, repo.Name)
isExist, err := util.IsExist(repoPath)
if err != nil {
log.Error("Unable to check if %s exists. Error: %v", repoPath, err)
return err
}
if isExist {
// repo already exists - We have two or three options.
// 1. We fail stating that the directory exists
// 2. We create the db repository to go with this data and adopt the git repo
// 3. We delete it and start afresh
//
// Previously Gitea would just delete and start afresh - this was naughty.
// So we will now fail and delegate to other functionality to adopt or delete
log.Error("Files already exist in %s and we are not going to adopt or delete.", repoPath)
return repo_model.ErrRepoFilesAlreadyExist{
Uname: u.Name,
Name: repo.Name,
}
}

if err = initRepository(ctx, repoPath, doer, repo, opts); err != nil {
if err2 := util.RemoveAll(repoPath); err2 != nil {
log.Error("initRepository: %v", err)
return fmt.Errorf(
"delete repo directory %s/%s failed(2): %v", u.Name, repo.Name, err2)
}
return fmt.Errorf("initRepository: %w", err)
}

// Initialize Issue Labels if selected
if len(opts.IssueLabels) > 0 {
if err = InitializeLabels(ctx, repo.ID, opts.IssueLabels, false); err != nil {
rollbackRepo = repo
rollbackRepo.OwnerID = u.ID
return fmt.Errorf("InitializeLabels: %w", err)
}
}

if err := CheckDaemonExportOK(ctx, repo); err != nil {
return fmt.Errorf("checkDaemonExportOK: %w", err)
}

if stdout, _, err := git.NewCommand(ctx, "update-server-info").
SetDescription(fmt.Sprintf("CreateRepository(git update-server-info): %s", repoPath)).
RunStdString(&git.RunOpts{Dir: repoPath}); err != nil {
log.Error("CreateRepository(git update-server-info) in %v: Stdout: %s\nError: %v", repo, stdout, err)
rollbackRepo = repo
rollbackRepo.OwnerID = u.ID
return fmt.Errorf("CreateRepository(git update-server-info): %w", err)
}
return nil
}); err != nil {
if rollbackRepo != nil {
if errDelete := models.DeleteRepository(doer, rollbackRepo.OwnerID, rollbackRepo.ID); errDelete != nil {
log.Error("Rollback deleteRepository: %v", errDelete)
}
}

return nil, err
}

return repo, nil
}

const notRegularFileMode = os.ModeSymlink | os.ModeNamedPipe | os.ModeSocket | os.ModeDevice | os.ModeCharDevice | os.ModeIrregular

// getDirectorySize returns the disk consumption for a given path
Expand Down

0 comments on commit 58c0c0b

Please sign in to comment.