Skip to content

Commit 7a06b31

Browse files
committed
repository_ruleset: Implement validations for target, conditions and rules
Signed-off-by: Timo Sand <[email protected]>
1 parent 55b9f29 commit 7a06b31

1 file changed

Lines changed: 88 additions & 0 deletions

File tree

github/resource_github_repository_ruleset.go

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ import (
1010
"strconv"
1111

1212
"github.com/google/go-github/v77/github"
13+
"github.com/hashicorp/terraform-plugin-log/tflog"
14+
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/customdiff"
1315
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
1416
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation"
1517
)
@@ -26,6 +28,11 @@ func resourceGithubRepositoryRuleset() *schema.Resource {
2628

2729
SchemaVersion: 1,
2830

31+
CustomizeDiff: customdiff.All(
32+
validateRepositoryRulesetConditions,
33+
validateRepositoryRulesetRules,
34+
),
35+
2936
Schema: map[string]*schema.Schema{
3037
"name": {
3138
Type: schema.TypeString,
@@ -783,3 +790,84 @@ func resourceGithubRepositoryRulesetImport(d *schema.ResourceData, meta any) ([]
783790

784791
return []*schema.ResourceData{d}, nil
785792
}
793+
794+
// validateRepositoryRulesetConditions validates conditions based on target type.
795+
// For push targets, ref_name must not be set.
796+
// For branch/tag targets, ref_name can be set in conditions.
797+
func validateRepositoryRulesetConditions(ctx context.Context, d *schema.ResourceDiff, _ any) error {
798+
target := d.Get("target").(string)
799+
tflog.Debug(ctx, "Validating repository ruleset conditions", map[string]any{"target": target})
800+
801+
conditionsRaw := d.Get("conditions").([]any)
802+
if len(conditionsRaw) == 0 {
803+
tflog.Debug(ctx, "No conditions block, skipping validation")
804+
return nil
805+
}
806+
807+
conditions := conditionsRaw[0].(map[string]any)
808+
809+
if target == "push" {
810+
if conditions["ref_name"] != nil && len(conditions["ref_name"].([]any)) > 0 {
811+
tflog.Debug(ctx, "Invalid ref_name for push target")
812+
return fmt.Errorf("ref_name must not be set for push target")
813+
}
814+
}
815+
816+
tflog.Debug(ctx, "Conditions validation passed", map[string]any{"target": target})
817+
return nil
818+
}
819+
820+
// validateRepositoryRulesetRules validates rules based on target type.
821+
// Push targets can only use push-specific rules (file_path_restriction, max_file_size, etc.).
822+
// Branch/tag targets cannot use push-only rules.
823+
//
824+
// Note: This function reuses branchTagOnlyRules and pushOnlyRules from
825+
// resource_github_organization_ruleset.go since they're in the same package.
826+
func validateRepositoryRulesetRules(ctx context.Context, d *schema.ResourceDiff, _ any) error {
827+
target := d.Get("target").(string)
828+
tflog.Debug(ctx, "Validating repository ruleset rules", map[string]any{"target": target})
829+
830+
rulesRaw := d.Get("rules").([]any)
831+
if len(rulesRaw) == 0 {
832+
tflog.Debug(ctx, "No rules block, skipping validation")
833+
return nil
834+
}
835+
836+
rules := rulesRaw[0].(map[string]any)
837+
838+
switch target {
839+
case "push":
840+
for _, ruleName := range branchTagOnlyRules {
841+
ruleValue := rules[ruleName]
842+
if ruleValue == nil {
843+
continue
844+
}
845+
switch v := ruleValue.(type) {
846+
case bool:
847+
if v {
848+
tflog.Debug(ctx, "Invalid rule for push target", map[string]any{"rule": ruleName, "value": v})
849+
return fmt.Errorf("rule %q is not valid for push target; push targets only support: %v", ruleName, pushOnlyRules)
850+
}
851+
case []any:
852+
if len(v) > 0 {
853+
tflog.Debug(ctx, "Invalid rule for push target", map[string]any{"rule": ruleName, "value": v})
854+
return fmt.Errorf("rule %q is not valid for push target; push targets only support: %v", ruleName, pushOnlyRules)
855+
}
856+
}
857+
}
858+
case "branch", "tag":
859+
for _, ruleName := range pushOnlyRules {
860+
ruleValue := rules[ruleName]
861+
if ruleValue == nil {
862+
continue
863+
}
864+
if ruleList, ok := ruleValue.([]any); ok && len(ruleList) > 0 {
865+
tflog.Debug(ctx, "Invalid rule for branch/tag target", map[string]any{"rule": ruleName, "target": target})
866+
return fmt.Errorf("rule %q is only valid for push target, not for %s target", ruleName, target)
867+
}
868+
}
869+
}
870+
871+
tflog.Debug(ctx, "Rules validation passed", map[string]any{"target": target})
872+
return nil
873+
}

0 commit comments

Comments
 (0)