新增: 批量更改文件统一接口以及结构体定义
This commit is contained in:
parent
f2d50f4cb8
commit
93de827180
|
@ -25,6 +25,24 @@ import (
|
|||
"golang.org/x/text/transform"
|
||||
)
|
||||
|
||||
type FileActionType int
|
||||
|
||||
const (
|
||||
ActionTypeCreate FileActionType = iota + 1
|
||||
ActionTypeUpdate
|
||||
ActionTypeDelete
|
||||
)
|
||||
|
||||
var fileActionTypes = map[string]FileActionType{
|
||||
"create": ActionTypeCreate,
|
||||
"update": ActionTypeUpdate,
|
||||
"delete": ActionTypeDelete,
|
||||
}
|
||||
|
||||
func ToFileActionType(name string) FileActionType {
|
||||
return fileActionTypes[name]
|
||||
}
|
||||
|
||||
// IdentityOptions for a person's identity like an author or committer
|
||||
type IdentityOptions struct {
|
||||
Name string
|
||||
|
@ -54,6 +72,25 @@ type UpdateRepoFileOptions struct {
|
|||
Signoff bool
|
||||
}
|
||||
|
||||
type BatchSingleFileOption struct {
|
||||
Content string
|
||||
TreePath string
|
||||
FromTreePath string
|
||||
ActionType FileActionType
|
||||
}
|
||||
type BatchUpdateFileOptions struct {
|
||||
Files []BatchSingleFileOption
|
||||
LastCommitID string
|
||||
OldBranch string
|
||||
NewBranch string
|
||||
Message string
|
||||
SHA string
|
||||
Author *IdentityOptions
|
||||
Commiter *IdentityOptions
|
||||
Dates *CommitDateOptions
|
||||
Signoff bool
|
||||
}
|
||||
|
||||
func detectEncodingAndBOM(entry *git.TreeEntry, repo *models.Repository) (string, bool) {
|
||||
reader, err := entry.Blob().DataAsync()
|
||||
if err != nil {
|
||||
|
@ -466,3 +503,9 @@ func CreateOrUpdateRepoFile(repo *models.Repository, doer *models.User, opts *Up
|
|||
}
|
||||
return file, nil
|
||||
}
|
||||
|
||||
func CreateOrUpdateOrDeleteRepofiles(repo *models.Repository, doer *models.User, opts *BatchUpdateFileOptions) ([]*structs.FileResponse, error) {
|
||||
var responses []*structs.FileResponse
|
||||
|
||||
return responses, nil
|
||||
}
|
||||
|
|
|
@ -31,8 +31,16 @@ type CreateFileOptions struct {
|
|||
}
|
||||
|
||||
// BatchCreateFileOptions options for creating more files
|
||||
type BatchCreateFileOptions struct {
|
||||
BatchFiles []CreateFileOptions `json:"batch_files"`
|
||||
type BatchChangeFileOptions struct {
|
||||
Header FileOptions `json:"header"`
|
||||
Files []struct {
|
||||
// enum: text,base64
|
||||
Encoding string `json:"encoding"`
|
||||
FilePath string `json:"file_path"`
|
||||
Content string `json:"content"`
|
||||
// enum: create,update,delete
|
||||
ActionType string `json:"action_type"`
|
||||
} `json:"files"`
|
||||
}
|
||||
|
||||
// DeleteFileOptions options for deleting files (used for other File structs below)
|
||||
|
@ -44,11 +52,6 @@ type DeleteFileOptions struct {
|
|||
SHA string `json:"sha" binding:"Required"`
|
||||
}
|
||||
|
||||
// BatchDeleteFileOptions options for deleting files
|
||||
type BatchDeleteFileOptions struct {
|
||||
BatchFiles []DeleteFileOptions `json:"batch_files"`
|
||||
}
|
||||
|
||||
// UpdateFileOptions options for updating files
|
||||
// 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 {
|
||||
|
@ -60,11 +63,6 @@ type UpdateFileOptions struct {
|
|||
FromPath string `json:"from_path" binding:"MaxSize(500)"`
|
||||
}
|
||||
|
||||
// BatchUpdateFileOptions options for updating more files.
|
||||
type BatchUpdateFileOptions struct {
|
||||
BatchFiles []UpdateFileOptions `json:"batch_files"`
|
||||
}
|
||||
|
||||
// FileLinksResponse contains the links for a repo's file
|
||||
type FileLinksResponse struct {
|
||||
Self *string `json:"self"`
|
||||
|
|
|
@ -1032,10 +1032,8 @@ func Routes() *web.Route {
|
|||
m.Put("", bind(api.UpdateFileOptions{}), repo.UpdateFile)
|
||||
m.Delete("", bind(api.DeleteFileOptions{}), repo.DeleteFile)
|
||||
}, reqRepoWriter(models.UnitTypeCode), reqToken())
|
||||
m.Group("/batch/*", func() {
|
||||
m.Post("", bind(api.BatchCreateFileOptions{}), repo.BatchCreateFile)
|
||||
m.Put("", bind(api.BatchUpdateFileOptions{}), repo.BatchUpdateFile)
|
||||
m.Delete("", bind(api.BatchDeleteFileOptions{}), repo.BatchDeleteFile)
|
||||
m.Group("/batch", func() {
|
||||
m.Post("", bind(api.BatchChangeFileOptions{}), repo.BatchChangeFile)
|
||||
}, reqRepoWriter(models.UnitTypeCode), reqToken())
|
||||
}, reqRepoReader(models.UnitTypeCode))
|
||||
m.Get("/signing-key.gpg", misc.SigningKey)
|
||||
|
|
|
@ -285,11 +285,11 @@ func CreateFile(ctx *context.APIContext) {
|
|||
}
|
||||
}
|
||||
|
||||
// BatchCreateFile handles API call for creating a file***
|
||||
func BatchCreateFile(ctx *context.APIContext) {
|
||||
// swagger:operation POST /repos/{owner}/{repo}/contents/batch/{filepath} repository repoBatchCreateFile
|
||||
// BatchChangeFile handles API call for change some files***
|
||||
func BatchChangeFile(ctx *context.APIContext) {
|
||||
// swagger:operation POST /repos/{owner}/{repo}/contents/batch repository repoBatchChangeFile
|
||||
// ---
|
||||
// summary: Create some files in a repository***
|
||||
// summary: Change some files in a repository***
|
||||
// consumes:
|
||||
// - application/json
|
||||
// produces:
|
||||
|
@ -305,16 +305,11 @@ func BatchCreateFile(ctx *context.APIContext) {
|
|||
// description: name of the repo
|
||||
// type: string
|
||||
// required: true
|
||||
// - name: filepath
|
||||
// in: path
|
||||
// description: path of the file to create
|
||||
// type: string
|
||||
// required: true
|
||||
// - name: body
|
||||
// in: body
|
||||
// required: true
|
||||
// schema:
|
||||
// "$ref": "#/definitions/BatchCreateFileOptions"
|
||||
// "$ref": "#/definitions/BatchChangeFileOptions"
|
||||
// responses:
|
||||
// "201":
|
||||
// "$ref": "#/responses/FileResponse"
|
||||
|
@ -324,7 +319,32 @@ func BatchCreateFile(ctx *context.APIContext) {
|
|||
// "$ref": "#/responses/notFound"
|
||||
// "422":
|
||||
// "$ref": "#/responses/error"
|
||||
apiBatchOpts := web.GetForm(ctx).(*api.BatchChangeFileOptions)
|
||||
fmt.Println(apiBatchOpts)
|
||||
|
||||
if ctx.Repo.Repository.IsEmpty {
|
||||
ctx.Error(http.StatusUnprocessableEntity, "RepoIsEmpty", fmt.Errorf("repo is empty"))
|
||||
}
|
||||
|
||||
if apiBatchOpts.Header.BranchName == "" {
|
||||
apiBatchOpts.Header.BranchName = ctx.Repo.Repository.DefaultBranch
|
||||
}
|
||||
|
||||
if apiBatchOpts.Header.Message == "" {
|
||||
apiBatchOpts.Header.Message = time.Now().Format("RFC3339")
|
||||
}
|
||||
|
||||
if apiBatchOpts.Header.Dates.Author.IsZero() {
|
||||
apiBatchOpts.Header.Dates.Author = time.Now()
|
||||
}
|
||||
|
||||
if apiBatchOpts.Header.Dates.Committer.IsZero() {
|
||||
apiBatchOpts.Header.Dates.Committer = time.Now()
|
||||
}
|
||||
|
||||
if _, err := createOrUpdateOrDeleteFiles(ctx, apiBatchOpts); err != nil {
|
||||
handleCreateOrUpdateFileError(ctx, err)
|
||||
}
|
||||
ctx.JSON(http.StatusOK, map[string]string{})
|
||||
}
|
||||
|
||||
|
@ -435,47 +455,51 @@ func handleCreateOrUpdateFileError(ctx *context.APIContext, err error) {
|
|||
ctx.Error(http.StatusInternalServerError, "UpdateFile", err)
|
||||
}
|
||||
|
||||
// BatchUpdateFile handles API call for updating a file
|
||||
func BatchUpdateFile(ctx *context.APIContext) {
|
||||
// swagger:operation PUT /repos/{owner}/{repo}/contents/batch/{filepath} repository repoBatchUpdateFile
|
||||
// ---
|
||||
// summary: Update some files in a repository***
|
||||
// consumes:
|
||||
// - application/json
|
||||
// produces:
|
||||
// - application/jsoncontent
|
||||
// parameters:
|
||||
// - name: owner
|
||||
// in: path
|
||||
// description: owner of the repo
|
||||
// type: string
|
||||
// required: true
|
||||
// - name: repo
|
||||
// in: path
|
||||
// description: name of the repo
|
||||
// type: string
|
||||
// required: true
|
||||
// - name: filepath
|
||||
// in: path
|
||||
// description: path of the file to update
|
||||
// type: string
|
||||
// required: true
|
||||
// - name: body
|
||||
// in: body
|
||||
// required: true
|
||||
// schema:
|
||||
// "$ref": "#/definitions/BatchUpdateFileOptions"
|
||||
// responses:
|
||||
// "200":
|
||||
// "$ref": "#/responses/FileResponse"
|
||||
// "403":
|
||||
// "$ref": "#/responses/error"
|
||||
// "404":
|
||||
// "$ref": "#/responses/notFound"
|
||||
// "422":
|
||||
// "$ref": "#/responses/error"
|
||||
func createOrUpdateOrDeleteFiles(ctx *context.APIContext, apiBatchOpts *api.BatchChangeFileOptions) ([]*api.FileResponse, error) {
|
||||
if !canWriteFiles(ctx.Repo) {
|
||||
return nil, models.ErrUserDoesNotHaveAccessToRepo{
|
||||
UserID: ctx.User.ID,
|
||||
RepoName: ctx.Repo.Repository.LowerName,
|
||||
}
|
||||
}
|
||||
|
||||
ctx.JSON(http.StatusOK, map[string]string{})
|
||||
var files []repofiles.BatchSingleFileOption
|
||||
for _, f := range apiBatchOpts.Files {
|
||||
if f.Encoding == "base64" {
|
||||
content, err := base64.StdEncoding.DecodeString(f.Content)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
f.Content = string(content)
|
||||
}
|
||||
files = append(files, repofiles.BatchSingleFileOption{
|
||||
Content: f.Content,
|
||||
TreePath: f.FilePath,
|
||||
ActionType: repofiles.ToFileActionType(f.ActionType),
|
||||
})
|
||||
}
|
||||
|
||||
opts := &repofiles.BatchUpdateFileOptions{
|
||||
Files: files,
|
||||
Message: apiBatchOpts.Header.Message,
|
||||
OldBranch: apiBatchOpts.Header.BranchName,
|
||||
NewBranch: apiBatchOpts.Header.NewBranchName,
|
||||
Commiter: &repofiles.IdentityOptions{
|
||||
Name: apiBatchOpts.Header.Committer.Name,
|
||||
Email: apiBatchOpts.Header.Committer.Email,
|
||||
},
|
||||
Author: &repofiles.IdentityOptions{
|
||||
Name: apiBatchOpts.Header.Author.Name,
|
||||
Email: apiBatchOpts.Header.Author.Email,
|
||||
},
|
||||
Dates: &repofiles.CommitDateOptions{
|
||||
Author: apiBatchOpts.Header.Dates.Author,
|
||||
Committer: apiBatchOpts.Header.Dates.Committer,
|
||||
},
|
||||
Signoff: apiBatchOpts.Header.Signoff,
|
||||
}
|
||||
|
||||
return repofiles.CreateOrUpdateOrDeleteRepofiles(ctx.Repo.Repository, ctx.User, opts)
|
||||
}
|
||||
|
||||
// Called from both CreateFile or UpdateFile to handle both
|
||||
|
@ -601,49 +625,6 @@ func DeleteFile(ctx *context.APIContext) {
|
|||
}
|
||||
}
|
||||
|
||||
// BatchDeleteFile Delete some files in a repository
|
||||
func BatchDeleteFile(ctx *context.APIContext) {
|
||||
// swagger:operation DELETE /repos/{owner}/{repo}/contents/batch/{filepath} repository repoBatchDeleteFile
|
||||
// ---
|
||||
// summary: Delete some files in a repository***
|
||||
// consumes:
|
||||
// - application/json
|
||||
// produces:
|
||||
// - application/json
|
||||
// parameters:
|
||||
// - name: owner
|
||||
// in: path
|
||||
// description: owner of the repo
|
||||
// type: string
|
||||
// required: true
|
||||
// - name: repo
|
||||
// in: path
|
||||
// description: name of the repo
|
||||
// type: string
|
||||
// required: true
|
||||
// - name: filepath
|
||||
// in: path
|
||||
// description: path of the file to delete
|
||||
// type: string
|
||||
// required: true
|
||||
// - name: body
|
||||
// in: body
|
||||
// required: true
|
||||
// schema:
|
||||
// "$ref": "#/definitions/BatchDeleteFileOptions"
|
||||
// responses:
|
||||
// "200":
|
||||
// "$ref": "#/responses/FileDeleteResponse"
|
||||
// "400":
|
||||
// "$ref": "#/responses/error"
|
||||
// "403":
|
||||
// "$ref": "#/responses/error"
|
||||
// "404":
|
||||
// "$ref": "#/responses/error"
|
||||
|
||||
ctx.JSON(http.StatusOK, map[string]string{})
|
||||
}
|
||||
|
||||
// GetContents Get the metadata and contents (if a file) of an entry in a repository, or a list of entries if a dir
|
||||
func GetContents(ctx *context.APIContext) {
|
||||
// swagger:operation GET /repos/{owner}/{repo}/contents/{filepath} repository repoGetContents
|
||||
|
|
|
@ -120,7 +120,7 @@ type swaggerParameterBodies struct {
|
|||
CreateFileOptions api.CreateFileOptions
|
||||
|
||||
// in:body
|
||||
BatchCreateFileOptions api.BatchCreateFileOptions
|
||||
BatchChangeFileOptions api.BatchChangeFileOptions
|
||||
|
||||
// in:body
|
||||
UpdateFileOptions api.UpdateFileOptions
|
||||
|
|
|
@ -3469,65 +3469,7 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"/repos/{owner}/{repo}/contents/batch/{filepath}": {
|
||||
"put": {
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/jsoncontent"
|
||||
],
|
||||
"tags": [
|
||||
"repository"
|
||||
],
|
||||
"summary": "Update some files in a repository***",
|
||||
"operationId": "repoBatchUpdateFile",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"description": "owner of the repo",
|
||||
"name": "owner",
|
||||
"in": "path",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"description": "name of the repo",
|
||||
"name": "repo",
|
||||
"in": "path",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"description": "path of the file to update",
|
||||
"name": "filepath",
|
||||
"in": "path",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"name": "body",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/BatchUpdateFileOptions"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"$ref": "#/responses/FileResponse"
|
||||
},
|
||||
"403": {
|
||||
"$ref": "#/responses/error"
|
||||
},
|
||||
"404": {
|
||||
"$ref": "#/responses/notFound"
|
||||
},
|
||||
"422": {
|
||||
"$ref": "#/responses/error"
|
||||
}
|
||||
}
|
||||
},
|
||||
"/repos/{owner}/{repo}/contents/batch": {
|
||||
"post": {
|
||||
"consumes": [
|
||||
"application/json"
|
||||
|
@ -3538,8 +3480,8 @@
|
|||
"tags": [
|
||||
"repository"
|
||||
],
|
||||
"summary": "Create some files in a repository***",
|
||||
"operationId": "repoBatchCreateFile",
|
||||
"summary": "Change some files in a repository***",
|
||||
"operationId": "repoBatchChangeFile",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
|
@ -3555,19 +3497,12 @@
|
|||
"in": "path",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"description": "path of the file to create",
|
||||
"name": "filepath",
|
||||
"in": "path",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"name": "body",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/BatchCreateFileOptions"
|
||||
"$ref": "#/definitions/BatchChangeFileOptions"
|
||||
}
|
||||
}
|
||||
],
|
||||
|
@ -3585,64 +3520,6 @@
|
|||
"$ref": "#/responses/error"
|
||||
}
|
||||
}
|
||||
},
|
||||
"delete": {
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"repository"
|
||||
],
|
||||
"summary": "Delete some files in a repository***",
|
||||
"operationId": "repoBatchDeleteFile",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"description": "owner of the repo",
|
||||
"name": "owner",
|
||||
"in": "path",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"description": "name of the repo",
|
||||
"name": "repo",
|
||||
"in": "path",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"description": "path of the file to delete",
|
||||
"name": "filepath",
|
||||
"in": "path",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"name": "body",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/BatchDeleteFileOptions"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"$ref": "#/responses/FileDeleteResponse"
|
||||
},
|
||||
"400": {
|
||||
"$ref": "#/responses/error"
|
||||
},
|
||||
"403": {
|
||||
"$ref": "#/responses/error"
|
||||
},
|
||||
"404": {
|
||||
"$ref": "#/responses/error"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/repos/{owner}/{repo}/contents/{filepath}": {
|
||||
|
@ -13640,16 +13517,46 @@
|
|||
},
|
||||
"x-go-package": "code.gitea.io/gitea/modules/structs"
|
||||
},
|
||||
"BatchCreateFileOptions": {
|
||||
"BatchChangeFileOptions": {
|
||||
"description": "BatchCreateFileOptions options for creating more files",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"batch_files": {
|
||||
"files": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/CreateFileOptions"
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"action_type": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"create",
|
||||
"update",
|
||||
"delete"
|
||||
],
|
||||
"x-go-name": "ActionType"
|
||||
},
|
||||
"content": {
|
||||
"type": "string",
|
||||
"x-go-name": "Content"
|
||||
},
|
||||
"encoding": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"text",
|
||||
"base64"
|
||||
],
|
||||
"x-go-name": "Encoding"
|
||||
},
|
||||
"file_path": {
|
||||
"type": "string",
|
||||
"x-go-name": "FilePath"
|
||||
}
|
||||
}
|
||||
},
|
||||
"x-go-name": "BatchFiles"
|
||||
"x-go-name": "Files"
|
||||
},
|
||||
"header": {
|
||||
"$ref": "#/definitions/FileOptions"
|
||||
}
|
||||
},
|
||||
"x-go-package": "code.gitea.io/gitea/modules/structs"
|
||||
|
@ -16304,6 +16211,42 @@
|
|||
},
|
||||
"x-go-package": "code.gitea.io/gitea/modules/structs"
|
||||
},
|
||||
"FileOptions": {
|
||||
"description": "FileOptions options for all file APIs",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"author": {
|
||||
"$ref": "#/definitions/Identity"
|
||||
},
|
||||
"branch": {
|
||||
"description": "branch (optional) to base this file from. if not given, the default branch is used",
|
||||
"type": "string",
|
||||
"x-go-name": "BranchName"
|
||||
},
|
||||
"committer": {
|
||||
"$ref": "#/definitions/Identity"
|
||||
},
|
||||
"dates": {
|
||||
"$ref": "#/definitions/CommitDateOptions"
|
||||
},
|
||||
"message": {
|
||||
"description": "message (optional) for the commit of this file. if not supplied, a default message will be used",
|
||||
"type": "string",
|
||||
"x-go-name": "Message"
|
||||
},
|
||||
"new_branch": {
|
||||
"description": "new_branch (optional) will make a new branch from `branch` before creating the file",
|
||||
"type": "string",
|
||||
"x-go-name": "NewBranchName"
|
||||
},
|
||||
"signoff": {
|
||||
"description": "Add a Signed-off-by trailer by the committer at the end of the commit log message.",
|
||||
"type": "boolean",
|
||||
"x-go-name": "Signoff"
|
||||
}
|
||||
},
|
||||
"x-go-package": "code.gitea.io/gitea/modules/structs"
|
||||
},
|
||||
"FileResponse": {
|
||||
"description": "FileResponse contains information about a repo's file",
|
||||
"type": "object",
|
||||
|
|
Loading…
Reference in New Issue