integrations / integrations/terraform-provider-github

[MAINT]: Tracking issue to fully support repository renaming for resources with required repo name fields

Open
#3,180 2 comments 0 reactions 0 assignees View on GitHub
Type: Maintenance
Dominant language
Go
Stars
1.2k
Forks
1k
Avg merge
1d 14h
Merged PRs (30d)
8

Description

### Describe the need



This issue tracks adding full support for repository renaming across all resources that have a required repository (or similar) field. When a GitHub
repository is renamed, resources referencing the old name break on the next terraform plan/apply because the stored repository name in state no longer
matches the GitHub API.

## Why This Is Needed

When a repository is renamed (either via github_repository name change or externally through the GitHub UI/API), any dependent resource that stores the
repository name as part of its ID or state will:

1. Fail with a 404 on the next Read, causing Terraform to believe the resource was deleted
2. Force unnecessary recreation of resources that could otherwise survive a rename
3. Break terraform plan with confusing diffs showing the old vs new repository name

The provider already has a pattern for handling this — the diffRepository function in util_diff.go — but it is not yet applied to all affected resources ([see resources still needing migration](https://github.com/search?q=repo%3Aintegrations%2Fterraform-provider-github+path%3Agithub%2Fresource*.go+%22repository%22%3A+NOT+diffRepository+NOT+path%3A*_test.go+NOT+path%3A*_migration.go+NOT+path%3Agithub%2Fresource_github_repository.go&type=code)).

### Existing Pattern

The diffRepository function (util_diff.go) handles renames by:

1. Storing a repository_id (numeric) alongside the repository name
2. On CustomizeDiff, checking if the repository name changed
3. Looking up the new name via the API and comparing numeric IDs
4. Only forcing a new resource if the actual repository changed (different ID), not just the name

#### Resources Already Using diffRepository

- github_actions_secret
- github_actions_variable
- github_actions_environment_secret
- github_actions_environment_variable
- github_dependabot_secret
- github_repository_file
- github_repository_collaborators
- github_repository_environment
- github_repository_environment_deployment_policy
- github_repository_vulnerability_alerts
- github_repository_pages

### Before (current — breaks on rename)
```
func resourceGithubExample() *schema.Resource {
return &schema.Resource{
// ...
Schema: map[string]*schema.Schema{
"repository": {
Type: schema.TypeString,
Required: true,
ForceNew: true, // Forces recreation on ANY name change
},
},
}
}

func resourceGithubExampleRead(ctx context.Context, d *schema.ResourceData, meta any) diag.Diagnostics {
repoName := d.Get("repository").(string)
// Uses old name from state → 404 if renamed
}
```
### After (target — survives rename)
```
func resourceGithubExample() *schema.Resource {
return &schema.Resource{
// ...
CustomizeDiffFunc: customdiff.Sequence(
diffRepository,
),
Schema: map[string]*schema.Schema{
"repository": {
Type: schema.TypeString,
Required: true,
},
"repository_id": {
Type: schema.TypeInt,
Computed: true,
},
},
}
}

func resourceGithubExampleRead(ctx context.Context, d *schema.ResourceData, meta any) diag.Diagnostics {
repoName := d.Get("repository").(string)
// Fetch from API, then update state with current name
_ = d.Set("repository", repo.GetName())
_ = d.Set("repository_id", repo.GetID())
}
```
## Related Issues

- #2996 — [MAINT] Migrate all resources and data sources to Context-aware CRUD functions
- #3070 — [MAINT] Tracking issue for refactoring logging to use tflog
- #2925 — [MAINT] Update transport implementation

Note: These migrations can be paired — when touching a resource to add rename support, also migrate to Context-aware CRUD functions (#2996) and tflog
(#3070) in the same PR.

## Migration Checklist

### Resources Needing diffRepository Support (26 files)

#### Branch

- [ ] resource_github_branch.go — github_branch (field: repository)
- [ ] resource_github_branch_default.go — github_branch_default (field: repository)
- [ ] resource_github_branch_protection.go — github_branch_protection (field: repository_id)
- [ ] resource_github_branch_protection_v3.go — github_branch_protection_v3 (field: repository)

#### Repository

- [ ] resource_github_repository_collaborator.go — github_repository_collaborator (field: repository)
- [ ] resource_github_repository_custom_property.go — github_repository_custom_property (field: repository)
- [ ] resource_github_repository_dependabot_security_updates.go — github_repository_dependabot_security_updates (field: repository)
- [ ] resource_github_repository_deploy_key.go — github_repository_deploy_key (field: repository)
- [ ] resource_github_repository_deployment_branch_policy.go — github_repository_deployment_branch_policy (field: repository)
- [ ] resource_github_repository_milestone.go — github_repository_milestone (field: repository)
- [ ] resource_github_repository_project.go — github_repository_project (field: repository, deprecated)
- [ ] resource_github_repository_pull_request.go — github_repository_pull_request (field: base_repository)
- [ ] resource_github_repository_ruleset.go — github_repository_ruleset (field: repository)
- [ ] resource_github_repository_topics.go — github_repository_topics (field: repository)
- [ ] resource_github_repository_webhook.go — github_repository_webhook (field: repository)

#### Actions

- [ ] resource_github_actions_repository_oidc_subject_claim_customization_template.go — github_actions_repository_oidc_subject_claim_customization_template (field: repository)
- [ ] resource_github_actions_repository_permissions.go — github_actions_repository_permissions (field: repository)
- [ ] resource_github_workflow_repository_permissions.go — github_workflow_repository_permissions (field: repository)

#### Codespaces

- [ ] resource_github_codespaces_secret.go — github_codespaces_secret (field: repository)

#### Issues

- [ ] resource_github_issue.go — github_issue (field: repository)
- [ ] resource_github_issue_label.go — github_issue_label (field: repository)
- [ ] resource_github_issue_labels.go — github_issue_labels (field: repository)

#### Other

- [ ] resource_github_app_installation_repository.go — github_app_installation_repository (field: repository)
- [ ] resource_github_release.go — github_release (field: repository)
- [ ] resource_github_team_repository.go — github_team_repository (field: repository)

#### Already Handled (11 files)

- [x] resource_github_actions_secret.go — github_actions_secret
- [x] resource_github_actions_variable.go — github_actions_variable
- [x] resource_github_actions_environment_secret.go — github_actions_environment_secret
- [x] resource_github_actions_environment_variable.go — github_actions_environment_variable
- [x] resource_github_dependabot_secret.go — github_dependabot_secret
- [x] resource_github_repository_file.go — github_repository_file
- [x] resource_github_repository_collaborators.go — github_repository_collaborators
- [x] resource_github_repository_environment.go — github_repository_environment
- [x] resource_github_repository_environment_deployment_policy.go — github_repository_environment_deployment_policy
- [x] resource_github_repository_vulnerability_alerts.go — github_repository_vulnerability_alerts
- [x] resource_github_repository_pages.go — github_repository_pages

#### Known Test Workarounds to Clean Up

- resource_github_actions_environment_secret_test.go — Remove lifecycle { ignore_changes = all } workaround
- resource_github_actions_environment_variable_test.go — Remove lifecycle { ignore_changes = all } workaround

### Suggested Approach

1. Use diffRepository as the standard pattern: Apply the existing util_diff.go pattern to each resource
2. Add repository_id as a Computed field: Store the numeric repository ID alongside the name for rename detection
3. Update Read functions: Set repository and repository_id from the API response so state stays current
4. Remove ForceNew from repository fields: Where present, replace with diffRepository so renames don't force recreation
5. Add acceptance tests: Follow the update_renamed_repo test pattern from resource_github_actions_secret_test.go
6. Bump SchemaVersion: Add a StateUpgrader to populate repository_id for existing state
7. Pair with other migrations: When touching a file, also migrate to Context-aware CRUD (#2996) and tflog (#3070)

### Special Cases

- github_branch_protection: Already uses repository_id as a required field (node ID format), but the rename semantics differ from the diffRepository
pattern — needs separate investigation
- github_repository_project: Deprecated resource — may not be worth migrating
- github_repository_pull_request: Uses base_repository instead of repository — diffRepository may need a variant or the field name standardized

## References

- github/util_diff.go — Existing diffRepository implementation
- github/resource_github_actions_secret.go — Reference implementation using diffRepository
- github/resource_github_actions_secret_test.go — Reference test with update_renamed_repo case
- https://developer.hashicorp.com/terraform/plugin/sdkv2/resources/customizing-differences
- https://docs.github.com/en/rest/repos/repos — Rename is a PATCH to the repository endpoint

## Contributing

Each resource can be migrated independently. When contributing:

1. Pick a resource from the checklist above
2. Add a repository_id Computed field to the schema
3. Add CustomizeDiffFunc: customdiff.Sequence(diffRepository) (or append to existing sequence)
4. Remove ForceNew: true from the repository field if present
5. Update the Read function to set repository and repository_id from API response
6. Add a StateUpgrader to populate repository_id for existing state
7. Add an update_renamed_repo acceptance test
8. Run make build && make lint to verify
9. Submit a PR referencing this issue

### SDK Version

_No response_

### API Version

_No response_

### Relevant log output

```shell

```

### Code of Conduct

- [x] I agree to follow this project's Code of Conduct

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.