Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
99 changes: 45 additions & 54 deletions github/resource_github_emu_group_mapping.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,13 +49,18 @@ func resourceGithubEMUGroupMapping() *schema.Resource {
Computed: true,
},
},
SchemaVersion: 1,
SchemaVersion: 2,
StateUpgraders: []schema.StateUpgrader{
{
Type: resourceGithubEMUGroupMappingV0().CoreConfigSchema().ImpliedType(),
Upgrade: resourceGithubEMUGroupMappingStateUpgradeV0,
Version: 0,
},
{
Type: resourceGithubEMUGroupMappingV1().CoreConfigSchema().ImpliedType(),
Upgrade: resourceGithubEMUGroupMappingStateUpgradeV1,
Version: 1,
},
},
}
}
Expand All @@ -69,18 +74,19 @@ func resourceGithubEMUGroupMappingCreate(ctx context.Context, d *schema.Resource
}
client := meta.(*Owner).v3client
orgName := meta.(*Owner).name
tflog.SetField(ctx, "org_name", orgName)

teamSlug := d.Get("team_slug").(string)
tflog.SetField(ctx, "team_slug", teamSlug)

groupID := toInt64(d.Get("group_id"))
tflog.SetField(ctx, "group_id", groupID)
eg := &github.ExternalGroup{
GroupID: github.Ptr(groupID),
}

tflog.Debug(ctx, "Connecting external group to team via GitHub API")
tflog.Debug(ctx, "Connecting external group to team via GitHub API", map[string]any{
"org_name": orgName,
"team_slug": teamSlug,
"group_id": groupID,
})

group, resp, err := client.Teams.UpdateConnectedExternalGroup(ctx, orgName, teamSlug, eg)
if err != nil {
Expand All @@ -94,20 +100,23 @@ func resourceGithubEMUGroupMappingCreate(ctx context.Context, d *schema.Resource
return diag.FromErr(err)
}

newResourceID, err := buildID(strconv.FormatInt(teamID, 10), teamSlug, strconv.FormatInt(groupID, 10))
newResourceID, err := buildID(strconv.FormatInt(groupID, 10), strconv.FormatInt(teamID, 10))
if err != nil {
return diag.FromErr(err)
}

if err := d.Set("team_id", int(teamID)); err != nil {
return diag.FromErr(err)
}

tflog.Trace(ctx, "Setting resource ID", map[string]any{
"resource_id": newResourceID,
})
d.SetId(newResourceID)

tflog.Trace(ctx, "Setting team_id", map[string]any{
"team_id": teamID,
})
if err := d.Set("team_id", int(teamID)); err != nil {
return diag.FromErr(err)
}

etag := resp.Header.Get("ETag")
tflog.Trace(ctx, "Setting state attribute: etag", map[string]any{
"etag": etag,
Expand All @@ -116,21 +125,23 @@ func resourceGithubEMUGroupMappingCreate(ctx context.Context, d *schema.Resource
return diag.FromErr(err)
}

tflog.Trace(ctx, "Setting group_name", map[string]any{
"group_name": group.GetGroupName(),
})
if err := d.Set("group_name", group.GetGroupName()); err != nil {
return diag.FromErr(err)
}

tflog.Trace(ctx, "Resource created or updated successfully", map[string]any{
tflog.Trace(ctx, "Resource created successfully", map[string]any{
"resource_id": d.Id(),
})

return nil
}

func resourceGithubEMUGroupMappingRead(ctx context.Context, d *schema.ResourceData, meta any) diag.Diagnostics {
tflog.Trace(ctx, "Reading EMU group mapping", map[string]any{
"resource_id": d.Id(),
})
ctx = tflog.SetField(ctx, "resource_id", d.Id())
tflog.Trace(ctx, "Reading EMU group mapping")

err := checkOrganization(meta)
if err != nil {
Expand All @@ -142,36 +153,29 @@ func resourceGithubEMUGroupMappingRead(ctx context.Context, d *schema.ResourceDa
groupID := toInt64(d.Get("group_id"))
teamSlug := d.Get("team_slug").(string)

tflog.SetField(ctx, "group_id", groupID)
tflog.SetField(ctx, "team_slug", teamSlug)
tflog.SetField(ctx, "org_name", orgName)

tflog.Debug(ctx, "Querying external groups linked to team from GitHub API")
tflog.Debug(ctx, "Querying external groups linked to team from GitHub API", map[string]any{
"org_name": orgName,
"team_slug": teamSlug,
})

groupsList, resp, err := client.Teams.ListExternalGroupsForTeamBySlug(ctx, orgName, teamSlug)
if err != nil {
if resp != nil && resp.StatusCode == http.StatusBadRequest {
tflog.Info(ctx, "Removing EMU group mapping from state because the team has explicit members in GitHub", map[string]any{
"resource_id": d.Id(),
})
tflog.Info(ctx, "Removing EMU group mapping from state because the team has explicit members in GitHub")
d.SetId("")
return nil
}
if resp != nil && (resp.StatusCode == http.StatusNotFound) {
// If the Group is not found, remove it from state
tflog.Info(ctx, "Removing EMU group mapping from state because team no longer exists in GitHub", map[string]any{
"resource_id": d.Id(),
})
tflog.Info(ctx, "Removing EMU group mapping from state because team no longer exists in GitHub")
d.SetId("")
return nil
}
return diag.FromErr(err)
}

if len(groupsList.Groups) < 1 {
tflog.Info(ctx, "Removing EMU group mapping from state because no external groups are linked to the team", map[string]any{
"resource_id": d.Id(),
})
tflog.Info(ctx, "Removing EMU group mapping from state because no external groups are linked to the team")
d.SetId("")
return nil
}
Expand All @@ -180,8 +184,9 @@ func resourceGithubEMUGroupMappingRead(ctx context.Context, d *schema.ResourceDa
group := groupsList.Groups[0]

tflog.Debug(ctx, "Successfully retrieved external group from GitHub API", map[string]any{
"group_id": group.GetGroupID(),
"group_name": group.GetGroupName(),
"configured_group_id": groupID,
"upstream_group_id": group.GetGroupID(),
"group_name": group.GetGroupName(),
})

if group.GetGroupID() != groupID {
Expand All @@ -205,30 +210,30 @@ func resourceGithubEMUGroupMappingRead(ctx context.Context, d *schema.ResourceDa
}

func resourceGithubEMUGroupMappingUpdate(ctx context.Context, d *schema.ResourceData, meta any) diag.Diagnostics {
tflog.Trace(ctx, "Updating EMU group mapping", map[string]any{
"resource_id": d.Id(),
})
ctx = tflog.SetField(ctx, "resource_id", d.Id())
tflog.Trace(ctx, "Updating EMU group mapping")

err := checkOrganization(meta)
if err != nil {
return diag.FromErr(err)
}
client := meta.(*Owner).v3client
orgName := meta.(*Owner).name
tflog.SetField(ctx, "org_name", orgName)

teamSlug := d.Get("team_slug").(string)
tflog.SetField(ctx, "team_slug", teamSlug)

groupID := toInt64(d.Get("group_id"))
tflog.SetField(ctx, "group_id", groupID)
eg := &github.ExternalGroup{
GroupID: github.Ptr(groupID),
}

if d.HasChanges("group_id", "team_slug") {
if d.HasChange("team_slug") {

tflog.Debug(ctx, "Updating connected external group via GitHub API")
tflog.Debug(ctx, "Updating connected external group via GitHub API", map[string]any{
"org_name": orgName,
"team_slug": teamSlug,
"group_id": groupID,
})

group, resp, err := client.Teams.UpdateConnectedExternalGroup(ctx, orgName, teamSlug, eg)
if err != nil {
Expand All @@ -248,23 +253,9 @@ func resourceGithubEMUGroupMappingUpdate(ctx context.Context, d *schema.Resource
if err := d.Set("group_name", group.GetGroupName()); err != nil {
return diag.FromErr(err)
}

teamID := toInt64(d.Get("team_id"))

newResourceID, err := buildID(strconv.FormatInt(teamID, 10), teamSlug, strconv.FormatInt(groupID, 10))
if err != nil {
return diag.FromErr(err)
}

tflog.Trace(ctx, "Setting resource ID", map[string]any{
"resource_id": newResourceID,
})
d.SetId(newResourceID)
}

tflog.Trace(ctx, "Updated successfully", map[string]any{
"resource_id": d.Id(),
})
tflog.Trace(ctx, "Updated successfully")

return nil
}
Expand Down Expand Up @@ -346,7 +337,7 @@ func resourceGithubEMUGroupMappingImport(ctx context.Context, d *schema.Resource
return nil, err
}

resourceID, err := buildID(strconv.FormatInt(teamID, 10), teamSlug, groupIDString)
resourceID, err := buildID(groupIDString, strconv.FormatInt(teamID, 10))
if err != nil {
return nil, err
}
Expand Down
54 changes: 54 additions & 0 deletions github/resource_github_emu_group_mapping_migration.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package github

import (
"context"
"fmt"
"net/http"
"strconv"

Expand Down Expand Up @@ -66,3 +67,56 @@ func resourceGithubEMUGroupMappingStateUpgradeV0(ctx context.Context, rawState m
tflog.Trace(ctx, "GitHub EMU Group Mapping State after migration", map[string]any{"state": rawState})
return rawState, nil
}

func resourceGithubEMUGroupMappingV1() *schema.Resource {
return &schema.Resource{
Schema: map[string]*schema.Schema{
"team_id": {
Type: schema.TypeInt,
Computed: true,
Description: "ID of the GitHub team.",
},
"team_slug": {
Type: schema.TypeString,
Required: true,
Description: "Slug of the GitHub team.",
},
"group_id": {
Type: schema.TypeInt,
Required: true,
ForceNew: true,
Description: "Integer corresponding to the external group ID to be linked.",
},
"group_name": {
Type: schema.TypeString,
Computed: true,
Description: "Name of the external group.",
},
"etag": {
Type: schema.TypeString,
Computed: true,
},
},
}
}

func resourceGithubEMUGroupMappingStateUpgradeV1(ctx context.Context, rawState map[string]any, meta any) (map[string]any, error) {
tflog.Trace(ctx, "GitHub EMU Group Mapping State before migration v1 => v2", map[string]any{"state": rawState})

oldResourceID, ok := rawState["id"].(string)
if !ok {
return nil, fmt.Errorf("id is not a string")
}
teamID, _, groupID, err := parseID3(oldResourceID)
if err != nil {
return nil, fmt.Errorf("could not parse ID: %w", err)
}
resourceID, err := buildID(groupID, teamID)
if err != nil {
return nil, fmt.Errorf("could not build ID: %w", err)
}
rawState["id"] = resourceID

tflog.Trace(ctx, "GitHub EMU Group Mapping State after migration", map[string]any{"state": rawState})
return rawState, nil
}
42 changes: 42 additions & 0 deletions github/resource_github_emu_group_mapping_migration_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package github

import (
"testing"

"github.com/google/go-cmp/cmp"
)

func Test_resourceGithubEMUGroupMappingStateUpgradeV1(t *testing.T) {
t.Parallel()

for _, d := range []struct {
testName string
rawState map[string]any
want map[string]any
shouldError bool
}{
{
testName: "migrates v1 to v2",
rawState: map[string]any{
"id": "123456:test-team:7765543",
},
want: map[string]any{
"id": "7765543:123456",
},
shouldError: false,
},
} {
t.Run(d.testName, func(t *testing.T) {
t.Parallel()

got, err := resourceGithubEMUGroupMappingStateUpgradeV1(t.Context(), d.rawState, nil)
if (err != nil) != d.shouldError {
t.Fatalf("unexpected error state")
}

if diff := cmp.Diff(got, d.want); !d.shouldError && diff != "" {
t.Fatalf("got %+v, want %+v: %s", got, d.want, diff)
}
})
}
}
Loading