Files
autogits/common/git_utils_test.go
Adam Majer c5db1c83a7 PR: detect and rebase project git commits
When project is advanced, and we have other package changes
to same project, the project git changes need to be rebased. The
simplest way of doing this is to skip all the submodule conflicts
and re-create them. This allows the submodules changes to be
mergeable again.
2025-07-15 19:08:05 +02:00

598 lines
22 KiB
Go

package common
/*
* This file is part of Autogits.
*
* Copyright © 2024 SUSE LLC
*
* Autogits is free software: you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free Software
* Foundation, either version 2 of the License, or (at your option) any later
* version.
*
* Autogits is distributed in the hope that it will be useful, but WITHOUT ANY
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
* PARTICULAR PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with
* Foobar. If not, see <https://www.gnu.org/licenses/>.
*/
import (
"bufio"
"bytes"
"os"
"os/exec"
"path"
"slices"
"strings"
"testing"
)
func TestGitClone(t *testing.T) {
tests := []struct {
name string
repo string
branch string
remoteName string
remoteUrl string
}{
{
name: "Basic clone",
repo: "pkgAclone",
branch: "main",
remoteName: "pkgA_main",
remoteUrl: "/pkgA",
},
{
name: "Remote branch is non-existent",
repo: "pkgAclone",
branch: "main_not_here",
remoteName: "pkgA_main",
remoteUrl: "/pkgA",
},
}
return
execPath, err := os.Getwd()
if err != nil {
t.Fatal(err)
}
d := t.TempDir()
os.Chdir(d)
defer os.Chdir(execPath)
cmd := exec.Command(path.Join(execPath, "test_clone_setup.sh"))
if _, err := cmd.Output(); err != nil {
t.Fatal(err)
}
gh, err := AllocateGitWorkTree(d, "Test", "test@example.com")
if err != nil {
t.Fatal(err)
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
g, err := gh.CreateGitHandler("org")
if err != nil {
t.Fatal(err)
}
if _, err := g.GitClone(test.repo, test.branch, "file://"+d+test.remoteUrl); err != nil {
t.Fatal(err)
}
id, err := g.GitBranchHead(test.repo, test.branch)
if err != nil {
t.Fatal(err)
}
t.Fatal(id)
})
}
}
func TestGitMsgParsing(t *testing.T) {
t.Run("tree message with size 56", func(t *testing.T) {
const hdr = "f40888ea4515fe2e8eea617a16f5f50a45f652d894de3ad181d58de3aafb8f98 tree 56\x00"
data := make(chan byte, 500)
for _, b := range []byte(hdr) {
data <- b
}
gitHdr, err := parseGitMsg(data)
if err != nil {
t.Error(err)
}
if gitHdr.hash != "f40888ea4515fe2e8eea617a16f5f50a45f652d894de3ad181d58de3aafb8f98" {
t.Errorf("Invalid hash %s", gitHdr.hash)
}
if gitHdr.size != 56 {
t.Errorf("Invalid msg size: %d", gitHdr.size)
}
if gitHdr.itemType != "tree" {
t.Errorf("Invalid msg type: %s", gitHdr.itemType)
}
})
t.Run("commit message with size 256", func(t *testing.T) {
const hdr = "f40888ea4515fe2e8eea617a16f5f50a45f652d894de3ad181d58de3aafb8f99 commit 256\x00"
data := make(chan byte, 500)
for _, b := range []byte(hdr) {
data <- b
}
gitHdr, err := parseGitMsg(data)
if err != nil {
t.Error(err)
}
if gitHdr.hash != "f40888ea4515fe2e8eea617a16f5f50a45f652d894de3ad181d58de3aafb8f99" {
t.Errorf("Invalid hash %s", gitHdr.hash)
}
if gitHdr.size != 256 {
t.Errorf("Invalid msg size: %d", gitHdr.size)
}
if gitHdr.itemType != "commit" {
t.Errorf("Invalid msg type: %s", gitHdr.itemType)
}
})
t.Run("invalid tree message with size 56", func(t *testing.T) {
const hdr = "f408r8ea4515fe2e8eea617a16f5f50a45f652d894de3ad181d58de3aafb8f98 tree 56\x00"
data := make(chan byte, 500)
for _, b := range []byte(hdr) {
data <- b
}
gitHdr, err := parseGitMsg(data)
if err.Error() != "Invalid character during object hash parse 'r' at 4" {
t.Error(err)
}
if gitHdr.hash != "" {
t.Errorf("Invalid hash %s", gitHdr.hash)
}
if gitHdr.size != 0 {
t.Errorf("Invalid msg size: %d", gitHdr.size)
}
if gitHdr.itemType != "" {
t.Errorf("Invalid msg type: %s", gitHdr.itemType)
}
})
}
func TestGitCommitParsing(t *testing.T) {
t.Run("parse valid commit message", func(t *testing.T) {
const commitData = "f40888ea4515fe2e8eea617a16f5f50a45f652d894de3ad181d58de3aafb8f99 commit 253\000" +
`tree e20033df9f18780756ba4a96dbc7eb1a626253961039cb674156f266ba7a4e53
parent 429cc2fe02170ca5668f0461928c7e7430c7a17cd64ac298286d7162572a7703
author Adam Majer <amajer@suse.com> 1720709149 +0200
committer Adam Majer <amajer@suse.com> 1720709149 +0200
.` + "\000"
ch := make(chan byte, 5000)
for _, b := range []byte(commitData) {
ch <- b
}
commit, err := parseGitCommit(ch)
if err != nil {
t.Error(err)
}
if commit.Tree != "e20033df9f18780756ba4a96dbc7eb1a626253961039cb674156f266ba7a4e53" {
t.Errorf("Invalid commit object: %#v", commit)
}
if commit.Msg != "." {
t.Errorf("Invalid commit msg: '%s'", commit.Msg)
}
})
t.Run("parse multiline headers", func(t *testing.T) {
const commitData = "cae5831ab48470ff060a5aaa12eb6e5a7acaf91e commit 1492\000" +
`tree 1f9c8fe8099615d6d3921528402ac53f09213b02
parent e08a654fae0ecc91678819e0b62a2e014bad3339
author Yagiz Nizipli <yagiz@nizipli.com> 1720967314 -0400
committer GitHub <noreply@github.com> 1720967314 +0200
gpgsig -----BEGIN PGP SIGNATURE-----
wsFcBAABCAAQBQJmk+CSCRC1aQ7uu5UhlAAAQIYQAEQXCl3bUUuegiz5/oitIIF7
6xhndcjQIuqY4dONIeOARrGwbKh8OtMHpfJhMRUmvWvXrsTA6P1PWl0YcyyIMzHZ
a4sBsWyxA0uSztVywpvksvk6EdMoEXeXrHS3cBxePsH8bI+Pwnsv27PsevEwpyIT
reB4zZsoGySFVqf2lnXxG5hSRMYw++BDXSDMZk2BP9BvueRXasJ0lT1c7HlbHepF
TWzwyHZ91OhXjrdPY7qLQEEV/frwuM+UrxOPb2e83ZTg81vXFuugURfhHNx4Iu+F
LCMvOeaF2vO5yJtMe8+tY1l0Wb8S1aWcGCECN2XCXmmnWxt+yYh2gjqxq3y0DMcz
zvg6arQIepDFLkQPZMDlUCIjIJQn4FbAaQAvoyMF8Pi5YmxhRqgo3iOB5SBE8eES
63ifZ311izuSdD+o3ObFpzLoTgq62kglwfegZN/X8CzTSIqrT1norYJEbSwkWID1
WeRHUHfC7f6N3XK8zeb83zmhBU58ghW9sp5/LcefGMRJmVhBWhjBCpeMUaFHdKhl
/dfgPl5gJrrJ+wM3O6iaay0R1Iv4Upe/yXrbQnIgGj/qqgMLEPBY8lzNYimVTLxd
2ObrcXnERo3wwxeUgWaAARbEGQjC51DK/2SXxVGUh+IokicsBNRKU7lVWwwFFely
ntjtge6Gs9pA5rSIilPH
=V1bK
-----END PGP SIGNATURE-----
meta: change email address of anonrig
PR-URL: https://github.com/nodejs/node/pull/53829
Reviewed-By: Antoine du Hamel <duhamelantoine1995@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Luigi Pinca <luigipinca@gmail.com>
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Reviewed-By: Ulises Gascón <ulisesgascongonzalez@gmail.com>
Reviewed-By: Richard Lau <rlau@redhat.com>
Reviewed-By: Marco Ippolito <marcoippolito54@gmail.com>` + "\000"
ch := make(chan byte, 5000)
for _, b := range []byte(commitData) {
ch <- b
}
commit, err := parseGitCommit(ch)
if err != nil {
t.Error(err)
}
if commit.Tree != "1f9c8fe8099615d6d3921528402ac53f09213b02" {
t.Errorf("Invalid commit object: %#v", commit)
}
if commit.Msg[len(commit.Msg)-55:] != "Reviewed-By: Marco Ippolito <marcoippolito54@gmail.com>" {
t.Errorf("Invalid commit msg: '%s'", commit.Msg[len(commit.Msg)-55:])
}
})
t.Run("parse multiline headers", func(t *testing.T) {
const commitData = "c07c52c57a10fb355956df3caad2986613838f149274fbe312ad76560764829d commit 1150\000" + `tree 3e06b280ea056141ed5e8af9794a41ae5281930c45321803eab53a240cb60044
parent 19362a2cecb1fd25a89e03611d08ac68dcb1732f9dc0a68a40926356787fa4ca
author Adrian Schröter <adrian@suse.de> 1746600403 +0200
committer Adrian Schröter <adrian@suse.de> 1746600403 +0200
gpgsig-sha256 -----BEGIN PGP SIGNATURE-----
iQIzBAABCgAdFiEE1QF1zm/pNbvyhgLFkY2MlUwI22cFAmgbAd0ACgkQkY2MlUwI
22dxtA//eUCzIqxVdaEnOrFeTyxKig/mCOjaAyctmwr0vXUyElRtjXe4TzVG3QtR
uDfhIrKYLZ2tU/0TewTW/4XopWxLuqEzVQLrjuYl7K5P3GoYk52W1yGT0szzm7/i
87j4UdRL9YGU/gYO7nSzstcfTP6AcmYzVUoOnwYR0K2vyOVjO4niL3mFXxLkIgIt
jd82xcE4JpQz9Yjyq2nDdz4A55kLAwsqY+dOct4oC6bZmj1/JeoGQfPvUsvsQgcI
syCHVh0GBxjvSv50V/VPzxQTFMal/TdtvAD4kmP/9RDi/5THzus8Peam8pV0gEIC
Q15ZcuLwIsC9i7ifUDYgzLgBBRdpSI0qji4Y6clWULPVjsyghgyfQw1trBSySpC8
O1XfajUM+rXyrBLP6kzY+zl/zyzRdJ8JhljmC+SmNuyyEB77Hkn83k0f+aBhhqC2
4b3fIsKtwJZ1w6gr6SSz1BottiT9ShQzRaL8iRoF/2l5MkHPR+QFg2J7EIBqCbCQ
hFUjdvWAXQBWkkTQlJmLmJBXDOLQg3o6xCbnZM0gPFjZWE7e3Mpky7H0+xPnoeg9
ukuvkexXQ6yrdiekA7HRLc76Te/I0m7KDOOWZ3rbJV6uH/3ps4FbLQTZO12AtZ6J
n8hYdYfw9yjCxiKUjnEtXtDRe8DJpqv+hO0Wj4MI5gIA2JE2lzY=
=Keg5
-----END PGP SIGNATURE-----
dummy change, don't merge
` + "\000"
ch := make(chan byte)
go func() {
for _, b := range []byte(commitData) {
ch <- b
}
}()
commit, err := parseGitCommit(ch)
if err != nil {
t.Error(err)
}
if commit.Tree != "3e06b280ea056141ed5e8af9794a41ae5281930c45321803eab53a240cb60044" {
t.Errorf("Invalid commit object: %#v", commit)
}
if commit.Msg != "dummy change, don't merge\n" {
t.Errorf("Invalid commit msg: '%s'", commit.Msg)
}
})
t.Run("parse tree object", func(t *testing.T) {
const treeData = "\x31\x61\x30\x35\x64\x62\x37\x33\x36\x39\x33\x37\x34\x33\x30\x65\x31\x38\x64\x66\x34\x33\x61\x32\x37\x61\x39\x38\x30\x30\x31\x30\x31\x32\x65\x31\x65\x64\x32\x30\x34\x38\x32\x39\x38\x36\x37\x31\x32\x38\x66\x32\x63\x65\x38\x34\x30\x36\x62\x35\x63\x66\x63\x39\x20\x74\x72\x65\x65\x20\x32\x30\x35\x00\x34\x30\x30\x30\x30\x20\x62\x6f\x74\x73\x2d\x63\x6f\x6d\x6d\x6f\x6e\x00\x93\x17\xaa\x47\xf6\xea\x37\xe8\xbc\xe2\x80\x77\x57\x90\xf4\xa8\x01\xd7\xe3\x70\x2f\x84\xfb\xe1\xb0\x0e\x4a\x2c\x1c\x75\x2c\x2b\x34\x30\x30\x30\x30\x20\x6f\x62\x73\x2d\x73\x74\x61\x67\x69\x6e\x67\x2d\x62\x6f\x74\x00\x79\x77\x8b\x28\x7d\x37\x10\x59\xb9\x71\x28\x36\xed\x20\x31\x5f\xfb\xe1\xed\xb5\xba\x4f\x5e\xbb\x65\x65\x68\x23\x77\x32\x58\xfe\x34\x30\x30\x30\x30\x20\x70\x72\x2d\x72\x65\x76\x69\x65\x77\x00\x36\x0d\x45\xcb\x76\xb8\x93\xb3\x21\xba\xfa\xd5\x00\x9d\xfc\x59\xab\x88\xc1\x3c\x81\xcb\x48\x5a\xe0\x29\x29\x0f\xe3\x6b\x3c\x5e\x34\x30\x30\x30\x30\x20\x70\x72\x6a\x67\x69\x74\x2d\x75\x70\x64\x61\x74\x65\x72\x00\xb4\x0b\x1c\xf5\xfb\xec\x9a\xb2\x9f\x48\x3e\x21\x18\x0d\x51\xb7\x98\x6e\x21\x99\x74\x84\x67\x71\x41\x24\x42\xfc\xc9\x04\x12\x99\x00"
ch := make(chan byte, 1000)
for _, b := range []byte(treeData) {
ch <- b
}
tree, err := parseGitTree(ch)
if err != nil {
t.Error(err)
}
found := false
t.Log(tree.items)
for _, item := range tree.items {
if item.name == "bots-common" && item.hash == "9317aa47f6ea37e8bce280775790f4a801d7e3702f84fbe1b00e4a2c1c752c2b" && item.isTree() {
found = true
t.Log("found")
break
}
}
if !found {
t.Error("expected sub-tree not found")
}
})
t.Run("parse tree object with submodules", func(t *testing.T) {
const treeData = "\x34\x38\x34\x66\x31\x62\x65\x65\x63\x39\x35\x63\x61\x36\x62\x38\x36\x30\x64\x30\x64\x37\x63\x35\x65\x34\x38\x37\x31\x36\x36\x62\x30\x38\x65\x31\x61\x34\x35\x36\x37\x36\x62\x31\x37\x64\x39\x65\x65\x66\x32\x39\x39\x39\x65\x39\x64\x37\x34\x63\x62\x63\x64\x36\x20\x74\x72\x65\x65\x20\x33\x34\x39\x00\x31\x30\x30\x36\x34\x34\x20\x2e\x67\x69\x74\x6d\x6f\x64\x75\x6c\x65\x73\x00\xc8\x1e\x14\x29\xc5\xd4\x07\xfc\x32\xf1\xd7\xe2\x64\xee\x88\xfc\xce\xfc\x44\xf7\xae\x2e\xc4\x6e\x2c\x15\x27\x26\x65\xd4\xb8\x78\x31\x30\x30\x36\x34\x34\x20\x52\x45\x41\x44\x4d\x45\x2e\x6d\x64\x00\x90\x22\x84\x13\xbf\xd3\x5c\xfb\x1e\x27\x6b\xd6\x17\x3e\x89\xed\x0f\xc6\x31\x85\x24\x58\x6d\x9d\xf0\x6a\x1e\x17\x57\x19\x8d\xc2\x31\x36\x30\x30\x30\x30\x20\x6d\x69\x6e\x67\x77\x33\x32\x2d\x67\x63\x63\x00\xdc\x55\xb8\x28\x32\x8c\x8e\x49\x4f\x67\x87\x4a\x7d\x8c\x03\xdd\x1c\x6b\x4e\x02\xd1\x6b\x86\xe0\x8e\x47\xd7\x0e\xcd\x79\x96\x80\x31\x36\x30\x30\x30\x30\x20\x6e\x6f\x64\x65\x6a\x73\x2d\x63\x6f\x6d\x6d\x6f\x6e\x00\xd6\xa7\x4c\x08\x40\x6c\xe4\x0c\xc8\xf7\xbf\xf2\xd5\xcf\x30\x90\x87\xa8\x72\x83\x61\xcc\x75\x35\x4b\x08\x62\xba\x50\x81\x93\xb8\x31\x36\x30\x30\x30\x30\x20\x6e\x6f\x64\x65\x6a\x73\x32\x31\x00\x24\xee\x6b\xee\x74\x59\xa3\x86\xda\xda\xbf\x8a\x9f\x6a\xe4\xfa\x15\xc3\xf8\x10\xbf\xa0\x1c\xee\x52\x38\x13\x8a\xa2\x14\xd1\x80\x31\x36\x30\x30\x30\x30\x20\x6e\x6f\x64\x65\x6a\x73\x32\x32\x00\x87\x3a\x32\x3b\x26\x2e\xbb\x3b\xd7\x7b\x25\x92\xb2\xe1\x1b\xdd\x08\xdb\xc7\x21\xcb\xf4\xac\x9f\x97\x63\x7e\x58\xe1\xff\xfc\xe7\x31\x36\x30\x30\x30\x30\x20\x70\x79\x74\x68\x6f\x6e\x33\x31\x31\x00\x35\xc7\x02\xe8\x50\x1e\xed\xeb\x5c\xe4\x3d\x6f\x34\x60\xd1\x1c\x79\x1c\xfe\xfa\xa7\x72\x48\xf0\x8c\xad\x55\xd0\x0c\x37\xe7\x3a\x00"
ch := make(chan byte, 1000)
for _, b := range []byte(treeData) {
ch <- b
}
tree, err := parseGitTree(ch)
if err != nil {
t.Error(err)
}
found := false
for _, item := range tree.items {
t.Log(item)
if item.name == "nodejs22" && item.hash == "873a323b262ebb3bd77b2592b2e11bdd08dbc721cbf4ac9f97637e58e1fffce7" && item.isSubmodule() {
found = true
break
}
}
if !found {
t.Error("expected submodule not found")
}
})
t.Run("parse nested trees with subtrees", func(t *testing.T) {
const data = "873a323b262ebb3bd77b2592b2e11bdd08dbc721cbf4ac9f97637e58e1fffce7 tree 1083\x00100644\x20\x2Egitattributes\x00\xD8v\xA95\x87\xC1\xA9\xFCPn\xDD\xD4\x13\x9B\x8E\xD2\xCFs\xBD\x11q\x8A\xAE\x8A\x7Cg\xE2C\x14J\x01\xB0100644\x20\x2Egitignore\x00\xC3\xCD\x8En\x887\x3AJ\xA0P\xEEL\xD4\xF5\xD2v\x9C\xA6v\xC5D\x60\x40\x95\xD1\x0B\xA4\xB8\x86\xD4rE100644\x20COPYING\x00\x12\x2A\x28\xC8\xB9\x5D\x9B\x8A\x23\x1F\xE96\x07\x3F\xA9D\x90\xFD\xCE\x2Bi\x2D\x031\x5C\xCC\xC4fx\x00\xC22100644\x20README\x2Emd\x00\x92D\xF7\xFF\x0E0\x5C\xF2\xAC\x0DA\x06\x92\x0B\xD6z\x3CGh\x00y\x7EW1\xB9a\x8Ch\x215Fa100644\x20_service\x00\xC51\xF2\x12\xF3\x24\x9C\xD9\x9F\x0A\x93Mp\x12\xC1\xF7i\x05\x95\xC5Z\x06\x95i\x3Az\xC3\xF59\x7E\xF8\x1B100644\x20autogits\x2Echanges\x00\xF7\x8D\xBF\x0A\xCB\x5D\xB7y\x8C\xA9\x9C\xEB\x92\xAFd\x2C\x98\x23\x0C\x13\x13\xED\xDE\x5D\xBALD6\x3BR\x5B\xCA100644\x20autogits\x2Espec\x00\xD2\xBC\x20v\xD3\xE5F\xCA\xEE\xEA\x18\xC84\x0D\xA7\xCA\xD8O\xF2\x0A\xAB\x40\x2A\xFAL\x3B\xB4\xE6\x11\xE7o\xD140000\x20common\x00\xE2\xC9dg\xD0\x5D\xD1\xF1\x8ARW\xF0\x96\xD6\x29\x2F\x8F\xD9\xC7\x82\x1A\xB7\xAAw\xB0\xCE\xA8\xFE\xC8\xD7D\xF2100755\x20dev_test_helper\x2Esh\x00\xECY\xDD\xB3rz\x9Fh\xD4\x2E\x85\x02\x13\xF8\xFE\xB57\x8B\x1B6\x8E\x09dC\x1E\xE0\x90\x09\x08\xED\xBD_40000\x20devel\x2Dimporter\x00v\x98\x9B\x92\xD8\x24lu\xFC\xB2d\xC9\xCENb\xEE\x0F\x21\x8B\x92\x88\xDBs\xF8\x2E\xA8\xC8W\x1C\x20\xCF\xD440000\x20doc\x00\x8Akyq\xD0\xCF\xB8\x2F\x80Y\x2F\x11\xF0\x14\xA9\xFE\x96\x14\xE0W\x2C\xCF\xB9\x86\x7E\xFDi\xD7\x1F\x08Q\xFB40000\x20gitea\x2Devents\x2Drabbitmq\x2Dpublisher\x00\x5Cb\x3Fh\xA2\x06\x06\x0Cd\x09\xA5\xD9\xF7\x23\x5C\xF85\xF5\xB8\xBE\x7F\xD4O\x25t\xEF\xCC\xAB\x18\x7C\x0C\xF3100644\x20go\x2Emod\x00j\x85\x0B\x03\xC8\x9F\x9F\x0F\xC8\xE0\x8C\xF7\x3D\xC19\xF7\x12gk\xD6\x18JN\x24\xC0\x1C\xBE\x97oY\x02\x8D100644\x20go\x2Esum\x00h\x88\x2E\x27\xED\xD39\x8D\x12\x0F\x7D\x97\xA2\x5DE\xB9\x82o\x0Cu\xF4l\xA17s\x28\x2BQT\xE6\x12\x9040000\x20group\x2Dreview\x00\x7E\x7B\xB42\x0F\x3B\xC9o\x2C\xE79\x1DR\xE2\xE4i\xAE\xF6u\x90\x09\xD8\xC9c\xE7\xF7\xC7\x92\xFB\xD7\xDD140000\x20obs\x2Dstaging\x2Dbot\x00\x12\xE8\xAF\x09\xD4\x5D\x13\x8D\xC9\x0AvPDc\xB6\x7C\xAC4\xD9\xC5\xD4_\x98i\xBE2\xA7\x25aj\xE2k40000\x20obs\x2Dstatus\x2Dservice\x00MATY\xA3\xFA\xED\x05\xBE\xEB\x2B\x07\x9CN\xA9\xF3SB\x22MlV\xA4\x5D\xDA\x0B\x0F\x23\xA1\xA8z\xD740000\x20systemd\x00\x2D\xE2\x03\x7E\xBD\xEB6\x8F\xC5\x0E\x12\xD4\xBD\x97P\xDD\xA2\x92\xCE6n\x08Q\xCA\xE4\x15\x97\x8F\x26V\x3DW100644\x20vendor\x2Etar\x2Ezst\x00\xD9\x2Es\x03I\x91\x22\x24\xC86q\x91\x95\xEF\xA3\xC9\x3C\x06D\x90w\xAD\xCB\xAE\xEEu2i\xCE\x05\x09u40000\x20workflow\x2Ddirect\x00\x94\xDB\xDFc\xB5A\xD5\x16\xB3\xC3ng\x94J\xE7\x101jYF\x15Q\xE97\xCFg\x14\x12\x28\x3A\xFC\xDB40000\x20workflow\x2Dpr\x00\xC1\xD8Z9\x18\x60\xA2\xE2\xEF\xB0\xFC\xD7\x2Ah\xF07\x0D\xEC\x8A7\x7E\x1A\xAAn\x13\x9C\xEC\x05s\xE8\xBDf\x00"
ch := make(chan byte, 2000)
for _, b := range []byte(data) {
ch <- b
}
tree, err := parseGitTree(ch)
if err != nil {
t.Error(err)
}
found := false
for _, item := range tree.items {
t.Log(item)
if item.name == "workflow-pr" && item.hash == "c1d85a391860a2e2efb0fcd72a68f0370dec8a377e1aaa6e139cec0573e8bd66" && item.isTree() {
found = true
break
}
}
if !found {
t.Error("expected submodule not found")
}
})
}
func TestCommitTreeParsing(t *testing.T) {
gitDir := t.TempDir()
testDir, _ := os.Getwd()
var commitId string
cmd := exec.Command("/usr/bin/bash", path.Join(testDir, "tsetup.sh"))
cmd.Dir = gitDir
cmd.Stdout = writeFunc(func(data []byte) (int, error) {
commitId = commitId + strings.TrimSpace(string(data))
return len(data), nil
})
if err := cmd.Run(); err != nil {
t.Fatal(err.Error())
}
gh, err := AllocateGitWorkTree(gitDir, "", "")
if err != nil {
t.Fatal(err)
}
t.Run("GitCatFile commit", func(t *testing.T) {
h, _ := gh.ReadExistingPath(".")
defer h.Close()
file, err := h.GitCatFile("", commitId, "help")
if err != nil {
t.Error("failed", err)
}
if string(file) != "help\n" {
t.Error("expected 'help\\n' but got", string(file))
}
})
t.Run("GitCatFile commit", func(t *testing.T) {
h, _ := gh.ReadExistingPath(".")
defer h.Close()
file, err := h.GitCatFile("", "HEAD", "help")
if err != nil {
t.Error("failed", err)
}
if string(file) != "help\n" {
t.Error("expected 'help\\n' but got", string(file))
}
})
t.Run("GitCatFile bad commit", func(t *testing.T) {
h, _ := gh.ReadExistingPath(".")
defer h.Close()
file, err := h.GitCatFile("", "518b468f391bf01d5d76d497d7cbecfa8b46d185714cf8745800ae18afb21afd", "help")
if err == nil {
t.Error("expected error, but not nothing")
}
if string(file) != "" {
t.Error("expected 'help\\n' but got", file)
}
})
t.Run("reads HEAD and parses the tree", func(t *testing.T) {
const nodejs21 = "c678c57007d496a98bec668ae38f2c26a695f94af78012f15d044ccf066ccb41"
h, _ := gh.ReadExistingPath(".")
defer h.Close()
id, ok := h.GitSubmoduleCommitId("", "nodejs21", commitId)
if !ok {
t.Error("failed parse")
}
if id != nodejs21 {
t.Errorf("hash doesn't match: %s vs. expected %s", id, nodejs21)
}
})
t.Run("reads README.md", func(t *testing.T) {
h, _ := gh.ReadExistingPath(".")
defer h.Close()
data, err := h.GitCatFile("", commitId, "README.md")
if err != nil {
t.Errorf("failed parse: %v", err)
}
if string(data) != "foo\n" || len(data) != 4 {
t.Errorf("Wrong data of len: %d", len(data))
}
})
t.Run("read HEAD", func(t *testing.T) {
h, _ := gh.ReadExistingPath(".")
defer h.Close()
data, err := h.GitSubmoduleList("", "HEAD")
if err != nil {
t.Error("failed to get submodule list", err)
}
if len(data) != 5 {
t.Error("Invalid len of submodules", len(data))
}
})
t.Run("try to parse unknown item", func(t *testing.T) {
})
}
func TestGitStatusParse(t *testing.T) {
testData := []struct {
name string
data []byte
res []GitStatusData
}{
{
name: "Single modified line",
data: []byte("1 .M N... 100644 100644 100644 dbe4b3d5a0a2e385f78fd41d726baa20e9190f7b5a2e78cbd4885586832f39e7 dbe4b3d5a0a2e385f78fd41d726baa20e9190f7b5a2e78cbd4885586832f39e7 bots-common/git_utils.go\x00"),
res: []GitStatusData{
{
Path: "bots-common/git_utils.go",
Status: GitStatus_Modified,
},
},
},
{
name: "Untracked entries",
data: []byte("1 .M N... 100644 100644 100644 dbe4b3d5a0a2e385f78fd41d726baa20e9190f7b5a2e78cbd4885586832f39e7 dbe4b3d5a0a2e385f78fd41d726baa20e9190f7b5a2e78cbd4885586832f39e7 bots-common/git_utils.go\x00? bots-common/c.out\x00? doc/Makefile\x00"),
res: []GitStatusData{
{
Path: "bots-common/git_utils.go",
Status: GitStatus_Modified,
},
{
Path: "bots-common/c.out",
Status: GitStatus_Untracked,
},
{
Path: "doc/Makefile",
Status: GitStatus_Untracked,
},
},
},
{
name: "Untracked entries",
data: []byte("1 .M N... 100644 100644 100644 dbe4b3d5a0a2e385f78fd41d726baa20e9190f7b5a2e78cbd4885586832f39e7 dbe4b3d5a0a2e385f78fd41d726baa20e9190f7b5a2e78cbd4885586832f39e7 bots-common/git_utils.go\x00? bots-common/c.out\x00! doc/Makefile\x00"),
res: []GitStatusData{
{
Path: "bots-common/git_utils.go",
Status: GitStatus_Modified,
},
{
Path: "bots-common/c.out",
Status: GitStatus_Untracked,
},
{
Path: "doc/Makefile",
Status: GitStatus_Ignored,
},
},
},
{
name: "Nothing",
},
{
name: "Unmerged .gitmodules during a merge",
data: []byte("1 A. S... 000000 160000 160000 0000000000000000000000000000000000000000000000000000000000000000 ed07665aea0522096c88a7555f1fa9009ed0e0bac92de4613c3479516dd3d147 pkgB2\x00u UU N... 100644 100644 100644 100644 587ec403f01113f2629da538f6e14b84781f70ac59c41aeedd978ea8b1253a76 d23eb05d9ca92883ab9f4d28f3ec90c05f667f3a5c8c8e291bd65e03bac9ae3c 087b1d5f22dbf0aa4a879fff27fff03568b334c90daa5f2653f4a7961e24ea33 .gitmodules\x00"),
res: []GitStatusData{
{
Path: "pkgB2",
Status: GitStatus_Modified,
},
{
Path: ".gitmodules",
Status: GitStatus_Unmerged,
States: [3]string{"587ec403f01113f2629da538f6e14b84781f70ac59c41aeedd978ea8b1253a76", "d23eb05d9ca92883ab9f4d28f3ec90c05f667f3a5c8c8e291bd65e03bac9ae3c", "087b1d5f22dbf0aa4a879fff27fff03568b334c90daa5f2653f4a7961e24ea33"},
SubmoduleChanges: "N...",
},
},
},
{
name: "Renamed file",
data: []byte("1 M. N... 100644 100644 100644 d23eb05d9ca92883ab9f4d28f3ec90c05f667f3a5c8c8e291bd65e03bac9ae3c 896cd09f36d39e782d66ae32dd5614d4f4d83fc689f132aab2dfc019a9f5b6f3 .gitmodules\x002 R. S... 160000 160000 160000 3befe051a34612530acfa84c736d2454278453ec0f78ec028f25d2980f8c3559 3befe051a34612530acfa84c736d2454278453ec0f78ec028f25d2980f8c3559 R100 pkgQ\x00pkgC\x00"),
res: []GitStatusData{
{
Path: "pkgQ",
Status: GitStatus_Renamed,
States: [3]string{"pkgC"},
},
{
Path: ".gitmodules",
Status: GitStatus_Modified,
},
},
},
}
for _, test := range testData {
t.Run(test.name, func(t *testing.T) {
r, err := parseGitStatusData(bufio.NewReader(bytes.NewReader(test.data)))
if err != nil {
t.Fatal(err)
}
if len(r) != len(test.res) {
t.Fatal("len(r):", len(r), "is not expected", len(test.res))
}
for _, expected := range test.res {
if !slices.Contains(r, expected) {
t.Fatal("result", r, "doesn't contains expected", expected)
}
}
})
}
}