custom-targets/git-ops/git-deployer/git.go (73 lines of code) (raw):
// Copyright 2023 Google LLC
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// https://www.apache.org/licenses/LICENSE-2.0
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package main
import (
"fmt"
)
const (
gitBin = "git"
remote = "origin"
)
// gitRepository holds the repository values for git commands.
type gitRepository struct {
dir string
hostname string
owner string
repoName string
email string
username string
}
// newGitRepository returns a gitRepository to interact with a repository.
func newGitRepository(hostname, owner, repoName, email, username string) *gitRepository {
return &gitRepository{
hostname: hostname,
owner: owner,
repoName: repoName,
email: email,
username: username,
}
}
// cloneRepo clones a Git repository to the local filesystem.
func (g *gitRepository) cloneRepo(secret string) ([]byte, error) {
args := []string{"clone", fmt.Sprintf("https://%s:%s@%s/%s/%s.git", g.owner, secret, g.hostname, g.owner, g.repoName)}
g.dir = g.repoName
return runCmd(gitBin, args, "", false)
}
// config sets up the git config with a username and email in the Git repository.
func (g *gitRepository) config() error {
uArgs := []string{"config", "user.name", fmt.Sprintf("%q", g.username)}
if _, err := runCmd(gitBin, uArgs, g.dir, true); err != nil {
return err
}
// We need to set some value for the email otherwise run into errors when writing commits.
email := g.email
if len(email) == 0 {
email = "<>"
}
eArgs := []string{"config", "user.email", email}
if _, err := runCmd(gitBin, eArgs, g.dir, true); err != nil {
return err
}
return nil
}
// checkoutBranch checkouts and resets an existing branch or creates a new one.
func (g *gitRepository) checkoutBranch(branch string) ([]byte, error) {
args := []string{"checkout", "-B", branch}
return runCmd(gitBin, args, g.dir, true)
}
// add adds all the files in the working tree to the index.
func (g *gitRepository) add() ([]byte, error) {
args := []string{"add", "."}
return runCmd(gitBin, args, g.dir, true)
}
// detectDiff gets the working tree status and uses the porcelain command to simplify scripting.
func (g *gitRepository) detectDiff() ([]byte, error) {
args := []string{"status", "--porcelain"}
return runCmd(gitBin, args, g.dir, true)
}
// commit commits the changes in the index to the repository with the provided message.
func (g *gitRepository) commit(msg string) ([]byte, error) {
args := []string{"commit", "-a", "-m", msg}
return runCmd(gitBin, args, g.dir, true)
}
// push pushes the changes a remote branch.
func (g *gitRepository) push(branch string) ([]byte, error) {
args := []string{"push", remote, branch}
return runCmd(gitBin, args, g.dir, true)
}
// checkIfExists checks if a branch exists on the remote.
func (g *gitRepository) checkIfExists(branch string) ([]byte, error) {
args := []string{"ls-remote", "--heads", remote, fmt.Sprintf("refs/heads/%s", branch)}
return runCmd(gitBin, args, g.dir, true)
}
// pull pulls changes from a remote branch.
func (g *gitRepository) pull(branch string) ([]byte, error) {
args := []string{"pull", remote, branch}
return runCmd(gitBin, args, g.dir, true)
}