forked from toolshed/abra
Compare commits
19 Commits
0.1.8-alph
...
0.2.0-alph
Author | SHA1 | Date | |
---|---|---|---|
75fb9a2774 | |||
0d500b636d | |||
5dd97cace0 | |||
ae32b1eed2 | |||
113bdf9e86 | |||
d4d4da19b7 | |||
454ee696d6 | |||
ca16c002ba | |||
91cc8b00b3 | |||
d0828c4d8d | |||
b69aed3bcf | |||
875255fd8c | |||
2dca602c0b | |||
1dca8a1067 | |||
37022bf0c8 | |||
eb5b35d47f
|
|||
ece1130797
|
|||
c266316f7e
|
|||
d804276cf2 |
@ -19,6 +19,7 @@ to scaling apps up and spinning them down.
|
||||
appNewCommand,
|
||||
appConfigCommand,
|
||||
appDeployCommand,
|
||||
appUpgradeCommand,
|
||||
appUndeployCommand,
|
||||
appBackupCommand,
|
||||
appRestoreCommand,
|
||||
|
@ -2,11 +2,16 @@ package app
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
abraFormatter "coopcloud.tech/abra/cli/formatter"
|
||||
"coopcloud.tech/abra/cli/internal"
|
||||
"coopcloud.tech/abra/pkg/catalogue"
|
||||
"coopcloud.tech/abra/pkg/client"
|
||||
stack "coopcloud.tech/abra/pkg/client/stack"
|
||||
"coopcloud.tech/abra/pkg/config"
|
||||
"coopcloud.tech/abra/pkg/recipe"
|
||||
"github.com/AlecAivazis/survey/v2"
|
||||
"github.com/sirupsen/logrus"
|
||||
"github.com/urfave/cli/v2"
|
||||
)
|
||||
@ -15,14 +20,63 @@ var appDeployCommand = &cli.Command{
|
||||
Name: "deploy",
|
||||
Aliases: []string{"d"},
|
||||
Usage: "Deploy an app",
|
||||
Flags: []cli.Flag{
|
||||
internal.ForceFlag,
|
||||
},
|
||||
Description: `
|
||||
This command deploys a new instance of an app. It does not support changing the
|
||||
version of an existing deployed app, for this you need to look at the "abra app
|
||||
upgrade <app>" command.
|
||||
|
||||
You may pass "--force" to re-deploy the same version again. This can be useful
|
||||
if the container runtime has gotten into a weird state or your doing some live
|
||||
hacking.
|
||||
`,
|
||||
Action: func(c *cli.Context) error {
|
||||
app := internal.ValidateApp(c)
|
||||
stackName := app.StackName()
|
||||
|
||||
cl, err := client.New(app.Server)
|
||||
if err != nil {
|
||||
logrus.Fatal(err)
|
||||
}
|
||||
|
||||
logrus.Debugf("checking whether '%s' is already deployed", stackName)
|
||||
|
||||
isDeployed, deployedVersion, err := stack.IsDeployed(c.Context, cl, stackName)
|
||||
if err != nil {
|
||||
logrus.Fatal(err)
|
||||
}
|
||||
|
||||
if isDeployed {
|
||||
if internal.Force {
|
||||
logrus.Infof("continuing with deployment due to '--force/-f' being set")
|
||||
} else {
|
||||
logrus.Fatalf("'%s' is already deployed", stackName)
|
||||
}
|
||||
}
|
||||
|
||||
version := deployedVersion
|
||||
if version == "" {
|
||||
versions, err := catalogue.GetRecipeCatalogueVersions(app.Type)
|
||||
if err != nil {
|
||||
logrus.Fatal(err)
|
||||
}
|
||||
if len(versions) > 0 {
|
||||
version = versions[len(versions)-1]
|
||||
logrus.Infof("choosing '%s' as version to deploy", version)
|
||||
if err := recipe.EnsureVersion(app.Type, version); err != nil {
|
||||
logrus.Fatal(err)
|
||||
}
|
||||
} else {
|
||||
version = "latest commit"
|
||||
logrus.Warning("no versions detected, using latest commit")
|
||||
if err := recipe.EnsureLatest(app.Type); err != nil {
|
||||
logrus.Fatal(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
abraShPath := fmt.Sprintf("%s/%s/%s", config.APPS_DIR, app.Type, "abra.sh")
|
||||
abraShEnv, err := config.ReadAbraShEnvVars(abraShPath)
|
||||
if err != nil {
|
||||
@ -38,7 +92,7 @@ var appDeployCommand = &cli.Command{
|
||||
}
|
||||
deployOpts := stack.Deploy{
|
||||
Composefiles: composeFiles,
|
||||
Namespace: app.StackName(),
|
||||
Namespace: stackName,
|
||||
Prune: false,
|
||||
ResolveImage: stack.ResolveImageAlways,
|
||||
}
|
||||
@ -47,6 +101,10 @@ var appDeployCommand = &cli.Command{
|
||||
logrus.Fatal(err)
|
||||
}
|
||||
|
||||
if err := DeployOverview(app, version); err != nil {
|
||||
logrus.Fatal(err)
|
||||
}
|
||||
|
||||
if err := stack.RunDeploy(cl, deployOpts, compose); err != nil {
|
||||
logrus.Fatal(err)
|
||||
}
|
||||
@ -66,3 +124,61 @@ var appDeployCommand = &cli.Command{
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
// DeployOverview shows a deployment overview
|
||||
func DeployOverview(app config.App, version string) error {
|
||||
tableCol := []string{"server", "compose", "domain", "stack", "version"}
|
||||
table := abraFormatter.CreateTable(tableCol)
|
||||
|
||||
deployConfig := "compose.yml"
|
||||
if composeFiles, ok := app.Env["COMPOSE_FILE"]; ok {
|
||||
deployConfig = strings.Join(strings.Split(composeFiles, ":"), "\n")
|
||||
}
|
||||
|
||||
table.Append([]string{app.Server, deployConfig, app.Domain, app.StackName(), version})
|
||||
table.Render()
|
||||
|
||||
response := false
|
||||
prompt := &survey.Confirm{
|
||||
Message: "continue with deployment?",
|
||||
}
|
||||
|
||||
if err := survey.AskOne(prompt, &response); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if !response {
|
||||
logrus.Fatal("exiting as requested")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// NewVersionOverview shows an upgrade or downgrade overview
|
||||
func NewVersionOverview(app config.App, currentVersion, newVersion string) error {
|
||||
tableCol := []string{"server", "compose", "domain", "stack", "current version", "to be deployed"}
|
||||
table := abraFormatter.CreateTable(tableCol)
|
||||
|
||||
deployConfig := "compose.yml"
|
||||
if composeFiles, ok := app.Env["COMPOSE_FILE"]; ok {
|
||||
deployConfig = strings.Join(strings.Split(composeFiles, ":"), "\n")
|
||||
}
|
||||
|
||||
table.Append([]string{app.Server, deployConfig, app.Domain, app.StackName(), currentVersion, newVersion})
|
||||
table.Render()
|
||||
|
||||
response := false
|
||||
prompt := &survey.Confirm{
|
||||
Message: "continue with deployment?",
|
||||
}
|
||||
|
||||
if err := survey.AskOne(prompt, &response); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if !response {
|
||||
logrus.Fatal("exiting as requested")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
package app
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
@ -81,6 +82,13 @@ can take some time.
|
||||
table := abraFormatter.CreateTable(tableCol)
|
||||
table.SetAutoMergeCellsByColumnIndex([]int{0})
|
||||
|
||||
var (
|
||||
versionedAppsCount int
|
||||
unversionedAppsCount int
|
||||
onLatestCount int
|
||||
canUpgradeCount int
|
||||
)
|
||||
|
||||
for _, app := range apps {
|
||||
var tableRow []string
|
||||
if app.Type == appType || appType == "" {
|
||||
@ -98,8 +106,10 @@ can take some time.
|
||||
status = statusMeta["status"]
|
||||
}
|
||||
tableRow = append(tableRow, status, version)
|
||||
versionedAppsCount++
|
||||
} else {
|
||||
tableRow = append(tableRow, status, version)
|
||||
unversionedAppsCount++
|
||||
}
|
||||
|
||||
var newUpdates []string
|
||||
@ -131,6 +141,7 @@ can take some time.
|
||||
tableRow = append(tableRow, "unknown")
|
||||
} else {
|
||||
tableRow = append(tableRow, "on latest")
|
||||
onLatestCount++
|
||||
}
|
||||
} else {
|
||||
// FIXME: jeezus golang why do you not have a list reverse function
|
||||
@ -138,12 +149,23 @@ can take some time.
|
||||
newUpdates[i], newUpdates[j] = newUpdates[j], newUpdates[i]
|
||||
}
|
||||
tableRow = append(tableRow, strings.Join(newUpdates, "\n"))
|
||||
canUpgradeCount++
|
||||
}
|
||||
}
|
||||
}
|
||||
table.Append(tableRow)
|
||||
}
|
||||
|
||||
stats := fmt.Sprintf(
|
||||
"Total apps: %v | Versioned: %v | Unversioned: %v | On latest: %v | Can upgrade: %v",
|
||||
len(apps),
|
||||
versionedAppsCount,
|
||||
unversionedAppsCount,
|
||||
onLatestCount,
|
||||
canUpgradeCount,
|
||||
)
|
||||
|
||||
table.SetCaption(true, stats)
|
||||
table.Render()
|
||||
|
||||
return nil
|
||||
|
@ -3,6 +3,7 @@ package app
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
abraFormatter "coopcloud.tech/abra/cli/formatter"
|
||||
"coopcloud.tech/abra/cli/internal"
|
||||
@ -15,11 +16,50 @@ import (
|
||||
"github.com/urfave/cli/v2"
|
||||
)
|
||||
|
||||
var watch bool
|
||||
var watchFlag = &cli.BoolFlag{
|
||||
Name: "watch",
|
||||
Aliases: []string{"w"},
|
||||
Value: false,
|
||||
Usage: "Watch status by polling repeatedly",
|
||||
Destination: &watch,
|
||||
}
|
||||
|
||||
var appPsCommand = &cli.Command{
|
||||
Name: "ps",
|
||||
Usage: "Check app status",
|
||||
Aliases: []string{"p"},
|
||||
Flags: []cli.Flag{
|
||||
watchFlag,
|
||||
},
|
||||
Action: func(c *cli.Context) error {
|
||||
if !watch {
|
||||
showPSOutput(c)
|
||||
return nil
|
||||
}
|
||||
|
||||
// TODO: how do we make this update in-place in an x-platform way?
|
||||
for {
|
||||
showPSOutput(c)
|
||||
time.Sleep(2 * time.Second)
|
||||
}
|
||||
},
|
||||
BashComplete: func(c *cli.Context) {
|
||||
appNames, err := config.GetAppNames()
|
||||
if err != nil {
|
||||
logrus.Warn(err)
|
||||
}
|
||||
if c.NArg() > 0 {
|
||||
return
|
||||
}
|
||||
for _, a := range appNames {
|
||||
fmt.Println(a)
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
// showPSOutput renders ps output.
|
||||
func showPSOutput(c *cli.Context) {
|
||||
app := internal.ValidateApp(c)
|
||||
|
||||
cl, err := client.New(app.Server)
|
||||
@ -35,35 +75,25 @@ var appPsCommand = &cli.Command{
|
||||
logrus.Fatal(err)
|
||||
}
|
||||
|
||||
tableCol := []string{"id", "image", "command", "created", "status", "ports", "names"}
|
||||
tableCol := []string{"image", "created", "status", "ports", "names"}
|
||||
table := abraFormatter.CreateTable(tableCol)
|
||||
|
||||
for _, container := range containers {
|
||||
var containerNames []string
|
||||
for _, containerName := range container.Names {
|
||||
trimmed := strings.TrimPrefix(containerName, "/")
|
||||
containerNames = append(containerNames, trimmed)
|
||||
}
|
||||
|
||||
tableRow := []string{
|
||||
abraFormatter.ShortenID(container.ID),
|
||||
abraFormatter.RemoveSha(container.Image),
|
||||
abraFormatter.Truncate(container.Command),
|
||||
abraFormatter.HumanDuration(container.Created),
|
||||
container.Status,
|
||||
formatter.DisplayablePorts(container.Ports),
|
||||
strings.Join(container.Names, ", "),
|
||||
strings.Join(containerNames, "\n"),
|
||||
}
|
||||
table.Append(tableRow)
|
||||
}
|
||||
|
||||
table.Render()
|
||||
return nil
|
||||
},
|
||||
BashComplete: func(c *cli.Context) {
|
||||
appNames, err := config.GetAppNames()
|
||||
if err != nil {
|
||||
logrus.Warn(err)
|
||||
}
|
||||
if c.NArg() > 0 {
|
||||
return
|
||||
}
|
||||
for _, a := range appNames {
|
||||
fmt.Println(a)
|
||||
}
|
||||
},
|
||||
}
|
||||
|
@ -3,14 +3,15 @@ package app
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"context"
|
||||
|
||||
"coopcloud.tech/abra/pkg/catalogue"
|
||||
stack "coopcloud.tech/abra/pkg/client/stack"
|
||||
"coopcloud.tech/abra/pkg/config"
|
||||
"coopcloud.tech/abra/pkg/recipe"
|
||||
"coopcloud.tech/tagcmp"
|
||||
|
||||
"coopcloud.tech/abra/cli/internal"
|
||||
appPkg "coopcloud.tech/abra/pkg/app"
|
||||
"coopcloud.tech/abra/pkg/catalogue"
|
||||
"coopcloud.tech/abra/pkg/client"
|
||||
"github.com/AlecAivazis/survey/v2"
|
||||
"github.com/sirupsen/logrus"
|
||||
"github.com/urfave/cli/v2"
|
||||
)
|
||||
@ -18,8 +19,21 @@ import (
|
||||
var appRollbackCommand = &cli.Command{
|
||||
Name: "rollback",
|
||||
Usage: "Roll an app back to a previous version",
|
||||
Aliases: []string{"r"},
|
||||
ArgsUsage: "[<version>]",
|
||||
Aliases: []string{"r", "downgrade"},
|
||||
ArgsUsage: "<app>",
|
||||
Flags: []cli.Flag{
|
||||
internal.ForceFlag,
|
||||
},
|
||||
Description: `
|
||||
This command rolls an app back to a previous version if one exists.
|
||||
|
||||
You may pass "--force/-f" to downgrade to the same version again. This can be
|
||||
useful if the container runtime has gotten into a weird state or your doing
|
||||
some live hacking.
|
||||
|
||||
This action could be destructive, please ensure you have a copy of your app
|
||||
data beforehand - see "abra app backup <app>" for more.
|
||||
`,
|
||||
BashComplete: func(c *cli.Context) {
|
||||
appNames, err := config.GetAppNames()
|
||||
if err != nil {
|
||||
@ -34,48 +48,110 @@ var appRollbackCommand = &cli.Command{
|
||||
},
|
||||
Action: func(c *cli.Context) error {
|
||||
app := internal.ValidateApp(c)
|
||||
stackName := app.StackName()
|
||||
|
||||
ctx := context.Background()
|
||||
cl, err := client.New(app.Server)
|
||||
if err != nil {
|
||||
logrus.Fatal(err)
|
||||
}
|
||||
|
||||
recipeMeta, err := catalogue.GetRecipeMeta(app.Type)
|
||||
logrus.Debugf("checking whether '%s' is already deployed", stackName)
|
||||
|
||||
isDeployed, deployedVersion, err := stack.IsDeployed(c.Context, cl, stackName)
|
||||
if err != nil {
|
||||
logrus.Fatal(err)
|
||||
}
|
||||
if len(recipeMeta.Versions) == 0 {
|
||||
logrus.Fatalf("no catalogue versions available for '%s'", app.Type)
|
||||
}
|
||||
|
||||
deployedVersions, isDeployed, err := appPkg.DeployedVersions(ctx, cl, app)
|
||||
if err != nil {
|
||||
logrus.Fatal(err)
|
||||
if deployedVersion == "" {
|
||||
logrus.Fatalf("failed to determine version of deployed '%s'", app.Name)
|
||||
}
|
||||
|
||||
if !isDeployed {
|
||||
logrus.Fatalf("'%s' is not deployed?", app.Name)
|
||||
}
|
||||
if _, exists := deployedVersions["app"]; !exists {
|
||||
logrus.Fatalf("no versioned 'app' service for '%s', cannot determine version", app.Name)
|
||||
|
||||
versions, err := catalogue.GetRecipeCatalogueVersions(app.Type)
|
||||
if err != nil {
|
||||
logrus.Fatal(err)
|
||||
}
|
||||
|
||||
version := c.Args().Get(1)
|
||||
if version == "" {
|
||||
// TODO:
|
||||
// using deployedVersions["app"], get index+1 version from catalogue
|
||||
// otherwise bail out saying there is nothing to rollback to
|
||||
} else {
|
||||
// TODO
|
||||
// ensure this version is listed in the catalogue
|
||||
// ensure this version is "older" (lower down in the list)
|
||||
var availableDowngrades []string
|
||||
for _, version := range versions {
|
||||
parsedDeployedVersion, err := tagcmp.Parse(deployedVersion)
|
||||
if err != nil {
|
||||
logrus.Fatal(err)
|
||||
}
|
||||
parsedVersion, err := tagcmp.Parse(version)
|
||||
if err != nil {
|
||||
logrus.Fatal(err)
|
||||
}
|
||||
if parsedVersion != parsedDeployedVersion && parsedVersion.IsLessThan(parsedDeployedVersion) {
|
||||
availableDowngrades = append(availableDowngrades, version)
|
||||
}
|
||||
}
|
||||
|
||||
// TODO
|
||||
// display table of existing state and expected state and prompt
|
||||
// run the deployment with this target version!
|
||||
if len(availableDowngrades) == 0 {
|
||||
logrus.Fatal("no available downgrades, you're on latest")
|
||||
}
|
||||
|
||||
logrus.Fatal("command not implemented yet, coming soon TM")
|
||||
// FIXME: jeezus golang why do you not have a list reverse function
|
||||
for i, j := 0, len(availableDowngrades)-1; i < j; i, j = i+1, j-1 {
|
||||
availableDowngrades[i], availableDowngrades[j] = availableDowngrades[j], availableDowngrades[i]
|
||||
}
|
||||
|
||||
var chosenDowngrade string
|
||||
if !internal.Force {
|
||||
prompt := &survey.Select{
|
||||
Message: fmt.Sprintf("Please select a downgrade (current version: '%s'):", deployedVersion),
|
||||
Options: availableDowngrades,
|
||||
}
|
||||
if err := survey.AskOne(prompt, &chosenDowngrade); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if internal.Force {
|
||||
chosenDowngrade = availableDowngrades[0]
|
||||
logrus.Debugf("choosing '%s' as version to downgrade to", chosenDowngrade)
|
||||
}
|
||||
|
||||
if err := recipe.EnsureVersion(app.Type, chosenDowngrade); err != nil {
|
||||
logrus.Fatal(err)
|
||||
}
|
||||
|
||||
abraShPath := fmt.Sprintf("%s/%s/%s", config.APPS_DIR, app.Type, "abra.sh")
|
||||
abraShEnv, err := config.ReadAbraShEnvVars(abraShPath)
|
||||
if err != nil {
|
||||
logrus.Fatal(err)
|
||||
}
|
||||
for k, v := range abraShEnv {
|
||||
app.Env[k] = v
|
||||
}
|
||||
|
||||
composeFiles, err := config.GetAppComposeFiles(app.Type, app.Env)
|
||||
if err != nil {
|
||||
logrus.Fatal(err)
|
||||
}
|
||||
deployOpts := stack.Deploy{
|
||||
Composefiles: composeFiles,
|
||||
Namespace: stackName,
|
||||
Prune: false,
|
||||
ResolveImage: stack.ResolveImageAlways,
|
||||
}
|
||||
compose, err := config.GetAppComposeConfig(app.Name, deployOpts, app.Env)
|
||||
if err != nil {
|
||||
logrus.Fatal(err)
|
||||
}
|
||||
|
||||
if !internal.Force {
|
||||
if err := NewVersionOverview(app, deployedVersion, chosenDowngrade); err != nil {
|
||||
logrus.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
if err := stack.RunDeploy(cl, deployOpts, compose); err != nil {
|
||||
logrus.Fatal(err)
|
||||
}
|
||||
|
||||
return nil
|
||||
},
|
||||
|
157
cli/app/upgrade.go
Normal file
157
cli/app/upgrade.go
Normal file
@ -0,0 +1,157 @@
|
||||
package app
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"coopcloud.tech/abra/cli/internal"
|
||||
"coopcloud.tech/abra/pkg/catalogue"
|
||||
"coopcloud.tech/abra/pkg/client"
|
||||
stack "coopcloud.tech/abra/pkg/client/stack"
|
||||
"coopcloud.tech/abra/pkg/config"
|
||||
"coopcloud.tech/abra/pkg/recipe"
|
||||
"coopcloud.tech/tagcmp"
|
||||
"github.com/AlecAivazis/survey/v2"
|
||||
"github.com/sirupsen/logrus"
|
||||
"github.com/urfave/cli/v2"
|
||||
)
|
||||
|
||||
var appUpgradeCommand = &cli.Command{
|
||||
Name: "upgrade",
|
||||
Aliases: []string{"u"},
|
||||
Usage: "Upgrade an app",
|
||||
ArgsUsage: "<app>",
|
||||
Flags: []cli.Flag{
|
||||
internal.ForceFlag,
|
||||
},
|
||||
Description: `
|
||||
This command supports upgrading an app. You can use it to choose and roll out a
|
||||
new upgrade to an existing app.
|
||||
|
||||
This command specifically supports changing the version of running apps, as
|
||||
opposed to "abra app deploy <app>" which will not change the version of a
|
||||
deployed app.
|
||||
|
||||
You may pass "--force/-f" to upgrade to the same version again. This can be
|
||||
useful if the container runtime has gotten into a weird state or your doing
|
||||
some live hacking.
|
||||
|
||||
This action could be destructive, please ensure you have a copy of your app
|
||||
data beforehand - see "abra app backup <app>" for more.
|
||||
`,
|
||||
Action: func(c *cli.Context) error {
|
||||
app := internal.ValidateApp(c)
|
||||
stackName := app.StackName()
|
||||
|
||||
cl, err := client.New(app.Server)
|
||||
if err != nil {
|
||||
logrus.Fatal(err)
|
||||
}
|
||||
|
||||
logrus.Debugf("checking whether '%s' is already deployed", stackName)
|
||||
|
||||
isDeployed, deployedVersion, err := stack.IsDeployed(c.Context, cl, stackName)
|
||||
if err != nil {
|
||||
logrus.Fatal(err)
|
||||
}
|
||||
|
||||
if deployedVersion == "" {
|
||||
logrus.Fatalf("failed to determine version of deployed '%s'", app.Name)
|
||||
}
|
||||
|
||||
if !isDeployed {
|
||||
logrus.Fatalf("'%s' is not deployed?", app.Name)
|
||||
}
|
||||
|
||||
versions, err := catalogue.GetRecipeCatalogueVersions(app.Type)
|
||||
if err != nil {
|
||||
logrus.Fatal(err)
|
||||
}
|
||||
|
||||
var availableUpgrades []string
|
||||
for _, version := range versions {
|
||||
parsedDeployedVersion, err := tagcmp.Parse(deployedVersion)
|
||||
if err != nil {
|
||||
logrus.Fatal(err)
|
||||
}
|
||||
parsedVersion, err := tagcmp.Parse(version)
|
||||
if err != nil {
|
||||
logrus.Fatal(err)
|
||||
}
|
||||
if parsedVersion.IsGreaterThan(parsedDeployedVersion) {
|
||||
availableUpgrades = append(availableUpgrades, version)
|
||||
}
|
||||
}
|
||||
|
||||
if len(availableUpgrades) == 0 {
|
||||
logrus.Fatal("no available upgrades, you're on latest")
|
||||
}
|
||||
|
||||
var chosenUpgrade string
|
||||
if !internal.Force {
|
||||
prompt := &survey.Select{
|
||||
Message: fmt.Sprintf("Please select an upgrade (current version: '%s'):", deployedVersion),
|
||||
Options: availableUpgrades,
|
||||
}
|
||||
if err := survey.AskOne(prompt, &chosenUpgrade); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if internal.Force {
|
||||
chosenUpgrade = availableUpgrades[len(availableUpgrades)-1]
|
||||
logrus.Debugf("choosing '%s' as version to upgrade to", chosenUpgrade)
|
||||
}
|
||||
|
||||
if err := recipe.EnsureVersion(app.Type, chosenUpgrade); err != nil {
|
||||
logrus.Fatal(err)
|
||||
}
|
||||
|
||||
abraShPath := fmt.Sprintf("%s/%s/%s", config.APPS_DIR, app.Type, "abra.sh")
|
||||
abraShEnv, err := config.ReadAbraShEnvVars(abraShPath)
|
||||
if err != nil {
|
||||
logrus.Fatal(err)
|
||||
}
|
||||
for k, v := range abraShEnv {
|
||||
app.Env[k] = v
|
||||
}
|
||||
|
||||
composeFiles, err := config.GetAppComposeFiles(app.Type, app.Env)
|
||||
if err != nil {
|
||||
logrus.Fatal(err)
|
||||
}
|
||||
deployOpts := stack.Deploy{
|
||||
Composefiles: composeFiles,
|
||||
Namespace: stackName,
|
||||
Prune: false,
|
||||
ResolveImage: stack.ResolveImageAlways,
|
||||
}
|
||||
compose, err := config.GetAppComposeConfig(app.Name, deployOpts, app.Env)
|
||||
if err != nil {
|
||||
logrus.Fatal(err)
|
||||
}
|
||||
|
||||
if !internal.Force {
|
||||
if err := NewVersionOverview(app, deployedVersion, chosenUpgrade); err != nil {
|
||||
logrus.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
if err := stack.RunDeploy(cl, deployOpts, compose); err != nil {
|
||||
logrus.Fatal(err)
|
||||
}
|
||||
|
||||
return nil
|
||||
},
|
||||
BashComplete: func(c *cli.Context) {
|
||||
appNames, err := config.GetAppNames()
|
||||
if err != nil {
|
||||
logrus.Warn(err)
|
||||
}
|
||||
if c.NArg() > 0 {
|
||||
return
|
||||
}
|
||||
for _, a := range appNames {
|
||||
fmt.Println(a)
|
||||
}
|
||||
},
|
||||
}
|
@ -2,12 +2,12 @@ package app
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
abraFormatter "coopcloud.tech/abra/cli/formatter"
|
||||
"coopcloud.tech/abra/cli/internal"
|
||||
appPkg "coopcloud.tech/abra/pkg/app"
|
||||
"coopcloud.tech/abra/pkg/catalogue"
|
||||
"coopcloud.tech/abra/pkg/client"
|
||||
"coopcloud.tech/abra/pkg/client/stack"
|
||||
"coopcloud.tech/abra/pkg/config"
|
||||
"github.com/docker/distribution/reference"
|
||||
@ -32,65 +32,61 @@ func getImagePath(image string) (string, error) {
|
||||
var appVersionCommand = &cli.Command{
|
||||
Name: "version",
|
||||
Aliases: []string{"v"},
|
||||
Usage: "Show version of all services in app",
|
||||
Usage: "Show app versions",
|
||||
Description: `
|
||||
This command shows all information about versioning related to a deployed app.
|
||||
This includes the individual image names, tags and digests. But also the Co-op
|
||||
Cloud recipe version.
|
||||
`,
|
||||
Action: func(c *cli.Context) error {
|
||||
app := internal.ValidateApp(c)
|
||||
stackName := app.StackName()
|
||||
|
||||
composeFiles, err := config.GetAppComposeFiles(app.Type, app.Env)
|
||||
if err != nil {
|
||||
logrus.Fatal(err)
|
||||
}
|
||||
opts := stack.Deploy{Composefiles: composeFiles}
|
||||
compose, err := config.GetAppComposeConfig(app.Type, opts, app.Env)
|
||||
cl, err := client.New(app.Server)
|
||||
if err != nil {
|
||||
logrus.Fatal(err)
|
||||
}
|
||||
|
||||
ch := make(chan stack.StackStatus, len(compose.Services))
|
||||
for _, service := range compose.Services {
|
||||
label := fmt.Sprintf("coop-cloud.%s.%s.version", app.StackName(), service.Name)
|
||||
go func(s string, l string) {
|
||||
ch <- stack.GetDeployedServicesByLabel(s, l)
|
||||
}(app.Server, label)
|
||||
logrus.Debugf("checking whether '%s' is already deployed", stackName)
|
||||
|
||||
isDeployed, deployedVersion, err := stack.IsDeployed(c.Context, cl, stackName)
|
||||
if err != nil {
|
||||
logrus.Fatal(err)
|
||||
}
|
||||
|
||||
tableCol := []string{"name", "image", "version", "digest"}
|
||||
if deployedVersion == "" {
|
||||
logrus.Fatalf("failed to determine version of deployed '%s'", app.Name)
|
||||
}
|
||||
|
||||
if !isDeployed {
|
||||
logrus.Fatalf("'%s' is not deployed?", app.Name)
|
||||
}
|
||||
|
||||
recipeMeta, err := catalogue.GetRecipeMeta(app.Type)
|
||||
if err != nil {
|
||||
logrus.Fatal(err)
|
||||
}
|
||||
|
||||
versionsMeta := make(map[string]catalogue.ServiceMeta)
|
||||
for _, recipeVersion := range recipeMeta.Versions {
|
||||
if currentVersion, exists := recipeVersion[deployedVersion]; exists {
|
||||
versionsMeta = currentVersion
|
||||
}
|
||||
}
|
||||
|
||||
if len(versionsMeta) == 0 {
|
||||
logrus.Fatalf("PANIC: could not retrieve deployed version ('%s') from recipe catalogue?", deployedVersion)
|
||||
}
|
||||
|
||||
tableCol := []string{"name", "image", "version", "tag", "digest"}
|
||||
table := abraFormatter.CreateTable(tableCol)
|
||||
|
||||
statuses := make(map[string]stack.StackStatus)
|
||||
for range compose.Services {
|
||||
status := <-ch
|
||||
if len(status.Services) > 0 {
|
||||
serviceName := appPkg.ParseServiceName(status.Services[0].Spec.Name)
|
||||
statuses[serviceName] = status
|
||||
}
|
||||
}
|
||||
|
||||
sort.SliceStable(compose.Services, func(i, j int) bool {
|
||||
return compose.Services[i].Name < compose.Services[j].Name
|
||||
})
|
||||
|
||||
for _, service := range compose.Services {
|
||||
if status, ok := statuses[service.Name]; ok {
|
||||
statusService := status.Services[0]
|
||||
label := fmt.Sprintf("coop-cloud.%s.%s.version", app.StackName(), service.Name)
|
||||
version, digest := appPkg.ParseVersionLabel(statusService.Spec.Labels[label])
|
||||
image, err := getImagePath(statusService.Spec.Labels["com.docker.stack.image"])
|
||||
if err != nil {
|
||||
logrus.Fatal(err)
|
||||
}
|
||||
table.Append([]string{service.Name, image, version, digest})
|
||||
continue
|
||||
}
|
||||
|
||||
image, err := getImagePath(service.Image)
|
||||
if err != nil {
|
||||
logrus.Fatal(err)
|
||||
}
|
||||
table.Append([]string{service.Name, image, "?", "?"})
|
||||
for serviceName, versionMeta := range versionsMeta {
|
||||
table.Append([]string{serviceName, versionMeta.Image, deployedVersion, versionMeta.Tag, versionMeta.Digest})
|
||||
}
|
||||
|
||||
table.Render()
|
||||
|
||||
return nil
|
||||
},
|
||||
BashComplete: func(c *cli.Context) {
|
||||
|
@ -96,7 +96,7 @@ var appVolumeRemoveCommand = &cli.Command{
|
||||
|
||||
var appVolumeCommand = &cli.Command{
|
||||
Name: "volume",
|
||||
Aliases: []string{"v"},
|
||||
Aliases: []string{"vl"},
|
||||
Usage: "Manage app volumes",
|
||||
ArgsUsage: "<command>",
|
||||
Subcommands: []*cli.Command{
|
||||
|
61
go.mod
61
go.mod
@ -1,6 +1,6 @@
|
||||
module coopcloud.tech/abra
|
||||
|
||||
go 1.17
|
||||
go 1.16
|
||||
|
||||
require (
|
||||
coopcloud.tech/tagcmp v0.0.0-20211011140827-4f27c74467eb
|
||||
@ -25,75 +25,16 @@ require (
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 // indirect
|
||||
github.com/Microsoft/go-winio v0.4.17 // indirect
|
||||
github.com/Microsoft/hcsshim v0.8.21 // indirect
|
||||
github.com/ProtonMail/go-crypto v0.0.0-20210428141323-04723f9f07d7 // indirect
|
||||
github.com/acomagu/bufpipe v1.0.3 // indirect
|
||||
github.com/beorn7/perks v1.0.1 // indirect
|
||||
github.com/cespare/xxhash/v2 v2.1.1 // indirect
|
||||
github.com/containerd/cgroups v1.0.1 // indirect
|
||||
github.com/containerd/containerd v1.5.5 // indirect
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.0 // indirect
|
||||
github.com/docker/docker-credential-helpers v0.6.4 // indirect
|
||||
github.com/docker/go v1.5.1-1.0.20160303222718-d30aec9fd63c // indirect
|
||||
github.com/docker/go-connections v0.4.0 // indirect
|
||||
github.com/docker/go-metrics v0.0.1 // indirect
|
||||
github.com/emirpasic/gods v1.12.0 // indirect
|
||||
github.com/facebookgo/stack v0.0.0-20160209184415-751773369052 // indirect
|
||||
github.com/fvbommel/sortorder v1.0.2 // indirect
|
||||
github.com/go-git/gcfg v1.5.0 // indirect
|
||||
github.com/go-git/go-billy/v5 v5.3.1 // indirect
|
||||
github.com/gogo/protobuf v1.3.2 // indirect
|
||||
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e // indirect
|
||||
github.com/golang/protobuf v1.5.0 // indirect
|
||||
github.com/google/go-cmp v0.5.5 // indirect
|
||||
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect
|
||||
github.com/gorilla/mux v1.8.0 // indirect
|
||||
github.com/imdario/mergo v0.3.12 // indirect
|
||||
github.com/inconshreveable/mousetrap v1.0.0 // indirect
|
||||
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect
|
||||
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect
|
||||
github.com/kevinburke/ssh_config v0.0.0-20201106050909-4977a11b4351 // indirect
|
||||
github.com/mattn/go-colorable v0.1.2 // indirect
|
||||
github.com/mattn/go-isatty v0.0.14 // indirect
|
||||
github.com/mattn/go-runewidth v0.0.13 // indirect
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369 // indirect
|
||||
github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b // indirect
|
||||
github.com/miekg/pkcs11 v1.0.3 // indirect
|
||||
github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db // indirect
|
||||
github.com/mitchellh/go-homedir v1.1.0 // indirect
|
||||
github.com/mitchellh/mapstructure v1.1.2 // indirect
|
||||
github.com/moby/sys/mount v0.2.0 // indirect
|
||||
github.com/moby/sys/mountinfo v0.4.1 // indirect
|
||||
github.com/morikuni/aec v1.0.0 // indirect
|
||||
github.com/opencontainers/go-digest v1.0.0 // indirect
|
||||
github.com/opencontainers/image-spec v1.0.1 // indirect
|
||||
github.com/opencontainers/runc v1.0.2 // indirect
|
||||
github.com/prometheus/client_golang v1.11.0 // indirect
|
||||
github.com/prometheus/client_model v0.2.0 // indirect
|
||||
github.com/prometheus/common v0.26.0 // indirect
|
||||
github.com/prometheus/procfs v0.6.0 // indirect
|
||||
github.com/rivo/uniseg v0.2.0 // indirect
|
||||
github.com/russross/blackfriday/v2 v2.0.1 // indirect
|
||||
github.com/sergi/go-diff v1.1.0 // indirect
|
||||
github.com/shurcooL/sanitized_anchor_name v1.0.0 // indirect
|
||||
github.com/spf13/cobra v1.0.0 // indirect
|
||||
github.com/spf13/pflag v1.0.5 // indirect
|
||||
github.com/theupdateframework/notary v0.7.0 // indirect
|
||||
github.com/xanzy/ssh-agent v0.3.0 // indirect
|
||||
github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f // indirect
|
||||
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect
|
||||
github.com/xeipuuv/gojsonschema v1.2.0 // indirect
|
||||
go.opencensus.io v0.22.3 // indirect
|
||||
golang.org/x/crypto v0.0.0-20210817164053-32db794688a5 // indirect
|
||||
golang.org/x/net v0.0.0-20210326060303-6b1517762897 // indirect
|
||||
golang.org/x/sys v0.0.0-20210910150752-751e447fb3d0 // indirect
|
||||
golang.org/x/term v0.0.0-20210615171337-6886f2dfbf5b // indirect
|
||||
golang.org/x/text v0.3.4 // indirect
|
||||
google.golang.org/genproto v0.0.0-20201110150050-8816d57aaa9a // indirect
|
||||
google.golang.org/grpc v1.33.2 // indirect
|
||||
google.golang.org/protobuf v1.26.0 // indirect
|
||||
gopkg.in/warnings.v0 v0.1.2 // indirect
|
||||
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||
)
|
||||
|
2
go.sum
2
go.sum
@ -21,8 +21,6 @@ cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIA
|
||||
cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw=
|
||||
cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos=
|
||||
cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk=
|
||||
coopcloud.tech/tagcmp v0.0.0-20211007122926-aa7b4ff851f6 h1:EV1aomKx6n0jLZ847ejeqroE4K9E+yX5NvEyQufkZVk=
|
||||
coopcloud.tech/tagcmp v0.0.0-20211007122926-aa7b4ff851f6/go.mod h1:ESVm0wQKcbcFi06jItF3rI7enf4Jt2PvbkWpDDHk1DQ=
|
||||
coopcloud.tech/tagcmp v0.0.0-20211011140827-4f27c74467eb h1:Jf+Dnna2kXcNQvcA5JMp6d2Uyvg2pIVJfip9+X5FrH0=
|
||||
coopcloud.tech/tagcmp v0.0.0-20211011140827-4f27c74467eb/go.mod h1:ESVm0wQKcbcFi06jItF3rI7enf4Jt2PvbkWpDDHk1DQ=
|
||||
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
|
||||
|
@ -54,15 +54,15 @@ type tag = string
|
||||
// service represents a service within a recipe.
|
||||
type service = string
|
||||
|
||||
// serviceMeta represents meta info associated with a service.
|
||||
type serviceMeta struct {
|
||||
// ServiceMeta represents meta info associated with a service.
|
||||
type ServiceMeta struct {
|
||||
Digest string `json:"digest"`
|
||||
Image string `json:"image"`
|
||||
Tag string `json:"tag"`
|
||||
}
|
||||
|
||||
// RecipeVersions are the versions associated with a recipe.
|
||||
type RecipeVersions []map[tag]map[service]serviceMeta
|
||||
type RecipeVersions []map[tag]map[service]ServiceMeta
|
||||
|
||||
// RecipeMeta represents metadata for a recipe in the abra catalogue.
|
||||
type RecipeMeta struct {
|
||||
@ -405,7 +405,6 @@ func GetRecipeVersions(recipeName string) (RecipeVersions, error) {
|
||||
checkOutOpts := &git.CheckoutOptions{
|
||||
Create: false,
|
||||
Force: true,
|
||||
Keep: false,
|
||||
Branch: plumbing.ReferenceName(ref.Name()),
|
||||
}
|
||||
if err := worktree.Checkout(checkOutOpts); err != nil {
|
||||
@ -420,7 +419,7 @@ func GetRecipeVersions(recipeName string) (RecipeVersions, error) {
|
||||
return err
|
||||
}
|
||||
|
||||
versionMeta := make(map[string]serviceMeta)
|
||||
versionMeta := make(map[string]ServiceMeta)
|
||||
for _, service := range recipe.Config.Services {
|
||||
|
||||
img, err := reference.ParseNormalizedNamed(service.Image)
|
||||
@ -438,7 +437,7 @@ func GetRecipeVersions(recipeName string) (RecipeVersions, error) {
|
||||
return err
|
||||
}
|
||||
|
||||
versionMeta[service.Name] = serviceMeta{
|
||||
versionMeta[service.Name] = ServiceMeta{
|
||||
Digest: digest,
|
||||
Image: path,
|
||||
Tag: img.(reference.NamedTagged).Tag(),
|
||||
@ -447,7 +446,7 @@ func GetRecipeVersions(recipeName string) (RecipeVersions, error) {
|
||||
logrus.Debugf("collecting digest: '%s', image: '%s', tag: '%s'", digest, path, tag)
|
||||
}
|
||||
|
||||
versions = append(versions, map[string]map[string]serviceMeta{tag: versionMeta})
|
||||
versions = append(versions, map[string]map[string]ServiceMeta{tag: versionMeta})
|
||||
|
||||
return nil
|
||||
}); err != nil {
|
||||
@ -467,7 +466,6 @@ func GetRecipeVersions(recipeName string) (RecipeVersions, error) {
|
||||
checkOutOpts := &git.CheckoutOptions{
|
||||
Create: false,
|
||||
Force: true,
|
||||
Keep: false,
|
||||
Branch: plumbing.ReferenceName(refName),
|
||||
}
|
||||
if err := worktree.Checkout(checkOutOpts); err != nil {
|
||||
|
@ -2,6 +2,7 @@ package stack
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
abraClient "coopcloud.tech/abra/pkg/client"
|
||||
@ -92,6 +93,50 @@ func GetAllDeployedServices(contextName string) StackStatus {
|
||||
return StackStatus{services, nil}
|
||||
}
|
||||
|
||||
// GetDeployedServicesByName filters services by name
|
||||
func GetDeployedServicesByName(ctx context.Context, cl *dockerclient.Client, stackName, serviceName string) StackStatus {
|
||||
filters := filters.NewArgs()
|
||||
filters.Add("name", fmt.Sprintf("%s_%s", stackName, serviceName))
|
||||
|
||||
services, err := cl.ServiceList(ctx, types.ServiceListOptions{Filters: filters})
|
||||
if err != nil {
|
||||
return StackStatus{[]swarm.Service{}, err}
|
||||
}
|
||||
|
||||
return StackStatus{services, nil}
|
||||
}
|
||||
|
||||
// IsDeployed chekcks whether an appp is deployed or not.
|
||||
func IsDeployed(ctx context.Context, cl *dockerclient.Client, stackName string) (bool, string, error) {
|
||||
version := ""
|
||||
isDeployed := false
|
||||
|
||||
filter := filters.NewArgs()
|
||||
filter.Add("label", fmt.Sprintf("%s=%s", convert.LabelNamespace, stackName))
|
||||
|
||||
services, err := cl.ServiceList(ctx, types.ServiceListOptions{Filters: filter})
|
||||
if err != nil {
|
||||
return false, version, err
|
||||
}
|
||||
|
||||
if len(services) > 0 {
|
||||
for _, service := range services {
|
||||
labelKey := fmt.Sprintf("coop-cloud.%s.version", stackName)
|
||||
if deployedVersion, ok := service.Spec.Labels[labelKey]; ok {
|
||||
version = deployedVersion
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
logrus.Debugf("'%s' has been detected as deployed with version '%s'", stackName, version)
|
||||
|
||||
return true, version, nil
|
||||
}
|
||||
|
||||
logrus.Debugf("'%s' has been detected as not deployed", stackName)
|
||||
return isDeployed, version, nil
|
||||
}
|
||||
|
||||
// pruneServices removes services that are no longer referenced in the source
|
||||
func pruneServices(ctx context.Context, cl *dockerclient.Client, namespace convert.Namespace, services map[string]struct{}) {
|
||||
oldServices, err := GetStackServices(ctx, cl, namespace.Name())
|
||||
|
@ -62,7 +62,6 @@ func EnsureUpToDate(dir string) error {
|
||||
checkOutOpts := &git.CheckoutOptions{
|
||||
Create: false,
|
||||
Force: true,
|
||||
Keep: false,
|
||||
Branch: plumbing.ReferenceName(refName),
|
||||
}
|
||||
if err := worktree.Checkout(checkOutOpts); err != nil {
|
||||
|
@ -119,10 +119,10 @@ func EnsureVersion(recipeName, version string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
logrus.Debugf("read '%s' as tags for recipe '%s'", tags, recipeName)
|
||||
|
||||
var parsedTags []string
|
||||
var tagRef plumbing.ReferenceName
|
||||
if err := tags.ForEach(func(ref *plumbing.Reference) (err error) {
|
||||
parsedTags = append(parsedTags, ref.Name().Short())
|
||||
if ref.Name().Short() == version {
|
||||
tagRef = ref.Name()
|
||||
}
|
||||
@ -131,6 +131,8 @@ func EnsureVersion(recipeName, version string) error {
|
||||
return err
|
||||
}
|
||||
|
||||
logrus.Debugf("read '%s' as tags for recipe '%s'", strings.Join(parsedTags, ", "), recipeName)
|
||||
|
||||
if tagRef.String() == "" {
|
||||
return fmt.Errorf("%s is not available?", version)
|
||||
}
|
||||
@ -140,12 +142,56 @@ func EnsureVersion(recipeName, version string) error {
|
||||
return err
|
||||
}
|
||||
|
||||
opts := &git.CheckoutOptions{Branch: tagRef, Keep: true}
|
||||
opts := &git.CheckoutOptions{
|
||||
Branch: tagRef,
|
||||
Create: false,
|
||||
Force: true,
|
||||
}
|
||||
if err := worktree.Checkout(opts); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
logrus.Debugf("successfully checked '%s' out to '%s' in '%s'", recipeName, tagRef, recipeDir)
|
||||
logrus.Debugf("successfully checked '%s' out to '%s' in '%s'", recipeName, tagRef.Short(), recipeDir)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// EnsureLatest makes sure the latest commit is checkout on for a local recipe repository.
|
||||
func EnsureLatest(recipeName string) error {
|
||||
recipeDir := path.Join(config.ABRA_DIR, "apps", recipeName)
|
||||
|
||||
logrus.Debugf("attempting to open git repository in '%s'", recipeDir)
|
||||
|
||||
repo, err := git.PlainOpen(recipeDir)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
worktree, err := repo.Worktree()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
branch := "master"
|
||||
if _, err := repo.Branch("master"); err != nil {
|
||||
if _, err := repo.Branch("main"); err != nil {
|
||||
logrus.Debugf("failed to select branch in '%s'", path.Join(config.APPS_DIR, recipeName))
|
||||
return err
|
||||
}
|
||||
branch = "main"
|
||||
}
|
||||
|
||||
refName := fmt.Sprintf("refs/heads/%s", branch)
|
||||
checkOutOpts := &git.CheckoutOptions{
|
||||
Create: false,
|
||||
Force: true,
|
||||
Branch: plumbing.ReferenceName(refName),
|
||||
}
|
||||
|
||||
if err := worktree.Checkout(checkOutOpts); err != nil {
|
||||
logrus.Debugf("failed to check out '%s' in '%s'", branch, recipeDir)
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
ABRA_VERSION="0.1.8-alpha"
|
||||
ABRA_VERSION="0.2.0-alpha"
|
||||
ABRA_RELEASE_URL="https://git.coopcloud.tech/api/v1/repos/coop-cloud/abra/releases/tags/$ABRA_VERSION"
|
||||
|
||||
function show_banner {
|
||||
@ -35,13 +35,11 @@ function install_abra_release {
|
||||
fi
|
||||
|
||||
# FIXME: support different architectures
|
||||
release_url=$(curl -s "$ABRA_RELEASE_URL" |
|
||||
python3 -c "import sys, json; \
|
||||
payload = json.load(sys.stdin); \
|
||||
url = [a['browser_download_url'] for a in payload['assets'] if 'linux_x86_64' in a['name']][0]; \
|
||||
print(url)")
|
||||
PLATFORM=$(uname -s | tr '[:upper:]' '[:lower:]')_$(uname -m)
|
||||
sed_command='s/.*"assets":\[\{[^}]*"name":"abra.*_'"$PLATFORM"'"[^}]*"browser_download_url":"([^"]*)".*\].*/\1/p'
|
||||
release_url=$(curl -s $ABRA_RELEASE_URL | sed -En $sed_command)
|
||||
|
||||
echo "downloading $ABRA_VERSION x86_64 binary release for abra..."
|
||||
echo "downloading $ABRA_VERSION $PLATFORM binary release for abra..."
|
||||
curl --progress-bar "$release_url" --output "$HOME/.local/bin/abra"
|
||||
chmod +x "$HOME/.local/bin/abra"
|
||||
|
||||
|
Reference in New Issue
Block a user