aboutsummaryrefslogtreecommitdiffstats
path: root/modules
diff options
context:
space:
mode:
Diffstat (limited to 'modules')
-rw-r--r--modules/actions/log.go163
-rw-r--r--modules/actions/task_state.go101
-rw-r--r--modules/actions/task_state_test.go112
-rw-r--r--modules/actions/workflows.go75
-rw-r--r--modules/context/context.go2
-rw-r--r--modules/context/repo.go1
-rw-r--r--modules/notification/notification.go20
-rw-r--r--modules/private/hook.go1
-rw-r--r--modules/repository/env.go1
-rw-r--r--modules/setting/actions.go29
-rw-r--r--modules/setting/setting.go2
-rw-r--r--modules/storage/storage.go14
-rw-r--r--modules/structs/commit_status.go2
-rw-r--r--modules/templates/helper.go3
14 files changed, 526 insertions, 0 deletions
diff --git a/modules/actions/log.go b/modules/actions/log.go
new file mode 100644
index 0000000000..3868101992
--- /dev/null
+++ b/modules/actions/log.go
@@ -0,0 +1,163 @@
+// Copyright 2022 The Gitea Authors. All rights reserved.
+// SPDX-License-Identifier: MIT
+
+package actions
+
+import (
+ "bufio"
+ "context"
+ "fmt"
+ "io"
+ "os"
+ "strings"
+ "time"
+
+ "code.gitea.io/gitea/models/dbfs"
+ "code.gitea.io/gitea/modules/log"
+ "code.gitea.io/gitea/modules/storage"
+
+ runnerv1 "code.gitea.io/actions-proto-go/runner/v1"
+ "google.golang.org/protobuf/types/known/timestamppb"
+)
+
+const (
+ MaxLineSize = 64 * 1024
+ DBFSPrefix = "actions_log/"
+
+ timeFormat = "2006-01-02T15:04:05.0000000Z07:00"
+ defaultBufSize = MaxLineSize
+)
+
+func WriteLogs(ctx context.Context, filename string, offset int64, rows []*runnerv1.LogRow) ([]int, error) {
+ name := DBFSPrefix + filename
+ f, err := dbfs.OpenFile(ctx, name, os.O_WRONLY|os.O_CREATE)
+ if err != nil {
+ return nil, fmt.Errorf("dbfs OpenFile %q: %w", name, err)
+ }
+ defer f.Close()
+ if _, err := f.Seek(offset, io.SeekStart); err != nil {
+ return nil, fmt.Errorf("dbfs Seek %q: %w", name, err)
+ }
+
+ writer := bufio.NewWriterSize(f, defaultBufSize)
+
+ ns := make([]int, 0, len(rows))
+ for _, row := range rows {
+ n, err := writer.WriteString(FormatLog(row.Time.AsTime(), row.Content) + "\n")
+ if err != nil {
+ return nil, err
+ }
+ ns = append(ns, n)
+ }
+
+ if err := writer.Flush(); err != nil {
+ return nil, err
+ }
+ return ns, nil
+}
+
+func ReadLogs(ctx context.Context, inStorage bool, filename string, offset, limit int64) ([]*runnerv1.LogRow, error) {
+ f, err := openLogs(ctx, inStorage, filename)
+ if err != nil {
+ return nil, err
+ }
+ defer f.Close()
+
+ if _, err := f.Seek(offset, io.SeekStart); err != nil {
+ return nil, fmt.Errorf("file seek: %w", err)
+ }
+
+ scanner := bufio.NewScanner(f)
+ maxLineSize := len(timeFormat) + MaxLineSize + 1
+ scanner.Buffer(make([]byte, maxLineSize), maxLineSize)
+
+ var rows []*runnerv1.LogRow
+ for scanner.Scan() && (int64(len(rows)) < limit || limit < 0) {
+ t, c, err := ParseLog(scanner.Text())
+ if err != nil {
+ return nil, fmt.Errorf("parse log %q: %w", scanner.Text(), err)
+ }
+ rows = append(rows, &runnerv1.LogRow{
+ Time: timestamppb.New(t),
+ Content: c,
+ })
+ }
+
+ if err := scanner.Err(); err != nil {
+ return nil, fmt.Errorf("scan: %w", err)
+ }
+
+ return rows, nil
+}
+
+func TransferLogs(ctx context.Context, filename string) (func(), error) {
+ name := DBFSPrefix + filename
+ remove := func() {
+ if err := dbfs.Remove(ctx, name); err != nil {
+ log.Warn("dbfs remove %q: %v", name, err)
+ }
+ }
+ f, err := dbfs.Open(ctx, name)
+ if err != nil {
+ return nil, fmt.Errorf("dbfs open %q: %w", name, err)
+ }
+ defer f.Close()
+
+ if _, err := storage.Actions.Save(filename, f, -1); err != nil {
+ return nil, fmt.Errorf("storage save %q: %w", filename, err)
+ }
+ return remove, nil
+}
+
+func RemoveLogs(ctx context.Context, inStorage bool, filename string) error {
+ if !inStorage {
+ name := DBFSPrefix + filename
+ err := dbfs.Remove(ctx, name)
+ if err != nil {
+ return fmt.Errorf("dbfs remove %q: %w", name, err)
+ }
+ return nil
+ }
+ err := storage.Actions.Delete(filename)
+ if err != nil {
+ return fmt.Errorf("storage delete %q: %w", filename, err)
+ }
+ return nil
+}
+
+func openLogs(ctx context.Context, inStorage bool, filename string) (io.ReadSeekCloser, error) {
+ if !inStorage {
+ name := DBFSPrefix + filename
+ f, err := dbfs.Open(ctx, name)
+ if err != nil {
+ return nil, fmt.Errorf("dbfs open %q: %w", name, err)
+ }
+ return f, nil
+ }
+ f, err := storage.Actions.Open(filename)
+ if err != nil {
+ return nil, fmt.Errorf("storage open %q: %w", filename, err)
+ }
+ return f, nil
+}
+
+func FormatLog(timestamp time.Time, content string) string {
+ // Content shouldn't contain new line, it will break log indexes, other control chars are safe.
+ content = strings.ReplaceAll(content, "\n", `\n`)
+ if len(content) > MaxLineSize {
+ content = content[:MaxLineSize]
+ }
+ return fmt.Sprintf("%s %s", timestamp.UTC().Format(timeFormat), content)
+}
+
+func ParseLog(in string) (time.Time, string, error) {
+ index := strings.IndexRune(in, ' ')
+ if index < 0 {
+ return time.Time{}, "", fmt.Errorf("invalid log: %q", in)
+ }
+ timestamp, err := time.Parse(timeFormat, in[:index])
+ if err != nil {
+ return time.Time{}, "", err
+ }
+ return timestamp, in[index+1:], nil
+}
diff --git a/modules/actions/task_state.go b/modules/actions/task_state.go
new file mode 100644
index 0000000000..cbbc0b357d
--- /dev/null
+++ b/modules/actions/task_state.go
@@ -0,0 +1,101 @@
+// Copyright 2022 The Gitea Authors. All rights reserved.
+// SPDX-License-Identifier: MIT
+
+package actions
+
+import (
+ actions_model "code.gitea.io/gitea/models/actions"
+)
+
+const (
+ preStepName = "Set up job"
+ postStepName = "Complete job"
+)
+
+// FullSteps returns steps with "Set up job" and "Complete job"
+func FullSteps(task *actions_model.ActionTask) []*actions_model.ActionTaskStep {
+ if len(task.Steps) == 0 {
+ return fullStepsOfEmptySteps(task)
+ }
+
+ firstStep := task.Steps[0]
+ var logIndex int64
+
+ preStep := &actions_model.ActionTaskStep{
+ Name: preStepName,
+ LogLength: task.LogLength,
+ Started: task.Started,
+ Status: actions_model.StatusRunning,
+ }
+
+ if firstStep.Status.HasRun() || firstStep.Status.IsRunning() {
+ preStep.LogLength = firstStep.LogIndex
+ preStep.Stopped = firstStep.Started
+ preStep.Status = actions_model.StatusSuccess
+ } else if task.Status.IsDone() {
+ preStep.Stopped = task.Stopped
+ preStep.Status = actions_model.StatusFailure
+ }
+ logIndex += preStep.LogLength
+
+ var lastHasRunStep *actions_model.ActionTaskStep
+ for _, step := range task.Steps {
+ if step.Status.HasRun() {
+ lastHasRunStep = step
+ }
+ logIndex += step.LogLength
+ }
+ if lastHasRunStep == nil {
+ lastHasRunStep = preStep
+ }
+
+ postStep := &actions_model.ActionTaskStep{
+ Name: postStepName,
+ Status: actions_model.StatusWaiting,
+ }
+ if task.Status.IsDone() {
+ postStep.LogIndex = logIndex
+ postStep.LogLength = task.LogLength - postStep.LogIndex
+ postStep.Status = task.Status
+ postStep.Started = lastHasRunStep.Stopped
+ postStep.Stopped = task.Stopped
+ }
+ ret := make([]*actions_model.ActionTaskStep, 0, len(task.Steps)+2)
+ ret = append(ret, preStep)
+ ret = append(ret, task.Steps...)
+ ret = append(ret, postStep)
+
+ return ret
+}
+
+func fullStepsOfEmptySteps(task *actions_model.ActionTask) []*actions_model.ActionTaskStep {
+ preStep := &actions_model.ActionTaskStep{
+ Name: preStepName,
+ LogLength: task.LogLength,
+ Started: task.Started,
+ Stopped: task.Stopped,
+ Status: actions_model.StatusRunning,
+ }
+
+ postStep := &actions_model.ActionTaskStep{
+ Name: postStepName,
+ LogIndex: task.LogLength,
+ Started: task.Stopped,
+ Stopped: task.Stopped,
+ Status: actions_model.StatusWaiting,
+ }
+
+ if task.Status.IsDone() {
+ preStep.Status = task.Status
+ if preStep.Status.IsSuccess() {
+ postStep.Status = actions_model.StatusSuccess
+ } else {
+ postStep.Status = actions_model.StatusCancelled
+ }
+ }
+
+ return []*actions_model.ActionTaskStep{
+ preStep,
+ postStep,
+ }
+}
diff --git a/modules/actions/task_state_test.go b/modules/actions/task_state_test.go
new file mode 100644
index 0000000000..3a599fbcbd
--- /dev/null
+++ b/modules/actions/task_state_test.go
@@ -0,0 +1,112 @@
+// Copyright 2022 The Gitea Authors. All rights reserved.
+// SPDX-License-Identifier: MIT
+
+package actions
+
+import (
+ "testing"
+
+ actions_model "code.gitea.io/gitea/models/actions"
+
+ "github.com/stretchr/testify/assert"
+)
+
+func TestFullSteps(t *testing.T) {
+ tests := []struct {
+ name string
+ task *actions_model.ActionTask
+ want []*actions_model.ActionTaskStep
+ }{
+ {
+ name: "regular",
+ task: &actions_model.ActionTask{
+ Steps: []*actions_model.ActionTaskStep{
+ {Status: actions_model.StatusSuccess, LogIndex: 10, LogLength: 80, Started: 10010, Stopped: 10090},
+ },
+ Status: actions_model.StatusSuccess,
+ Started: 10000,
+ Stopped: 10100,
+ LogLength: 100,
+ },
+ want: []*actions_model.ActionTaskStep{
+ {Name: preStepName, Status: actions_model.StatusSuccess, LogIndex: 0, LogLength: 10, Started: 10000, Stopped: 10010},
+ {Status: actions_model.StatusSuccess, LogIndex: 10, LogLength: 80, Started: 10010, Stopped: 10090},
+ {Name: postStepName, Status: actions_model.StatusSuccess, LogIndex: 90, LogLength: 10, Started: 10090, Stopped: 10100},
+ },
+ },
+ {
+ name: "failed step",
+ task: &actions_model.ActionTask{
+ Steps: []*actions_model.ActionTaskStep{
+ {Status: actions_model.StatusSuccess, LogIndex: 10, LogLength: 20, Started: 10010, Stopped: 10020},
+ {Status: actions_model.StatusFailure, LogIndex: 30, LogLength: 60, Started: 10020, Stopped: 10090},
+ {Status: actions_model.StatusCancelled, LogIndex: 0, LogLength: 0, Started: 0, Stopped: 0},
+ },
+ Status: actions_model.StatusFailure,
+ Started: 10000,
+ Stopped: 10100,
+ LogLength: 100,
+ },
+ want: []*actions_model.ActionTaskStep{
+ {Name: preStepName, Status: actions_model.StatusSuccess, LogIndex: 0, LogLength: 10, Started: 10000, Stopped: 10010},
+ {Status: actions_model.StatusSuccess, LogIndex: 10, LogLength: 20, Started: 10010, Stopped: 10020},
+ {Status: actions_model.StatusFailure, LogIndex: 30, LogLength: 60, Started: 10020, Stopped: 10090},
+ {Status: actions_model.StatusCancelled, LogIndex: 0, LogLength: 0, Started: 0, Stopped: 0},
+ {Name: postStepName, Status: actions_model.StatusFailure, LogIndex: 90, LogLength: 10, Started: 10090, Stopped: 10100},
+ },
+ },
+ {
+ name: "first step is running",
+ task: &actions_model.ActionTask{
+ Steps: []*actions_model.ActionTaskStep{
+ {Status: actions_model.StatusRunning, LogIndex: 10, LogLength: 80, Started: 10010, Stopped: 0},
+ },
+ Status: actions_model.StatusRunning,
+ Started: 10000,
+ Stopped: 10100,
+ LogLength: 100,
+ },
+ want: []*actions_model.ActionTaskStep{
+ {Name: preStepName, Status: actions_model.StatusSuccess, LogIndex: 0, LogLength: 10, Started: 10000, Stopped: 10010},
+ {Status: actions_model.StatusRunning, LogIndex: 10, LogLength: 80, Started: 10010, Stopped: 0},
+ {Name: postStepName, Status: actions_model.StatusWaiting, LogIndex: 0, LogLength: 0, Started: 0, Stopped: 0},
+ },
+ },
+ {
+ name: "first step has canceled",
+ task: &actions_model.ActionTask{
+ Steps: []*actions_model.ActionTaskStep{
+ {Status: actions_model.StatusCancelled, LogIndex: 0, LogLength: 0, Started: 0, Stopped: 0},
+ },
+ Status: actions_model.StatusFailure,
+ Started: 10000,
+ Stopped: 10100,
+ LogLength: 100,
+ },
+ want: []*actions_model.ActionTaskStep{
+ {Name: preStepName, Status: actions_model.StatusFailure, LogIndex: 0, LogLength: 100, Started: 10000, Stopped: 10100},
+ {Status: actions_model.StatusCancelled, LogIndex: 0, LogLength: 0, Started: 0, Stopped: 0},
+ {Name: postStepName, Status: actions_model.StatusFailure, LogIndex: 100, LogLength: 0, Started: 10100, Stopped: 10100},
+ },
+ },
+ {
+ name: "empty steps",
+ task: &actions_model.ActionTask{
+ Steps: []*actions_model.ActionTaskStep{},
+ Status: actions_model.StatusSuccess,
+ Started: 10000,
+ Stopped: 10100,
+ LogLength: 100,
+ },
+ want: []*actions_model.ActionTaskStep{
+ {Name: preStepName, Status: actions_model.StatusSuccess, LogIndex: 0, LogLength: 100, Started: 10000, Stopped: 10100},
+ {Name: postStepName, Status: actions_model.StatusSuccess, LogIndex: 100, LogLength: 0, Started: 10100, Stopped: 10100},
+ },
+ },
+ }
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+ assert.Equalf(t, tt.want, FullSteps(tt.task), "FullSteps(%v)", tt.task)
+ })
+ }
+}
diff --git a/modules/actions/workflows.go b/modules/actions/workflows.go
new file mode 100644
index 0000000000..d340a1aa65
--- /dev/null
+++ b/modules/actions/workflows.go
@@ -0,0 +1,75 @@
+// Copyright 2022 The Gitea Authors. All rights reserved.
+// SPDX-License-Identifier: MIT
+
+package actions
+
+import (
+ "bytes"
+ "io"
+ "strings"
+
+ "code.gitea.io/gitea/modules/git"
+ "code.gitea.io/gitea/modules/log"
+ webhook_module "code.gitea.io/gitea/modules/webhook"
+
+ "github.com/nektos/act/pkg/model"
+)
+
+func ListWorkflows(commit *git.Commit) (git.Entries, error) {
+ tree, err := commit.SubTree(".gitea/workflows")
+ if _, ok := err.(git.ErrNotExist); ok {
+ tree, err = commit.SubTree(".github/workflows")
+ }
+ if _, ok := err.(git.ErrNotExist); ok {
+ return nil, nil
+ }
+ if err != nil {
+ return nil, err
+ }
+
+ entries, err := tree.ListEntriesRecursiveFast()
+ if err != nil {
+ return nil, err
+ }
+
+ ret := make(git.Entries, 0, len(entries))
+ for _, entry := range entries {
+ if strings.HasSuffix(entry.Name(), ".yml") || strings.HasSuffix(entry.Name(), ".yaml") {
+ ret = append(ret, entry)
+ }
+ }
+ return ret, nil
+}
+
+func DetectWorkflows(commit *git.Commit, event webhook_module.HookEventType) (map[string][]byte, error) {
+ entries, err := ListWorkflows(commit)
+ if err != nil {
+ return nil, err
+ }
+
+ workflows := make(map[string][]byte, len(entries))
+ for _, entry := range entries {
+ f, err := entry.Blob().DataAsync()
+ if err != nil {
+ return nil, err
+ }
+ content, err := io.ReadAll(f)
+ _ = f.Close()
+ if err != nil {
+ return nil, err
+ }
+ workflow, err := model.ReadWorkflow(bytes.NewReader(content))
+ if err != nil {
+ log.Warn("ignore invalid workflow %q: %v", entry.Name(), err)
+ continue
+ }
+ for _, e := range workflow.On() {
+ if e == event.Event() {
+ workflows[entry.Name()] = content
+ break
+ }
+ }
+ }
+
+ return workflows, nil
+}
diff --git a/modules/context/context.go b/modules/context/context.go
index 6273093060..84f40ce063 100644
--- a/modules/context/context.go
+++ b/modules/context/context.go
@@ -805,6 +805,7 @@ func Contexter(ctx context.Context) func(next http.Handler) http.Handler {
ctx.Data["EnableOpenIDSignIn"] = setting.Service.EnableOpenIDSignIn
ctx.Data["DisableMigrations"] = setting.Repository.DisableMigrations
ctx.Data["DisableStars"] = setting.Repository.DisableStars
+ ctx.Data["EnableActions"] = setting.Actions.Enabled
ctx.Data["ManifestData"] = setting.ManifestData
@@ -812,6 +813,7 @@ func Contexter(ctx context.Context) func(next http.Handler) http.Handler {
ctx.Data["UnitIssuesGlobalDisabled"] = unit.TypeIssues.UnitGlobalDisabled()
ctx.Data["UnitPullsGlobalDisabled"] = unit.TypePullRequests.UnitGlobalDisabled()
ctx.Data["UnitProjectsGlobalDisabled"] = unit.TypeProjects.UnitGlobalDisabled()
+ ctx.Data["UnitActionsGlobalDisabled"] = unit.TypeActions.UnitGlobalDisabled()
ctx.Data["locale"] = locale
ctx.Data["AllLangs"] = translation.AllLangs()
diff --git a/modules/context/repo.go b/modules/context/repo.go
index a5ade21e43..38c1d84541 100644
--- a/modules/context/repo.go
+++ b/modules/context/repo.go
@@ -1043,6 +1043,7 @@ func UnitTypes() func(ctx *Context) {
ctx.Data["UnitTypeExternalTracker"] = unit_model.TypeExternalTracker
ctx.Data["UnitTypeProjects"] = unit_model.TypeProjects
ctx.Data["UnitTypePackages"] = unit_model.TypePackages
+ ctx.Data["UnitTypeActions"] = unit_model.TypeActions
}
}
diff --git a/modules/notification/notification.go b/modules/notification/notification.go
index 2300b68f78..da2a7ab3a0 100644
--- a/modules/notification/notification.go
+++ b/modules/notification/notification.go
@@ -10,6 +10,7 @@ import (
packages_model "code.gitea.io/gitea/models/packages"
repo_model "code.gitea.io/gitea/models/repo"
user_model "code.gitea.io/gitea/models/user"
+ "code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/notification/action"
"code.gitea.io/gitea/modules/notification/base"
"code.gitea.io/gitea/modules/notification/indexer"
@@ -106,6 +107,13 @@ func NotifyAutoMergePullRequest(ctx context.Context, doer *user_model.User, pr *
// NotifyNewPullRequest notifies new pull request to notifiers
func NotifyNewPullRequest(ctx context.Context, pr *issues_model.PullRequest, mentions []*user_model.User) {
+ if err := pr.LoadIssue(ctx); err != nil {
+ log.Error("%v", err)
+ return
+ }
+ if err := pr.Issue.LoadPoster(ctx); err != nil {
+ return
+ }
for _, notifier := range notifiers {
notifier.NotifyNewPullRequest(ctx, pr, mentions)
}
@@ -120,6 +128,10 @@ func NotifyPullRequestSynchronized(ctx context.Context, doer *user_model.User, p
// NotifyPullRequestReview notifies new pull request review
func NotifyPullRequestReview(ctx context.Context, pr *issues_model.PullRequest, review *issues_model.Review, comment *issues_model.Comment, mentions []*user_model.User) {
+ if err := review.LoadReviewer(ctx); err != nil {
+ log.Error("%v", err)
+ return
+ }
for _, notifier := range notifiers {
notifier.NotifyPullRequestReview(ctx, pr, review, comment, mentions)
}
@@ -127,6 +139,10 @@ func NotifyPullRequestReview(ctx context.Context, pr *issues_model.PullRequest,
// NotifyPullRequestCodeComment notifies new pull request code comment
func NotifyPullRequestCodeComment(ctx context.Context, pr *issues_model.PullRequest, comment *issues_model.Comment, mentions []*user_model.User) {
+ if err := comment.LoadPoster(ctx); err != nil {
+ log.Error("LoadPoster: %v", err)
+ return
+ }
for _, notifier := range notifiers {
notifier.NotifyPullRequestCodeComment(ctx, pr, comment, mentions)
}
@@ -169,6 +185,10 @@ func NotifyDeleteComment(ctx context.Context, doer *user_model.User, c *issues_m
// NotifyNewRelease notifies new release to notifiers
func NotifyNewRelease(ctx context.Context, rel *repo_model.Release) {
+ if err := rel.LoadAttributes(ctx); err != nil {
+ log.Error("LoadPublisher: %v", err)
+ return
+ }
for _, notifier := range notifiers {
notifier.NotifyNewRelease(ctx, rel)
}
diff --git a/modules/private/hook.go b/modules/private/hook.go
index 027014270a..9533eaae59 100644
--- a/modules/private/hook.go
+++ b/modules/private/hook.go
@@ -57,6 +57,7 @@ type HookOptions struct {
PullRequestID int64
DeployKeyID int64 // if the pusher is a DeployKey, then UserID is the repo's org user.
IsWiki bool
+ ActionPerm int
}
// SSHLogOption ssh log options
diff --git a/modules/repository/env.go b/modules/repository/env.go
index 646bf35cc6..30edd1c9e3 100644
--- a/modules/repository/env.go
+++ b/modules/repository/env.go
@@ -27,6 +27,7 @@ const (
EnvPRID = "GITEA_PR_ID"
EnvIsInternal = "GITEA_INTERNAL_PUSH"
EnvAppURL = "GITEA_ROOT_URL"
+ EnvActionPerm = "GITEA_ACTION_PERM"
)
// InternalPushingEnvironment returns an os environment to switch off hooks on push
diff --git a/modules/setting/actions.go b/modules/setting/actions.go
new file mode 100644
index 0000000000..5c83a73aeb
--- /dev/null
+++ b/modules/setting/actions.go
@@ -0,0 +1,29 @@
+// Copyright 2022 The Gitea Authors. All rights reserved.
+// SPDX-License-Identifier: MIT
+
+package setting
+
+import (
+ "code.gitea.io/gitea/modules/log"
+)
+
+// Actions settings
+var (
+ Actions = struct {
+ Storage // how the created logs should be stored
+ Enabled bool
+ DefaultActionsURL string `ini:"DEFAULT_ACTIONS_URL"`
+ }{
+ Enabled: false,
+ DefaultActionsURL: "https://gitea.com",
+ }
+)
+
+func newActions() {
+ sec := Cfg.Section("actions")
+ if err := sec.MapTo(&Actions); err != nil {
+ log.Fatal("Failed to map Actions settings: %v", err)
+ }
+
+ Actions.Storage = getStorage("actions_log", "", nil)
+}
diff --git a/modules/setting/setting.go b/modules/setting/setting.go
index 92861fb528..f591727ca3 100644
--- a/modules/setting/setting.go
+++ b/modules/setting/setting.go
@@ -1074,6 +1074,8 @@ func loadFromConf(allowEmpty bool, extraConfig string) {
newPackages()
+ newActions()
+
if err = Cfg.Section("ui").MapTo(&UI); err != nil {
log.Fatal("Failed to map UI settings: %v", err)
} else if err = Cfg.Section("markdown").MapTo(&Markdown); err != nil {
diff --git a/modules/storage/storage.go b/modules/storage/storage.go
index 671e0ce565..d8998b1922 100644
--- a/modules/storage/storage.go
+++ b/modules/storage/storage.go
@@ -125,6 +125,9 @@ var (
// Packages represents packages storage
Packages ObjectStorage = uninitializedStorage
+
+ // Actions represents actions storage
+ Actions ObjectStorage = uninitializedStorage
)
// Init init the stoarge
@@ -136,6 +139,7 @@ func Init() error {
initLFS,
initRepoArchives,
initPackages,
+ initActions,
} {
if err := f(); err != nil {
return err
@@ -204,3 +208,13 @@ func initPackages() (err error) {
Packages, err = NewStorage(setting.Packages.Storage.Type, &setting.Packages.Storage)
return err
}
+
+func initActions() (err error) {
+ if !setting.Actions.Enabled {
+ Actions = discardStorage("Actions isn't enabled")
+ return nil
+ }
+ log.Info("Initialising Actions storage with type: %s", setting.Actions.Storage.Type)
+ Actions, err = NewStorage(setting.Actions.Storage.Type, &setting.Actions.Storage)
+ return err
+}
diff --git a/modules/structs/commit_status.go b/modules/structs/commit_status.go
index dfde79190c..7e3b629b7a 100644
--- a/modules/structs/commit_status.go
+++ b/modules/structs/commit_status.go
@@ -18,6 +18,8 @@ const (
CommitStatusFailure CommitStatusState = "failure"
// CommitStatusWarning is for when the CommitStatus is Warning
CommitStatusWarning CommitStatusState = "warning"
+ // CommitStatusRunning is for when the CommitStatus is Running
+ CommitStatusRunning CommitStatusState = "running"
)
// NoBetterThan returns true if this State is no better than the given State
diff --git a/modules/templates/helper.go b/modules/templates/helper.go
index 7b997b49d9..a390d94592 100644
--- a/modules/templates/helper.go
+++ b/modules/templates/helper.go
@@ -472,6 +472,9 @@ func NewFuncMap() []template.FuncMap {
curBranch,
)
},
+ "RefShortName": func(ref string) string {
+ return git.RefName(ref).ShortName()
+ },
}}
}