@@ -2,6 +2,7 @@ package cmd
22
33import (
44 "fmt"
5+ "time"
56
67 "github.com/InitiatDev/initiat-cli/internal/client"
78 "github.com/InitiatDev/initiat-cli/internal/env"
@@ -36,15 +37,34 @@ var envListCmd = &cobra.Command{
3637 }
3738
3839 activeEnv , _ := env .GetActiveEnvironment ()
40+ localEnvs , _ := env .ListLocalEnvironments ()
41+ localEnvMap := make (map [string ]env.EnvironmentInfo )
42+ for _ , localEnv := range localEnvs {
43+ localEnvMap [localEnv .Slug ] = localEnv
44+ }
3945
4046 fmt .Println ("Environments:" )
4147 for _ , environment := range environments {
48+ status := "not synced"
49+ syncTime := "never"
50+
51+ if localEnv , exists := localEnvMap [environment .Slug ]; exists {
52+ if localEnv .HasSecrets {
53+ status = "synced"
54+ if ! localEnv .Synced .IsZero () {
55+ syncTime = formatTimeAgo (localEnv .Synced )
56+ }
57+ } else {
58+ status = "no secrets"
59+ }
60+ }
61+
4262 marker := " "
4363 if environment .Slug == activeEnv {
4464 marker = "*"
4565 }
4666
47- fmt .Printf ("%s %-10s (%d secrets)\n " , marker , environment .Slug , environment .SecretsCount )
67+ fmt .Printf ("%s %-10s %-10s %s (%d secrets)\n " , marker , environment .Slug , status , syncTime , environment .SecretsCount )
4868 }
4969
5070 return nil
@@ -101,6 +121,48 @@ var envSwitchCmd = &cobra.Command{
101121 },
102122}
103123
124+ var envSyncCmd = & cobra.Command {
125+ Use : "sync [--env <slug>]" ,
126+ Short : "Sync secrets from cloud" ,
127+ Long : `Sync secrets from Initiat Cloud to local environment(s).` ,
128+ RunE : func (cmd * cobra.Command , args []string ) error {
129+ if ! env .IsInitCompleted () {
130+ return fmt .Errorf ("initiat environment not initialized. Run 'initiat env init' first" )
131+ }
132+
133+ projectCtx , err := GetProjectContext ()
134+ if err != nil {
135+ return fmt .Errorf ("failed to get project context: %w" , err )
136+ }
137+
138+ envSlug , _ := cmd .Flags ().GetString ("env" )
139+
140+ if envSlug != "" {
141+ apiClient := client .New ()
142+ _ , err = apiClient .GetEnvironment (projectCtx .OrgSlug , projectCtx .ProjectSlug , envSlug )
143+ if err != nil {
144+ return fmt .Errorf ("environment '%s' does not exist: %w" , envSlug , err )
145+ }
146+
147+ err = env .SyncEnvironment (envSlug , projectCtx .OrgSlug , projectCtx .ProjectSlug )
148+ if err != nil {
149+ return fmt .Errorf ("failed to sync environment %s: %w" , envSlug , err )
150+ }
151+
152+ fmt .Printf ("Synced environment '%s'\n " , envSlug )
153+ } else {
154+ err = env .SyncAllEnvironments (projectCtx .OrgSlug , projectCtx .ProjectSlug )
155+ if err != nil {
156+ return fmt .Errorf ("failed to sync environments: %w" , err )
157+ }
158+
159+ fmt .Printf ("Synced all environments\n " )
160+ }
161+
162+ return nil
163+ },
164+ }
165+
104166var envCurrentCmd = & cobra.Command {
105167 Use : "current" ,
106168 Short : "Show current environment" ,
@@ -160,27 +222,6 @@ var envUnsetCmd = &cobra.Command{
160222 },
161223}
162224
163- var envLoadCmd = & cobra.Command {
164- Use : "load" ,
165- Short : "Load environment secrets (for direnv)" ,
166- Long : `Load and export secrets for the active environment. This command is intended to be used by direnv via eval.` ,
167- Hidden : true ,
168- RunE : func (cmd * cobra.Command , args []string ) error {
169- projectCtx , err := GetProjectContext ()
170- if err != nil {
171- return fmt .Errorf ("failed to get project context: %w" , err )
172- }
173-
174- output , err := env .LoadEnvironmentSecrets (projectCtx .OrgSlug , projectCtx .ProjectSlug )
175- if err != nil {
176- return err
177- }
178-
179- fmt .Print (output )
180- return nil
181- },
182- }
183-
184225var envInitCmd = & cobra.Command {
185226 Use : "init" ,
186227 Short : "Initialize environment setup" ,
@@ -267,13 +308,35 @@ var envInitCmd = &cobra.Command{
267308 },
268309}
269310
311+ func formatTimeAgo (t time.Time ) string {
312+ now := time .Now ()
313+ duration := now .Sub (t )
314+
315+ switch {
316+ case duration < time .Minute :
317+ return "just now"
318+ case duration < time .Hour :
319+ minutes := int (duration .Minutes ())
320+ return fmt .Sprintf ("%dm ago" , minutes )
321+ case duration < 24 * time .Hour :
322+ hours := int (duration .Hours ())
323+ return fmt .Sprintf ("%dh ago" , hours )
324+ default :
325+ const hoursPerDay = 24
326+ days := int (duration .Hours () / hoursPerDay )
327+ return fmt .Sprintf ("%dd ago" , days )
328+ }
329+ }
330+
270331func init () {
271332 envCmd .AddCommand (envListCmd )
272333 envCmd .AddCommand (envSwitchCmd )
334+ envCmd .AddCommand (envSyncCmd )
273335 envCmd .AddCommand (envCurrentCmd )
274336 envCmd .AddCommand (envUnsetCmd )
275337 envCmd .AddCommand (envInitCmd )
276- envCmd .AddCommand (envLoadCmd )
338+
339+ envSyncCmd .Flags ().String ("env" , "" , "Sync specific environment" )
277340
278341 rootCmd .AddCommand (envCmd )
279342}
0 commit comments