Skip to content

Commit eadd7e4

Browse files
committed
refactor(runner_group): selected_workflows set
Change `selected_workflows` from `TypeList` to `TypeSet` in both `github_actions_runner_group` and `github_enterprise_actions_runner_group` resources. A `TypeList` is order-sensitive, causing Terraform to detect spurious drift when the GitHub API returns workflows in a different order than specified in configuration. A `TypeSet` compares elements regardless of order, eliminating the persistent plan diff. Fix #3478.
1 parent cd39775 commit eadd7e4

7 files changed

Lines changed: 221 additions & 17 deletions

‎docs/resources/actions_runner_group.md‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ The following arguments are supported:
2929
- `name` - (Required) Name of the runner group
3030
- `restricted_to_workflows` - (Optional) If true, the runner group will be restricted to running only the workflows specified in the selected_workflows array. Defaults to false.
3131
- `selected_repository_ids` - (Optional) IDs of the repositories which should be added to the runner group
32-
- `selected_workflows` - (Optional) List of workflows the runner group should be allowed to run. This setting will be ignored unless restricted_to_workflows is set to true.
32+
- `selected_workflows` - (Optional) Set of workflows the runner group should be allowed to run. The order of items is not significant. This setting will be ignored unless restricted_to_workflows is set to true.
3333
- `visibility` - (Optional) Visibility of a runner group. Whether the runner group can include `all`, `selected`, or `private` repositories. A value of `private` is not currently supported due to limitations in the GitHub API.
3434
- `allows_public_repositories` - (Optional) Whether public repositories can be added to the runner group. Defaults to false.
3535

@@ -44,7 +44,7 @@ The following arguments are supported:
4444
- `selected_repositories_url` - GitHub API URL for the runner group's repositories
4545
- `visibility` - The visibility of the runner group
4646
- `restricted_to_workflows` - If true, the runner group will be restricted to running only the workflows specified in the selected_workflows array. Defaults to false.
47-
- `selected_workflows` - List of workflows the runner group should be allowed to run. This setting will be ignored unless restricted_to_workflows is set to true.
47+
- `selected_workflows` - Set of workflows the runner group should be allowed to run. The order of items is not significant. This setting will be ignored unless restricted_to_workflows is set to true.
4848

4949
## Import
5050

‎docs/resources/enterprise_actions_runner_group.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ The following arguments are supported:
4343
- `selected_organization_ids` - (Optional) IDs of the organizations which should be added to the runner group
4444
- `allows_public_repositories` - (Optional) Whether public repositories can be added to the runner group. Defaults to false.
4545
- `restricted_to_workflows` - (Optional) If true, the runner group will be restricted to running only the workflows specified in the selected_workflows array. Defaults to false.
46-
- `selected_workflows` - (Optional) List of workflows the runner group should be allowed to run. This setting will be ignored unless restricted_to_workflows is set to true.
46+
- `selected_workflows` - (Optional) Set of workflows the runner group should be allowed to run. The order of items is not significant. This setting will be ignored unless restricted_to_workflows is set to true.
4747

4848
## Attributes Reference
4949

‎github/resource_github_actions_runner_group.go‎

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,15 @@ func resourceGithubActionsRunnerGroup() *schema.Resource {
2323
StateContext: schema.ImportStatePassthroughContext,
2424
},
2525

26+
SchemaVersion: 1,
27+
StateUpgraders: []schema.StateUpgrader{
28+
{
29+
Type: resourceGithubActionsRunnerGroupV0().CoreConfigSchema().ImpliedType(),
30+
Upgrade: resourceGithubActionsRunnerGroupStateUpgradeV0,
31+
Version: 0,
32+
},
33+
},
34+
2635
Schema: map[string]*schema.Schema{
2736
"id": {
2837
Type: schema.TypeString,
@@ -87,7 +96,7 @@ func resourceGithubActionsRunnerGroup() *schema.Resource {
8796
Description: "If 'true', the runner group will be restricted to running only the workflows specified in the 'selected_workflows' array. Defaults to 'false'.",
8897
},
8998
"selected_workflows": {
90-
Type: schema.TypeList,
99+
Type: schema.TypeSet,
91100
Elem: &schema.Schema{Type: schema.TypeString},
92101
Optional: true,
93102
Description: "List of workflows the runner group should be allowed to run. This setting will be ignored unless restricted_to_workflows is set to 'true'.",
@@ -112,7 +121,7 @@ func resourceGithubActionsRunnerGroupCreate(d *schema.ResourceData, meta any) er
112121

113122
selectedWorkflows := []string{}
114123
if workflows, ok := d.GetOk("selected_workflows"); ok {
115-
for _, workflow := range workflows.([]any) {
124+
for _, workflow := range workflows.(*schema.Set).List() {
116125
selectedWorkflows = append(selectedWorkflows, workflow.(string))
117126
}
118127
}
@@ -316,7 +325,7 @@ func resourceGithubActionsRunnerGroupUpdate(d *schema.ResourceData, meta any) er
316325
selectedWorkflows := []string{}
317326
allowsPublicRepositories := d.Get("allows_public_repositories").(bool)
318327
if workflows, ok := d.GetOk("selected_workflows"); ok {
319-
for _, workflow := range workflows.([]any) {
328+
for _, workflow := range workflows.(*schema.Set).List() {
320329
selectedWorkflows = append(selectedWorkflows, workflow.(string))
321330
}
322331
}
Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
package github
2+
3+
import (
4+
"context"
5+
"log"
6+
7+
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
8+
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation"
9+
)
10+
11+
func resourceGithubActionsRunnerGroupV0() *schema.Resource {
12+
return &schema.Resource{
13+
SchemaVersion: 0,
14+
15+
Schema: map[string]*schema.Schema{
16+
"id": {
17+
Type: schema.TypeString,
18+
Computed: true,
19+
Description: "The ID of the runner group.",
20+
},
21+
"allows_public_repositories": {
22+
Type: schema.TypeBool,
23+
Optional: true,
24+
Default: false,
25+
Description: "Whether public repositories can be added to the runner group.",
26+
},
27+
"default": {
28+
Type: schema.TypeBool,
29+
Computed: true,
30+
Description: "Whether this is the default runner group.",
31+
},
32+
"etag": {
33+
Type: schema.TypeString,
34+
Computed: true,
35+
Description: "An etag representing the runner group object",
36+
},
37+
"inherited": {
38+
Type: schema.TypeBool,
39+
Computed: true,
40+
Description: "Whether the runner group is inherited from the enterprise level",
41+
},
42+
"name": {
43+
Type: schema.TypeString,
44+
Required: true,
45+
Description: "Name of the runner group.",
46+
},
47+
"runners_url": {
48+
Type: schema.TypeString,
49+
Computed: true,
50+
Description: "The GitHub API URL for the runner group's runners.",
51+
},
52+
"selected_repository_ids": {
53+
Type: schema.TypeSet,
54+
Elem: &schema.Schema{
55+
Type: schema.TypeInt,
56+
},
57+
Set: schema.HashInt,
58+
Optional: true,
59+
Description: "List of repository IDs that can access the runner group.",
60+
},
61+
"selected_repositories_url": {
62+
Type: schema.TypeString,
63+
Computed: true,
64+
Description: "GitHub API URL for the runner group's repositories.",
65+
},
66+
"visibility": {
67+
Type: schema.TypeString,
68+
Required: true,
69+
Description: "The visibility of the runner group.",
70+
ValidateDiagFunc: validation.ToDiagFunc(validation.StringInSlice([]string{"all", "selected", "private"}, false)),
71+
},
72+
"restricted_to_workflows": {
73+
Type: schema.TypeBool,
74+
Optional: true,
75+
Default: false,
76+
Description: "If 'true', the runner group will be restricted to running only the workflows specified in the 'selected_workflows' array. Defaults to 'false'.",
77+
},
78+
"selected_workflows": {
79+
Type: schema.TypeList,
80+
Elem: &schema.Schema{Type: schema.TypeString},
81+
Optional: true,
82+
Description: "List of workflows the runner group should be allowed to run. This setting will be ignored unless restricted_to_workflows is set to 'true'.",
83+
},
84+
},
85+
}
86+
}
87+
88+
func resourceGithubActionsRunnerGroupStateUpgradeV0(_ context.Context, rawState map[string]any, _ any) (map[string]any, error) {
89+
log.Printf("[DEBUG] GitHub Actions Runner Group Attributes before migration: %#v", rawState)
90+
91+
// No transformation needed. The SDK re-encodes selected_workflows from
92+
// TypeList (index-based keys) to TypeSet (hash-based keys) automatically
93+
// when it persists the state with the new schema version.
94+
95+
log.Printf("[DEBUG] GitHub Actions Runner Group Attributes after migration: %#v", rawState)
96+
97+
return rawState, nil
98+
}

‎github/resource_github_actions_runner_group_test.go‎

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -68,16 +68,11 @@ func TestAccGithubActionsRunnerGroup(t *testing.T) {
6868
githubRepository := state.RootModule().Resources["github_repository.test"].Primary
6969
fullName := githubRepository.Attributes["full_name"]
7070

71-
runnerGroup := state.RootModule().Resources["github_actions_runner_group.test"].Primary
72-
workflowActual := runnerGroup.Attributes["selected_workflows.0"]
73-
7471
workflowExpected := fmt.Sprintf("%s/.github/workflows/test.yml@refs/heads/main", fullName)
7572

76-
if workflowActual != workflowExpected {
77-
return fmt.Errorf("actual selected workflows %s not the same as expected selected workflows %s",
78-
workflowActual, workflowExpected)
79-
}
80-
return nil
73+
return resource.TestCheckTypeSetElemAttr(
74+
"github_actions_runner_group.test", "selected_workflows.*", workflowExpected,
75+
)(state)
8176
},
8277
resource.TestCheckResourceAttr(
8378
"github_actions_runner_group.test", "allows_public_repositories",

‎github/resource_github_enterprise_actions_runner_group.go‎

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,15 @@ func resourceGithubActionsEnterpriseRunnerGroup() *schema.Resource {
2424
State: resourceGithubActionsEnterpriseRunnerGroupImport,
2525
},
2626

27+
SchemaVersion: 1,
28+
StateUpgraders: []schema.StateUpgrader{
29+
{
30+
Type: resourceGithubActionsEnterpriseRunnerGroupV0().CoreConfigSchema().ImpliedType(),
31+
Upgrade: resourceGithubActionsEnterpriseRunnerGroupStateUpgradeV0,
32+
Version: 0,
33+
},
34+
},
35+
2736
Schema: map[string]*schema.Schema{
2837
"enterprise_slug": {
2938
Type: schema.TypeString,
@@ -69,7 +78,7 @@ func resourceGithubActionsEnterpriseRunnerGroup() *schema.Resource {
6978
Description: "If 'true', the runner group will be restricted to running only the workflows specified in the 'selected_workflows' array. Defaults to 'false'.",
7079
},
7180
"selected_workflows": {
72-
Type: schema.TypeList,
81+
Type: schema.TypeSet,
7382
Elem: &schema.Schema{Type: schema.TypeString},
7483
Optional: true,
7584
Description: "List of workflows the runner group should be allowed to run. This setting will be ignored unless restricted_to_workflows is set to 'true'.",
@@ -104,7 +113,7 @@ func resourceGithubActionsEnterpriseRunnerGroupCreate(d *schema.ResourceData, me
104113

105114
selectedWorkflows := []string{}
106115
if workflows, ok := d.GetOk("selected_workflows"); ok {
107-
for _, workflow := range workflows.([]any) {
116+
for _, workflow := range workflows.(*schema.Set).List() {
108117
selectedWorkflows = append(selectedWorkflows, workflow.(string))
109118
}
110119
}
@@ -291,7 +300,7 @@ func resourceGithubActionsEnterpriseRunnerGroupUpdate(d *schema.ResourceData, me
291300
selectedWorkflows := []string{}
292301
allowsPublicRepositories := d.Get("allows_public_repositories").(bool)
293302
if workflows, ok := d.GetOk("selected_workflows"); ok {
294-
for _, workflow := range workflows.([]any) {
303+
for _, workflow := range workflows.(*schema.Set).List() {
295304
selectedWorkflows = append(selectedWorkflows, workflow.(string))
296305
}
297306
}
Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
package github
2+
3+
import (
4+
"context"
5+
"log"
6+
7+
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
8+
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation"
9+
)
10+
11+
func resourceGithubActionsEnterpriseRunnerGroupV0() *schema.Resource {
12+
return &schema.Resource{
13+
SchemaVersion: 0,
14+
15+
Schema: map[string]*schema.Schema{
16+
"enterprise_slug": {
17+
Type: schema.TypeString,
18+
Required: true,
19+
Description: "The slug of the enterprise.",
20+
},
21+
"allows_public_repositories": {
22+
Type: schema.TypeBool,
23+
Optional: true,
24+
Default: false,
25+
Description: "Whether public repositories can be added to the runner group.",
26+
},
27+
"default": {
28+
Type: schema.TypeBool,
29+
Computed: true,
30+
Description: "Whether this is the default runner group.",
31+
},
32+
"etag": {
33+
Type: schema.TypeString,
34+
Computed: true,
35+
Description: "An etag representing the runner group object",
36+
},
37+
"name": {
38+
Type: schema.TypeString,
39+
Required: true,
40+
Description: "Name of the runner group.",
41+
},
42+
"runners_url": {
43+
Type: schema.TypeString,
44+
Computed: true,
45+
Description: "The GitHub API URL for the runner group's runners.",
46+
},
47+
"visibility": {
48+
Type: schema.TypeString,
49+
Required: true,
50+
Description: "The visibility of the runner group.",
51+
ValidateDiagFunc: validation.ToDiagFunc(validation.StringInSlice([]string{"all", "selected"}, false)),
52+
},
53+
"restricted_to_workflows": {
54+
Type: schema.TypeBool,
55+
Optional: true,
56+
Default: false,
57+
Description: "If 'true', the runner group will be restricted to running only the workflows specified in the 'selected_workflows' array. Defaults to 'false'.",
58+
},
59+
"selected_workflows": {
60+
Type: schema.TypeList,
61+
Elem: &schema.Schema{Type: schema.TypeString},
62+
Optional: true,
63+
Description: "List of workflows the runner group should be allowed to run. This setting will be ignored unless restricted_to_workflows is set to 'true'.",
64+
},
65+
"selected_organization_ids": {
66+
Type: schema.TypeSet,
67+
Elem: &schema.Schema{
68+
Type: schema.TypeInt,
69+
},
70+
Set: schema.HashInt,
71+
Optional: true,
72+
Description: "List of organization IDs that can access the runner group.",
73+
},
74+
"selected_organizations_url": {
75+
Type: schema.TypeString,
76+
Computed: true,
77+
Description: "GitHub API URL for the runner group's organizations.",
78+
},
79+
},
80+
}
81+
}
82+
83+
func resourceGithubActionsEnterpriseRunnerGroupStateUpgradeV0(_ context.Context, rawState map[string]any, _ any) (map[string]any, error) {
84+
log.Printf("[DEBUG] GitHub Enterprise Actions Runner Group Attributes before migration: %#v", rawState)
85+
86+
// No transformation needed. The SDK re-encodes selected_workflows from
87+
// TypeList (index-based keys) to TypeSet (hash-based keys) automatically
88+
// when it persists the state with the new schema version.
89+
90+
log.Printf("[DEBUG] GitHub Enterprise Actions Runner Group Attributes after migration: %#v", rawState)
91+
92+
return rawState, nil
93+
}

0 commit comments

Comments
 (0)