Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

cmd/atlas: print deployment url #2014

Merged
merged 1 commit into from
Aug 23, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
22 changes: 14 additions & 8 deletions cmd/atlas/internal/cloudapi/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -165,17 +165,17 @@ type (
)

// ReportMigrationSet reports a set of migration deployments to the Atlas Cloud API.
func (c *Client) ReportMigrationSet(ctx context.Context, input ReportMigrationSetInput) error {
func (c *Client) ReportMigrationSet(ctx context.Context, input ReportMigrationSetInput) (string, error) {
var (
payload struct {
ReportMigrationSet struct {
Success bool `json:"success"`
URL string `json:"url"`
} `json:"reportMigrationSet"`
}
query = `
mutation ReportMigrationSet($input: ReportMigrationSetInput!) {
reportMigrationSet(input: $input) {
success
url
}
}`
vars = struct {
Expand All @@ -184,21 +184,24 @@ func (c *Client) ReportMigrationSet(ctx context.Context, input ReportMigrationSe
Input: input,
}
)
return c.post(ctx, query, vars, &payload)
if err := c.post(ctx, query, vars, &payload); err != nil {
return "", err
}
return payload.ReportMigrationSet.URL, nil
}

// ReportMigration reports a migration deployment to the Atlas Cloud API.
func (c *Client) ReportMigration(ctx context.Context, input ReportMigrationInput) error {
func (c *Client) ReportMigration(ctx context.Context, input ReportMigrationInput) (string, error) {
var (
payload struct {
ReportMigration struct {
Success bool `json:"success"`
URL string `json:"url"`
} `json:"reportMigration"`
}
query = `
mutation ReportMigration($input: ReportMigrationInput!) {
reportMigration(input: $input) {
success
url
}
}`
vars = struct {
Expand All @@ -207,7 +210,10 @@ func (c *Client) ReportMigration(ctx context.Context, input ReportMigrationInput
Input: input,
}
)
return c.post(ctx, query, vars, &payload)
if err := c.post(ctx, query, vars, &payload); err != nil {
return "", err
}
return payload.ReportMigration.URL, nil
}

func (c *Client) post(ctx context.Context, query string, vars, data any) error {
Expand Down
11 changes: 8 additions & 3 deletions cmd/atlas/internal/cloudapi/client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,11 +59,12 @@ func TestClient_Error(t *testing.T) {
}))
client := New(srv.URL, "atlas")
defer srv.Close()
err := client.ReportMigration(context.Background(), ReportMigrationInput{
link, err := client.ReportMigration(context.Background(), ReportMigrationInput{
EnvName: "foo",
ProjectName: "bar",
})
require.EqualError(t, err, "variable.input.driver error", "error is trimmed")
require.Empty(t, link)
}

func TestClient_ReportMigration(t *testing.T) {
Expand All @@ -78,14 +79,16 @@ func TestClient_ReportMigration(t *testing.T) {
require.NoError(t, err)
require.Equal(t, env, input.Variables.Input.EnvName)
require.Equal(t, project, input.Variables.Input.ProjectName)
fmt.Fprintf(w, `{"data":{"reportMigration":{"url":"https://atlas.com"}}}`)
}))
client := New(srv.URL, "atlas")
defer srv.Close()
err := client.ReportMigration(context.Background(), ReportMigrationInput{
link, err := client.ReportMigration(context.Background(), ReportMigrationInput{
EnvName: env,
ProjectName: project,
})
require.NoError(t, err)
require.NotEmpty(t, link)
}

func TestClient_ReportMigrationSet(t *testing.T) {
Expand All @@ -110,10 +113,11 @@ func TestClient_ReportMigrationSet(t *testing.T) {
require.Equal(t, env, input.Variables.Input.Completed[1].EnvName)
require.Equal(t, project, input.Variables.Input.Completed[1].ProjectName)
require.Equal(t, "dir-2", input.Variables.Input.Completed[1].DirName)
fmt.Fprintf(w, `{"data":{"reportMigrationSet":{"url":"https://atlas.com"}}}`)
}))
client := New(srv.URL, "atlas")
defer srv.Close()
err := client.ReportMigrationSet(context.Background(), ReportMigrationSetInput{
link, err := client.ReportMigrationSet(context.Background(), ReportMigrationSetInput{
ID: id,
Planned: planned,
Log: []ReportStep{{Text: log}},
Expand All @@ -131,4 +135,5 @@ func TestClient_ReportMigrationSet(t *testing.T) {
},
})
require.NoError(t, err)
require.NotEmpty(t, link)
}
26 changes: 17 additions & 9 deletions cmd/atlas/internal/cmdapi/migrate.go
Original file line number Diff line number Diff line change
Expand Up @@ -361,31 +361,39 @@ func (s *MigrateReportSet) Flush(cmd *cobra.Command, cmdErr error) {
if cmdErr != nil && s.Error == nil {
s.StepLogError(cmdErr.Error())
}
var err error
var (
err error
link string
)
switch {
// Skip reporting if set is empty,
// or there is no cloud connectivity.
case s.Planned == 0, s.client == nil:
return
// Single migration that was completed.
case s.Planned == 1 && len(s.Completed) == 1:
err = s.client.ReportMigration(cmd.Context(), s.Completed[0])
link, err = s.client.ReportMigration(cmd.Context(), s.Completed[0])
// Single migration that failed to start.
case s.Planned == 1 && len(s.Completed) == 0:
s.EndTime = time.Now()
err = s.client.ReportMigrationSet(cmd.Context(), s.ReportMigrationSetInput)
link, err = s.client.ReportMigrationSet(cmd.Context(), s.ReportMigrationSetInput)
// Multi environment migration (e.g., multi-tenancy).
case s.Planned > 1:
s.EndTime = time.Now()
err = s.client.ReportMigrationSet(cmd.Context(), s.ReportMigrationSetInput)
link, err = s.client.ReportMigrationSet(cmd.Context(), s.ReportMigrationSetInput)
}
if err != nil {
switch {
case err != nil:
txt := fmt.Sprintf("Error: %s", strings.TrimRight(err.Error(), "\n"))
// Ensure errors are printed in new lines.
if cmd.Flags().Changed(flagFormat) {
txt = "\n" + txt
}
cmd.PrintErrln(txt)
// Unlike errors that are printed to stderr, links are printed to stdout.
// We do it only if the format was not customized by the user (e.g., JSON).
case link != "" && !cmd.Flags().Changed(flagFormat):
cmd.Println(link)
}
}

Expand All @@ -397,7 +405,7 @@ func (r *MigrateReport) Init(c *sqlclient.Client, l *cmdlog.MigrateApply, rrw cm
// RecordTargetID asks the revisions-table to allow or provide
// the target identifier if cloud reporting is enabled.
func (r *MigrateReport) RecordTargetID(ctx context.Context) error {
if r.CloudEnabled() {
if r.CloudEnabled(ctx) {
id, err := r.rrw.ID(ctx, operatorVersion())
if err != nil {
return err
Expand All @@ -409,7 +417,7 @@ func (r *MigrateReport) RecordTargetID(ctx context.Context) error {

// Done closes and flushes this report.
func (r *MigrateReport) Done(cmd *cobra.Command, flags migrateApplyFlags) error {
if !r.CloudEnabled() {
if !r.CloudEnabled(cmd.Context()) {
return logApply(cmd, cmd.OutOrStdout(), flags, r.log)
}
var (
Expand Down Expand Up @@ -470,8 +478,8 @@ func (r *MigrateReport) Done(cmd *cobra.Command, flags migrateApplyFlags) error
}

// CloudEnabled reports if cloud reporting is enabled.
func (r *MigrateReport) CloudEnabled() bool {
return r.env != nil && r.env.cfg != nil && r.env.cfg.Client != nil && r.env.cfg.Project != ""
func (r *MigrateReport) CloudEnabled(ctx context.Context) bool {
return r.env != nil && r.env.cfg != nil && r.env.cfg.Project != "" && (r.env.cfg.Client != nil || cloudapi.FromContext(ctx) != nil)
}

func logApply(cmd *cobra.Command, w io.Writer, flags migrateApplyFlags, r *cmdlog.MigrateApply) error {
Expand Down
10 changes: 7 additions & 3 deletions cmd/atlas/internal/cmdapi/migrate_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -818,11 +818,13 @@ func TestMigrate_ApplyCloudReport(t *testing.T) {
w.WriteHeader(status)
}
require.NoError(t, json.Unmarshal(m.Variables.Input, &reports))
fmt.Fprint(w, `{"data":{"reportMigrationSet":{"url": "https://gh.atlasgo.cloud/deployments/sets/94489280524"}}}`)
case strings.Contains(m.Query, "mutation") && strings.Contains(m.Query, "ReportMigration"):
if status != 0 {
w.WriteHeader(status)
}
require.NoError(t, json.Unmarshal(m.Variables.Input, &report))
fmt.Fprint(w, `{"data":{"reportMigration":{"url": "https://gh.atlasgo.cloud/deployments/51539607559"}}}`)
default:
t.Fatalf("unexpected query: %s", m.Query)
}
Expand Down Expand Up @@ -869,7 +871,7 @@ env {
"--var", "cloud_url="+srv.URL,
)
require.NoError(t, err)
require.Equal(t, "No migration files to execute\n", s)
require.Equal(t, "No migration files to execute\nhttps://gh.atlasgo.cloud/deployments/51539607559\n", s)
require.NotEmpty(t, report.Target.ID)
_, err = uuid.Parse(report.Target.ID)
require.NoError(t, err, "target id is not a valid uuid")
Expand Down Expand Up @@ -908,7 +910,7 @@ env {
require.NoError(t, err)
// Reporting does not affect the output.
require.True(t, strings.HasPrefix(s, "Migrating to version 2 (2 migrations in total):"))
require.True(t, strings.HasSuffix(s, " -- 2 migrations \n -- 2 sql statements\n"))
require.True(t, strings.HasSuffix(s, " -- 2 migrations \n -- 2 sql statements\nhttps://gh.atlasgo.cloud/deployments/51539607559\n"))
require.Equal(t, "", report.FromVersion, "from empty database")
require.Equal(t, "2", report.ToVersion)
require.Equal(t, "2", report.CurrentVersion)
Expand Down Expand Up @@ -998,6 +1000,8 @@ func TestMigrate_ApplyCloudReportSet(t *testing.T) {
case strings.Contains(m.Query, "mutation"):
if status != 0 {
w.WriteHeader(status)
} else {
fmt.Fprint(w, `{"data":{"reportMigrationSet":{"url":"https://gh.atlasgo.cloud/deployments/sets/94489280524"}}}`)
}
require.NoError(t, json.Unmarshal(m.Variables.Input, &report))
default:
Expand Down Expand Up @@ -1053,7 +1057,7 @@ env {
"--var", "cloud_url="+srv.URL,
)
require.NoError(t, err)
require.Equal(t, "No migration files to execute\nNo migration files to execute\n", s)
require.Equal(t, "No migration files to execute\nNo migration files to execute\nhttps://gh.atlasgo.cloud/deployments/sets/94489280524\n", s)
require.NotEmpty(t, report.ID)
_, err = uuid.Parse(report.ID)
require.NoError(t, err, "set id is not a valid uuid")
Expand Down