224 lines
5.8 KiB
Go
224 lines
5.8 KiB
Go
package catalogue
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
"io/ioutil"
|
|
"path"
|
|
|
|
"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"
|
|
"coopcloud.tech/abra/pkg/log"
|
|
"coopcloud.tech/abra/pkg/recipe"
|
|
"github.com/go-git/go-git/v5"
|
|
"github.com/urfave/cli"
|
|
)
|
|
|
|
var catalogueGenerateCommand = cli.Command{
|
|
Name: "generate",
|
|
Aliases: []string{"g"},
|
|
Usage: "Generate the recipe catalogue",
|
|
Flags: []cli.Flag{
|
|
internal.DebugFlag,
|
|
internal.NoInputFlag,
|
|
internal.PublishFlag,
|
|
internal.DryFlag,
|
|
internal.SkipUpdatesFlag,
|
|
internal.ChaosFlag,
|
|
internal.OfflineFlag,
|
|
},
|
|
Before: internal.SubCommandBefore,
|
|
Description: `
|
|
Generate a new copy of the recipe catalogue which can be found on:
|
|
|
|
https://recipes.coopcloud.tech (website that humans read)
|
|
https://recipes.coopcloud.tech/recipes.json (JSON that Abra reads)
|
|
|
|
It polls the entire git.coopcloud.tech/coop-cloud/... recipe repository
|
|
listing, parses README.md and git tags to produce recipe metadata which is
|
|
loaded into the catalogue JSON file.
|
|
|
|
It is possible to generate new metadata for a single recipe by passing
|
|
<recipe>. The existing local catalogue will be updated, not overwritten.
|
|
|
|
It is quite easy to get rate limited by Docker Hub when running this command.
|
|
If you have a Hub account you can have Abra log you in to avoid this. Pass
|
|
"--user" and "--pass".
|
|
|
|
Push your new release to git.coopcloud.tech with "-p/--publish". This requires
|
|
that you have permission to git push to these repositories and have your SSH
|
|
keys configured on your account.
|
|
`,
|
|
ArgsUsage: "[<recipe>]",
|
|
BashComplete: autocomplete.RecipeNameComplete,
|
|
Action: func(c *cli.Context) error {
|
|
recipeName := c.Args().First()
|
|
|
|
if recipeName != "" {
|
|
internal.ValidateRecipe(c)
|
|
}
|
|
|
|
if !internal.Chaos {
|
|
if err := catalogue.EnsureIsClean(); err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
}
|
|
|
|
repos, err := recipe.ReadReposMetadata()
|
|
if err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
|
|
var barLength int
|
|
var logMsg string
|
|
if recipeName != "" {
|
|
barLength = 1
|
|
logMsg = fmt.Sprintf("ensuring %v recipe is cloned & up-to-date", barLength)
|
|
} else {
|
|
barLength = len(repos)
|
|
logMsg = fmt.Sprintf("ensuring %v recipes are cloned & up-to-date, this could take some time...", barLength)
|
|
}
|
|
|
|
if !internal.SkipUpdates {
|
|
log.Warn(logMsg)
|
|
if err := recipe.UpdateRepositories(repos, recipeName); err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
}
|
|
|
|
catl := make(recipe.RecipeCatalogue)
|
|
catlBar := formatter.CreateProgressbar(barLength, "generating catalogue metadata...")
|
|
for _, recipeMeta := range repos {
|
|
if recipeName != "" && recipeName != recipeMeta.Name {
|
|
catlBar.Add(1)
|
|
continue
|
|
}
|
|
|
|
versions, err := recipe.GetRecipeVersions(recipeMeta.Name, internal.Offline)
|
|
if err != nil {
|
|
log.Warn(err)
|
|
}
|
|
|
|
features, category, err := recipe.GetRecipeFeaturesAndCategory(recipeMeta.Name)
|
|
if err != nil {
|
|
log.Warn(err)
|
|
}
|
|
|
|
catl[recipeMeta.Name] = recipe.RecipeMeta{
|
|
Name: recipeMeta.Name,
|
|
Repository: recipeMeta.CloneURL,
|
|
SSHURL: recipeMeta.SSHURL,
|
|
Icon: recipeMeta.AvatarURL,
|
|
DefaultBranch: recipeMeta.DefaultBranch,
|
|
Description: recipeMeta.Description,
|
|
Website: recipeMeta.Website,
|
|
Versions: versions,
|
|
Category: category,
|
|
Features: features,
|
|
}
|
|
|
|
catlBar.Add(1)
|
|
}
|
|
|
|
recipesJSON, err := json.MarshalIndent(catl, "", " ")
|
|
if err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
|
|
if recipeName == "" {
|
|
if err := ioutil.WriteFile(config.RECIPES_JSON, recipesJSON, 0764); err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
} else {
|
|
catlFS, err := recipe.ReadRecipeCatalogue(internal.Offline)
|
|
if err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
|
|
catlFS[recipeName] = catl[recipeName]
|
|
|
|
updatedRecipesJSON, err := json.MarshalIndent(catlFS, "", " ")
|
|
if err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
|
|
if err := ioutil.WriteFile(config.RECIPES_JSON, updatedRecipesJSON, 0764); err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
}
|
|
|
|
log.Infof("generated new recipe catalogue in %s", config.RECIPES_JSON)
|
|
|
|
cataloguePath := path.Join(config.ABRA_DIR, "catalogue")
|
|
if internal.Publish {
|
|
|
|
isClean, err := gitPkg.IsClean(cataloguePath)
|
|
if err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
|
|
if isClean {
|
|
if !internal.Dry {
|
|
log.Fatalf("no changes discovered in %s, nothing to publish?", cataloguePath)
|
|
}
|
|
}
|
|
|
|
msg := "chore: publish new catalogue release changes"
|
|
if err := gitPkg.Commit(cataloguePath, msg, internal.Dry); err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
|
|
repo, err := git.PlainOpen(cataloguePath)
|
|
if err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
|
|
sshURL := fmt.Sprintf(config.SSH_URL_TEMPLATE, config.CATALOGUE_JSON_REPO_NAME)
|
|
if err := gitPkg.CreateRemote(repo, "origin-ssh", sshURL, internal.Dry); err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
|
|
if err := gitPkg.Push(cataloguePath, "origin-ssh", false, internal.Dry); err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
}
|
|
|
|
repo, err := git.PlainOpen(cataloguePath)
|
|
if err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
|
|
head, err := repo.Head()
|
|
if err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
|
|
if !internal.Dry && internal.Publish {
|
|
url := fmt.Sprintf("%s/%s/commit/%s", config.REPOS_BASE_URL, config.CATALOGUE_JSON_REPO_NAME, head.Hash())
|
|
log.Infof("new changes published: %s", url)
|
|
}
|
|
|
|
if internal.Dry {
|
|
log.Info("dry run: no changes published")
|
|
}
|
|
|
|
return nil
|
|
},
|
|
}
|
|
|
|
// CatalogueCommand defines the `abra catalogue` command and sub-commands.
|
|
var CatalogueCommand = cli.Command{
|
|
Name: "catalogue",
|
|
Usage: "Manage the recipe catalogue",
|
|
Aliases: []string{"c"},
|
|
ArgsUsage: "<recipe>",
|
|
Description: "This command helps recipe packagers interact with the recipe catalogue",
|
|
Subcommands: []cli.Command{
|
|
catalogueGenerateCommand,
|
|
},
|
|
}
|