Skip to content

Conversation

@stevehipwell
Copy link
Collaborator

Resolves #3049


Before the change?

After the change?

Pull request checklist

  • Schema migrations have been created if needed (example)
  • Tests for the changes have been added (for bug fixes / features)
  • Docs have been reviewed and added / updated if needed (for bug fixes / features)

Does this introduce a breaking change?

Please see our docs on breaking changes to help!

  • Yes
  • No

@stevehipwell stevehipwell added this to the v6.10.0 Release milestone Jan 9, 2026
@stevehipwell stevehipwell requested a review from nickfloyd January 9, 2026 20:16
@stevehipwell stevehipwell self-assigned this Jan 9, 2026
@stevehipwell stevehipwell added the Type: Bug Something isn't working as documented label Jan 9, 2026
@github-actions
Copy link

github-actions bot commented Jan 9, 2026

👋 Hi! Thank you for this contribution! Just to let you know, our GitHub SDK team does a round of issue and PR reviews twice a week, every Monday and Friday! We have a process in place for prioritizing and responding to your input. Because you are a part of this community please feel free to comment, add to, or pick up any issues/PRs that are labeled with Status: Up for grabs. You & others like you are the reason all of this works! So thank you & happy coding! 🚀

Copy link
Member

@nickfloyd nickfloyd left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I really like this approach vs what we have. I just had some thoughts to consider.

//
// To solve this, we must unset the values and allow Terraform to decide whether or
// not this resource should be modified or left as-is (ignore_changes).
if updatedAt, ok := d.GetOk("updated_at"); ok && updatedAt != secret.UpdatedAt.String() {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I belive this will be a breaking change due to ignore_changes - there will be forced recreations now. Not sure if we want a migration path for the users who rely on that or just mark it as a breaking change.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry, I'm not sure I follow how the new code would be breaking? The comment here is incorrect as this will always force new (note this resource doesn't have the destroy_on_drift input to suppress this behaviour).

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just looking into this further and it looks like this resource was relying on a lifecycle block to ignore changes. I've updated the docs to show this correctly being implemented on the new remote_updated_at field. I wouldn't consider a change to how meta arguments work a breaking change.

ReadContext: resourceGithubActionsEnvironmentSecretRead,
DeleteContext: resourceGithubActionsEnvironmentSecretDelete,

CustomizeDiff: func(ctx context.Context, diff *schema.ResourceDiff, m any) error {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I really like this approach. Any concerns around external changes to the resource forcing the destruction and recreation of the secret?

For instance...
Let's say a user config has:

resource "github_actions_environment_secret" "api_key" {
  ...
  plaintext_value = "secret-value-123"
  
  lifecycle {
    ignore_changes = [plaintext_value]
  }
}
  1. User runs terraform apply
  2. Other user updates the secret via UI
  3. User runs terraform apply

The old way the apply would detect no changes. This new approach updated_at and remote_updated_at would be different and therefore force a recreation.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AFAIK setting ignore_changes = [plaintext_value, updated_at, remote_updated_at] should resolve that

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IMHO this is a documentation issue, what @deiga added should be the correct solution. If it's not then we'd need to add in the explicit destroy_on_drift field that I'd planned on deprecating.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The correct setting is ignore_changes = [remote_updated_at] and there is now a test to validate this.

Comment on lines +77 to +79
var testAccProviders map[string]*schema.Provider = map[string]*schema.Provider{
"github": Provider(),
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AFAIK we should be getting rid of using testAccProviders the recommended approach is to only use ProviderFactories.

Could you mark this as deprecated?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've made the change to do this already (and stashed them), but I'm holding off adding them in to the PR until the actual changes have been reviewed.

ReadContext: resourceGithubActionsEnvironmentSecretRead,
DeleteContext: resourceGithubActionsEnvironmentSecretDelete,

CustomizeDiff: func(ctx context.Context, diff *schema.ResourceDiff, m any) error {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion: I think we should be able to forgo adding the remote_updated_at field as we could use customdiff.ForceNewIfChange (https://pkg.go.dev/github.com/hashicorp/terraform-plugin-sdk/v2/helper/customdiff#ForceNewIfChange) here

Something along the lines of:

CustomizeDiff: 
	customdiff.ForceNewIfChange(
		"updated_at", 
		func(ctx context.Context, oldValue, newValue, meta any) bool {
			remoteUpdatedAt := newValue
			if len(remoteUpdatedAt) == 0 {
				return false
			}

			updatedAt := oldValue
			if updatedAt != remoteUpdatedAt {

				if len(updatedAt) != 0 {
					return true
				}
			}

			return false
		}
)

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unfortunately you can't do this (I actually coded it up to make sure my mental model was correct). If we're doing drift detection we can't rely on a field updated in the read path as it will never have a change in the pan path. In this case update_at is only updated in read if it's not been able to be calculated as part of the create path, this contrasts with remote_updated_at which is always updated.

ReadContext: resourceGithubActionsEnvironmentSecretRead,
DeleteContext: resourceGithubActionsEnvironmentSecretDelete,

CustomizeDiff: func(ctx context.Context, diff *schema.ResourceDiff, m any) error {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AFAIK setting ignore_changes = [plaintext_value, updated_at, remote_updated_at] should resolve that

@stevehipwell
Copy link
Collaborator Author

I've updated the implementation to not require a recreate now that the diff is being handled correctly. I've also updated the pattern to correctly handle repo identity and support repo renames.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Type: Bug Something isn't working as documented

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[BUG]: Provider produced inconsistent result after apply (v6.9.1)

3 participants