Skip to content

Refactoring #108

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 8 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
86 changes: 44 additions & 42 deletions backup.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,59 +17,61 @@ var appFS = afero.NewOsFs()
var gitCommand = "git"
var gethomeDir = homedir.Dir

func updateExistingClone(repoDir string, bare bool, repo *Repository) ([]byte, error) {
log.Printf("%s exists, updating. \n", repo.Name)
var cmd *exec.Cmd
if bare {
cmd = execCommand(gitCommand, "-C", repoDir, "remote", "update", "--prune")
} else {
cmd = execCommand(gitCommand, "-C", repoDir, "pull")
}
return cmd.CombinedOutput()
}

func newClone(repoDir string, bare bool, repo *Repository, useHTTPSClone *bool) ([]byte, error) {

log.Printf("Cloning %s\n", repo.Name)
log.Printf("%#v\n", repo)

Check failure

Code scanning / CodeQL

Clear-text logging of sensitive information

[Sensitive data returned by an access to bitbucketPassword](1) flows to a logging call.

if repo.Private && ignorePrivate != nil && *ignorePrivate {
log.Printf("Skipping %s as it is a private repo.\n", repo.Name)
return nil, nil
}

if useHTTPSClone != nil && *useHTTPSClone {
// Add username and token to the clone URL
// https://gitlab.com/amitsaha/testproject1 => https://amitsaha:[email protected]/amitsaha/testproject1
u, err := url.Parse(repo.CloneURL)
if err != nil {
log.Fatalf("Invalid clone URL: %v\n", err)
}
repo.CloneURL = u.Scheme + "://" + gitHostUsername + ":" + gitHostToken + "@" + u.Host + u.Path
}

var cmd *exec.Cmd
if bare {
cmd = execCommand(gitCommand, "clone", "--mirror", repo.CloneURL, repoDir)
} else {
cmd = execCommand(gitCommand, "clone", repo.CloneURL, repoDir)
}
return cmd.CombinedOutput()
}

// Check if we have a copy of the repo already, if
// we do, we update the repo, else we do a fresh clone
func backUp(backupDir string, repo *Repository, bare bool, wg *sync.WaitGroup) ([]byte, error) {
defer wg.Done()

var dirName string
dirName := repo.Name
if bare {
dirName = repo.Name + ".git"
} else {
dirName = repo.Name
dirName += ".git"
}
repoDir := path.Join(backupDir, repo.Namespace, dirName)

_, err := appFS.Stat(repoDir)

var stdoutStderr []byte
if err == nil {
log.Printf("%s exists, updating. \n", repo.Name)
var cmd *exec.Cmd
if bare {
cmd = execCommand(gitCommand, "-C", repoDir, "remote", "update", "--prune")
} else {
cmd = execCommand(gitCommand, "-C", repoDir, "pull")
}
stdoutStderr, err = cmd.CombinedOutput()
} else {
log.Printf("Cloning %s\n", repo.Name)
log.Printf("%#v\n", repo)

if repo.Private && ignorePrivate != nil && *ignorePrivate {
log.Printf("Skipping %s as it is a private repo.\n", repo.Name)
return stdoutStderr, nil
}

if useHTTPSClone != nil && *useHTTPSClone {
// Add username and token to the clone URL
// https://gitlab.com/amitsaha/testproject1 => https://amitsaha:[email protected]/amitsaha/testproject1
u, err := url.Parse(repo.CloneURL)
if err != nil {
log.Fatalf("Invalid clone URL: %v\n", err)
}
repo.CloneURL = u.Scheme + "://" + gitHostUsername + ":" + gitHostToken + "@" + u.Host + u.Path
}

var cmd *exec.Cmd
if bare {
cmd = execCommand(gitCommand, "clone", "--mirror", repo.CloneURL, repoDir)
} else {
cmd = execCommand(gitCommand, "clone", repo.CloneURL, repoDir)
}
stdoutStderr, err = cmd.CombinedOutput()
return updateExistingClone(repoDir, bare, repo)
}
return stdoutStderr, err
return newClone(repoDir, bare, repo, useHTTPSClone)
}

func setupBackupDir(backupDir, service, githostURL *string) string {
Expand Down
5 changes: 0 additions & 5 deletions bitbucket.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package main

import (
"log"
"strings"

bitbucket "github.com/ktrysmt/go-bitbucket"
Expand All @@ -14,10 +13,6 @@ func getBitbucketRepositories(
ignoreFork bool,
) ([]*Repository, error) {

if client == nil {
log.Fatalf("Couldn't acquire a client to talk to %s", service)
}

var repositories []*Repository
var cloneURL string

Expand Down
83 changes: 38 additions & 45 deletions client.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ package main

import (
"context"
"errors"
"fmt"
"log"
"net/http"
"net/url"
"os"
Expand All @@ -21,28 +21,28 @@ import (
var keyringServiceName = "gitbackup-cli"
var gitbackupClientID = "7b56a77c7dfba0800524"

func startOAuthFlow() string {
func startOAuthFlow() (*string, error) {
clientID := gitbackupClientID
scopes := []string{"repo", "user", "admin:org"}
httpClient := http.DefaultClient

code, err := device.RequestCode(httpClient, "https://github.com/login/device/code", clientID, scopes)
if err != nil {
panic(err)
return nil, err
}

fmt.Printf("Copy code: %s\n", code.UserCode)
fmt.Printf("then open: %s\n", code.VerificationURI)

accessToken, err := device.PollToken(httpClient, "https://github.com/login/oauth/access_token", clientID, code)
if err != nil {
panic(err)
return nil, err
}

return accessToken.Token
return &accessToken.Token, nil
}

func saveToken(service string, token string) error {
func saveTokenToKeyring(service string, token *string) error {
ring, err := keyring.Open(keyring.Config{
ServiceName: keyringServiceName,
})
Expand All @@ -52,12 +52,12 @@ func saveToken(service string, token string) error {

err = ring.Set(keyring.Item{
Key: service + "_TOKEN",
Data: []byte(token),
Data: []byte(*token),
})
return err
}

func getToken(service string) (string, error) {
func getTokenFromKeyring(service string) (string, error) {
ring, err := keyring.Open(keyring.Config{
ServiceName: keyringServiceName,
})
Expand All @@ -71,34 +71,30 @@ func getToken(service string) (string, error) {
return string(i.Data), nil
}

func newClient(service string, gitHostURL string) interface{} {
var gitHostURLParsed *url.URL
func newClient(c *appConfig) (interface{}, error) {
var err error
var gitHostURLParsed *url.URL

// If a git host URL has been passed in, we assume it's
// a gitlab installation
if len(gitHostURL) != 0 {
gitHostURLParsed, err = url.Parse(gitHostURL)
if c != nil && len(c.gitHostURL) != 0 {
gitHostURLParsed, err = url.Parse(c.gitHostURL)
if err != nil {
log.Fatalf("Invalid gitlab URL: %s", gitHostURL)
return nil, err
}
api, _ := url.Parse("api/v4/")
gitHostURLParsed = gitHostURLParsed.ResolveReference(api)
}

if service == "github" {
switch c.service {
case "github":
githubToken := os.Getenv("GITHUB_TOKEN")
if githubToken == "" {
githubToken, err = getToken("GITHUB")
githubToken, err = getTokenFromKeyring("GITHUB")
if err != nil {
githubToken = startOAuthFlow()
}
if githubToken == "" {
log.Fatal("GitHub token not available")
} else {
err := saveToken("GITHUB", githubToken)
githubToken, err := startOAuthFlow()
if githubToken == nil || err != nil {
return nil, fmt.Errorf("GitHub token not available %w", err)
}
err = saveTokenToKeyring("GITHUB", githubToken)
if err != nil {
log.Fatal("Error saving token")
return nil, fmt.Errorf("Error saving token")
}
}
}
Expand All @@ -111,13 +107,17 @@ func newClient(service string, gitHostURL string) interface{} {
if gitHostURLParsed != nil {
client.BaseURL = gitHostURLParsed
}
return client
}
return client, nil

case "gitlab":

if service == "gitlab" {
if gitHostURLParsed != nil {
api, _ := url.Parse("api/v4/")
gitHostURLParsed = gitHostURLParsed.ResolveReference(api)
}
gitlabToken := os.Getenv("GITLAB_TOKEN")
if gitlabToken == "" {
log.Fatal("GITLAB_TOKEN environment variable not set")
return nil, fmt.Errorf("GITLAB_TOKEN environment variable not set")
}
gitHostToken = gitlabToken

Expand All @@ -127,30 +127,23 @@ func newClient(service string, gitHostURL string) interface{} {
}
client, err := gitlab.NewClient(gitlabToken, baseUrlOption)
if err != nil {
log.Fatalf("Error creating gitlab client: %v", err)
return nil, fmt.Errorf("Error creating gitlab client: %v", err)
}
return client
}
return client, nil

if service == "bitbucket" {
case "bitbucket":
bitbucketUsername := os.Getenv("BITBUCKET_USERNAME")
if bitbucketUsername == "" {
log.Fatal("BITBUCKET_USERNAME environment variable not set")
}

bitbucketPassword := os.Getenv("BITBUCKET_PASSWORD")
if bitbucketPassword == "" {
log.Fatal("BITBUCKET_PASSWORD environment variable not set")
if bitbucketUsername == "" || bitbucketPassword == "" {
return nil, fmt.Errorf("BITBUCKET_USERNAME and BITBUCKET_PASSWORD environment variables must be set")
}

gitHostToken = bitbucketPassword

client := bitbucket.NewBasicAuth(bitbucketUsername, bitbucketPassword)
if gitHostURLParsed != nil {
client.SetApiBaseURL(gitHostURLParsed.String())
}
return client
return client, nil
default:
return nil, errors.New("invalid service")
}

return nil
}
Loading