forked from coop-cloud/abra
fix: ensure catalogue is clean/up-to-date
Closes coop-cloud/organising#367
This commit is contained in:
parent
834d41ef50
commit
32de2ee5de
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
}
|
|
@ -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"
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue