Skip to content

Commit d3913b5

Browse files
srtaalejzimeg
andauthored
feat: add --force-remote flag to manifest sync (#617)
Co-authored-by: Eden Zimbelman <eden.zimbelman@salesforce.com>
1 parent adaae5e commit d3913b5

5 files changed

Lines changed: 49 additions & 1 deletion

File tree

‎cmd/manifest/sync.go‎

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,8 @@ func NewSyncCommand(clients *shared.ClientFactory) *cobra.Command {
3737
Hidden: true,
3838
Example: style.ExampleCommandsf([]style.ExampleCommand{
3939
{Command: "manifest sync", Meaning: "Sync project manifest with app settings"},
40+
{Command: "manifest sync --force", Meaning: "Push project manifest to app settings without prompting"},
41+
{Command: "manifest sync --force-remote", Meaning: "Pull app settings to project manifest without prompting"},
4042
}),
4143
Args: cobra.NoArgs,
4244
PreRunE: func(cmd *cobra.Command, args []string) error {
@@ -47,6 +49,10 @@ func NewSyncCommand(clients *shared.ClientFactory) *cobra.Command {
4749
style.CommandText("--experiment manifest-sync"),
4850
)
4951
}
52+
if clients.Config.ForceFlag && clients.Config.ForceRemoteFlag {
53+
return slackerror.New(slackerror.ErrMismatchedFlags).
54+
WithMessage("Cannot use both %s and %s flags", style.CommandText("--force"), style.CommandText("--force-remote"))
55+
}
5056
return cmdutil.IsValidProjectDirectory(clients)
5157
},
5258
RunE: func(cmd *cobra.Command, args []string) error {
@@ -65,5 +71,6 @@ func NewSyncCommand(clients *shared.ClientFactory) *cobra.Command {
6571
return err
6672
},
6773
}
74+
cmd.Flags().BoolVar(&clients.Config.ForceRemoteFlag, "force-remote", false, "use all app settings values without prompting")
6875
return cmd
6976
}

‎cmd/manifest/sync_test.go‎

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,16 @@ func TestSyncCommand(t *testing.T) {
4545
// the gate itself should pass.
4646
ExpectedErrorStrings: []string{},
4747
},
48+
"errors when both --force and --force-remote are set": {
49+
CmdArgs: []string{"--force-remote"},
50+
Setup: func(t *testing.T, ctx context.Context, cm *shared.ClientsMock, cf *shared.ClientFactory) {
51+
cm.AddDefaultMocks()
52+
cf.Config.ExperimentsFlag = []string{string(experiment.ManifestSync)}
53+
cf.Config.LoadExperiments(ctx, cf.IO.PrintDebug)
54+
cf.Config.ForceFlag = true
55+
},
56+
ExpectedErrorStrings: []string{"Cannot use both", "--force", "--force-remote"},
57+
},
4858
}, func(clients *shared.ClientFactory) *cobra.Command {
4959
return NewSyncCommand(clients)
5060
})

‎internal/config/config.go‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ type Config struct {
5353
DeprecatedWorkspaceFlag string
5454
DisableTelemetryFlag bool
5555
ForceFlag bool
56+
ForceRemoteFlag bool
5657
LogstashHostResolved string
5758
NoColor bool
5859
RuntimeFlag string

‎internal/manifest/sync.go‎

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,11 +82,17 @@ func Sync(ctx context.Context, clients *shared.ClientFactory, app types.App, aut
8282
if err != nil {
8383
return nil, err
8484
}
85+
case clients.Config.ForceRemoteFlag:
86+
merged, err = MergeAllFrom(localManifest.AppManifest, remoteManifest.AppManifest, diffs, MergeAllRemote)
87+
if err != nil {
88+
return nil, err
89+
}
8590
case !clients.IO.IsTTY():
8691
return nil, slackerror.New(slackerror.ErrAppManifestUpdate).
87-
WithRemediation("Run %s interactively to resolve manifest differences, or pass %s to push the project manifest to app settings",
92+
WithRemediation("Run %s interactively to resolve manifest differences, or pass %s to push the project manifest to app settings or %s to pull app settings to project",
8893
style.Commandf("manifest sync", false),
8994
style.CommandText("--force"),
95+
style.CommandText("--force-remote"),
9096
)
9197
default:
9298
merged, err = resolveInteractively(ctx, clients, localManifest.AppManifest, remoteManifest.AppManifest, diffs)

‎internal/manifest/sync_test.go‎

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -196,6 +196,30 @@ func Test_Sync(t *testing.T) {
196196
f.clientsMock.API.AssertCalled(t, "UpdateApp", mock.Anything, "xoxb-test", "A123", mock.Anything, true, true)
197197
})
198198

199+
t.Run("force-remote flag merges all remote and pushes to API", func(t *testing.T) {
200+
f := newSyncTestFixture(t)
201+
f.projectConfig.On("GetManifestSource", mock.Anything).Return(config.ManifestSourceLocal, nil)
202+
f.manifestMock.On("GetManifestLocal", mock.Anything, mock.Anything, mock.Anything).
203+
Return(localManifest, nil)
204+
f.manifestMock.On("GetManifestRemote", mock.Anything, mock.Anything, mock.Anything).
205+
Return(remoteManifest, nil)
206+
f.clients.Config.ForceRemoteFlag = true
207+
f.clientsMock.API.On("UpdateApp", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).
208+
Return(api.UpdateAppResult{}, nil)
209+
f.cacheMock.On("NewManifestHash", mock.Anything, mock.Anything).Return(cache.Hash("newhash"), nil)
210+
f.cacheMock.On("SetManifestHash", mock.Anything, mock.Anything, mock.Anything).Return(nil)
211+
_ = afero.WriteFile(f.fs, "/project/manifest.json", []byte(`{"display_information":{"name":"App"}}`), 0644)
212+
213+
result, err := Sync(f.ctx, f.clients, testApp, testAuth)
214+
215+
require.NoError(t, err)
216+
require.NotNil(t, result)
217+
assert.True(t, result.HasDifferences)
218+
assert.True(t, result.WriteBack.Written)
219+
// Verify remote value was used — the merged manifest should have "Remote" description
220+
assert.Equal(t, "Remote", result.Merged.DisplayInformation.Description)
221+
})
222+
199223
t.Run("API UpdateApp failure is propagated", func(t *testing.T) {
200224
f := newSyncTestFixture(t)
201225
f.projectConfig.On("GetManifestSource", mock.Anything).Return(config.ManifestSourceLocal, nil)

0 commit comments

Comments
 (0)