code.gitea.io/gitea@v1.22.3/models/repo/repo_unit.go (about)

     1  // Copyright 2017 The Gitea Authors. All rights reserved.
     2  // SPDX-License-Identifier: MIT
     3  
     4  package repo
     5  
     6  import (
     7  	"context"
     8  	"fmt"
     9  	"slices"
    10  	"strings"
    11  
    12  	"code.gitea.io/gitea/models/db"
    13  	"code.gitea.io/gitea/models/perm"
    14  	"code.gitea.io/gitea/models/unit"
    15  	"code.gitea.io/gitea/modules/json"
    16  	"code.gitea.io/gitea/modules/setting"
    17  	"code.gitea.io/gitea/modules/timeutil"
    18  	"code.gitea.io/gitea/modules/util"
    19  
    20  	"xorm.io/xorm"
    21  	"xorm.io/xorm/convert"
    22  )
    23  
    24  // ErrUnitTypeNotExist represents a "UnitTypeNotExist" kind of error.
    25  type ErrUnitTypeNotExist struct {
    26  	UT unit.Type
    27  }
    28  
    29  // IsErrUnitTypeNotExist checks if an error is a ErrUnitNotExist.
    30  func IsErrUnitTypeNotExist(err error) bool {
    31  	_, ok := err.(ErrUnitTypeNotExist)
    32  	return ok
    33  }
    34  
    35  func (err ErrUnitTypeNotExist) Error() string {
    36  	return fmt.Sprintf("Unit type does not exist: %s", err.UT.String())
    37  }
    38  
    39  func (err ErrUnitTypeNotExist) Unwrap() error {
    40  	return util.ErrNotExist
    41  }
    42  
    43  // RepoUnit describes all units of a repository
    44  type RepoUnit struct { //revive:disable-line:exported
    45  	ID                 int64
    46  	RepoID             int64              `xorm:"INDEX(s)"`
    47  	Type               unit.Type          `xorm:"INDEX(s)"`
    48  	Config             convert.Conversion `xorm:"TEXT"`
    49  	CreatedUnix        timeutil.TimeStamp `xorm:"INDEX CREATED"`
    50  	EveryoneAccessMode perm.AccessMode    `xorm:"NOT NULL DEFAULT 0"`
    51  }
    52  
    53  func init() {
    54  	db.RegisterModel(new(RepoUnit))
    55  }
    56  
    57  // UnitConfig describes common unit config
    58  type UnitConfig struct{}
    59  
    60  // FromDB fills up a UnitConfig from serialized format.
    61  func (cfg *UnitConfig) FromDB(bs []byte) error {
    62  	return json.UnmarshalHandleDoubleEncode(bs, &cfg)
    63  }
    64  
    65  // ToDB exports a UnitConfig to a serialized format.
    66  func (cfg *UnitConfig) ToDB() ([]byte, error) {
    67  	return json.Marshal(cfg)
    68  }
    69  
    70  // ExternalWikiConfig describes external wiki config
    71  type ExternalWikiConfig struct {
    72  	ExternalWikiURL string
    73  }
    74  
    75  // FromDB fills up a ExternalWikiConfig from serialized format.
    76  func (cfg *ExternalWikiConfig) FromDB(bs []byte) error {
    77  	return json.UnmarshalHandleDoubleEncode(bs, &cfg)
    78  }
    79  
    80  // ToDB exports a ExternalWikiConfig to a serialized format.
    81  func (cfg *ExternalWikiConfig) ToDB() ([]byte, error) {
    82  	return json.Marshal(cfg)
    83  }
    84  
    85  // ExternalTrackerConfig describes external tracker config
    86  type ExternalTrackerConfig struct {
    87  	ExternalTrackerURL           string
    88  	ExternalTrackerFormat        string
    89  	ExternalTrackerStyle         string
    90  	ExternalTrackerRegexpPattern string
    91  }
    92  
    93  // FromDB fills up a ExternalTrackerConfig from serialized format.
    94  func (cfg *ExternalTrackerConfig) FromDB(bs []byte) error {
    95  	return json.UnmarshalHandleDoubleEncode(bs, &cfg)
    96  }
    97  
    98  // ToDB exports a ExternalTrackerConfig to a serialized format.
    99  func (cfg *ExternalTrackerConfig) ToDB() ([]byte, error) {
   100  	return json.Marshal(cfg)
   101  }
   102  
   103  // IssuesConfig describes issues config
   104  type IssuesConfig struct {
   105  	EnableTimetracker                bool
   106  	AllowOnlyContributorsToTrackTime bool
   107  	EnableDependencies               bool
   108  }
   109  
   110  // FromDB fills up a IssuesConfig from serialized format.
   111  func (cfg *IssuesConfig) FromDB(bs []byte) error {
   112  	return json.UnmarshalHandleDoubleEncode(bs, &cfg)
   113  }
   114  
   115  // ToDB exports a IssuesConfig to a serialized format.
   116  func (cfg *IssuesConfig) ToDB() ([]byte, error) {
   117  	return json.Marshal(cfg)
   118  }
   119  
   120  // PullRequestsConfig describes pull requests config
   121  type PullRequestsConfig struct {
   122  	IgnoreWhitespaceConflicts     bool
   123  	AllowMerge                    bool
   124  	AllowRebase                   bool
   125  	AllowRebaseMerge              bool
   126  	AllowSquash                   bool
   127  	AllowFastForwardOnly          bool
   128  	AllowManualMerge              bool
   129  	AutodetectManualMerge         bool
   130  	AllowRebaseUpdate             bool
   131  	DefaultDeleteBranchAfterMerge bool
   132  	DefaultMergeStyle             MergeStyle
   133  	DefaultAllowMaintainerEdit    bool
   134  }
   135  
   136  // FromDB fills up a PullRequestsConfig from serialized format.
   137  func (cfg *PullRequestsConfig) FromDB(bs []byte) error {
   138  	// AllowRebaseUpdate = true as default for existing PullRequestConfig in DB
   139  	cfg.AllowRebaseUpdate = true
   140  	return json.UnmarshalHandleDoubleEncode(bs, &cfg)
   141  }
   142  
   143  // ToDB exports a PullRequestsConfig to a serialized format.
   144  func (cfg *PullRequestsConfig) ToDB() ([]byte, error) {
   145  	return json.Marshal(cfg)
   146  }
   147  
   148  // IsMergeStyleAllowed returns if merge style is allowed
   149  func (cfg *PullRequestsConfig) IsMergeStyleAllowed(mergeStyle MergeStyle) bool {
   150  	return mergeStyle == MergeStyleMerge && cfg.AllowMerge ||
   151  		mergeStyle == MergeStyleRebase && cfg.AllowRebase ||
   152  		mergeStyle == MergeStyleRebaseMerge && cfg.AllowRebaseMerge ||
   153  		mergeStyle == MergeStyleSquash && cfg.AllowSquash ||
   154  		mergeStyle == MergeStyleFastForwardOnly && cfg.AllowFastForwardOnly ||
   155  		mergeStyle == MergeStyleManuallyMerged && cfg.AllowManualMerge
   156  }
   157  
   158  // GetDefaultMergeStyle returns the default merge style for this pull request
   159  func (cfg *PullRequestsConfig) GetDefaultMergeStyle() MergeStyle {
   160  	if len(cfg.DefaultMergeStyle) != 0 {
   161  		return cfg.DefaultMergeStyle
   162  	}
   163  
   164  	if setting.Repository.PullRequest.DefaultMergeStyle != "" {
   165  		return MergeStyle(setting.Repository.PullRequest.DefaultMergeStyle)
   166  	}
   167  
   168  	return MergeStyleMerge
   169  }
   170  
   171  type ActionsConfig struct {
   172  	DisabledWorkflows []string
   173  }
   174  
   175  func (cfg *ActionsConfig) EnableWorkflow(file string) {
   176  	cfg.DisabledWorkflows = util.SliceRemoveAll(cfg.DisabledWorkflows, file)
   177  }
   178  
   179  func (cfg *ActionsConfig) ToString() string {
   180  	return strings.Join(cfg.DisabledWorkflows, ",")
   181  }
   182  
   183  func (cfg *ActionsConfig) IsWorkflowDisabled(file string) bool {
   184  	return slices.Contains(cfg.DisabledWorkflows, file)
   185  }
   186  
   187  func (cfg *ActionsConfig) DisableWorkflow(file string) {
   188  	for _, workflow := range cfg.DisabledWorkflows {
   189  		if file == workflow {
   190  			return
   191  		}
   192  	}
   193  
   194  	cfg.DisabledWorkflows = append(cfg.DisabledWorkflows, file)
   195  }
   196  
   197  // FromDB fills up a ActionsConfig from serialized format.
   198  func (cfg *ActionsConfig) FromDB(bs []byte) error {
   199  	return json.UnmarshalHandleDoubleEncode(bs, &cfg)
   200  }
   201  
   202  // ToDB exports a ActionsConfig to a serialized format.
   203  func (cfg *ActionsConfig) ToDB() ([]byte, error) {
   204  	return json.Marshal(cfg)
   205  }
   206  
   207  // ProjectsMode represents the projects enabled for a repository
   208  type ProjectsMode string
   209  
   210  const (
   211  	// ProjectsModeRepo allows only repo-level projects
   212  	ProjectsModeRepo ProjectsMode = "repo"
   213  	// ProjectsModeOwner allows only owner-level projects
   214  	ProjectsModeOwner ProjectsMode = "owner"
   215  	// ProjectsModeAll allows both kinds of projects
   216  	ProjectsModeAll ProjectsMode = "all"
   217  	// ProjectsModeNone doesn't allow projects
   218  	ProjectsModeNone ProjectsMode = "none"
   219  )
   220  
   221  // ProjectsConfig describes projects config
   222  type ProjectsConfig struct {
   223  	ProjectsMode ProjectsMode
   224  }
   225  
   226  // FromDB fills up a ProjectsConfig from serialized format.
   227  func (cfg *ProjectsConfig) FromDB(bs []byte) error {
   228  	return json.UnmarshalHandleDoubleEncode(bs, &cfg)
   229  }
   230  
   231  // ToDB exports a ProjectsConfig to a serialized format.
   232  func (cfg *ProjectsConfig) ToDB() ([]byte, error) {
   233  	return json.Marshal(cfg)
   234  }
   235  
   236  func (cfg *ProjectsConfig) GetProjectsMode() ProjectsMode {
   237  	if cfg.ProjectsMode != "" {
   238  		return cfg.ProjectsMode
   239  	}
   240  
   241  	return ProjectsModeAll
   242  }
   243  
   244  func (cfg *ProjectsConfig) IsProjectsAllowed(m ProjectsMode) bool {
   245  	projectsMode := cfg.GetProjectsMode()
   246  
   247  	if m == ProjectsModeNone {
   248  		return true
   249  	}
   250  
   251  	return projectsMode == m || projectsMode == ProjectsModeAll
   252  }
   253  
   254  // BeforeSet is invoked from XORM before setting the value of a field of this object.
   255  func (r *RepoUnit) BeforeSet(colName string, val xorm.Cell) {
   256  	switch colName {
   257  	case "type":
   258  		switch unit.Type(db.Cell2Int64(val)) {
   259  		case unit.TypeExternalWiki:
   260  			r.Config = new(ExternalWikiConfig)
   261  		case unit.TypeExternalTracker:
   262  			r.Config = new(ExternalTrackerConfig)
   263  		case unit.TypePullRequests:
   264  			r.Config = new(PullRequestsConfig)
   265  		case unit.TypeIssues:
   266  			r.Config = new(IssuesConfig)
   267  		case unit.TypeActions:
   268  			r.Config = new(ActionsConfig)
   269  		case unit.TypeProjects:
   270  			r.Config = new(ProjectsConfig)
   271  		case unit.TypeCode, unit.TypeReleases, unit.TypeWiki, unit.TypePackages:
   272  			fallthrough
   273  		default:
   274  			r.Config = new(UnitConfig)
   275  		}
   276  	}
   277  }
   278  
   279  // Unit returns Unit
   280  func (r *RepoUnit) Unit() unit.Unit {
   281  	return unit.Units[r.Type]
   282  }
   283  
   284  // CodeConfig returns config for unit.TypeCode
   285  func (r *RepoUnit) CodeConfig() *UnitConfig {
   286  	return r.Config.(*UnitConfig)
   287  }
   288  
   289  // PullRequestsConfig returns config for unit.TypePullRequests
   290  func (r *RepoUnit) PullRequestsConfig() *PullRequestsConfig {
   291  	return r.Config.(*PullRequestsConfig)
   292  }
   293  
   294  // ReleasesConfig returns config for unit.TypeReleases
   295  func (r *RepoUnit) ReleasesConfig() *UnitConfig {
   296  	return r.Config.(*UnitConfig)
   297  }
   298  
   299  // ExternalWikiConfig returns config for unit.TypeExternalWiki
   300  func (r *RepoUnit) ExternalWikiConfig() *ExternalWikiConfig {
   301  	return r.Config.(*ExternalWikiConfig)
   302  }
   303  
   304  // IssuesConfig returns config for unit.TypeIssues
   305  func (r *RepoUnit) IssuesConfig() *IssuesConfig {
   306  	return r.Config.(*IssuesConfig)
   307  }
   308  
   309  // ExternalTrackerConfig returns config for unit.TypeExternalTracker
   310  func (r *RepoUnit) ExternalTrackerConfig() *ExternalTrackerConfig {
   311  	return r.Config.(*ExternalTrackerConfig)
   312  }
   313  
   314  // ActionsConfig returns config for unit.ActionsConfig
   315  func (r *RepoUnit) ActionsConfig() *ActionsConfig {
   316  	return r.Config.(*ActionsConfig)
   317  }
   318  
   319  // ProjectsConfig returns config for unit.ProjectsConfig
   320  func (r *RepoUnit) ProjectsConfig() *ProjectsConfig {
   321  	return r.Config.(*ProjectsConfig)
   322  }
   323  
   324  func getUnitsByRepoID(ctx context.Context, repoID int64) (units []*RepoUnit, err error) {
   325  	var tmpUnits []*RepoUnit
   326  	if err := db.GetEngine(ctx).Where("repo_id = ?", repoID).Find(&tmpUnits); err != nil {
   327  		return nil, err
   328  	}
   329  
   330  	for _, u := range tmpUnits {
   331  		if !u.Type.UnitGlobalDisabled() {
   332  			units = append(units, u)
   333  		}
   334  	}
   335  
   336  	return units, nil
   337  }
   338  
   339  // UpdateRepoUnit updates the provided repo unit
   340  func UpdateRepoUnit(ctx context.Context, unit *RepoUnit) error {
   341  	_, err := db.GetEngine(ctx).ID(unit.ID).Update(unit)
   342  	return err
   343  }