Push equivalent to clone mirror? #927

Open
opened 2022-08-29 02:44:24 -05:00 by Marakai · 1 comment
Marakai commented 2022-08-29 02:44:24 -05:00 (Migrated from github.com)

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).

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).
Marakai commented 2022-08-30 01:24:35 -05:00 (Migrated from github.com)

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
}
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 in to join this conversation.
No Milestone
No project
No Assignees
1 Participants
Notifications
Due Date
The due date is invalid or out of range. Please use the format 'yyyy-mm-dd'.

No due date set.

Dependencies

No dependencies set.

Reference: jcarr/git2go#927
No description provided.