Added remote push capability to tagless mode

Importing tagless RPM can now push to the remote.

The push behavior should emulate the default tagged mode.

-Skip Grube
This commit is contained in:
Skip Grube 2022-09-04 00:14:36 -04:00
parent 16b12ef42b
commit d99f126761
No known key found for this signature in database
GPG Key ID: D391F8393BEA6D9C
1 changed files with 207 additions and 2 deletions

View File

@ -656,6 +656,13 @@ func ProcessRPM(pd *data.ProcessData) (*srpmprocpb.ProcessResponse, error) {
}
pushRefspecs = append(pushRefspecs, config.RefSpec("HEAD:"+plumbing.NewTagReferenceName(newTag)))
fmt.Printf("pushRefspecs == %+v \n", pushRefspecs)
fmt.Println("blah blah blah")
err = repo.Push(&git.PushOptions{
RemoteName: "origin",
@ -679,6 +686,7 @@ func ProcessRPM(pd *data.ProcessData) (*srpmprocpb.ProcessResponse, error) {
// Process for when we want to import a tagless repo (like from CentOS Stream)
//
func processRPMTagless(pd *data.ProcessData) (*srpmprocpb.ProcessResponse, error) {
pd.Log.Println("Tagless mode detected, attempting import of latest commit")
@ -692,16 +700,52 @@ func processRPMTagless(pd *data.ProcessData) (*srpmprocpb.ProcessResponse, error
md.BlobCache = map[string][]byte{}
// TODO: add tagless module support
/*
remotePrefix := "rpms"
if pd.ModuleMode {
remotePrefix = "modules"
}
*/
// already uploaded blobs are skipped
// var alreadyUploadedBlobs []string
// Set up our remote URL for pushing our repo to
var tagIgnoreList []string
if pd.NoDupMode {
repo, err := git.Init(memory.NewStorage(), memfs.New())
if err != nil {
return nil, fmt.Errorf("could not init git repo: %v", err)
}
remoteUrl := fmt.Sprintf("%s/%s/%s.git", pd.UpstreamPrefix, remotePrefix, gitlabify(md.Name))
refspec := config.RefSpec("+refs/heads/*:refs/remotes/origin/*")
remote, err := repo.CreateRemote(&config.RemoteConfig{
Name: "origin",
URLs: []string{remoteUrl},
Fetch: []config.RefSpec{refspec},
})
if err != nil {
return nil, fmt.Errorf("could not create remote: %v", err)
}
list, err := remote.List(&git.ListOptions{
Auth: pd.Authenticator,
})
if err != nil {
log.Println("ignoring no-dup-mode")
} else {
for _, ref := range list {
if !strings.HasPrefix(string(ref.Name()), "refs/tags/imports") {
continue
}
tagIgnoreList = append(tagIgnoreList, string(ref.Name()))
}
}
}
sourceRepo := *md.Repo
sourceWorktree := *md.Worktree
@ -752,12 +796,173 @@ func processRPMTagless(pd *data.ProcessData) (*srpmprocpb.ProcessResponse, error
pd.Log.Println("Successfully determined version of tagless checkout: ", rpmVersion)
md.PushBranch = fmt.Sprintf("%s%d%s", pd.BranchPrefix, pd.Version, pd.BranchSuffix)
// Make an initial repo we will use to push to our target
pushRepo, err := git.PlainInit(localPath + "_gitpush", false)
if err != nil {
return nil, fmt.Errorf("could not create new dist Repo: %v", err)
}
w, err := pushRepo.Worktree()
if err != nil {
return nil, fmt.Errorf("could not get dist Worktree: %v", err)
}
// Create a remote "origin" in our empty git, make the upstream equal to the branch we want to modify
pushUrl := fmt.Sprintf("%s/%s/%s.git", pd.UpstreamPrefix, remotePrefix, gitlabify(md.Name))
refspec := config.RefSpec(fmt.Sprintf("+refs/heads/%s:refs/remotes/origin/%s", md.PushBranch, md.PushBranch))
// Make our remote repo the target one - the one we want to push our update to
pushRepoRemote, err := pushRepo.CreateRemote(&config.RemoteConfig{
Name: "origin",
URLs: []string{pushUrl},
Fetch: []config.RefSpec{refspec},
})
if err != nil {
return nil, fmt.Errorf("could not create remote: %v", err)
}
// fetch our branch data (md.PushBranch) into this new repo
err = pushRepo.Fetch(&git.FetchOptions{
RemoteName: "origin",
RefSpecs: []config.RefSpec{refspec},
Auth: pd.Authenticator,
})
refName := plumbing.NewBranchReferenceName(md.PushBranch)
var hash plumbing.Hash
h := plumbing.NewSymbolicReference(plumbing.HEAD, refName)
if err := pushRepo.Storer.CheckAndSetReference(h, nil); err != nil {
return nil, fmt.Errorf("Could not set symbolic reference: %v", err)
}
err = w.Checkout(&git.CheckoutOptions{
Branch: plumbing.NewRemoteReferenceName("origin", md.PushBranch),
Hash: hash,
Force: true,
})
os.Rename(fmt.Sprintf("%s/SPECS", localPath), fmt.Sprintf("%s_gitpush/SPECS", localPath) )
os.Rename(fmt.Sprintf("%s/SOURCES", localPath), fmt.Sprintf("%s_gitpush/SOURCES", localPath) )
os.Rename(fmt.Sprintf("%s/.gitignore", localPath), fmt.Sprintf("%s_gitpush/.gitignore", localPath) )
os.Rename(fmt.Sprintf("%s/.%s.metadata", localPath, md.Name ), fmt.Sprintf("%s_gitpush/.%s.metadata", localPath, md.Name) )
err = w.AddWithOptions(&git.AddOptions{All: true} )
if err != nil {
fmt.Printf("ERROR == %v \n", err)
return nil, fmt.Errorf("Error adding SOURCES/ , SPECS/ or .metadata file to commit list.")
}
status, err := w.Status()
fmt.Println("Current repo status == ", status)
// assign tag for our new remote we're about to push (derived from the SRPM version)
newTag := "refs/tags/imports/" + md.PushBranch + "/" + rpmVersion
newTag = strings.Replace(newTag, "%", "_", -1)
// pushRefspecs is a list of all the references we want to push (tags + heads)
// It's an array of colon-separated strings which map local references to their remote counterparts
var pushRefspecs []config.RefSpec
// We need to find out if the remote repo already has this branch
// If it doesn't, we want to add *:* to our references for commit. This will allow us to push the new branch
// If it does, we can simply push HEAD:refs/heads/<BRANCH>
newRepo := true
refList, _ := pushRepoRemote.List(&git.ListOptions{Auth: pd.Authenticator,})
for _, ref := range refList {
if strings.HasSuffix(ref.Name().String(), fmt.Sprintf("heads/%s", md.PushBranch)) {
newRepo = false
break
}
}
if newRepo == true {
pushRefspecs = append(pushRefspecs, config.RefSpec("*:*"))
pd.Log.Printf("Looks like a new remote repo, committing all local objects to new remote branch")
}
// Identify specific references we want to push
// Should be refs/heads/<target_branch>, and a tag called imports/<target_branch>/<rpm_nvr>
pushRefspecs = append(pushRefspecs, config.RefSpec(fmt.Sprintf("HEAD:refs/heads/%s", md.PushBranch)) )
pushRefspecs = append(pushRefspecs, config.RefSpec(fmt.Sprintf("HEAD:%s", newTag)) )
// Actually do the commit (locally)
commit, err := w.Commit("import from tagless source "+pd.Importer.ImportName(pd, md), &git.CommitOptions{
Author: &object.Signature{
Name: pd.GitCommitterName,
Email: pd.GitCommitterEmail,
When: time.Now(),
},
})
if err != nil {
return nil, fmt.Errorf("could not commit object: %v", err)
}
obj, err := pushRepo.CommitObject(commit)
if err != nil {
return nil, fmt.Errorf("could not get commit object: %v", err)
}
pd.Log.Printf("Committed local repo tagless mode transform:\n%s", obj.String())
// After commit, we will now tag our local repo on disk:
_, err = pushRepo.CreateTag(newTag, commit, &git.CreateTagOptions{
Tagger: &object.Signature{
Name: pd.GitCommitterName,
Email: pd.GitCommitterEmail,
When: time.Now(),
},
Message: "import " + md.TagBranch + " from " + pd.RpmLocation + "(import from tagless source)",
SignKey: nil,
})
if err != nil {
return nil, fmt.Errorf("could not create tag: %v", err)
}
pd.Log.Printf("Pushing these references to the remote: %+v \n", pushRefspecs)
// Do the actual push to the remote target repository
err = pushRepo.Push(&git.PushOptions{
RemoteName: "origin",
Auth: pd.Authenticator,
RefSpecs: pushRefspecs,
Force: true,
})
if err != nil {
return nil, fmt.Errorf("could not push to remote: %v", err)
}
// Clean up temporary path after succesful import (disabled during development)
/*
if err := os.RemoveAll(localPath); err != nil {
log.Printf("Error cleaning up temporary git checkout directory %s . Non-fatal, continuing anyway...\n", localPath)
}
if err := os.RemoveAll(fmt.Sprintf("%s_gitpush", localPath)); err != nil {
log.Printf("Error cleaning up temporary git checkout directory %s . Non-fatal, continuing anyway...\n", fmt.Sprintf("%s_gitpush", localPath))
}
*/
}