Support unprotected file patterns (#16395)
Fixes #16381 Note that changes to unprotected files via the web editor still cannot be pushed directly to the protected branch. I could easily add such support for edits and deletes if needed. But for adding, uploading or renaming unprotected files, it is not trivial. * Extract & Move GetAffectedFiles to modules/git
This commit is contained in:
parent
eb03e819d3
commit
3d6cb25e31
17 changed files with 254 additions and 126 deletions
|
@ -199,6 +199,7 @@ type ProtectBranchForm struct {
|
|||
DismissStaleApprovals bool
|
||||
RequireSignedCommits bool
|
||||
ProtectedFilePatterns string
|
||||
UnprotectedFilePatterns string
|
||||
}
|
||||
|
||||
// Validate validates the fields
|
||||
|
|
|
@ -245,70 +245,59 @@ func checkConflicts(pr *models.PullRequest, gitRepo *git.Repository, tmpBasePath
|
|||
|
||||
// CheckFileProtection check file Protection
|
||||
func CheckFileProtection(oldCommitID, newCommitID string, patterns []glob.Glob, limit int, env []string, repo *git.Repository) ([]string, error) {
|
||||
// 1. If there are no patterns short-circuit and just return nil
|
||||
if len(patterns) == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// 2. Prep the pipe
|
||||
stdoutReader, stdoutWriter, err := os.Pipe()
|
||||
affectedFiles, err := git.GetAffectedFiles(oldCommitID, newCommitID, env, repo)
|
||||
if err != nil {
|
||||
log.Error("Unable to create os.Pipe for %s", repo.Path)
|
||||
return nil, err
|
||||
}
|
||||
defer func() {
|
||||
_ = stdoutReader.Close()
|
||||
_ = stdoutWriter.Close()
|
||||
}()
|
||||
|
||||
changedProtectedFiles := make([]string, 0, limit)
|
||||
|
||||
// 3. Run `git diff --name-only` to get the names of the changed files
|
||||
err = git.NewCommand("diff", "--name-only", oldCommitID, newCommitID).
|
||||
RunInDirTimeoutEnvFullPipelineFunc(env, -1, repo.Path,
|
||||
stdoutWriter, nil, nil,
|
||||
func(ctx context.Context, cancel context.CancelFunc) error {
|
||||
// Close the writer end of the pipe to begin processing
|
||||
_ = stdoutWriter.Close()
|
||||
defer func() {
|
||||
// Close the reader on return to terminate the git command if necessary
|
||||
_ = stdoutReader.Close()
|
||||
}()
|
||||
|
||||
// Now scan the output from the command
|
||||
scanner := bufio.NewScanner(stdoutReader)
|
||||
for scanner.Scan() {
|
||||
path := strings.TrimSpace(scanner.Text())
|
||||
if len(path) == 0 {
|
||||
continue
|
||||
}
|
||||
lpath := strings.ToLower(path)
|
||||
for _, pat := range patterns {
|
||||
if pat.Match(lpath) {
|
||||
changedProtectedFiles = append(changedProtectedFiles, path)
|
||||
break
|
||||
}
|
||||
}
|
||||
if len(changedProtectedFiles) >= limit {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if len(changedProtectedFiles) > 0 {
|
||||
return models.ErrFilePathProtected{
|
||||
Path: changedProtectedFiles[0],
|
||||
}
|
||||
}
|
||||
return scanner.Err()
|
||||
})
|
||||
// 4. log real errors if there are any...
|
||||
if err != nil && !models.IsErrFilePathProtected(err) {
|
||||
log.Error("Unable to check file protection for commits from %s to %s in %s: %v", oldCommitID, newCommitID, repo.Path, err)
|
||||
for _, affectedFile := range affectedFiles {
|
||||
lpath := strings.ToLower(affectedFile)
|
||||
for _, pat := range patterns {
|
||||
if pat.Match(lpath) {
|
||||
changedProtectedFiles = append(changedProtectedFiles, lpath)
|
||||
break
|
||||
}
|
||||
}
|
||||
if len(changedProtectedFiles) >= limit {
|
||||
break
|
||||
}
|
||||
}
|
||||
if len(changedProtectedFiles) > 0 {
|
||||
err = models.ErrFilePathProtected{
|
||||
Path: changedProtectedFiles[0],
|
||||
}
|
||||
}
|
||||
|
||||
return changedProtectedFiles, err
|
||||
}
|
||||
|
||||
// CheckUnprotectedFiles check if the commit only touches unprotected files
|
||||
func CheckUnprotectedFiles(oldCommitID, newCommitID string, patterns []glob.Glob, env []string, repo *git.Repository) (bool, error) {
|
||||
if len(patterns) == 0 {
|
||||
return false, nil
|
||||
}
|
||||
affectedFiles, err := git.GetAffectedFiles(oldCommitID, newCommitID, env, repo)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
for _, affectedFile := range affectedFiles {
|
||||
lpath := strings.ToLower(affectedFile)
|
||||
unprotected := false
|
||||
for _, pat := range patterns {
|
||||
if pat.Match(lpath) {
|
||||
unprotected = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !unprotected {
|
||||
return false, nil
|
||||
}
|
||||
}
|
||||
return true, nil
|
||||
}
|
||||
|
||||
// checkPullFilesProtection check if pr changed protected files and save results
|
||||
func checkPullFilesProtection(pr *models.PullRequest, gitRepo *git.Repository) error {
|
||||
if err := pr.LoadProtectedBranch(); err != nil {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue