Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 14 additions & 4 deletions internal/setup/gitlab.go
Original file line number Diff line number Diff line change
Expand Up @@ -1187,12 +1187,22 @@ func (g *gitlabSetup) defaultBranch(ctx context.Context) {
g.r.add(step, StatusWould, "would protect %s: push No one, merge Maintainers, no force push", b)
return
}
if err := g.send(ctx, http.MethodPost, protect, nil, "projects", id(g.hub.ID), "protected_branches"); err != nil {
g.r.add(step, StatusFail, "cannot protect %s: %v", b, err)
perr := g.send(ctx, http.MethodPost, protect, nil, "projects", id(g.hub.ID), "protected_branches")
if perr == nil {
g.r.add(step, StatusDone, "protected %s: push No one, merge Maintainers, no force push", b)
return
}
// GitLab protects a new project's default branch from a background
// job: the read above may miss a protection the POST then meets
// (409). Read it again, and go on as for a branch found protected.
if !isStatus(perr, http.StatusConflict) {
g.r.add(step, StatusFail, "cannot protect %s: %v", b, perr)
return
}
if err := g.get(ctx, &pb, "projects", id(g.hub.ID), "protected_branches", b); err != nil {
g.r.add(step, StatusFail, "cannot protect %s: %v; and reading the protection GitLab reports: %v", b, perr, err)
return
}
g.r.add(step, StatusDone, "protected %s: push No one, merge Maintainers, no force push", b)
return
}
if pushOK(pb.Push) && mergeOK(pb.Merge) && !pb.AllowForcePush {
g.r.add(step, StatusOK, "%s is protected: push No one, merge %s, no force push", b, mergeLevels(pb.Merge))
Expand Down
13 changes: 13 additions & 0 deletions internal/setup/gitlab_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -709,3 +709,16 @@ func TestGitLabWriterOnHub(t *testing.T) {
t.Errorf("writer-guard %s %q, exit %d", s.Status, s.Detail, rep.ExitCode())
}
}

// TestGitLabLateProtection: the read of main misses the protection GitLab
// is still making for the new project, and the POST meets it (409):
// setup reads it again and protects main as for a branch found protected.
func TestGitLabLateProtection(t *testing.T) {
w := newGLWorld(t, "18.11")
w.f.lateProtection = true
rep := w.run(t, w.input(false))
if s := step(t, rep, "default-branch"); s.Status != StatusDone {
t.Errorf("default-branch %s %q", s.Status, s.Detail)
}
w.checkHub(t, rep)
}
32 changes: 20 additions & 12 deletions internal/setup/glfake_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,18 +41,22 @@ type glFake struct {
t *testing.T
srv *httptest.Server

mu sync.Mutex
version string
saAPI bool
saCreate bool
premium bool
next int64
users map[int64]*fUser
tokens map[string]*fToken
groups map[int64]*fGroup
projects map[int64]*fProject
writes []string // "METHOD path" of every request that is not a GET
failRoutes map[string]int
mu sync.Mutex
version string
saAPI bool
saCreate bool
premium bool
// lateProtection makes the first read of a protected branch answer 404
// although it exists: GitLab protects a new project's default branch
// from a background job, which a read may not see yet.
lateProtection bool
next int64
users map[int64]*fUser
tokens map[string]*fToken
groups map[int64]*fGroup
projects map[int64]*fProject
writes []string // "METHOD path" of every request that is not a GET
failRoutes map[string]int
}

type fUser struct {
Expand Down Expand Up @@ -766,6 +770,10 @@ func (f *glFake) serveProject(w http.ResponseWriter, r *http.Request, route stri
notFound(w)
case "GET projects/:projects/protected_branches/:protected_branches":
b := p.branches[s[3]]
if f.lateProtection {
f.lateProtection = false
b = nil
}
if b == nil {
notFound(w)
return
Expand Down
Loading