2019-05-11 18:29:17 +03:00
// Copyright 2019 The Gitea Authors. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package integrations
import (
"net/url"
2019-06-29 23:51:10 +03:00
"path/filepath"
2019-05-11 18:29:17 +03:00
"testing"
"time"
2021-12-10 04:27:50 +03:00
repo_model "code.gitea.io/gitea/models/repo"
2019-05-11 18:29:17 +03:00
"code.gitea.io/gitea/modules/git"
"code.gitea.io/gitea/modules/setting"
api "code.gitea.io/gitea/modules/structs"
"code.gitea.io/gitea/modules/test"
2021-11-24 10:56:24 +03:00
files_service "code.gitea.io/gitea/services/repository/files"
2019-05-11 18:29:17 +03:00
"github.com/stretchr/testify/assert"
)
2021-12-10 04:27:50 +03:00
func getCreateRepoFileOptions ( repo * repo_model . Repository ) * files_service . UpdateRepoFileOptions {
2021-11-24 10:56:24 +03:00
return & files_service . UpdateRepoFileOptions {
2019-05-11 18:29:17 +03:00
OldBranch : repo . DefaultBranch ,
NewBranch : repo . DefaultBranch ,
TreePath : "new/file.txt" ,
Message : "Creates new/file.txt" ,
Content : "This is a NEW file" ,
IsNewFile : true ,
Author : nil ,
Committer : nil ,
}
}
2021-12-10 04:27:50 +03:00
func getUpdateRepoFileOptions ( repo * repo_model . Repository ) * files_service . UpdateRepoFileOptions {
2021-11-24 10:56:24 +03:00
return & files_service . UpdateRepoFileOptions {
2019-05-11 18:29:17 +03:00
OldBranch : repo . DefaultBranch ,
NewBranch : repo . DefaultBranch ,
TreePath : "README.md" ,
Message : "Updates README.md" ,
SHA : "4b4851ad51df6a7d9f25c979345979eaeb5b349f" ,
Content : "This is UPDATED content for the README file" ,
IsNewFile : false ,
Author : nil ,
Committer : nil ,
}
}
2022-07-30 11:09:04 +03:00
func getExpectedFileResponseForRepofilesCreate ( commitID , lastCommitSHA string ) * api . FileResponse {
2019-06-29 23:51:10 +03:00
treePath := "new/file.txt"
encoding := "base64"
content := "VGhpcyBpcyBhIE5FVyBmaWxl"
selfURL := setting . AppURL + "api/v1/repos/user2/repo1/contents/" + treePath + "?ref=master"
htmlURL := setting . AppURL + "user2/repo1/src/branch/master/" + treePath
gitURL := setting . AppURL + "api/v1/repos/user2/repo1/git/blobs/103ff9234cefeee5ec5361d22b49fbb04d385885"
downloadURL := setting . AppURL + "user2/repo1/raw/branch/master/" + treePath
2019-05-11 18:29:17 +03:00
return & api . FileResponse {
2019-06-29 23:51:10 +03:00
Content : & api . ContentsResponse {
2022-07-30 11:09:04 +03:00
Name : filepath . Base ( treePath ) ,
Path : treePath ,
SHA : "103ff9234cefeee5ec5361d22b49fbb04d385885" ,
LastCommitSHA : lastCommitSHA ,
Type : "file" ,
Size : 18 ,
Encoding : & encoding ,
Content : & content ,
URL : & selfURL ,
HTMLURL : & htmlURL ,
GitURL : & gitURL ,
DownloadURL : & downloadURL ,
2019-05-11 18:29:17 +03:00
Links : & api . FileLinksResponse {
2019-06-29 23:51:10 +03:00
Self : & selfURL ,
GitURL : & gitURL ,
HTMLURL : & htmlURL ,
2019-05-11 18:29:17 +03:00
} ,
} ,
Commit : & api . FileCommitResponse {
CommitMeta : api . CommitMeta {
URL : setting . AppURL + "api/v1/repos/user2/repo1/git/commits/" + commitID ,
SHA : commitID ,
} ,
HTMLURL : setting . AppURL + "user2/repo1/commit/" + commitID ,
Author : & api . CommitUser {
Identity : api . Identity {
Name : "User Two" ,
Email : "user2@noreply.example.org" ,
} ,
Date : time . Now ( ) . UTC ( ) . Format ( time . RFC3339 ) ,
} ,
Committer : & api . CommitUser {
Identity : api . Identity {
Name : "User Two" ,
Email : "user2@noreply.example.org" ,
} ,
Date : time . Now ( ) . UTC ( ) . Format ( time . RFC3339 ) ,
} ,
Parents : [ ] * api . CommitMeta {
{
URL : setting . AppURL + "api/v1/repos/user2/repo1/git/commits/65f1bf27bc3bf70f64657658635e66094edbcb4d" ,
SHA : "65f1bf27bc3bf70f64657658635e66094edbcb4d" ,
} ,
} ,
Message : "Updates README.md\n" ,
Tree : & api . CommitMeta {
URL : setting . AppURL + "api/v1/repos/user2/repo1/git/trees/f93e3a1a1525fb5b91020da86e44810c87a2d7bc" ,
SHA : "f93e3a1a1525fb5b91020git dda86e44810c87a2d7bc" ,
} ,
} ,
Verification : & api . PayloadCommitVerification {
Verified : false ,
2019-10-16 16:42:42 +03:00
Reason : "gpg.error.not_signed_commit" ,
2019-05-11 18:29:17 +03:00
Signature : "" ,
Payload : "" ,
} ,
}
}
2022-07-30 11:09:04 +03:00
func getExpectedFileResponseForRepofilesUpdate ( commitID , filename , lastCommitSHA string ) * api . FileResponse {
2019-06-29 23:51:10 +03:00
encoding := "base64"
content := "VGhpcyBpcyBVUERBVEVEIGNvbnRlbnQgZm9yIHRoZSBSRUFETUUgZmlsZQ=="
selfURL := setting . AppURL + "api/v1/repos/user2/repo1/contents/" + filename + "?ref=master"
htmlURL := setting . AppURL + "user2/repo1/src/branch/master/" + filename
gitURL := setting . AppURL + "api/v1/repos/user2/repo1/git/blobs/dbf8d00e022e05b7e5cf7e535de857de57925647"
downloadURL := setting . AppURL + "user2/repo1/raw/branch/master/" + filename
2019-05-11 18:29:17 +03:00
return & api . FileResponse {
2019-06-29 23:51:10 +03:00
Content : & api . ContentsResponse {
2022-07-30 11:09:04 +03:00
Name : filename ,
Path : filename ,
SHA : "dbf8d00e022e05b7e5cf7e535de857de57925647" ,
LastCommitSHA : lastCommitSHA ,
Type : "file" ,
Size : 43 ,
Encoding : & encoding ,
Content : & content ,
URL : & selfURL ,
HTMLURL : & htmlURL ,
GitURL : & gitURL ,
DownloadURL : & downloadURL ,
2019-05-11 18:29:17 +03:00
Links : & api . FileLinksResponse {
2019-06-29 23:51:10 +03:00
Self : & selfURL ,
GitURL : & gitURL ,
HTMLURL : & htmlURL ,
2019-05-11 18:29:17 +03:00
} ,
} ,
Commit : & api . FileCommitResponse {
CommitMeta : api . CommitMeta {
URL : setting . AppURL + "api/v1/repos/user2/repo1/git/commits/" + commitID ,
SHA : commitID ,
} ,
HTMLURL : setting . AppURL + "user2/repo1/commit/" + commitID ,
Author : & api . CommitUser {
Identity : api . Identity {
Name : "User Two" ,
Email : "user2@noreply.example.org" ,
} ,
Date : time . Now ( ) . UTC ( ) . Format ( time . RFC3339 ) ,
} ,
Committer : & api . CommitUser {
Identity : api . Identity {
Name : "User Two" ,
Email : "user2@noreply.example.org" ,
} ,
Date : time . Now ( ) . UTC ( ) . Format ( time . RFC3339 ) ,
} ,
Parents : [ ] * api . CommitMeta {
{
URL : setting . AppURL + "api/v1/repos/user2/repo1/git/commits/65f1bf27bc3bf70f64657658635e66094edbcb4d" ,
SHA : "65f1bf27bc3bf70f64657658635e66094edbcb4d" ,
} ,
} ,
Message : "Updates README.md\n" ,
Tree : & api . CommitMeta {
URL : setting . AppURL + "api/v1/repos/user2/repo1/git/trees/f93e3a1a1525fb5b91020da86e44810c87a2d7bc" ,
SHA : "f93e3a1a1525fb5b91020da86e44810c87a2d7bc" ,
} ,
} ,
Verification : & api . PayloadCommitVerification {
Verified : false ,
2019-10-16 16:42:42 +03:00
Reason : "gpg.error.not_signed_commit" ,
2019-05-11 18:29:17 +03:00
Signature : "" ,
Payload : "" ,
} ,
}
}
func TestCreateOrUpdateRepoFileForCreate ( t * testing . T ) {
// setup
onGiteaRun ( t , func ( t * testing . T , u * url . URL ) {
ctx := test . MockContext ( t , "user2/repo1" )
ctx . SetParams ( ":id" , "1" )
test . LoadRepo ( t , ctx , 1 )
test . LoadRepoCommit ( t , ctx )
test . LoadUser ( t , ctx , 2 )
test . LoadGitRepo ( t , ctx )
2019-11-13 10:01:19 +03:00
defer ctx . Repo . GitRepo . Close ( )
2019-05-11 18:29:17 +03:00
repo := ctx . Repo . Repository
2022-03-22 10:03:22 +03:00
doer := ctx . Doer
2019-05-11 18:29:17 +03:00
opts := getCreateRepoFileOptions ( repo )
// test
2022-01-20 02:26:57 +03:00
fileResponse , err := files_service . CreateOrUpdateRepoFile ( git . DefaultContext , repo , doer , opts )
2019-05-11 18:29:17 +03:00
// asserts
2020-07-19 12:53:40 +03:00
assert . NoError ( t , err )
2022-03-29 22:13:41 +03:00
gitRepo , _ := git . OpenRepository ( git . DefaultContext , repo . RepoPath ( ) )
2019-11-13 10:01:19 +03:00
defer gitRepo . Close ( )
2019-05-11 18:29:17 +03:00
commitID , _ := gitRepo . GetBranchCommitID ( opts . NewBranch )
2022-07-30 11:09:04 +03:00
lastCommit , _ := gitRepo . GetCommitByPath ( "new/file.txt" )
expectedFileResponse := getExpectedFileResponseForRepofilesCreate ( commitID , lastCommit . ID . String ( ) )
2020-02-26 09:32:22 +03:00
assert . NotNil ( t , expectedFileResponse )
if expectedFileResponse != nil {
assert . EqualValues ( t , expectedFileResponse . Content , fileResponse . Content )
assert . EqualValues ( t , expectedFileResponse . Commit . SHA , fileResponse . Commit . SHA )
assert . EqualValues ( t , expectedFileResponse . Commit . HTMLURL , fileResponse . Commit . HTMLURL )
assert . EqualValues ( t , expectedFileResponse . Commit . Author . Email , fileResponse . Commit . Author . Email )
assert . EqualValues ( t , expectedFileResponse . Commit . Author . Name , fileResponse . Commit . Author . Name )
}
2019-05-11 18:29:17 +03:00
} )
}
func TestCreateOrUpdateRepoFileForUpdate ( t * testing . T ) {
// setup
onGiteaRun ( t , func ( t * testing . T , u * url . URL ) {
ctx := test . MockContext ( t , "user2/repo1" )
ctx . SetParams ( ":id" , "1" )
test . LoadRepo ( t , ctx , 1 )
test . LoadRepoCommit ( t , ctx )
test . LoadUser ( t , ctx , 2 )
test . LoadGitRepo ( t , ctx )
2019-11-13 10:01:19 +03:00
defer ctx . Repo . GitRepo . Close ( )
2019-05-11 18:29:17 +03:00
repo := ctx . Repo . Repository
2022-03-22 10:03:22 +03:00
doer := ctx . Doer
2019-05-11 18:29:17 +03:00
opts := getUpdateRepoFileOptions ( repo )
// test
2022-01-20 02:26:57 +03:00
fileResponse , err := files_service . CreateOrUpdateRepoFile ( git . DefaultContext , repo , doer , opts )
2019-05-11 18:29:17 +03:00
// asserts
2020-07-19 12:53:40 +03:00
assert . NoError ( t , err )
2022-03-29 22:13:41 +03:00
gitRepo , _ := git . OpenRepository ( git . DefaultContext , repo . RepoPath ( ) )
2019-11-13 10:01:19 +03:00
defer gitRepo . Close ( )
2022-07-30 11:09:04 +03:00
commit , _ := gitRepo . GetBranchCommit ( opts . NewBranch )
lastCommit , _ := commit . GetCommitByPath ( opts . TreePath )
expectedFileResponse := getExpectedFileResponseForRepofilesUpdate ( commit . ID . String ( ) , opts . TreePath , lastCommit . ID . String ( ) )
2019-05-11 18:29:17 +03:00
assert . EqualValues ( t , expectedFileResponse . Content , fileResponse . Content )
assert . EqualValues ( t , expectedFileResponse . Commit . SHA , fileResponse . Commit . SHA )
assert . EqualValues ( t , expectedFileResponse . Commit . HTMLURL , fileResponse . Commit . HTMLURL )
assert . EqualValues ( t , expectedFileResponse . Commit . Author . Email , fileResponse . Commit . Author . Email )
assert . EqualValues ( t , expectedFileResponse . Commit . Author . Name , fileResponse . Commit . Author . Name )
} )
}
func TestCreateOrUpdateRepoFileForUpdateWithFileMove ( t * testing . T ) {
// setup
onGiteaRun ( t , func ( t * testing . T , u * url . URL ) {
ctx := test . MockContext ( t , "user2/repo1" )
ctx . SetParams ( ":id" , "1" )
test . LoadRepo ( t , ctx , 1 )
test . LoadRepoCommit ( t , ctx )
test . LoadUser ( t , ctx , 2 )
test . LoadGitRepo ( t , ctx )
2019-11-13 10:01:19 +03:00
defer ctx . Repo . GitRepo . Close ( )
2019-05-11 18:29:17 +03:00
repo := ctx . Repo . Repository
2022-03-22 10:03:22 +03:00
doer := ctx . Doer
2019-05-11 18:29:17 +03:00
opts := getUpdateRepoFileOptions ( repo )
opts . FromTreePath = "README.md"
2019-06-29 23:51:10 +03:00
opts . TreePath = "README_new.md" // new file name, README_new.md
2019-05-11 18:29:17 +03:00
// test
2022-01-20 02:26:57 +03:00
fileResponse , err := files_service . CreateOrUpdateRepoFile ( git . DefaultContext , repo , doer , opts )
2019-05-11 18:29:17 +03:00
// asserts
2020-07-19 12:53:40 +03:00
assert . NoError ( t , err )
2022-03-29 22:13:41 +03:00
gitRepo , _ := git . OpenRepository ( git . DefaultContext , repo . RepoPath ( ) )
2019-11-13 10:01:19 +03:00
defer gitRepo . Close ( )
2019-05-11 18:29:17 +03:00
commit , _ := gitRepo . GetBranchCommit ( opts . NewBranch )
2022-07-30 11:09:04 +03:00
lastCommit , _ := commit . GetCommitByPath ( opts . TreePath )
expectedFileResponse := getExpectedFileResponseForRepofilesUpdate ( commit . ID . String ( ) , opts . TreePath , lastCommit . ID . String ( ) )
2019-05-11 18:29:17 +03:00
// assert that the old file no longer exists in the last commit of the branch
fromEntry , err := commit . GetTreeEntryByPath ( opts . FromTreePath )
2019-11-16 21:21:39 +03:00
switch err . ( type ) {
case git . ErrNotExist :
// correct, continue
default :
t . Fatalf ( "expected git.ErrNotExist, got:%v" , err )
}
2019-05-11 18:29:17 +03:00
toEntry , err := commit . GetTreeEntryByPath ( opts . TreePath )
2020-07-19 12:53:40 +03:00
assert . NoError ( t , err )
2019-05-11 18:29:17 +03:00
assert . Nil ( t , fromEntry ) // Should no longer exist here
assert . NotNil ( t , toEntry ) // Should exist here
// assert SHA has remained the same but paths use the new file name
assert . EqualValues ( t , expectedFileResponse . Content . SHA , fileResponse . Content . SHA )
2019-06-29 23:51:10 +03:00
assert . EqualValues ( t , expectedFileResponse . Content . Name , fileResponse . Content . Name )
assert . EqualValues ( t , expectedFileResponse . Content . Path , fileResponse . Content . Path )
assert . EqualValues ( t , expectedFileResponse . Content . URL , fileResponse . Content . URL )
2019-05-11 18:29:17 +03:00
assert . EqualValues ( t , expectedFileResponse . Commit . SHA , fileResponse . Commit . SHA )
assert . EqualValues ( t , expectedFileResponse . Commit . HTMLURL , fileResponse . Commit . HTMLURL )
} )
}
// Test opts with branch names removed, should get same results as above test
func TestCreateOrUpdateRepoFileWithoutBranchNames ( t * testing . T ) {
// setup
onGiteaRun ( t , func ( t * testing . T , u * url . URL ) {
ctx := test . MockContext ( t , "user2/repo1" )
ctx . SetParams ( ":id" , "1" )
test . LoadRepo ( t , ctx , 1 )
test . LoadRepoCommit ( t , ctx )
test . LoadUser ( t , ctx , 2 )
test . LoadGitRepo ( t , ctx )
2019-11-13 10:01:19 +03:00
defer ctx . Repo . GitRepo . Close ( )
2019-05-11 18:29:17 +03:00
repo := ctx . Repo . Repository
2022-03-22 10:03:22 +03:00
doer := ctx . Doer
2019-05-11 18:29:17 +03:00
opts := getUpdateRepoFileOptions ( repo )
opts . OldBranch = ""
opts . NewBranch = ""
// test
2022-01-20 02:26:57 +03:00
fileResponse , err := files_service . CreateOrUpdateRepoFile ( git . DefaultContext , repo , doer , opts )
2019-05-11 18:29:17 +03:00
// asserts
2020-07-19 12:53:40 +03:00
assert . NoError ( t , err )
2022-03-29 22:13:41 +03:00
gitRepo , _ := git . OpenRepository ( git . DefaultContext , repo . RepoPath ( ) )
2019-11-13 10:01:19 +03:00
defer gitRepo . Close ( )
2022-07-30 11:09:04 +03:00
commit , _ := gitRepo . GetBranchCommit ( repo . DefaultBranch )
lastCommit , _ := commit . GetCommitByPath ( opts . TreePath )
expectedFileResponse := getExpectedFileResponseForRepofilesUpdate ( commit . ID . String ( ) , opts . TreePath , lastCommit . ID . String ( ) )
2019-05-11 18:29:17 +03:00
assert . EqualValues ( t , expectedFileResponse . Content , fileResponse . Content )
} )
}
func TestCreateOrUpdateRepoFileErrors ( t * testing . T ) {
// setup
onGiteaRun ( t , func ( t * testing . T , u * url . URL ) {
ctx := test . MockContext ( t , "user2/repo1" )
ctx . SetParams ( ":id" , "1" )
test . LoadRepo ( t , ctx , 1 )
test . LoadRepoCommit ( t , ctx )
test . LoadUser ( t , ctx , 2 )
test . LoadGitRepo ( t , ctx )
2019-11-13 10:01:19 +03:00
defer ctx . Repo . GitRepo . Close ( )
2019-05-11 18:29:17 +03:00
repo := ctx . Repo . Repository
2022-03-22 10:03:22 +03:00
doer := ctx . Doer
2019-05-11 18:29:17 +03:00
t . Run ( "bad branch" , func ( t * testing . T ) {
opts := getUpdateRepoFileOptions ( repo )
opts . OldBranch = "bad_branch"
2022-01-20 02:26:57 +03:00
fileResponse , err := files_service . CreateOrUpdateRepoFile ( git . DefaultContext , repo , doer , opts )
2019-05-11 18:29:17 +03:00
assert . Error ( t , err )
assert . Nil ( t , fileResponse )
expectedError := "branch does not exist [name: " + opts . OldBranch + "]"
assert . EqualError ( t , err , expectedError )
} )
t . Run ( "bad SHA" , func ( t * testing . T ) {
opts := getUpdateRepoFileOptions ( repo )
origSHA := opts . SHA
opts . SHA = "bad_sha"
2022-01-20 02:26:57 +03:00
fileResponse , err := files_service . CreateOrUpdateRepoFile ( git . DefaultContext , repo , doer , opts )
2019-05-11 18:29:17 +03:00
assert . Nil ( t , fileResponse )
assert . Error ( t , err )
expectedError := "sha does not match [given: " + opts . SHA + ", expected: " + origSHA + "]"
assert . EqualError ( t , err , expectedError )
} )
t . Run ( "new branch already exists" , func ( t * testing . T ) {
opts := getUpdateRepoFileOptions ( repo )
opts . NewBranch = "develop"
2022-01-20 02:26:57 +03:00
fileResponse , err := files_service . CreateOrUpdateRepoFile ( git . DefaultContext , repo , doer , opts )
2019-05-11 18:29:17 +03:00
assert . Nil ( t , fileResponse )
assert . Error ( t , err )
expectedError := "branch already exists [name: " + opts . NewBranch + "]"
assert . EqualError ( t , err , expectedError )
} )
t . Run ( "treePath is empty:" , func ( t * testing . T ) {
opts := getUpdateRepoFileOptions ( repo )
opts . TreePath = ""
2022-01-20 02:26:57 +03:00
fileResponse , err := files_service . CreateOrUpdateRepoFile ( git . DefaultContext , repo , doer , opts )
2019-05-11 18:29:17 +03:00
assert . Nil ( t , fileResponse )
assert . Error ( t , err )
expectedError := "path contains a malformed path component [path: ]"
assert . EqualError ( t , err , expectedError )
} )
t . Run ( "treePath is a git directory:" , func ( t * testing . T ) {
opts := getUpdateRepoFileOptions ( repo )
opts . TreePath = ".git"
2022-01-20 02:26:57 +03:00
fileResponse , err := files_service . CreateOrUpdateRepoFile ( git . DefaultContext , repo , doer , opts )
2019-05-11 18:29:17 +03:00
assert . Nil ( t , fileResponse )
assert . Error ( t , err )
expectedError := "path contains a malformed path component [path: " + opts . TreePath + "]"
assert . EqualError ( t , err , expectedError )
} )
t . Run ( "create file that already exists" , func ( t * testing . T ) {
opts := getCreateRepoFileOptions ( repo )
2022-01-20 20:46:10 +03:00
opts . TreePath = "README.md" // already exists
2022-01-20 02:26:57 +03:00
fileResponse , err := files_service . CreateOrUpdateRepoFile ( git . DefaultContext , repo , doer , opts )
2019-05-11 18:29:17 +03:00
assert . Nil ( t , fileResponse )
assert . Error ( t , err )
expectedError := "repository file already exists [path: " + opts . TreePath + "]"
assert . EqualError ( t , err , expectedError )
} )
} )
}