From 60a858166cd85b565546b8f6a7716c408d74df0a Mon Sep 17 00:00:00 2001
From: Timo Furrer <tuxtimo@gmail.com>
Date: Thu, 21 Apr 2022 10:23:57 +0200
Subject: [PATCH] Support `execute_filemode` field in Repository Files API

---
 repository_files.go      | 70 +++++++++++++++++++++-------------------
 repository_files_test.go | 52 ++++++++++++++++++-----------
 2 files changed, 70 insertions(+), 52 deletions(-)

diff --git a/repository_files.go b/repository_files.go
index 64189f3e6..e444b62fb 100644
--- a/repository_files.go
+++ b/repository_files.go
@@ -36,16 +36,17 @@ type RepositoryFilesService struct {
 //
 // GitLab API docs: https://docs.gitlab.com/ce/api/repository_files.html
 type File struct {
-	FileName     string `json:"file_name"`
-	FilePath     string `json:"file_path"`
-	Size         int    `json:"size"`
-	Encoding     string `json:"encoding"`
-	Content      string `json:"content"`
-	Ref          string `json:"ref"`
-	BlobID       string `json:"blob_id"`
-	CommitID     string `json:"commit_id"`
-	SHA256       string `json:"content_sha256"`
-	LastCommitID string `json:"last_commit_id"`
+	FileName        string `json:"file_name"`
+	FilePath        string `json:"file_path"`
+	Size            int    `json:"size"`
+	Encoding        string `json:"encoding"`
+	Content         string `json:"content"`
+	ExecuteFilemode bool   `json:"execute_filemode"`
+	Ref             string `json:"ref"`
+	BlobID          string `json:"blob_id"`
+	CommitID        string `json:"commit_id"`
+	SHA256          string `json:"content_sha256"`
+	LastCommitID    string `json:"last_commit_id"`
 }
 
 func (r File) String() string {
@@ -125,14 +126,15 @@ func (s *RepositoryFilesService) GetFileMetaData(pid interface{}, fileName strin
 	}
 
 	f := &File{
-		BlobID:       resp.Header.Get("X-Gitlab-Blob-Id"),
-		CommitID:     resp.Header.Get("X-Gitlab-Commit-Id"),
-		Encoding:     resp.Header.Get("X-Gitlab-Encoding"),
-		FileName:     resp.Header.Get("X-Gitlab-File-Name"),
-		FilePath:     resp.Header.Get("X-Gitlab-File-Path"),
-		Ref:          resp.Header.Get("X-Gitlab-Ref"),
-		SHA256:       resp.Header.Get("X-Gitlab-Content-Sha256"),
-		LastCommitID: resp.Header.Get("X-Gitlab-Last-Commit-Id"),
+		BlobID:          resp.Header.Get("X-Gitlab-Blob-Id"),
+		CommitID:        resp.Header.Get("X-Gitlab-Commit-Id"),
+		Encoding:        resp.Header.Get("X-Gitlab-Encoding"),
+		FileName:        resp.Header.Get("X-Gitlab-File-Name"),
+		FilePath:        resp.Header.Get("X-Gitlab-File-Path"),
+		ExecuteFilemode: resp.Header.Get("X-Gitlab-Execute-Filemode") == "true",
+		Ref:             resp.Header.Get("X-Gitlab-Ref"),
+		SHA256:          resp.Header.Get("X-Gitlab-Content-Sha256"),
+		LastCommitID:    resp.Header.Get("X-Gitlab-Last-Commit-Id"),
 	}
 
 	if sizeString := resp.Header.Get("X-Gitlab-Size"); sizeString != "" {
@@ -259,13 +261,14 @@ func (r FileInfo) String() string {
 // GitLab API docs:
 // https://docs.gitlab.com/ce/api/repository_files.html#create-new-file-in-repository
 type CreateFileOptions struct {
-	Branch        *string `url:"branch,omitempty" json:"branch,omitempty"`
-	StartBranch   *string `url:"start_branch,omitempty" json:"start_branch,omitempty"`
-	Encoding      *string `url:"encoding,omitempty" json:"encoding,omitempty"`
-	AuthorEmail   *string `url:"author_email,omitempty" json:"author_email,omitempty"`
-	AuthorName    *string `url:"author_name,omitempty" json:"author_name,omitempty"`
-	Content       *string `url:"content,omitempty" json:"content,omitempty"`
-	CommitMessage *string `url:"commit_message,omitempty" json:"commit_message,omitempty"`
+	Branch          *string `url:"branch,omitempty" json:"branch,omitempty"`
+	StartBranch     *string `url:"start_branch,omitempty" json:"start_branch,omitempty"`
+	Encoding        *string `url:"encoding,omitempty" json:"encoding,omitempty"`
+	AuthorEmail     *string `url:"author_email,omitempty" json:"author_email,omitempty"`
+	AuthorName      *string `url:"author_name,omitempty" json:"author_name,omitempty"`
+	Content         *string `url:"content,omitempty" json:"content,omitempty"`
+	CommitMessage   *string `url:"commit_message,omitempty" json:"commit_message,omitempty"`
+	ExecuteFilemode *bool   `url:"execute_filemode,omitempty" json:"execute_filemode,omitempty"`
 }
 
 // CreateFile creates a new file in a repository.
@@ -302,14 +305,15 @@ func (s *RepositoryFilesService) CreateFile(pid interface{}, fileName string, op
 // GitLab API docs:
 // https://docs.gitlab.com/ce/api/repository_files.html#update-existing-file-in-repository
 type UpdateFileOptions struct {
-	Branch        *string `url:"branch,omitempty" json:"branch,omitempty"`
-	StartBranch   *string `url:"start_branch,omitempty" json:"start_branch,omitempty"`
-	Encoding      *string `url:"encoding,omitempty" json:"encoding,omitempty"`
-	AuthorEmail   *string `url:"author_email,omitempty" json:"author_email,omitempty"`
-	AuthorName    *string `url:"author_name,omitempty" json:"author_name,omitempty"`
-	Content       *string `url:"content,omitempty" json:"content,omitempty"`
-	CommitMessage *string `url:"commit_message,omitempty" json:"commit_message,omitempty"`
-	LastCommitID  *string `url:"last_commit_id,omitempty" json:"last_commit_id,omitempty"`
+	Branch          *string `url:"branch,omitempty" json:"branch,omitempty"`
+	StartBranch     *string `url:"start_branch,omitempty" json:"start_branch,omitempty"`
+	Encoding        *string `url:"encoding,omitempty" json:"encoding,omitempty"`
+	AuthorEmail     *string `url:"author_email,omitempty" json:"author_email,omitempty"`
+	AuthorName      *string `url:"author_name,omitempty" json:"author_name,omitempty"`
+	Content         *string `url:"content,omitempty" json:"content,omitempty"`
+	CommitMessage   *string `url:"commit_message,omitempty" json:"commit_message,omitempty"`
+	LastCommitID    *string `url:"last_commit_id,omitempty" json:"last_commit_id,omitempty"`
+	ExecuteFilemode *bool   `url:"execute_filemode,omitempty" json:"execute_filemode,omitempty"`
 }
 
 // UpdateFile updates an existing file in a repository
diff --git a/repository_files_test.go b/repository_files_test.go
index 81e79534e..72f2bc95b 100644
--- a/repository_files_test.go
+++ b/repository_files_test.go
@@ -23,6 +23,7 @@ func TestRepositoryFilesService_GetFile(t *testing.T) {
 			  "encoding": "base64",
 			  "content": "IyA9PSBTY2hlbWEgSW5mb3...",
 			  "content_sha256": "4c294617b60715c1d218e61164a3abd4808a4284cbc30e6728a01ad9aada4481",
+			  "execute_filemode": true,
 			  "ref": "master",
 			  "blob_id": "79f7bbd25901e8334750839545a9bd021f0e4c83",
 			  "commit_id": "d5a3ff139356ce33e37e73add446f16869741b50",
@@ -32,16 +33,17 @@ func TestRepositoryFilesService_GetFile(t *testing.T) {
 	})
 
 	want := &File{
-		FileName:     "key.rb",
-		FilePath:     "app/models/key.rb",
-		Size:         1476,
-		Encoding:     "base64",
-		Content:      "IyA9PSBTY2hlbWEgSW5mb3...",
-		Ref:          "master",
-		BlobID:       "79f7bbd25901e8334750839545a9bd021f0e4c83",
-		CommitID:     "d5a3ff139356ce33e37e73add446f16869741b50",
-		SHA256:       "4c294617b60715c1d218e61164a3abd4808a4284cbc30e6728a01ad9aada4481",
-		LastCommitID: "570e7b2abdd848b95f2f578043fc23bd6f6fd24d",
+		FileName:        "key.rb",
+		FilePath:        "app/models/key.rb",
+		Size:            1476,
+		Encoding:        "base64",
+		Content:         "IyA9PSBTY2hlbWEgSW5mb3...",
+		ExecuteFilemode: true,
+		Ref:             "master",
+		BlobID:          "79f7bbd25901e8334750839545a9bd021f0e4c83",
+		CommitID:        "d5a3ff139356ce33e37e73add446f16869741b50",
+		SHA256:          "4c294617b60715c1d218e61164a3abd4808a4284cbc30e6728a01ad9aada4481",
+		LastCommitID:    "570e7b2abdd848b95f2f578043fc23bd6f6fd24d",
 	}
 
 	f, resp, err := client.RepositoryFiles.GetFile(13083, "app%2Fmodels%2Fkey%2Erb?ref=master", nil)
@@ -77,21 +79,23 @@ func TestRepositoryFilesService_GetFileMetaData(t *testing.T) {
 		w.Header().Set("X-Gitlab-Encoding", "base64")
 		w.Header().Set("X-Gitlab-File-Name", "key.rb")
 		w.Header().Set("X-Gitlab-File-Path", "app/models/key.rb")
+		w.Header().Set("X-Gitlab-Execute-Filemode", "true")
 		w.Header().Set("X-Gitlab-Last-Commit-Id", "570e7b2abdd848b95f2f578043fc23bd6f6fd24d")
 		w.Header().Set("X-Gitlab-Ref", "master")
 		w.Header().Set("X-Gitlab-Size", "1476")
 	})
 
 	want := &File{
-		FileName:     "key.rb",
-		FilePath:     "app/models/key.rb",
-		Size:         1476,
-		Encoding:     "base64",
-		Ref:          "master",
-		BlobID:       "79f7bbd25901e8334750839545a9bd021f0e4c83",
-		CommitID:     "d5a3ff139356ce33e37e73add446f16869741b50",
-		SHA256:       "4c294617b60715c1d218e61164a3abd4808a4284cbc30e6728a01ad9aada4481",
-		LastCommitID: "570e7b2abdd848b95f2f578043fc23bd6f6fd24d",
+		FileName:        "key.rb",
+		FilePath:        "app/models/key.rb",
+		Size:            1476,
+		Encoding:        "base64",
+		ExecuteFilemode: true,
+		Ref:             "master",
+		BlobID:          "79f7bbd25901e8334750839545a9bd021f0e4c83",
+		CommitID:        "d5a3ff139356ce33e37e73add446f16869741b50",
+		SHA256:          "4c294617b60715c1d218e61164a3abd4808a4284cbc30e6728a01ad9aada4481",
+		LastCommitID:    "570e7b2abdd848b95f2f578043fc23bd6f6fd24d",
 	}
 
 	f, resp, err := client.RepositoryFiles.GetFileMetaData(13083, "app%2Fmodels%2Fkey%2Erb?ref=master", nil)
@@ -267,6 +271,11 @@ func TestRepositoryFilesService_CreateFile(t *testing.T) {
 	require.NotNil(t, resp)
 	require.Equal(t, want, fi)
 
+	fi, resp, err = client.RepositoryFiles.CreateFile(13083, "app%2Fproject%2Erb", &CreateFileOptions{ExecuteFilemode: Bool(true)})
+	require.NoError(t, err)
+	require.NotNil(t, resp)
+	require.Equal(t, want, fi)
+
 	fi, resp, err = client.RepositoryFiles.CreateFile(13083.01, "app%2Fproject%2Erb", nil)
 	require.EqualError(t, err, "invalid ID type 13083.01, the ID must be an int or a string")
 	require.Nil(t, resp)
@@ -307,6 +316,11 @@ func TestRepositoryFilesService_UpdateFile(t *testing.T) {
 	require.NotNil(t, resp)
 	require.Equal(t, want, fi)
 
+	fi, resp, err = client.RepositoryFiles.UpdateFile(13083, "app%2Fproject%2Erb", &UpdateFileOptions{ExecuteFilemode: Bool(true)})
+	require.NoError(t, err)
+	require.NotNil(t, resp)
+	require.Equal(t, want, fi)
+
 	fi, resp, err = client.RepositoryFiles.UpdateFile(13083.01, "app%2Fproject%2Erb", nil)
 	require.EqualError(t, err, "invalid ID type 13083.01, the ID must be an int or a string")
 	require.Nil(t, resp)