Skip to content

Commit

Permalink
Address review comments
Browse files Browse the repository at this point in the history
  • Loading branch information
walkowif committed Jan 19, 2024
1 parent 065f7f2 commit d9987b4
Show file tree
Hide file tree
Showing 4 changed files with 27 additions and 16 deletions.
12 changes: 9 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,12 @@

[![build](https://github.com/insightsengineering/git-synchronizer/actions/workflows/test.yml/badge.svg)](https://github.com/insightsengineering/git-synchronizer/actions/workflows/test.yml)

`git-synchronizer` allows you to mirror a collection of `git` repositories from one location to another. For each source repository, you can set a destination repository to which the source should be mirrored (see example [configuration file](#configuration-file)).

`git-synchronizer` will:
* push all branches and tags from source to destination repository,
* remove branches and tags from the destination repository which are no longer present in source repository.

## Installing

Simply download the project for your distribution from the [releases](https://github.com/insightsengineering/git-synchronizer/releases) page. `git-synchronizer` is distributed as a single binary file and does not require any additional system requirements.
Expand All @@ -16,7 +22,7 @@ git-synchronizer --help

## Configuration file

If you'd like to set the options in a configuration file, by default `git-synchronizer` checks `~/.git-synchronizer`, `~/.git-synchronizer.yaml` and `~/.git-synchronizer.yml` files.
By default `git-synchronizer` attempts to read `~/.git-synchronizer`, `~/.git-synchronizer.yaml` and `~/.git-synchronizer.yml` configuration files.
If any of these files exist, `git-synchronizer` uses options defined there, unless they are overridden by command line flags.

You can also specify custom path to configuration file with `--config <your-configuration-file>.yml` command line flag.
Expand All @@ -29,12 +35,12 @@ defaults:
source:
auth:
method: token
# Name of environment variable storing the token.
# Name of environment variable storing the Personal Access Token with permissions to read source repositories.
token_name: GITHUB_TOKEN
destination:
auth:
method: token
# Name of environment variable storing the token.
# Name of environment variable storing the Personal Access Token with permissions to push to destination repositories.
token_name: GITLAB_TOKEN

# List of repository pairs to be synchronized.
Expand Down
20 changes: 10 additions & 10 deletions cmd/mirror.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ import (
"time"

git "github.com/go-git/go-git/v5"
"github.com/go-git/go-git/v5/config"
gitconfig "github.com/go-git/go-git/v5/config"
githttp "github.com/go-git/go-git/v5/plumbing/transport/http"
)

Expand Down Expand Up @@ -67,7 +67,7 @@ func ValidateRepositories(repositories []RepositoryPair) {
for _, repo := range repositories {
if stringInSlice(repo.Destination.RepositoryURL, allDestinationRepositories) {
log.Fatal(
"Error: multiple repositories set to be synchronized to the same destination repository: ",
"Multiple repositories set to be synchronized to the same destination repository: ",
repo.Source.RepositoryURL,
)
}
Expand All @@ -78,7 +78,7 @@ func ValidateRepositories(repositories []RepositoryPair) {
destinationProjectName := destinationURL[len(destinationURL)-1]
if sourceProjectName != destinationProjectName {
log.Warn(
"Warning: Source project name (", sourceProjectName,
"Source project name (", sourceProjectName,
") and destination project name (", destinationProjectName, ") differ!",
)
}
Expand Down Expand Up @@ -178,7 +178,7 @@ func GetFetchOptions(refSpec string, sourceAuth Authentication) *git.FetchOption
}
if sourcePat != "" {
gitFetchOptions := &git.FetchOptions{
RefSpecs: []config.RefSpec{config.RefSpec(refSpec)},
RefSpecs: []gitconfig.RefSpec{gitconfig.RefSpec(refSpec)},
Auth: &githttp.BasicAuth{
Username: basicAuthUsername,
Password: sourcePat,
Expand All @@ -187,7 +187,7 @@ func GetFetchOptions(refSpec string, sourceAuth Authentication) *git.FetchOption
return gitFetchOptions
}
gitFetchOptions := &git.FetchOptions{
RefSpecs: []config.RefSpec{config.RefSpec(refSpec)},
RefSpecs: []gitconfig.RefSpec{gitconfig.RefSpec(refSpec)},
}
return gitFetchOptions
}
Expand Down Expand Up @@ -253,7 +253,7 @@ func MirrorRepository(messages chan MirrorStatus, source, destination string, so
cloneDuration := time.Since(cloneStart)
cloneEnd, pushStart := time.Now(), time.Now()

_, err = repository.CreateRemote(&config.RemoteConfig{
_, err = repository.CreateRemote(&gitconfig.RemoteConfig{
Name: "destination",
URLs: []string{destination},
})
Expand All @@ -277,7 +277,7 @@ func MirrorRepository(messages chan MirrorStatus, source, destination string, so
log.Debug("Pushing branch ", branch, " to ", destination)
err = repository.Push(&git.PushOptions{
RemoteName: "destination",
RefSpecs: []config.RefSpec{config.RefSpec("+" + refBranchPrefix + branch + ":" + refBranchPrefix + branch)},
RefSpecs: []gitconfig.RefSpec{gitconfig.RefSpec("+" + refBranchPrefix + branch + ":" + refBranchPrefix + branch)},
Auth: destinationAuth, Force: true, Atomic: true})
ProcessError(err, "pushing branch "+branch+" to ", destination, &allErrors)
}
Expand All @@ -288,7 +288,7 @@ func MirrorRepository(messages chan MirrorStatus, source, destination string, so
log.Info("Removing branch ", branch, " from ", destination)
err = repository.Push(&git.PushOptions{
RemoteName: "destination",
RefSpecs: []config.RefSpec{config.RefSpec(":" + refBranchPrefix + branch)},
RefSpecs: []gitconfig.RefSpec{gitconfig.RefSpec(":" + refBranchPrefix + branch)},
Auth: destinationAuth, Force: true, Atomic: true})
ProcessError(err, "removing branch "+branch+" from ", destination, &allErrors)
}
Expand All @@ -297,7 +297,7 @@ func MirrorRepository(messages chan MirrorStatus, source, destination string, so
log.Info("Pushing all tags from ", source, " to ", destination)
err = repository.Push(&git.PushOptions{
RemoteName: "destination",
RefSpecs: []config.RefSpec{config.RefSpec("+" + refTagPrefix + "*:" + refTagPrefix + "*")},
RefSpecs: []gitconfig.RefSpec{gitconfig.RefSpec("+" + refTagPrefix + "*:" + refTagPrefix + "*")},
Auth: destinationAuth, Force: true, Atomic: true})
ProcessError(err, "pushing all tags to ", destination, &allErrors)

Expand All @@ -307,7 +307,7 @@ func MirrorRepository(messages chan MirrorStatus, source, destination string, so
log.Info("Removing tag ", tag, " from ", destination)
err := repository.Push(&git.PushOptions{
RemoteName: "destination",
RefSpecs: []config.RefSpec{config.RefSpec(":" + refTagPrefix + tag)},
RefSpecs: []gitconfig.RefSpec{gitconfig.RefSpec(":" + refTagPrefix + tag)},
Auth: destinationAuth, Force: true, Atomic: true})
ProcessError(err, "removing tag "+tag+" from ", destination, &allErrors)
}
Expand Down
9 changes: 6 additions & 3 deletions cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import (

var cfgFile string
var logLevel string
var workingDirectory string

type RepositoryPair struct {
Source Repository `mapstructure:"source"`
Expand Down Expand Up @@ -101,9 +102,9 @@ func newRootCommand() {
log.Trace("defaultSettings = ", string(defaultSettingsJSON))

if runtime.GOOS == "windows" {
localTempDirectory = os.Getenv("TMP") + `\tmp\git-synchronizer`
localTempDirectory = os.Getenv("TMP") + workingDirectory
} else {
localTempDirectory = "/tmp/git-synchronizer"
localTempDirectory = workingDirectory
}

SetRepositoryAuth(&inputRepositories, defaultSettings)
Expand All @@ -119,6 +120,8 @@ func newRootCommand() {
"config file (default is $HOME/.git-synchronizer.yaml)")
rootCmd.PersistentFlags().StringVarP(&logLevel, "logLevel", "l", "info",
"Logging level (trace, debug, info, warn, error). ")
rootCmd.PersistentFlags().StringVarP(&workingDirectory, "workingDirectory", "w", "/tmp/git-synchronizer",
"Directory where synchronized repositories will be cloned.")

// Add version command.
rootCmd.AddCommand(extension.NewVersionCobraCmd())
Expand Down Expand Up @@ -168,7 +171,7 @@ func Execute() {

func initializeConfig() {
for _, v := range []string{
"logLevel",
"logLevel", "workingDirectory",
} {
// If the flag has not been set in newRootCommand() and it has been set in initConfig().
// In other words: if it's not been provided in command line, but has been
Expand Down
2 changes: 2 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ module github.com/insightsengineering/git-synchronizer

go 1.21

toolchain go1.21.6

require (
github.com/go-git/go-git/v5 v5.11.0
github.com/jamiealquiza/envy v1.1.0
Expand Down

0 comments on commit d9987b4

Please sign in to comment.