Skip to content

Commit b5c256f

Browse files
release/0.15.0 (#317)
* refactor(copy-projects): extract project creation logic into a separate function * feat(compare): add compare command with workspaces subcommand * feat(compare): enhance workspace comparison command with default values and validation * feat(compare): add suffix and prefix filters for workspace comparison * feat(workspaces): add flags to skip empty workspaces and create destination project * feat(workspaces): add project existence check and description during workspace copy * feat(lock-teams): Add command to lock team permissions in organization * removing secret * fix(tokens): Remove hardcoded TFC tokens for security * wsListOptions naming * Added exclude workspaces * Add 'plan-only' flag to workspaces copy command for dry-run functionality * Add workspace name prefix and suffix options to workspaces copy command * Add log message for workspace copy operation in copyWorkspaces function * Add workspace name length validation and tagging during migration * Remove compare command and associated workspace comparison logic * Refactor workspace tagging to use binding * Add .DS_Store to .gitignore to prevent tracking of macOS system files * Update workspace copy command documentation and flags * Refactor team migration messages and update documentation for org-to-project migration * Update org-to-project migration flag description for clarity * Refactor `tfm lock teams` command documentation and remove alias * Standardize workspace naming convention by enforcing prefix and suffix, and log renaming actions * Standardize workspace renaming examples with consistent prefix and suffix format * updates from self review
1 parent 9ceb3c4 commit b5c256f

File tree

10 files changed

+529
-50
lines changed

10 files changed

+529
-50
lines changed

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,3 +17,5 @@ terraform_config_metadata.json
1717

1818
# Goreleaser build dir
1919
dist/
20+
21+
*.DS_Store*

cmd/copy/projects.go

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -341,10 +341,7 @@ func copyProjects(c tfclient.ClientContexts, projMapCfg map[string]string) error
341341
o.AddMessageUserProvided2(destProjectName, "exists in destination will not migrate", srcproject.Name)
342342
} else {
343343

344-
srcproject, err := c.DestinationClient.Projects.Create(c.DestinationContext, c.DestinationOrganizationName, tfe.ProjectCreateOptions{
345-
Type: "",
346-
Name: destProjectName,
347-
})
344+
srcproject, err := createProject(c, destProjectName)
348345

349346
if err != nil {
350347
fmt.Println("Could not create Project.\n\n Error:", err.Error())
@@ -355,3 +352,25 @@ func copyProjects(c tfclient.ClientContexts, projMapCfg map[string]string) error
355352
}
356353
return nil
357354
}
355+
356+
func createProject(c tfclient.ClientContexts, projectName string) (*tfe.Project, error) {
357+
o.AddMessageUserProvided("Creating Project in destination: ", projectName)
358+
359+
// Check if project name is >= 3 characters and <= 40 characters
360+
// Return error if not
361+
if len(projectName) <= 3 || len(projectName) >= 40 {
362+
return nil, errors.New("Project name must be between 3 and 40 characters")
363+
}
364+
365+
// Create the project in the destination organization
366+
project, err := c.DestinationClient.Projects.Create(c.DestinationContext, c.DestinationOrganizationName, tfe.ProjectCreateOptions{
367+
Name: projectName,
368+
Description: helper.ViperString("created by tfm"),
369+
})
370+
371+
if err != nil {
372+
return nil, errors.Wrap(err, "Failed to create Project in destination")
373+
}
374+
375+
return project, nil
376+
}

cmd/copy/teams.go

Lines changed: 65 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,6 @@
44
package copy
55

66
import (
7-
"fmt"
8-
97
"strings"
108

119
"github.com/hashicorp-services/tfm/output"
@@ -16,7 +14,8 @@ import (
1614
)
1715

1816
var (
19-
o output.Output
17+
o output.Output
18+
orgToProject bool
2019

2120
// `tfemig copy teams` command
2221
teamCopyCmd = &cobra.Command{
@@ -38,6 +37,7 @@ func init() {
3837

3938
// Add commands
4039
CopyCmd.AddCommand(teamCopyCmd)
40+
teamCopyCmd.Flags().BoolVarP(&orgToProject, "org-to-project", "o", false, "Migrate with organization access set to read-only.")
4141

4242
}
4343

@@ -137,34 +137,70 @@ func copyTeams(c tfclient.ClientContexts) error {
137137
for _, srcteam := range srcTeams {
138138
exists := doesTeamExist(srcteam.Name, destTeams)
139139
if exists {
140-
fmt.Println("Exists in destination will not migrate", srcteam.Name)
140+
o.AddMessageUserProvided("Exists in destination will not migrate", srcteam.Name)
141141
} else {
142-
fmt.Println("Migrating", srcteam.Name)
143-
srcteam, err := c.DestinationClient.Teams.Create(c.DestinationContext, c.DestinationOrganizationName, tfe.TeamCreateOptions{
144-
Type: "",
145-
Name: &srcteam.Name,
146-
SSOTeamID: &srcteam.SSOTeamID,
147-
OrganizationAccess: &tfe.OrganizationAccessOptions{
148-
ManagePolicies: &srcteam.OrganizationAccess.ManagePolicies,
149-
ManagePolicyOverrides: &srcteam.OrganizationAccess.ManagePolicyOverrides,
150-
ManageWorkspaces: &srcteam.OrganizationAccess.ManageWorkspaces,
151-
ManageVCSSettings: &srcteam.OrganizationAccess.ManageVCSSettings,
152-
ManageProviders: &srcteam.OrganizationAccess.ManageProviders,
153-
ManageModules: &srcteam.OrganizationAccess.ManageModules,
154-
ManageRunTasks: &srcteam.OrganizationAccess.ManageRunTasks,
155-
// release v202302-1
156-
ManageProjects: &srcteam.OrganizationAccess.ManageProjects,
157-
ReadWorkspaces: &srcteam.OrganizationAccess.ReadWorkspaces,
158-
ReadProjects: &srcteam.OrganizationAccess.ReadProjects,
159-
// release 202303-1
160-
ManageMembership: &srcteam.OrganizationAccess.ManageMembership,
161-
},
162-
Visibility: &srcteam.Visibility,
163-
})
164-
if err != nil {
165-
return err
142+
if orgToProject {
143+
o.AddMessageUserProvided("Migrating with read-only access", srcteam.Name)
144+
145+
// Take teams from source and create them in destination.
146+
// if orgToProject is true, it will create teams in the destination with higher organization access removed.
147+
team, err := c.DestinationClient.Teams.Create(c.DestinationContext, c.DestinationOrganizationName, tfe.TeamCreateOptions{
148+
Type: "",
149+
Name: &srcteam.Name,
150+
SSOTeamID: &srcteam.SSOTeamID,
151+
OrganizationAccess: &tfe.OrganizationAccessOptions{
152+
ManagePolicies: tfe.Bool(false),
153+
ManagePolicyOverrides: tfe.Bool(false),
154+
ManageWorkspaces: tfe.Bool(false),
155+
ManageVCSSettings: tfe.Bool(false),
156+
ManageProviders: tfe.Bool(false),
157+
ManageModules: tfe.Bool(false),
158+
ManageRunTasks: tfe.Bool(false),
159+
// release v202302-1
160+
ManageProjects: tfe.Bool(false),
161+
ReadWorkspaces: tfe.Bool(false),
162+
ReadProjects: tfe.Bool(false),
163+
// release 202303-1
164+
ManageMembership: tfe.Bool(false),
165+
},
166+
Visibility: &srcteam.Visibility,
167+
})
168+
169+
if err != nil {
170+
return err
171+
}
172+
173+
o.AddDeferredMessageRead("Created team in destination organization", team.Name)
174+
o.AddDeferredMessageRead("New ID", team.ID)
175+
176+
} else {
177+
o.AddMessageUserProvided("Migrating", srcteam.Name)
178+
srcteam, err := c.DestinationClient.Teams.Create(c.DestinationContext, c.DestinationOrganizationName, tfe.TeamCreateOptions{
179+
Type: "",
180+
Name: &srcteam.Name,
181+
SSOTeamID: &srcteam.SSOTeamID,
182+
OrganizationAccess: &tfe.OrganizationAccessOptions{
183+
ManagePolicies: &srcteam.OrganizationAccess.ManagePolicies,
184+
ManagePolicyOverrides: &srcteam.OrganizationAccess.ManagePolicyOverrides,
185+
ManageWorkspaces: &srcteam.OrganizationAccess.ManageWorkspaces,
186+
ManageVCSSettings: &srcteam.OrganizationAccess.ManageVCSSettings,
187+
ManageProviders: &srcteam.OrganizationAccess.ManageProviders,
188+
ManageModules: &srcteam.OrganizationAccess.ManageModules,
189+
ManageRunTasks: &srcteam.OrganizationAccess.ManageRunTasks,
190+
// release v202302-1
191+
ManageProjects: &srcteam.OrganizationAccess.ManageProjects,
192+
ReadWorkspaces: &srcteam.OrganizationAccess.ReadWorkspaces,
193+
ReadProjects: &srcteam.OrganizationAccess.ReadProjects,
194+
// release 202303-1
195+
ManageMembership: &srcteam.OrganizationAccess.ManageMembership,
196+
},
197+
Visibility: &srcteam.Visibility,
198+
})
199+
if err != nil {
200+
return err
201+
}
202+
o.AddDeferredMessageRead("Migrated", srcteam.Name)
166203
}
167-
o.AddDeferredMessageRead("Migrated", srcteam.Name)
168204
}
169205
}
170206
return nil

0 commit comments

Comments
 (0)