fix: ensure catalogue is clean/up-to-date
continuous-integration/drone/pr Build is failing Details
continuous-integration/drone/push Build is failing Details

Closes coop-cloud/organising#367
This commit is contained in:
decentral1se 2023-01-22 17:52:36 +01:00
parent 834d41ef50
commit 32de2ee5de
Signed by: decentral1se
GPG Key ID: 03789458B3D0C410
5 changed files with 155 additions and 74 deletions

View File

@ -8,6 +8,7 @@ import (
"coopcloud.tech/abra/cli/internal"
"coopcloud.tech/abra/pkg/autocomplete"
"coopcloud.tech/abra/pkg/catalogue"
"coopcloud.tech/abra/pkg/config"
"coopcloud.tech/abra/pkg/formatter"
gitPkg "coopcloud.tech/abra/pkg/git"
@ -97,6 +98,10 @@ keys configured on your account.
internal.ValidateRecipe(c, true)
}
if err := catalogue.EnsureUpToDate(); err != nil {
logrus.Fatal(err)
}
repos, err := recipe.ReadReposMetadata()
if err != nil {
logrus.Fatal(err)

View File

@ -0,0 +1,83 @@
package catalogue
import (
"fmt"
"os"
"path"
"strings"
"coopcloud.tech/abra/pkg/config"
gitPkg "coopcloud.tech/abra/pkg/git"
"github.com/go-git/go-git/v5"
"github.com/sirupsen/logrus"
)
// EnsureCatalogue ensures that the catalogue is cloned locally & present.
func EnsureCatalogue() error {
catalogueDir := path.Join(config.ABRA_DIR, "catalogue")
if _, err := os.Stat(catalogueDir); err != nil && os.IsNotExist(err) {
url := fmt.Sprintf("%s/%s.git", config.REPOS_BASE_URL, config.CATALOGUE_JSON_REPO_NAME)
if err := gitPkg.Clone(catalogueDir, url); err != nil {
return err
}
logrus.Debugf("cloned catalogue repository to %s", catalogueDir)
}
return nil
}
// EnsureUpToDate ensures that the local catalogue has no unstaged changes as
// is up to date. This is useful to run before doing catalogue generation.
func EnsureUpToDate() error {
isClean, err := gitPkg.IsClean(config.CATALOGUE_DIR)
if err != nil {
return err
}
if !isClean {
msg := "%s has locally unstaged changes? please commit/remove your changes before proceeding"
return fmt.Errorf(msg, config.CATALOGUE_DIR)
}
repo, err := git.PlainOpen(config.CATALOGUE_DIR)
if err != nil {
return err
}
remotes, err := repo.Remotes()
if err != nil {
return err
}
if len(remotes) == 0 {
msg := "cannot ensure %s is up-to-date, no git remotes configured"
logrus.Debugf(msg, config.CATALOGUE_DIR)
return nil
}
worktree, err := repo.Worktree()
if err != nil {
return err
}
branch, err := gitPkg.CheckoutDefaultBranch(repo, config.CATALOGUE_DIR)
if err != nil {
return err
}
opts := &git.PullOptions{
Force: true,
ReferenceName: branch,
}
if err := worktree.Pull(opts); err != nil {
if !strings.Contains(err.Error(), "already up-to-date") {
return err
}
}
logrus.Debugf("fetched latest git changes for %s", config.CATALOGUE_DIR)
return nil
}

View File

@ -19,6 +19,7 @@ var SERVERS_DIR = path.Join(ABRA_DIR, "servers")
var RECIPES_DIR = path.Join(ABRA_DIR, "recipes")
var VENDOR_DIR = path.Join(ABRA_DIR, "vendor")
var BACKUP_DIR = path.Join(ABRA_DIR, "backups")
var CATALOGUE_DIR = path.Join(ABRA_DIR, "catalogue")
var RECIPES_JSON = path.Join(ABRA_DIR, "catalogue", "recipes.json")
var REPOS_BASE_URL = "https://git.coopcloud.tech/coop-cloud"
var CATALOGUE_JSON_REPO_NAME = "recipes-catalogue-json"

View File

@ -1,14 +1,16 @@
package git
import (
"fmt"
"github.com/go-git/go-git/v5"
"github.com/go-git/go-git/v5/plumbing"
"github.com/sirupsen/logrus"
)
// Check if a branch exists in a repo.
// Use this and not repository.Branch(), because the latter does not
// actually check for existing branches.
// See https://github.com/go-git/go-git/issues/518
// Check if a branch exists in a repo. Use this and not repository.Branch(),
// because the latter does not actually check for existing branches. See
// https://github.com/go-git/go-git/issues/518 for more.
func HasBranch(repository *git.Repository, name string) bool {
var exist bool
if iter, err := repository.Branches(); err == nil {
@ -24,7 +26,7 @@ func HasBranch(repository *git.Repository, name string) bool {
return exist
}
// GetCurrentBranch retrieves the current branch of a repository
// GetCurrentBranch retrieves the current branch of a repository.
func GetCurrentBranch(repository *git.Repository) (string, error) {
branchRefs, err := repository.Branches()
if err != nil {
@ -52,3 +54,45 @@ func GetCurrentBranch(repository *git.Repository) (string, error) {
return currentBranchName, nil
}
// GetDefaultBranch retrieves the default branch of a repository.
func GetDefaultBranch(repo *git.Repository, repoPath string) (plumbing.ReferenceName, error) {
branch := "master"
if !HasBranch(repo, "master") {
if !HasBranch(repo, "main") {
return "", fmt.Errorf("failed to select default branch in %s", repoPath)
}
branch = "main"
}
return plumbing.ReferenceName(fmt.Sprintf("refs/heads/%s", branch)), nil
}
// CheckoutDefaultBranch checks out the default branch of a repository.
func CheckoutDefaultBranch(repo *git.Repository, repoPath string) (plumbing.ReferenceName, error) {
branch, err := GetDefaultBranch(repo, repoPath)
if err != nil {
return plumbing.ReferenceName(""), err
}
worktree, err := repo.Worktree()
if err != nil {
return plumbing.ReferenceName(""), err
}
checkOutOpts := &git.CheckoutOptions{
Create: false,
Force: true,
Branch: branch,
}
if err := worktree.Checkout(checkOutOpts); err != nil {
logrus.Debugf("failed to check out %s in %s", branch, repoPath)
return branch, err
}
logrus.Debugf("successfully checked out %v in %s", branch, repoPath)
return branch, nil
}

View File

@ -12,6 +12,7 @@ import (
"strings"
"time"
"coopcloud.tech/abra/pkg/catalogue"
"coopcloud.tech/abra/pkg/compose"
"coopcloud.tech/abra/pkg/config"
"coopcloud.tech/abra/pkg/formatter"
@ -359,11 +360,21 @@ func EnsureLatest(recipeName string) error {
return err
}
branch, err := GetDefaultBranch(repo, recipeName)
meta, err := GetRecipeMeta(recipeName)
if err != nil {
return err
}
var branch plumbing.ReferenceName
if meta.DefaultBranch != "" {
branch = plumbing.ReferenceName(fmt.Sprintf("refs/heads/%s", meta.DefaultBranch))
} else {
branch, err = gitPkg.GetDefaultBranch(repo, recipeDir)
if err != nil {
return err
}
}
checkOutOpts := &git.CheckoutOptions{
Create: false,
Force: true,
@ -575,7 +586,8 @@ func EnsureUpToDate(recipeName string) error {
}
if !isClean {
return fmt.Errorf("%s (%s) has locally unstaged changes? please commit/remove your changes before proceeding", recipeName, recipeDir)
msg := "%s (%s) has locally unstaged changes? please commit/remove your changes before proceeding"
return fmt.Errorf(msg, recipeName, recipeDir)
}
repo, err := git.PlainOpen(recipeDir)
@ -598,7 +610,7 @@ func EnsureUpToDate(recipeName string) error {
return err
}
branch, err := CheckoutDefaultBranch(repo, recipeName)
branch, err := gitPkg.CheckoutDefaultBranch(repo, recipeDir)
if err != nil {
return err
}
@ -619,55 +631,6 @@ func EnsureUpToDate(recipeName string) error {
return nil
}
func GetDefaultBranch(repo *git.Repository, recipeName string) (plumbing.ReferenceName, error) {
recipeDir := path.Join(config.RECIPES_DIR, recipeName)
meta, _ := GetRecipeMeta(recipeName)
if meta.DefaultBranch != "" {
return plumbing.ReferenceName(fmt.Sprintf("refs/heads/%s", meta.DefaultBranch)), nil
}
branch := "master"
if !gitPkg.HasBranch(repo, "master") {
if !gitPkg.HasBranch(repo, "main") {
return "", fmt.Errorf("failed to select default branch in %s", recipeDir)
}
branch = "main"
}
return plumbing.ReferenceName(fmt.Sprintf("refs/heads/%s", branch)), nil
}
func CheckoutDefaultBranch(repo *git.Repository, recipeName string) (plumbing.ReferenceName, error) {
recipeDir := path.Join(config.RECIPES_DIR, recipeName)
branch, err := GetDefaultBranch(repo, recipeName)
if err != nil {
return plumbing.ReferenceName(""), err
}
worktree, err := repo.Worktree()
if err != nil {
return plumbing.ReferenceName(""), err
}
checkOutOpts := &git.CheckoutOptions{
Create: false,
Force: true,
Branch: branch,
}
if err := worktree.Checkout(checkOutOpts); err != nil {
recipeDir := path.Join(config.RECIPES_DIR, recipeName)
logrus.Debugf("failed to check out %s in %s", branch, recipeDir)
return branch, err
}
logrus.Debugf("successfully checked out %v in %s", branch, recipeDir)
return branch, nil
}
type CatalogueOfflineError struct {
msg string
}
@ -717,7 +680,7 @@ func recipeCatalogueFSIsLatest() (bool, error) {
func ReadRecipeCatalogue() (RecipeCatalogue, error) {
recipes := make(RecipeCatalogue)
if err := EnsureCatalogue(); err != nil {
if err := catalogue.EnsureCatalogue(); err != nil {
return nil, err
}
@ -1024,7 +987,7 @@ func GetRecipeVersions(recipeName string) (RecipeVersions, error) {
return versions, err
}
_, err = CheckoutDefaultBranch(repo, recipeName)
_, err = gitPkg.CheckoutDefaultBranch(repo, recipeDir)
if err != nil {
return versions, err
}
@ -1048,18 +1011,3 @@ func GetRecipeCatalogueVersions(recipeName string, catl RecipeCatalogue) ([]stri
return versions, nil
}
// EnsureCatalogue ensures that the catalogue is cloned locally & present.
func EnsureCatalogue() error {
catalogueDir := path.Join(config.ABRA_DIR, "catalogue")
if _, err := os.Stat(catalogueDir); err != nil && os.IsNotExist(err) {
url := fmt.Sprintf("%s/%s.git", config.REPOS_BASE_URL, config.CATALOGUE_JSON_REPO_NAME)
if err := gitPkg.Clone(catalogueDir, url); err != nil {
return err
}
logrus.Debugf("cloned catalogue repository to %s", catalogueDir)
}
return nil
}