@@ -740,14 +740,6 @@ func resourceGithubRepositoryCreate(ctx context.Context, d *schema.ResourceData,
740740
741741 tflog .Info (ctx , "Fork created" , map [string ]any {"name" : fork .GetName ()})
742742 d .SetId (fork .GetName ())
743- tflog .Debug (ctx , "Set resource ID to just the name" , map [string ]any {"resource_id" : d .Id ()})
744-
745- _ = d .Set ("name" , fork .GetName ())
746- _ = d .Set ("full_name" , fork .GetFullName ()) // Add the full name for reference
747- _ = d .Set ("html_url" , fork .GetHTMLURL ())
748- _ = d .Set ("ssh_clone_url" , fork .GetSSHURL ())
749- _ = d .Set ("git_clone_url" , fork .GetGitURL ())
750- _ = d .Set ("http_clone_url" , fork .GetCloneURL ())
751743 } else {
752744 // Create without a repository template
753745 var repo * github.Repository
@@ -780,7 +772,56 @@ func resourceGithubRepositoryCreate(ctx context.Context, d *schema.ResourceData,
780772 }
781773 }
782774
783- return resourceGithubRepositoryUpdate (ctx , d , meta )
775+ // handle visibility updates separately from other fields
776+ visibility := repoReq .GetVisibility ()
777+ repoReq .Visibility = nil
778+
779+ // This change needs to be made with the correct visibility
780+ allowForking := repoReq .AllowForking
781+ if d .HasChanges ("visibility" , "private" ) {
782+ repoReq .AllowForking = nil
783+ }
784+
785+ if ! d .HasChange ("security_and_analysis" ) {
786+ repoReq .SecurityAndAnalysis = nil
787+ }
788+
789+ _ , _ , err := client .Repositories .Edit (ctx , owner , repoName , repoReq )
790+ if err != nil {
791+ return diag .FromErr (err )
792+ }
793+
794+ if v , ok := d .GetOkExists ("vulnerability_alerts" ); ok { //nolint:staticcheck // SA1019 // We sometimes need to use GetOkExists for booleans
795+ if val , ok := v .(bool ); ok {
796+ if err := updateVulnerabilityAlerts (ctx , client , owner , repoName , val ); err != nil {
797+ return diag .FromErr (err )
798+ }
799+ }
800+ }
801+
802+ if d .HasChanges ("visibility" , "private" ) {
803+ repoReq .Visibility = new (visibility )
804+ repoReq .AllowForking = allowForking
805+
806+ _ , resp , err := client .Repositories .Edit (ctx , owner , repoName , repoReq )
807+ if err != nil {
808+ if resp .StatusCode != 422 || ! strings .Contains (err .Error (), fmt .Sprintf ("Visibility is already %s" , visibility )) {
809+ return diag .FromErr (err )
810+ }
811+ }
812+ }
813+
814+ // Fetch final repo state after all mutations and set Computed fields
815+ finalRepo , _ , err := client .Repositories .Get (ctx , owner , d .Id ())
816+ if err != nil {
817+ return diag .FromErr (err )
818+ }
819+
820+ if diags := setRepositoryFieldsFromRepo (ctx , d , client , owner , finalRepo ); diags .HasError () {
821+ return diags
822+ }
823+
824+ return nil
784825}
785826
786827func resourceGithubRepositoryRead (ctx context.Context , d * schema.ResourceData , meta any ) diag.Diagnostics {
@@ -795,7 +836,6 @@ func resourceGithubRepositoryRead(ctx context.Context, d *schema.ResourceData, m
795836 owner = explicitOwner
796837 }
797838
798- ctx = context .WithValue (ctx , ctxId , d .Id ())
799839 if ! d .IsNewResource () {
800840 ctx = context .WithValue (ctx , ctxEtag , d .Get ("etag" ).(string ))
801841 }
@@ -816,100 +856,12 @@ func resourceGithubRepositoryRead(ctx context.Context, d *schema.ResourceData, m
816856 return diag .FromErr (err )
817857 }
818858
819- _ = d .Set ("etag" , resp .Header .Get ("ETag" ))
820- _ = d .Set ("name" , repoName )
821- _ = d .Set ("description" , repo .GetDescription ())
822- _ = d .Set ("primary_language" , repo .GetLanguage ())
823- _ = d .Set ("homepage_url" , repo .GetHomepage ())
824- _ = d .Set ("private" , repo .GetPrivate ())
825- _ = d .Set ("visibility" , repo .GetVisibility ())
826- _ = d .Set ("has_issues" , repo .GetHasIssues ())
827- _ = d .Set ("has_discussions" , repo .GetHasDiscussions ())
828- _ = d .Set ("has_projects" , repo .GetHasProjects ())
829- _ = d .Set ("has_wiki" , repo .GetHasWiki ())
830- _ = d .Set ("is_template" , repo .GetIsTemplate ())
831- _ = d .Set ("full_name" , repo .GetFullName ())
832- _ = d .Set ("default_branch" , repo .GetDefaultBranch ())
833- _ = d .Set ("html_url" , repo .GetHTMLURL ())
834- _ = d .Set ("ssh_clone_url" , repo .GetSSHURL ())
835- _ = d .Set ("svn_url" , repo .GetSVNURL ())
836- _ = d .Set ("git_clone_url" , repo .GetGitURL ())
837- _ = d .Set ("http_clone_url" , repo .GetCloneURL ())
838- _ = d .Set ("archived" , repo .GetArchived ())
839- _ = d .Set ("topics" , flattenStringList (repo .Topics ))
840- _ = d .Set ("node_id" , repo .GetNodeID ())
841- _ = d .Set ("repo_id" , repo .GetID ())
842-
843- if err := errors .Join (
844- d .Set ("allow_auto_merge" , repo .GetAllowAutoMerge ()),
845- d .Set ("allow_merge_commit" , repo .GetAllowMergeCommit ()),
846- d .Set ("allow_rebase_merge" , repo .GetAllowRebaseMerge ()),
847- d .Set ("allow_squash_merge" , repo .GetAllowSquashMerge ()),
848- d .Set ("allow_update_branch" , repo .GetAllowUpdateBranch ()),
849- d .Set ("allow_forking" , repo .GetAllowForking ()),
850- d .Set ("delete_branch_on_merge" , repo .GetDeleteBranchOnMerge ()),
851- d .Set ("web_commit_signoff_required" , repo .GetWebCommitSignoffRequired ()),
852- d .Set ("has_downloads" , repo .GetHasDownloads ()),
853- d .Set ("merge_commit_message" , repo .GetMergeCommitMessage ()),
854- d .Set ("merge_commit_title" , repo .GetMergeCommitTitle ()),
855- d .Set ("squash_merge_commit_message" , repo .GetSquashMergeCommitMessage ()),
856- d .Set ("squash_merge_commit_title" , repo .GetSquashMergeCommitTitle ()),
857- ); err != nil {
858- tflog .Warn (ctx , "Error setting repository fields, which were previously ignored for archived repositories" , map [string ]any {"error" : err .Error ()})
859- }
860-
861- if repo .GetHasPages () {
862- pages , _ , err := client .Repositories .GetPagesInfo (ctx , owner , repoName )
863- if err != nil {
864- return diag .FromErr (err )
865- }
866- if err := d .Set ("pages" , flattenPages (pages )); err != nil {
867- return diag .Errorf ("error setting pages: %s" , err .Error ())
868- }
869- }
870-
871- // Set fork information if this is a fork
872- if repo .GetFork () {
873- _ = d .Set ("fork" , "true" )
874-
875- // If the repository has parent information, set the source details
876- if repo .Parent != nil {
877- _ = d .Set ("source_owner" , repo .Parent .GetOwner ().GetLogin ())
878- _ = d .Set ("source_repo" , repo .Parent .GetName ())
879- }
880- } else {
881- _ = d .Set ("fork" , "false" )
882- _ = d .Set ("source_owner" , "" )
883- _ = d .Set ("source_repo" , "" )
884- }
885-
886- if repo .TemplateRepository != nil {
887- if err = d .Set ("template" , []any {
888- map [string ]any {
889- "owner" : repo .TemplateRepository .Owner .Login ,
890- "repository" : repo .TemplateRepository .Name ,
891- },
892- }); err != nil {
893- return diag .FromErr (err )
894- }
895- } else {
896- if err = d .Set ("template" , []any {}); err != nil {
897- return diag .FromErr (err )
898- }
859+ if err := d .Set ("etag" , resp .Header .Get ("ETag" )); err != nil {
860+ return diag .FromErr (err )
899861 }
900862
901- if repo .GetSecurityAndAnalysis () != nil {
902- vulnerabilityAlerts , _ , err := client .Repositories .GetVulnerabilityAlerts (ctx , owner , repoName )
903- if err != nil {
904- return diag .Errorf ("error reading repository vulnerability alerts: %s" , err .Error ())
905- }
906- if err = d .Set ("vulnerability_alerts" , vulnerabilityAlerts ); err != nil {
907- return diag .FromErr (err )
908- }
909-
910- if err = d .Set ("security_and_analysis" , flattenSecurityAndAnalysis (repo .SecurityAndAnalysis )); err != nil {
911- return diag .FromErr (err )
912- }
863+ if diags := setRepositoryFieldsFromRepo (ctx , d , client , owner , repo ); diags .HasError () {
864+ return diags
913865 }
914866
915867 return nil
@@ -952,7 +904,6 @@ func resourceGithubRepositoryUpdate(ctx context.Context, d *schema.ResourceData,
952904
953905 repoName := d .Id ()
954906 owner := meta .(* Owner ).name
955- ctx = context .WithValue (ctx , ctxId , d .Id ())
956907
957908 repo , _ , err := client .Repositories .Edit (ctx , owner , repoName , repoReq )
958909 if err != nil {
@@ -1009,22 +960,26 @@ func resourceGithubRepositoryUpdate(ctx context.Context, d *schema.ResourceData,
1009960 repoReq .AllowForking = allowForking
1010961
1011962 tflog .Debug (ctx , "Updating repository visibility" , map [string ]any {"from" : repo .GetVisibility (), "to" : visibility })
1012- _ , resp , err := client .Repositories .Edit (ctx , owner , repoName , repoReq )
963+ updatedRepo , resp , err := client .Repositories .Edit (ctx , owner , repoName , repoReq )
1013964 if err != nil {
1014965 if resp .StatusCode != 422 || ! strings .Contains (err .Error (), fmt .Sprintf ("Visibility is already %s" , visibility )) {
1015966 return diag .FromErr (err )
1016967 }
1017968 }
969+ repo = updatedRepo
970+ }
971+
972+ if diags := setRepositoryFieldsFromRepo (ctx , d , client , owner , repo ); diags .HasError () {
973+ return diags
1018974 }
1019975
1020- return resourceGithubRepositoryRead ( ctx , d , meta )
976+ return nil
1021977}
1022978
1023979func resourceGithubRepositoryDelete (ctx context.Context , d * schema.ResourceData , meta any ) diag.Diagnostics {
1024980 client := meta .(* Owner ).v3client
1025981 repoName := d .Id ()
1026982 owner := meta .(* Owner ).name
1027- ctx = context .WithValue (ctx , ctxId , d .Id ())
1028983
1029984 archiveOnDestroy := d .Get ("archive_on_destroy" ).(bool )
1030985 if archiveOnDestroy {
@@ -1054,6 +1009,120 @@ func resourceGithubRepositoryImport(ctx context.Context, d *schema.ResourceData,
10541009 return []* schema.ResourceData {d }, nil
10551010}
10561011
1012+ // setRepositoryFieldsFromRepo populates all Computed and Optional+Computed schema fields
1013+ // from a *github.Repository API response. Used by Create and Update to set state directly
1014+ // instead of chaining to Read. For fields requiring separate API calls (pages, vulnerability
1015+ // alerts), targeted calls are made here.
1016+ func setRepositoryFieldsFromRepo (ctx context.Context , d * schema.ResourceData , client * github.Client , owner string , repo * github.Repository ) diag.Diagnostics {
1017+ repoName := repo .GetName ()
1018+
1019+ if err := errors .Join (
1020+ d .Set ("name" , repoName ),
1021+ d .Set ("description" , repo .GetDescription ()),
1022+ d .Set ("primary_language" , repo .GetLanguage ()),
1023+ d .Set ("homepage_url" , repo .GetHomepage ()),
1024+ d .Set ("private" , repo .GetPrivate ()),
1025+ d .Set ("visibility" , repo .GetVisibility ()),
1026+ d .Set ("has_issues" , repo .GetHasIssues ()),
1027+ d .Set ("has_discussions" , repo .GetHasDiscussions ()),
1028+ d .Set ("has_projects" , repo .GetHasProjects ()),
1029+ d .Set ("has_wiki" , repo .GetHasWiki ()),
1030+ d .Set ("is_template" , repo .GetIsTemplate ()),
1031+ d .Set ("full_name" , repo .GetFullName ()),
1032+ d .Set ("default_branch" , repo .GetDefaultBranch ()),
1033+ d .Set ("html_url" , repo .GetHTMLURL ()),
1034+ d .Set ("ssh_clone_url" , repo .GetSSHURL ()),
1035+ d .Set ("svn_url" , repo .GetSVNURL ()),
1036+ d .Set ("git_clone_url" , repo .GetGitURL ()),
1037+ d .Set ("http_clone_url" , repo .GetCloneURL ()),
1038+ d .Set ("archived" , repo .GetArchived ()),
1039+ d .Set ("topics" , flattenStringList (repo .Topics )),
1040+ d .Set ("node_id" , repo .GetNodeID ()),
1041+ d .Set ("repo_id" , repo .GetID ()),
1042+ d .Set ("allow_auto_merge" , repo .GetAllowAutoMerge ()),
1043+ d .Set ("allow_merge_commit" , repo .GetAllowMergeCommit ()),
1044+ d .Set ("allow_rebase_merge" , repo .GetAllowRebaseMerge ()),
1045+ d .Set ("allow_squash_merge" , repo .GetAllowSquashMerge ()),
1046+ d .Set ("allow_update_branch" , repo .GetAllowUpdateBranch ()),
1047+ d .Set ("allow_forking" , repo .GetAllowForking ()),
1048+ d .Set ("delete_branch_on_merge" , repo .GetDeleteBranchOnMerge ()),
1049+ d .Set ("web_commit_signoff_required" , repo .GetWebCommitSignoffRequired ()),
1050+ d .Set ("has_downloads" , repo .GetHasDownloads ()),
1051+ d .Set ("merge_commit_message" , repo .GetMergeCommitMessage ()),
1052+ d .Set ("merge_commit_title" , repo .GetMergeCommitTitle ()),
1053+ d .Set ("squash_merge_commit_message" , repo .GetSquashMergeCommitMessage ()),
1054+ d .Set ("squash_merge_commit_title" , repo .GetSquashMergeCommitTitle ()),
1055+ ); err != nil {
1056+ return diag .FromErr (err )
1057+ }
1058+
1059+ // Fork info
1060+ if repo .GetFork () {
1061+ if err := d .Set ("fork" , "true" ); err != nil {
1062+ return diag .FromErr (err )
1063+ }
1064+ if repo .Parent != nil {
1065+ if err := errors .Join (
1066+ d .Set ("source_owner" , repo .Parent .GetOwner ().GetLogin ()),
1067+ d .Set ("source_repo" , repo .Parent .GetName ()),
1068+ ); err != nil {
1069+ return diag .FromErr (err )
1070+ }
1071+ }
1072+ } else {
1073+ if err := errors .Join (
1074+ d .Set ("fork" , "false" ),
1075+ d .Set ("source_owner" , "" ),
1076+ d .Set ("source_repo" , "" ),
1077+ ); err != nil {
1078+ return diag .FromErr (err )
1079+ }
1080+ }
1081+
1082+ // Template info
1083+ if repo .TemplateRepository != nil {
1084+ if err := d .Set ("template" , []any {
1085+ map [string ]any {
1086+ "owner" : repo .TemplateRepository .Owner .Login ,
1087+ "repository" : repo .TemplateRepository .Name ,
1088+ },
1089+ }); err != nil {
1090+ return diag .FromErr (err )
1091+ }
1092+ } else {
1093+ if err := d .Set ("template" , []any {}); err != nil {
1094+ return diag .FromErr (err )
1095+ }
1096+ }
1097+
1098+ // Pages (requires separate API call for computed fields like url, status)
1099+ if repo .GetHasPages () {
1100+ pages , _ , err := client .Repositories .GetPagesInfo (ctx , owner , repoName )
1101+ if err != nil {
1102+ return diag .FromErr (err )
1103+ }
1104+ if err := d .Set ("pages" , flattenPages (pages )); err != nil {
1105+ return diag .FromErr (err )
1106+ }
1107+ }
1108+
1109+ // Security and analysis + vulnerability alerts (requires separate API call)
1110+ if repo .GetSecurityAndAnalysis () != nil {
1111+ vulnerabilityAlerts , _ , err := client .Repositories .GetVulnerabilityAlerts (ctx , owner , repoName )
1112+ if err != nil {
1113+ return diag .Errorf ("error reading repository vulnerability alerts: %s" , err .Error ())
1114+ }
1115+ if err := errors .Join (
1116+ d .Set ("vulnerability_alerts" , vulnerabilityAlerts ),
1117+ d .Set ("security_and_analysis" , flattenSecurityAndAnalysis (repo .SecurityAndAnalysis )),
1118+ ); err != nil {
1119+ return diag .FromErr (err )
1120+ }
1121+ }
1122+
1123+ return nil
1124+ }
1125+
10571126func expandPages (input []any ) * github.Pages {
10581127 if len (input ) == 0 || input [0 ] == nil {
10591128 return nil
0 commit comments