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
22 changes: 10 additions & 12 deletions modules/structs/repo_file.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,6 @@ type FileOptions struct {
Signoff bool `json:"signoff"`
}

type FileOptionsWithSHA struct {
FileOptions
// the blob ID (SHA) for the file that already exists, it is required for changing existing files
// required: true
SHA string `json:"sha" binding:"Required"`
}

func (f *FileOptions) GetFileOptions() *FileOptions {
return f
}
Expand All @@ -41,7 +34,7 @@ type FileOptionsInterface interface {

var _ FileOptionsInterface = (*FileOptions)(nil)

// CreateFileOptions options for creating files
// CreateFileOptions options for creating a file
// Note: `author` and `committer` are optional (if only one is given, it will be used for the other, otherwise the authenticated user will be used)
type CreateFileOptions struct {
FileOptions
Expand All @@ -50,16 +43,21 @@ type CreateFileOptions struct {
ContentBase64 string `json:"content"`
}

// DeleteFileOptions options for deleting files (used for other File structs below)
// DeleteFileOptions options for deleting a file
// Note: `author` and `committer` are optional (if only one is given, it will be used for the other, otherwise the authenticated user will be used)
type DeleteFileOptions struct {
FileOptionsWithSHA
FileOptions
// the blob ID (SHA) for the file to delete
// required: true
SHA string `json:"sha" binding:"Required"`
}

// UpdateFileOptions options for updating files
// UpdateFileOptions options for updating or creating a file
// Note: `author` and `committer` are optional (if only one is given, it will be used for the other, otherwise the authenticated user will be used)
type UpdateFileOptions struct {
FileOptionsWithSHA
FileOptions
// the blob ID (SHA) for the file that already exists to update, or leave it empty to create a new file
SHA string `json:"sha"`
// content must be base64 encoded
// required: true
ContentBase64 string `json:"content"`
Expand Down
9 changes: 6 additions & 3 deletions routers/api/v1/repo/file.go
Original file line number Diff line number Diff line change
Expand Up @@ -525,7 +525,7 @@ func CreateFile(ctx *context.APIContext) {
func UpdateFile(ctx *context.APIContext) {
// swagger:operation PUT /repos/{owner}/{repo}/contents/{filepath} repository repoUpdateFile
// ---
// summary: Update a file in a repository
// summary: Update a file in a repository if SHA is set, or create the file if SHA is not set
// consumes:
// - application/json
// produces:
Expand Down Expand Up @@ -554,6 +554,8 @@ func UpdateFile(ctx *context.APIContext) {
// responses:
// "200":
// "$ref": "#/responses/FileResponse"
// "201":
// "$ref": "#/responses/FileResponse"
// "403":
// "$ref": "#/responses/error"
// "404":
Expand All @@ -572,8 +574,9 @@ func UpdateFile(ctx *context.APIContext) {
ctx.APIError(http.StatusUnprocessableEntity, err)
return
}
willCreate := apiOpts.SHA == ""
opts.Files = append(opts.Files, &files_service.ChangeRepoFile{
Operation: "update",
Operation: util.Iif(willCreate, "create", "update"),
ContentReader: contentReader,
SHA: apiOpts.SHA,
FromTreePath: apiOpts.FromPath,
Expand All @@ -587,7 +590,7 @@ func UpdateFile(ctx *context.APIContext) {
handleChangeRepoFilesError(ctx, err)
} else {
fileResponse := files_service.GetFileResponseFromFilesResponse(filesResponse, 0)
ctx.JSON(http.StatusOK, fileResponse)
ctx.JSON(util.Iif(willCreate, http.StatusCreated, http.StatusOK), fileResponse)
}
}

Expand Down
16 changes: 9 additions & 7 deletions templates/swagger/v1_json.tmpl

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

26 changes: 12 additions & 14 deletions tests/integration/api_repo_file_delete_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,21 +20,19 @@ import (

func getDeleteFileOptions() *api.DeleteFileOptions {
return &api.DeleteFileOptions{
FileOptionsWithSHA: api.FileOptionsWithSHA{
FileOptions: api.FileOptions{
BranchName: "master",
NewBranchName: "master",
Message: "Removing the file new/file.txt",
Author: api.Identity{
Name: "John Doe",
Email: "johndoe@example.com",
},
Committer: api.Identity{
Name: "Jane Doe",
Email: "janedoe@example.com",
},
SHA: "103ff9234cefeee5ec5361d22b49fbb04d385885",
FileOptions: api.FileOptions{
BranchName: "master",
NewBranchName: "master",
Message: "Removing the file new/file.txt",
Author: api.Identity{
Name: "John Doe",
Email: "johndoe@example.com",
},
Committer: api.Identity{
Name: "Jane Doe",
Email: "janedoe@example.com",
},
SHA: "103ff9234cefeee5ec5361d22b49fbb04d385885",
},
}
}
Expand Down
35 changes: 21 additions & 14 deletions tests/integration/api_repo_file_update_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,21 +28,19 @@ func getUpdateFileOptions() *api.UpdateFileOptions {
content := "This is updated text"
contentEncoded := base64.StdEncoding.EncodeToString([]byte(content))
return &api.UpdateFileOptions{
FileOptionsWithSHA: api.FileOptionsWithSHA{
FileOptions: api.FileOptions{
BranchName: "master",
NewBranchName: "master",
Message: "My update of new/file.txt",
Author: api.Identity{
Name: "John Doe",
Email: "johndoe@example.com",
},
Committer: api.Identity{
Name: "Anne Doe",
Email: "annedoe@example.com",
},
SHA: "103ff9234cefeee5ec5361d22b49fbb04d385885",
FileOptions: api.FileOptions{
BranchName: "master",
NewBranchName: "master",
Message: "My update of new/file.txt",
Author: api.Identity{
Name: "John Doe",
Email: "johndoe@example.com",
},
Committer: api.Identity{
Name: "Anne Doe",
Email: "annedoe@example.com",
},
SHA: "103ff9234cefeee5ec5361d22b49fbb04d385885",
},
ContentBase64: contentEncoded,
}
Expand Down Expand Up @@ -180,6 +178,15 @@ func TestAPIUpdateFile(t *testing.T) {
assert.Equal(t, expectedDownloadURL, *fileResponse.Content.DownloadURL)
assert.Equal(t, updateFileOptions.Message+"\n", fileResponse.Commit.Message)

// Test updating a file without SHA (should create the file)
updateFileOptions = getUpdateFileOptions()
updateFileOptions.SHA = ""
req = NewRequestWithJSON(t, "PUT", "/api/v1/repos/user2/repo1/contents/update-create.txt", &updateFileOptions).AddTokenAuth(token2)
resp = MakeRequest(t, req, http.StatusCreated)
DecodeJSON(t, resp, &fileResponse)
assert.Equal(t, "08bd14b2e2852529157324de9c226b3364e76136", fileResponse.Content.SHA)
assert.Equal(t, setting.AppURL+"user2/repo1/raw/branch/master/update-create.txt", *fileResponse.Content.DownloadURL)

// Test updating a file and renaming it
updateFileOptions = getUpdateFileOptions()
updateFileOptions.BranchName = repo1.DefaultBranch
Expand Down