Skip to content

Push equivalent to clone mirror? #927

Open

Description

@Marakai

Despite looking at the godocs, the tests and the source, I can't seem to figure out the correction PushOptions for the opposite of a mirror clone, i.e. push with the mirror options. Ideally, for my special use case with force.

I'm trying to clone from one server and push to another, using the mirror option. So, I:

  • mirror clone with a code example I found here in Issues
  • create a new remote pointing to the other server (the repo was already created separately)
  • ??? what pushoptions for mirror ???
  • push to the new repo on other server

This is using https, not ssh, if it matters.

On that notice, more examples would be very nice (looking at unit tests isn't quite the sames thing).

Activity

  1. Marakai commented on Aug 30, 2022

    @Marakai
    Author

    At this time, my somewhat naive first implementation, after poring through the source looks like this. However there are a number of issues that I've listed with inline comments.

    Note: this is built on MacOS. libgit2, libssh2 and openssl are installed via Homebrew. SSL certificates and CA are all installed as part of the corporate build. HTTPS pushes into Git are authenticated via access token.

    package migrate
    
    import (
    	"XXXXXX.ghe.com/gh-platform/gh-management-services/service/api"
    	gitwrap "XXXXXXX.ghe.com/gh-platform/gh-management-services/service/utils/git"
    	"context"
    	"errors"
    	libgit "github.com/libgit2/git2go/v33"
    )
    
    const GHAE = "XXXXXXX.ghe.com"
    
    func MirrorPush(ctx context.Context, github api.Github, org string, repoSlug string, repo *libgit.Repository) error {
    	if ghUrl, err := github.GetRepoUrl(org, repoSlug); err != nil {
    		return err
    	} else {
    		rcb := libgit.RemoteCallbacks{
    // This will not be called if I inject the token directly below. However, when called
    // I don't get a valid Credential and receive an error 
    // "could not find appropriate mechanism for credentials" 
    // when Push() is called below.
    			CredentialsCallback: func(url, username string, allowedTypes libgit.CredentialType) (*libgit.Credential, error) {
    				c, err := libgit.NewCredentialUsername(github.Token())
    				if err != nil {
    					return nil, err
    				}
    				return c, nil
    			},
    			CertificateCheckCallback: func(cert *libgit.Certificate, valid bool, hostname string) error {
    				if hostname != GHAE {
    					return errors.New("hostname does not match")
    				}
    				return nil
    			},
    		}
    		proxyopt := libgit.ProxyOptions{
    			Type: libgit.ProxyTypeAuto,
    			// Url: utils.GetProxyUrl(),
    		}
    		pushopts := libgit.PushOptions{
    			RemoteCallbacks: rcb,
    			PbParallelism:   0,
    			Headers:         nil,
    			ProxyOptions:    proxyopt,
    		}
    
    		logger.Notice(ctx, "starting push of %s into %s", repoSlug, ghUrl)
    		remote, err := repo.Remotes.CreateWithFetchspec("ghorigin", ghUrl, "+refs/*:refs/*")
    		if err != nil {
    			return err
    		}
    // A helper method to inject the access token during debugging and testing
    // It retrieves the token from a secure store
    // When injecting the token into the URL, the connection succeeds, but this is highly
    // undesirable due to risk of exposure
    		ghUrl = gitwrap.InjectToken(ghUrl, github.Token())
    
    		cfg, err := repo.Config()
    		if err != nil {
    			return err
    		}
    
    		if err = cfg.SetBool("remote.ghorigin.mirror", true); err != nil {
    			return err
    		}
    
    // When using the injected URL and able to connect, this call returns without error
    // But does NOT actually push anything!
    		if err = remote.Push(nil, &pushopts); err != nil {
    			return err
    		}
    		logger.Notice(ctx, "finished mirror-push of %s into %s", repoSlug, repo.Path())
    	}
    	return nil
    }
    
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions