1
0
mirror of https://github.com/goreleaser/goreleaser.git synced 2025-03-25 21:29:14 +02:00

fix(gitlab): Use start_branch for file creation if branch doesn't exist already (#4792)

Creating files on a new branch is only possible with the API if
`start_branch`
is given otherwise the API returns:

> You can only create or edit files when you are on a branch

Fixes https://github.com/goreleaser/goreleaser/issues/4543

---------

Co-authored-by: Carlos Alexandro Becker <caarlos0@users.noreply.github.com>
This commit is contained in:
Matthias Baur 2024-04-23 14:01:23 +02:00 committed by GitHub
parent 4015fa32bc
commit fd40f5d772
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 135 additions and 42 deletions

View File

@ -98,6 +98,24 @@ func (c *gitlabClient) getDefaultBranch(_ *context.Context, repo Repo) (string,
return p.DefaultBranch, nil
}
// checkBranchExists checks if a branch exists
func (c *gitlabClient) checkBranchExists(_ *context.Context, repo Repo, branch string) (bool, error) {
projectID := repo.Name
if repo.Owner != "" {
projectID = repo.Owner + "/" + projectID
}
// Verify if branch exists
_, res, err := c.client.Branches.GetBranch(projectID, branch)
if err != nil && res.StatusCode != 404 {
log.WithError(err).
Error("error verify branch existence")
return false, err
}
return res.StatusCode != 404, nil
}
// CloseMilestone closes a given milestone.
func (c *gitlabClient) CloseMilestone(_ *context.Context, repo Repo, title string) error {
milestone, err := c.getMilestoneByTitle(repo, title)
@ -135,57 +153,72 @@ func (c *gitlabClient) CreateFile(
commitAuthor config.CommitAuthor,
repo Repo,
content []byte, // the content of the formula.rb
path, // the path to the formula.rb
fileName, // the path to the formula.rb
message string, // the commit msg
) error {
fileName := path
projectID := repo.Name
if repo.Owner != "" {
projectID = repo.Owner + "/" + projectID
}
// Use the project default branch if we can get it...otherwise, just use
// 'master'
var branch, ref string
log.
WithField("projectID", projectID).
Debug("project id")
var branch, defaultBranch string
var branchExists bool
var err error
// Use the branch if given one
if repo.Branch != "" {
branch = repo.Branch
branchExists, err = c.checkBranchExists(ctx, repo, branch)
if err != nil {
return err
}
// Retrieving default branch because we need it for `start_branch`
if !branchExists {
defaultBranch, err = c.getDefaultBranch(ctx, repo)
if err != nil {
return err
}
}
log.
WithField("projectID", projectID).
WithField("branch", branch).
WithField("branchExists", branchExists).
Debug("using given branch")
} else {
// Try to get the default branch from the Git provider
branch, err = c.getDefaultBranch(ctx, repo)
if err != nil {
// Fall back to 'master' 😭
log.
WithField("fileName", fileName).
WithField("projectID", projectID).
WithField("requestedBranch", branch).
WithError(err).
Warn("error checking for default branch, using master")
ref = "master"
branch = "master"
return err
}
defaultBranch = branch
branchExists = true
log.
WithField("projectID", projectID).
WithField("branch", branch).
Debug("no branch given, using default branch")
}
ref = branch
opts := &gitlab.GetFileOptions{Ref: &ref}
castedContent := string(content)
log.
WithField("projectID", projectID).
WithField("ref", ref).
WithField("branch", branch).
Debug("projectID at brew")
log.
WithField("projectID", projectID).
Info("pushing")
// If the branch doesn't exist, we need to check the default branch
// because that's what we use as `start_branch` later if the file needs
// to be created.
opts := &gitlab.GetFileOptions{Ref: &defaultBranch}
if branchExists {
opts.Ref = &branch
}
// Check if the file already exists
_, res, err := c.client.RepositoryFiles.GetFile(projectID, fileName, opts)
if err != nil && (res == nil || res.StatusCode != 404) {
log := log.
WithField("fileName", fileName).
WithField("ref", ref).
WithField("branch", branch).
WithField("projectID", projectID)
if res != nil {
log = log.WithField("statusCode", res.StatusCode)
@ -196,24 +229,34 @@ func (c *gitlabClient) CreateFile(
}
log.
WithField("fileName", fileName).
WithField("branch", branch).
WithField("projectID", projectID).
Debug("found already existing brew formula file")
WithField("branch", branch).
WithField("fileName", fileName).
Info("pushing file")
stringContents := string(content)
if res.StatusCode == 404 {
// Create a new file because it's not already there
log.
WithField("fileName", fileName).
WithField("ref", ref).
WithField("projectID", projectID).
Debug("creating brew formula")
WithField("branch", branch).
WithField("fileName", fileName).
Debug("file doesn't exist, creating it")
createOpts := &gitlab.CreateFileOptions{
AuthorName: &commitAuthor.Name,
AuthorEmail: &commitAuthor.Email,
Content: &castedContent,
Content: &stringContents,
Branch: &branch,
CommitMessage: &message,
}
// Branch not found, thus Gitlab requires a "start branch" to create the file
if !branchExists {
createOpts.StartBranch = &defaultBranch
}
fileInfo, res, err := c.client.RepositoryFiles.CreateFile(projectID, fileName, createOpts)
if err != nil {
log := log.
@ -237,19 +280,26 @@ func (c *gitlabClient) CreateFile(
return nil
}
// Update the existing file
log.
WithField("fileName", fileName).
WithField("ref", ref).
WithField("branch", branch).
WithField("projectID", projectID).
Debug("updating brew formula")
Debug("file exists, updating it")
updateOpts := &gitlab.UpdateFileOptions{
AuthorName: &commitAuthor.Name,
AuthorEmail: &commitAuthor.Email,
Content: &castedContent,
Content: &stringContents,
Branch: &branch,
CommitMessage: &message,
}
// Branch not found, thus Gitlab requires a "start branch" to update the file
if !branchExists {
updateOpts.StartBranch = &defaultBranch
}
updateFileInfo, res, err := c.client.RepositoryFiles.UpdateFile(projectID, fileName, updateOpts)
if err != nil {
log := log.
@ -260,7 +310,7 @@ func (c *gitlabClient) CreateFile(
log = log.WithField("statusCode", res.StatusCode)
}
log.WithError(err).
Error("error updating brew formula file")
Error("error updating file")
return err
}
@ -272,7 +322,7 @@ func (c *gitlabClient) CreateFile(
if res != nil {
log = log.WithField("statusCode", res.StatusCode)
}
log.Debug("updated brew formula file")
log.Debug("updated file")
return nil
}

View File

@ -488,19 +488,52 @@ func TestGitLabChangelog(t *testing.T) {
func TestGitLabCreateFile(t *testing.T) {
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// Handle the test where we know the branch
// Handle the test where we know the branch and it exists
if strings.HasSuffix(r.URL.Path, "projects/someone/something/repository/branches/somebranch") {
w.WriteHeader(http.StatusOK)
fmt.Fprint(w, "{}")
return
}
if strings.HasSuffix(r.URL.Path, "projects/someone/something/repository/files/newfile.txt") {
_, err := io.Copy(w, strings.NewReader(`{ "file_path": "newfile.txt", "branch": "somebranch" }`))
require.NoError(t, err)
return
}
// Handle the test where we detect the branch
if strings.HasSuffix(r.URL.Path, "projects/someone/something") {
_, err := io.Copy(w, strings.NewReader(`{ "default_branch": "main" }`))
require.NoError(t, err)
return
}
if strings.HasSuffix(r.URL.Path, "projects/someone/something/repository/files/newfile-in-default.txt") {
_, err := io.Copy(w, strings.NewReader(`{ "file_path": "newfile.txt", "branch": "main" }`))
require.NoError(t, err)
return
}
// Handle the test where the branch doesn't exist already
if strings.HasSuffix(r.URL.Path, "projects/someone/something/repository/branches/non-existing-branch") {
w.WriteHeader(http.StatusNotFound)
return
}
if strings.HasSuffix(r.URL.Path, "projects/someone/something/repository/files/newfile-on-new-branch.txt") {
if r.Method == "POST" {
var resBody map[string]string
require.NoError(t, json.NewDecoder(r.Body).Decode(&resBody))
require.Equal(t, "master", resBody["start_branch"])
}
_, err := io.Copy(w, strings.NewReader(`{"file_path":"newfile-on-new-branch.txt","branch":"non-existing-branch"}`))
require.NoError(t, err)
return
}
// Handle the case with a projectID
if strings.HasSuffix(r.URL.Path, "projects/123456789/repository/branches/main") {
w.WriteHeader(http.StatusOK)
fmt.Fprint(w, "{}")
return
}
if strings.HasSuffix(r.URL.Path, "projects/123456789/repository/files/newfile-projectID.txt") {
_, err := io.Copy(w, strings.NewReader(`{ "file_path": "newfile-projectID.txt", "branch": "main" }`))
require.NoError(t, err)
@ -530,7 +563,7 @@ func TestGitLabCreateFile(t *testing.T) {
client, err := newGitLab(ctx, "test-token")
require.NoError(t, err)
// Test using an arbitrary branch
// Test using an arbitrary existing branch
repo := Repo{
Owner: "someone",
Name: "something",
@ -550,6 +583,16 @@ func TestGitLabCreateFile(t *testing.T) {
err = client.CreateFile(ctx, config.CommitAuthor{Name: repo.Owner}, repo, []byte("Hello there"), "newfile-in-default.txt", "test: test commit")
require.NoError(t, err)
// Test creating a new branch
repo = Repo{
Owner: "someone",
Name: "something",
Branch: "non-existing-branch",
}
err = client.CreateFile(ctx, config.CommitAuthor{Name: repo.Owner}, repo, []byte("Hello there"), "newfile-on-new-branch.txt", "test: test commit")
require.NoError(t, err)
// Test using projectID
repo = Repo{
Name: "123456789",