From 595dd0178e574455e58a661d41826fb1ccbb3159 Mon Sep 17 00:00:00 2001 From: Simo Kinnunen Date: Wed, 26 Nov 2025 16:57:25 +0900 Subject: [PATCH 1/9] feat: add Playwright check support --- checkly/helpers.go | 16 + checkly/provider.go | 40 +- checkly/resource_playwright_check_suite.go | 757 ++++++++++++++++++ .../resource_playwright_check_suite_test.go | 1 + checkly/resource_playwright_code_bundle.go | 347 ++++++++ checkly/validation.go | 14 + docs/resources/playwright_check_suite.md | 218 +++++ docs/resources/playwright_code_bundle.md | 52 ++ .../resource.tf | 47 ++ .../resource.tf | 17 + 10 files changed, 1490 insertions(+), 19 deletions(-) create mode 100644 checkly/resource_playwright_check_suite.go create mode 100644 checkly/resource_playwright_check_suite_test.go create mode 100644 checkly/resource_playwright_code_bundle.go create mode 100644 docs/resources/playwright_check_suite.md create mode 100644 docs/resources/playwright_code_bundle.md create mode 100644 examples/resources/checkly_playwright_check_suite/resource.tf create mode 100644 examples/resources/checkly_playwright_code_bundle/resource.tf diff --git a/checkly/helpers.go b/checkly/helpers.go index a9233e4..84810eb 100644 --- a/checkly/helpers.go +++ b/checkly/helpers.go @@ -1,6 +1,9 @@ package checkly import ( + "crypto/sha256" + "encoding/hex" + "io" "os" "strconv" "time" @@ -18,3 +21,16 @@ func apiCallTimeout() time.Duration { } return 15 * time.Second } + +func checksumSha256(r io.Reader) string { + hash := sha256.New() + + _, err := io.Copy(hash, r) + if err != nil { + panic("failed to calculate checksum: " + err.Error()) + } + + checksum := hex.EncodeToString(hash.Sum(nil)) + + return checksum +} diff --git a/checkly/provider.go b/checkly/provider.go index a48e843..6f46761 100644 --- a/checkly/provider.go +++ b/checkly/provider.go @@ -31,25 +31,27 @@ func Provider() *schema.Provider { }, }, ResourcesMap: map[string]*schema.Resource{ - "checkly_check": resourceCheck(), - "checkly_heartbeat": resourceHeartbeat(), // Renamed - "checkly_heartbeat_monitor": resourceHeartbeatMonitor(), - "checkly_tcp_check": resourceTCPCheck(), // Renamed - "checkly_tcp_monitor": resourceTCPMonitor(), - "checkly_check_group": resourceCheckGroup(), - "checkly_snippet": resourceSnippet(), - "checkly_dashboard": resourceDashboard(), - "checkly_maintenance_windows": resourceMaintenanceWindow(), - "checkly_alert_channel": resourceAlertChannel(), - "checkly_trigger_check": resourceTriggerCheck(), - "checkly_trigger_group": resourceTriggerGroup(), - "checkly_environment_variable": resourceEnvironmentVariable(), - "checkly_private_location": resourcePrivateLocation(), - "checkly_client_certificate": resourceClientCertificate(), - "checkly_status_page": resourceStatusPage(), - "checkly_status_page_service": resourceStatusPageService(), - "checkly_url_monitor": resourceURLMonitor(), - "checkly_dns_monitor": resourceDNSMonitor(), + "checkly_check": resourceCheck(), + "checkly_heartbeat": resourceHeartbeat(), // Renamed + "checkly_heartbeat_monitor": resourceHeartbeatMonitor(), + "checkly_tcp_check": resourceTCPCheck(), // Renamed + "checkly_tcp_monitor": resourceTCPMonitor(), + "checkly_check_group": resourceCheckGroup(), + "checkly_snippet": resourceSnippet(), + "checkly_dashboard": resourceDashboard(), + "checkly_maintenance_windows": resourceMaintenanceWindow(), + "checkly_alert_channel": resourceAlertChannel(), + "checkly_trigger_check": resourceTriggerCheck(), + "checkly_trigger_group": resourceTriggerGroup(), + "checkly_environment_variable": resourceEnvironmentVariable(), + "checkly_private_location": resourcePrivateLocation(), + "checkly_client_certificate": resourceClientCertificate(), + "checkly_status_page": resourceStatusPage(), + "checkly_status_page_service": resourceStatusPageService(), + "checkly_url_monitor": resourceURLMonitor(), + "checkly_dns_monitor": resourceDNSMonitor(), + "checkly_playwright_check_suite": resourcePlaywrightCheckSuite(), + "checkly_playwright_code_bundle": resourcePlaywrightCodeBundle(), }, DataSourcesMap: map[string]*schema.Resource{ "checkly_static_ips": dataSourceStaticIPs(), diff --git a/checkly/resource_playwright_check_suite.go b/checkly/resource_playwright_check_suite.go new file mode 100644 index 0000000..376460c --- /dev/null +++ b/checkly/resource_playwright_check_suite.go @@ -0,0 +1,757 @@ +package checkly + +import ( + "context" + "encoding/base64" + "fmt" + "slices" + "sort" + "strings" + + checkly "github.com/checkly/checkly-go-sdk" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +func resourcePlaywrightCheckSuite() *schema.Resource { + return &schema.Resource{ + Create: resourcePlaywrightCheckSuiteCreate, + Read: resourcePlaywrightCheckSuiteRead, + Update: resourcePlaywrightCheckSuiteUpdate, + Delete: resourcePlaywrightCheckSuiteDelete, + Importer: &schema.ResourceImporter{ + StateContext: schema.ImportStatePassthroughContext, + }, + Description: "Creates a DNS Monitor to check DNS record availability and response times.", + Schema: map[string]*schema.Schema{ + "name": { + Description: "The name of the check.", + Type: schema.TypeString, + Required: true, + }, + "frequency": { + Description: "How often the check should run in minutes. Possible values are `1`, `2`, `5`, `10`, `15`, `30`, `60`, `120`, `180`, `360`, `720`, and `1440`.", + Type: schema.TypeInt, + Required: true, + ValidateFunc: validateOneOf([]int{1, 2, 5, 10, 15, 30, 60, 120, 180, 360, 720, 1440}), + }, + "activated": { + Description: "Determines whether the check will run periodically or not after being deployed.", + Type: schema.TypeBool, + Required: true, + }, + "muted": { + Description: "Determines if any notifications will be sent out when the check fails and/or recovers. (Default `false`).", + Type: schema.TypeBool, + Optional: true, + Default: false, + }, + "run_parallel": { + Description: "Determines whether the check should run on all selected locations in parallel or round-robin. (Default `false`).", + Type: schema.TypeBool, + Optional: true, + Default: false, + }, + "locations": { + Description: "An array of one or more data center locations where to run the this check.", + Type: schema.TypeSet, + Optional: true, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "tags": { + Description: "A list of tags for organizing and filtering checks and monitors.", + Type: schema.TypeSet, + Optional: true, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "alert_channel_subscription": { + Description: "An array of channel IDs and whether they're activated or not. If you don't set at least one alert subscription for your check, we won't be able to alert you.", + Type: schema.TypeList, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "channel_id": { + Description: "The ID of the alert channel.", + Type: schema.TypeInt, + Required: true, + }, + "activated": { + Description: "Whether an alert should be sent to this channel.", + Type: schema.TypeBool, + Required: true, + }, + }, + }, + }, + "private_locations": { + Description: "An array of one or more private locations slugs.", + Type: schema.TypeSet, + Optional: true, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + alertSettingsAttributeName: makeAlertSettingsAttributeSchema(AlertSettingsAttributeSchemaOptions{ + Monitor: false, + }), + "use_global_alert_settings": { + Description: "When true, the account level alert settings will be used, not the alert setting defined on this check. (Default `true`).", + Type: schema.TypeBool, + Optional: true, + Default: true, + }, + "bundle": { + Description: "Attaches a code bundle to the check.", + Type: schema.TypeList, + Required: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "id": { + Description: "The ID of the code bundle.", + Type: schema.TypeString, + Required: true, + }, + "data": { + Description: "The auxiliary data of the code bundle.", + Type: schema.TypeString, + Required: true, + }, + }, + }, + }, + "runtime": { + Description: "Configure the runtime environment of the Playwright check.", + Type: schema.TypeList, + Required: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "steps": { + Description: "Customize the actions taken during test execution.", + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "install": { + Description: "Customize the install step, which is used to initialize the " + + "environment prior to starting the test run.", + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "command": { + Description: "The command used to install dependencies prior to " + + "running Playwright. The default value is the appropriate " + + "install command for your package manager (e.g. " + + "`npm install` for `npm`).", + Type: schema.TypeString, + Optional: true, + }, + }, + }, + }, + "test": { + Description: "Customize the test step.", + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "command": { + Description: "The command used to run Playwright. The default " + + "value is the appropriate exec command for your package " + + "manager (e.g. `npx playwright test` for `npm`).", + Type: schema.TypeString, + Optional: true, + }, + }, + }, + }, + }, + }, + }, + "playwright": { + Description: "Configure the Playwright capabilities that should be made available " + + "to the runtime environment.", + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "version": { + Description: "The Playwright version to use.", + Type: schema.TypeString, + Optional: true, + }, + "device": { + Description: "The list of devices that should be made available for Playwright.", + Type: schema.TypeSet, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "type": { + Description: "The type of the device.", + Type: schema.TypeString, + Required: true, + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + "group_id": { + Description: "The ID of the check group that this check is part of.", + Type: schema.TypeInt, + Optional: true, + }, + "group_order": { + Description: "The position of the check in the check group. It determines in what order checks and monitors are run when a group is triggered from the API or from CI/CD.", + Type: schema.TypeInt, + Optional: true, + }, + "trigger_incident": triggerIncidentAttributeSchema, + }, + } +} + +func resourcePlaywrightCheckSuiteCreate(d *schema.ResourceData, client any) error { + r, err := PlaywrightCheckSuiteResourceFromResourceData(d) + if err != nil { + return fmt.Errorf("failed to load Playwright check suite from resource data: %w", err) + } + + ctx, cancel := context.WithTimeout(context.Background(), apiCallTimeout()) + defer cancel() + + newCheck, err := client.(checkly.Client).CreatePlaywrightCheck(ctx, *r.PlaywrightCheck) + if err != nil { + return fmt.Errorf("failed to create Playwright check suite: %w", err) + } + + d.SetId(newCheck.ID) + + return resourcePlaywrightCheckSuiteRead(d, client) +} + +func resourcePlaywrightCheckSuiteRead(d *schema.ResourceData, client any) error { + ctx, cancel := context.WithTimeout(context.Background(), apiCallTimeout()) + defer cancel() + + check, err := client.(checkly.Client).GetPlaywrightCheck(ctx, d.Id()) + if err != nil { + if strings.Contains(err.Error(), "404") { + d.SetId("") + return nil + } + + return fmt.Errorf("failed to retrieve Playwright check suite %q: %w", d.Id(), err) + } + + resource, err := PlaywrightCheckSuiteResourceFromAPIModel(check, d) + if err != nil { + return fmt.Errorf("failed to convert API response to Playwright check suite resource: %w", err) + } + + err = resource.StoreResourceData(d) + if err != nil { + return fmt.Errorf("failed to store Playwright check suite %q state: %w", d.Id(), err) + } + + return nil +} + +func resourcePlaywrightCheckSuiteUpdate(d *schema.ResourceData, client any) error { + r, err := PlaywrightCheckSuiteResourceFromResourceData(d) + if err != nil { + return fmt.Errorf("failed to load Playwright check suite from resource data: %w", err) + } + + ctx, cancel := context.WithTimeout(context.Background(), apiCallTimeout()) + defer cancel() + + _, err = client.(checkly.Client).UpdatePlaywrightCheck(ctx, r.ID, *r.PlaywrightCheck) + if err != nil { + return fmt.Errorf("failed to update Playwright check suite %q: %w", d.Id(), err) + } + + d.SetId(r.ID) + + return resourcePlaywrightCheckSuiteRead(d, client) +} + +func resourcePlaywrightCheckSuiteDelete(d *schema.ResourceData, client any) error { + ctx, cancel := context.WithTimeout(context.Background(), apiCallTimeout()) + defer cancel() + + if err := client.(checkly.Client).DeletePlaywrightCheck(ctx, d.Id()); err != nil { + return fmt.Errorf("failed to delete Playwright check suite %q: %w", d.Id(), err) + } + + return nil +} + +type PlaywrightCheckSuiteResource struct { + *checkly.PlaywrightCheck + Bundle *PlaywrightCheckSuiteBundleAttribute + Runtime *PlaywrightCheckSuiteRuntimeAttribute +} + +func PlaywrightCheckSuiteResourceFromResourceData( + d *schema.ResourceData, +) (PlaywrightCheckSuiteResource, error) { + check := checkly.PlaywrightCheck{ + ID: d.Id(), + Name: d.Get("name").(string), + Frequency: d.Get("frequency").(int), + Activated: d.Get("activated").(bool), + Muted: d.Get("muted").(bool), + RunParallel: d.Get("run_parallel").(bool), + Locations: stringsFromSet(d.Get("locations").(*schema.Set)), + Tags: stringsFromSet(d.Get("tags").(*schema.Set)), + UseGlobalAlertSettings: d.Get("use_global_alert_settings").(bool), + GroupID: int64(d.Get("group_id").(int)), + GroupOrder: d.Get("group_order").(int), + AlertChannelSubscriptions: alertChannelSubscriptionsFromSet(d.Get("alert_channel_subscription").([]any)), + TriggerIncident: triggerIncidentFromSet(d.Get("trigger_incident").(*schema.Set)), + } + + alertSettings := alertSettingsFromSet(d.Get("alert_settings").([]any)) + check.AlertSettings = &alertSettings + + bundleAttr, err := PlaywrightCheckSuiteBundleAttributeFromList(d.Get("bundle").([]any)) + if err != nil { + return PlaywrightCheckSuiteResource{}, err + } + + if bundleAttr != nil { + bundlePath, err := base64.StdEncoding.DecodeString(bundleAttr.ID) + if err != nil { + return PlaywrightCheckSuiteResource{}, fmt.Errorf("invalid code bundle identifier %q: %w", bundleAttr.ID, err) + } + + check.CodeBundlePath = string(bundlePath) + + // We may want to make this configurable in the future, but for now + // this will do. + check.CacheHash = checksumSha256(strings.NewReader(bundleAttr.Data.ChecksumSha256)) + } + + runtimeAttr, err := PlaywrightCheckSuiteRuntimeAttributeFromList(d.Get("runtime").([]any)) + if err != nil { + return PlaywrightCheckSuiteResource{}, err + } + + if runtimeAttr != nil { + if runtimeAttr.Steps != nil { + if runtimeAttr.Steps.Test != nil { + check.TestCommand = runtimeAttr.Steps.Test.Command + } + + if runtimeAttr.Steps.Install != nil { + check.InstallCommand = &runtimeAttr.Steps.Install.Command + } + } + + if runtimeAttr.Playwright != nil { + check.PlaywrightVersion = runtimeAttr.Playwright.Version + + var browsers []string + for _, device := range *runtimeAttr.Playwright.Devices { + browsers = append(browsers, device.Type) + } + + check.Browsers = browsers + } + } + + resource := PlaywrightCheckSuiteResource{ + PlaywrightCheck: &check, + Bundle: bundleAttr, + Runtime: runtimeAttr, + } + + return resource, nil +} + +func PlaywrightCheckSuiteResourceFromAPIModel( + check *checkly.PlaywrightCheck, + d *schema.ResourceData, +) (PlaywrightCheckSuiteResource, error) { + // Use the current state as a template so that we don't have to access + // the archive file path manually (it needs to be kept because it only + // exists on the client). + bundleAttr, err := PlaywrightCheckSuiteBundleAttributeFromList(d.Get("bundle").([]any)) + if err != nil { + return PlaywrightCheckSuiteResource{}, err + } + + var runtimeAttr PlaywrightCheckSuiteRuntimeAttribute + + if check.TestCommand != "" || check.InstallCommand != nil { + runtimeAttr.Steps = new(PlaywrightCheckSuiteRuntimeStepsAttribute) + + if check.InstallCommand != nil { + runtimeAttr.Steps.Install = &PlaywrightCheckSuiteRuntimeStepsInstallAttribute{ + Command: *check.InstallCommand, + } + } + + if check.TestCommand != "" { + runtimeAttr.Steps.Test = &PlaywrightCheckSuiteRuntimeStepsTestAttribute{ + Command: check.TestCommand, + } + } + } + + if len(check.Browsers) != 0 || check.PlaywrightVersion != "" { + runtimeAttr.Playwright = new(PlaywrightCheckSuiteRuntimePlaywrightAttribute) + + if check.PlaywrightVersion != "" { + runtimeAttr.Playwright.Version = check.PlaywrightVersion + } + + if len(check.Browsers) != 0 { + slices.Sort(check.Browsers) + + devices := make(PlaywrightCheckSuiteRuntimePlaywrightDeviceAttributes, 0, len(check.Browsers)) + + for _, deviceType := range check.Browsers { + devices = append(devices, PlaywrightCheckSuiteRuntimePlaywrightDeviceAttribute{ + Type: deviceType, + }) + } + + runtimeAttr.Playwright.Devices = &devices + } + } + + resource := PlaywrightCheckSuiteResource{ + PlaywrightCheck: check, + Bundle: bundleAttr, + Runtime: &runtimeAttr, + } + + return resource, nil +} + +func (r *PlaywrightCheckSuiteResource) StoreResourceData( + d *schema.ResourceData, +) error { + d.Set("name", r.Name) + d.Set("activated", r.Activated) + d.Set("muted", r.Muted) + d.Set("run_parallel", r.RunParallel) + d.Set("locations", r.Locations) + d.Set("private_locations", r.PrivateLocations) + + sort.Strings(r.Tags) + d.Set("tags", r.Tags) + + d.Set("frequency", r.Frequency) + + if err := d.Set("alert_settings", setFromAlertSettings(*r.AlertSettings)); err != nil { + return fmt.Errorf("error setting alert settings for resource %s: %w", d.Id(), err) + } + d.Set("use_global_alert_settings", r.UseGlobalAlertSettings) + + err := d.Set("bundle", r.Bundle.ToList()) + if err != nil { + return err + } + + err = d.Set("runtime", r.Runtime.ToList()) + if err != nil { + return fmt.Errorf("error setting runtime for resource %s: %w", d.Id(), err) + } + + d.Set("group_id", r.GroupID) + d.Set("group_order", r.GroupOrder) + d.Set("alert_channel_subscription", r.AlertChannelSubscriptions) + d.Set("trigger_incident", setFromTriggerIncident(r.TriggerIncident)) + d.SetId(d.Id()) + return nil +} + +type PlaywrightCheckSuiteBundleAttribute struct { + ID string + Data *PlaywrightCodeBundleData +} + +func PlaywrightCheckSuiteBundleAttributeFromList( + list []any, +) (*PlaywrightCheckSuiteBundleAttribute, error) { + if len(list) == 0 { + return nil, nil + } + + m := list[0].(tfMap) + + data, err := PlaywrightCodeBundleDataFromString(m["data"].(string)) + if err != nil { + return nil, err + } + + a := PlaywrightCheckSuiteBundleAttribute{ + ID: m["id"].(string), + Data: data, + } + + return &a, nil +} + +func (a *PlaywrightCheckSuiteBundleAttribute) ToList() []tfMap { + if a == nil { + return []tfMap{} + } + + return []tfMap{ + { + "id": a.ID, + "data": a.Data.EncodeToString(), + }, + } +} + +type PlaywrightCheckSuiteRuntimeAttribute struct { + Steps *PlaywrightCheckSuiteRuntimeStepsAttribute + Playwright *PlaywrightCheckSuiteRuntimePlaywrightAttribute +} + +func PlaywrightCheckSuiteRuntimeAttributeFromList( + list []any, +) (*PlaywrightCheckSuiteRuntimeAttribute, error) { + if len(list) == 0 { + return nil, nil + } + + m := list[0].(tfMap) + + stepsAttr, err := PlaywrightCheckSuiteRuntimeStepsAttributeFromList(m["steps"].([]any)) + if err != nil { + return nil, err + } + + playwrightAttr, err := PlaywrightCheckSuiteRuntimePlaywrightAttributeFromList(m["playwright"].([]any)) + if err != nil { + return nil, err + } + + a := PlaywrightCheckSuiteRuntimeAttribute{ + Steps: stepsAttr, + Playwright: playwrightAttr, + } + + return &a, nil +} + +func (a *PlaywrightCheckSuiteRuntimeAttribute) ToList() []tfMap { + if a == nil { + return []tfMap{} + } + + return []tfMap{ + { + "steps": a.Steps.ToList(), + "playwright": a.Playwright.ToList(), + }, + } +} + +type PlaywrightCheckSuiteRuntimeStepsAttribute struct { + Install *PlaywrightCheckSuiteRuntimeStepsInstallAttribute + Test *PlaywrightCheckSuiteRuntimeStepsTestAttribute +} + +func PlaywrightCheckSuiteRuntimeStepsAttributeFromList( + list []any, +) (*PlaywrightCheckSuiteRuntimeStepsAttribute, error) { + if len(list) == 0 { + return nil, nil + } + + m := list[0].(tfMap) + + installAttr, err := PlaywrightCheckSuiteRuntimeStepsInstallAttributeFromList(m["install"].([]any)) + if err != nil { + return nil, err + } + + testAttr, err := PlaywrightCheckSuiteRuntimeStepsTestAttributeFromList(m["test"].([]any)) + if err != nil { + return nil, err + } + + a := PlaywrightCheckSuiteRuntimeStepsAttribute{ + Install: installAttr, + Test: testAttr, + } + + return &a, nil +} + +func (a *PlaywrightCheckSuiteRuntimeStepsAttribute) ToList() []tfMap { + if a == nil { + return []tfMap{} + } + + return []tfMap{ + { + "install": a.Install.ToList(), + "test": a.Test.ToList(), + }, + } +} + +type PlaywrightCheckSuiteRuntimeStepsInstallAttribute struct { + Command string +} + +func PlaywrightCheckSuiteRuntimeStepsInstallAttributeFromList( + list []any, +) (*PlaywrightCheckSuiteRuntimeStepsInstallAttribute, error) { + if len(list) == 0 { + return nil, nil + } + + m := list[0].(tfMap) + + a := PlaywrightCheckSuiteRuntimeStepsInstallAttribute{ + Command: m["command"].(string), + } + + return &a, nil +} + +func (a *PlaywrightCheckSuiteRuntimeStepsInstallAttribute) ToList() []tfMap { + if a == nil { + return []tfMap{} + } + + return []tfMap{ + { + "command": a.Command, + }, + } +} + +type PlaywrightCheckSuiteRuntimeStepsTestAttribute struct { + Command string +} + +func PlaywrightCheckSuiteRuntimeStepsTestAttributeFromList( + list []any, +) (*PlaywrightCheckSuiteRuntimeStepsTestAttribute, error) { + if len(list) == 0 { + return nil, nil + } + + m := list[0].(tfMap) + + a := PlaywrightCheckSuiteRuntimeStepsTestAttribute{ + Command: m["command"].(string), + } + + return &a, nil +} + +func (a *PlaywrightCheckSuiteRuntimeStepsTestAttribute) ToList() []tfMap { + if a == nil { + return []tfMap{} + } + + return []tfMap{ + { + "command": a.Command, + }, + } +} + +func PlaywrightCheckSuiteRuntimePlaywrightAttributeFromList( + list []any, +) (*PlaywrightCheckSuiteRuntimePlaywrightAttribute, error) { + if len(list) == 0 { + return nil, nil + } + + m := list[0].(tfMap) + + devices, err := PlaywrightCheckSuiteRuntimePlaywrightDeviceAttributesFromList(m["device"].(*schema.Set).List()) + if err != nil { + return nil, err + } + + a := PlaywrightCheckSuiteRuntimePlaywrightAttribute{ + Version: m["version"].(string), + Devices: devices, + } + + return &a, nil +} + +func (a *PlaywrightCheckSuiteRuntimePlaywrightAttribute) ToList() []tfMap { + if a == nil { + return []tfMap{} + } + + return []tfMap{ + { + "version": a.Version, + "device": a.Devices.ToList(), + }, + } +} + +type PlaywrightCheckSuiteRuntimePlaywrightAttribute struct { + Version string + Devices *PlaywrightCheckSuiteRuntimePlaywrightDeviceAttributes +} + +type PlaywrightCheckSuiteRuntimePlaywrightDeviceAttribute struct { + Type string +} + +type PlaywrightCheckSuiteRuntimePlaywrightDeviceAttributes []PlaywrightCheckSuiteRuntimePlaywrightDeviceAttribute + +func PlaywrightCheckSuiteRuntimePlaywrightDeviceAttributesFromList( + list []any, +) (*PlaywrightCheckSuiteRuntimePlaywrightDeviceAttributes, error) { + if len(list) == 0 { + return nil, nil + } + + a := make(PlaywrightCheckSuiteRuntimePlaywrightDeviceAttributes, 0, len(list)) + + for _, device := range list { + a = append(a, PlaywrightCheckSuiteRuntimePlaywrightDeviceAttribute{ + Type: device.(tfMap)["type"].(string), + }) + } + + return &a, nil +} + +func (a *PlaywrightCheckSuiteRuntimePlaywrightDeviceAttributes) ToList() []tfMap { + if a == nil { + return []tfMap{} + } + + m := []tfMap{} + + for _, device := range *a { + m = append(m, tfMap{ + "type": device.Type, + }) + } + + return m +} diff --git a/checkly/resource_playwright_check_suite_test.go b/checkly/resource_playwright_check_suite_test.go new file mode 100644 index 0000000..a792995 --- /dev/null +++ b/checkly/resource_playwright_check_suite_test.go @@ -0,0 +1 @@ +package checkly diff --git a/checkly/resource_playwright_code_bundle.go b/checkly/resource_playwright_code_bundle.go new file mode 100644 index 0000000..7340ff6 --- /dev/null +++ b/checkly/resource_playwright_code_bundle.go @@ -0,0 +1,347 @@ +package checkly + +import ( + "bytes" + "context" + "encoding/base64" + "encoding/json" + "errors" + "fmt" + "os" + + checkly "github.com/checkly/checkly-go-sdk" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/customdiff" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +func resourcePlaywrightCodeBundle() *schema.Resource { + return &schema.Resource{ + CreateContext: resourcePlaywrightCodeBundleCreate, + ReadContext: resourcePlaywrightCodeBundleRead, + DeleteContext: resourcePlaywrightCodeBundleDelete, + Description: "A managed code bundle which can be used in Playwright Check Suite resources.", + Schema: map[string]*schema.Schema{ + "source_archive": { + Description: "", + Type: schema.TypeList, + Required: true, + ForceNew: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "file": { + Description: "", + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validateFileExists(), + }, + }, + }, + }, + "data": { + Description: "An opaque, computed value containing auxiliary " + + "data of the code bundle. This value should be passed " + + "as-is to a check resource.", + Type: schema.TypeString, + Computed: true, + ForceNew: true, + }, + }, + CustomizeDiff: customdiff.Sequence( + func(_ context.Context, diff *schema.ResourceDiff, meta any) error { + bundle, err := PlaywrightCodeBundleResourceFromResourceDiff(diff) + if err != nil { + return fmt.Errorf("failed to thaw code bundle from resource diff: %v", err) + } + + switch { + case bundle.SourceArchive != nil: + checksum, err := bundle.SourceArchive.ChecksumSha256() + if err != nil { + return fmt.Errorf("failed to calculate source archive checksum: %v", err) + } + + switch { + case bundle.Data.Version < 1: + // Data should be updated. + case checksum != bundle.Data.ChecksumSha256: + // Data should be updated. + default: + // Data needs no update. + return nil + } + + bundle.Data.Version = 1 + bundle.Data.ChecksumSha256 = checksum + + err = diff.SetNew("data", bundle.Data.EncodeToString()) + if err != nil { + return fmt.Errorf("failed to set %q: %v", "data", err) + } + + return nil + default: + return fmt.Errorf("bundle has no source") + } + }, + ), + } +} + +func resourcePlaywrightCodeBundleCreate( + ctx context.Context, + d *schema.ResourceData, + client any, +) (diags diag.Diagnostics) { + ctx, cancel := context.WithTimeout(ctx, apiCallTimeout()) + defer cancel() + + bundle, err := PlaywrightCodeBundleResourceFromResourceData(d) + if err != nil { + return diag.Errorf("failed to thaw code bundle from resource data: %v", err) + } + + switch { + case bundle.SourceArchive != nil: + result, err := bundle.SourceArchive.Upload(ctx, client.(checkly.Client)) + if err != nil { + return diag.Errorf("failed to upload source archive: %v", err) + } + + d.SetId(base64.StdEncoding.EncodeToString([]byte(result.Key))) + + err = d.Set("source_archive", bundle.SourceArchive.ToList()) + if err != nil { + return diag.Errorf("failed to set %q state: %v", "source_archive", err) + } + + err = d.Set("data", bundle.Data.EncodeToString()) + if err != nil { + return diag.Errorf("failed to set %q state: %v", "data", err) + } + + return nil + default: + return diag.Errorf("bundle has no source") + } +} + +func resourcePlaywrightCodeBundleRead( + ctx context.Context, + d *schema.ResourceData, + client any, +) (diags diag.Diagnostics) { + ctx, cancel := context.WithTimeout(ctx, apiCallTimeout()) + defer cancel() + + key, err := base64.StdEncoding.DecodeString(d.Id()) + if err != nil { + return diag.Errorf("failed to thaw code bundle from resource data: %v", err) + } + + bundle, err := PlaywrightCodeBundleResourceFromResourceData(d) + if err != nil { + return diag.Errorf("failed to thaw code bundle from resource data: %v", err) + } + + result, err := client.(checkly.Client).PeekCodeBundle(ctx, string(key)) + if err != nil { + if errors.Is(err, checkly.ErrCodeBundleNotFound) { + d.SetId("") + return nil + } + + return diag.Errorf("failed to peek code bundle: %v", err) + } + + if result.ChecksumSha256 != "" { + bundle.Data.ChecksumSha256 = result.ChecksumSha256 + + err = d.Set("data", bundle.Data.EncodeToString()) + if err != nil { + return diag.Errorf("failed to set %q state: %v", "data", err) + } + } + + return nil +} + +func resourcePlaywrightCodeBundleDelete( + ctx context.Context, + d *schema.ResourceData, + client any, +) (diags diag.Diagnostics) { + // The code bundle cannot actually be deleted. It will be cleaned up when + // it is no longer in use. + return diags +} + +type PlaywrightCodeBundleData struct { + Version int `json:"v"` + ChecksumSha256 string `json:"s256"` +} + +func PlaywrightCodeBundleDataFromString(s string) (*PlaywrightCodeBundleData, error) { + if s == "" { + return new(PlaywrightCodeBundleData), nil + } + + b64, err := base64.StdEncoding.DecodeString(s) + if err != nil { + return nil, fmt.Errorf("failed to decode code bundle data %q: %w", s, err) + } + + dec := json.NewDecoder(bytes.NewReader(b64)) + + var t PlaywrightCodeBundleData + + err = dec.Decode(&t) + if err != nil { + return nil, fmt.Errorf("failed to decode code bundle data %q: %w", s, err) + } + + return &t, err +} + +func (t *PlaywrightCodeBundleData) EncodeToString() string { + buf := new(bytes.Buffer) + + enc := json.NewEncoder(buf) + + err := enc.Encode(t) + if err != nil { + // This should not be possible, so let's panic. + panic(fmt.Errorf("failed to encode code bundle data %q: %w", t, err)) + } + + return base64.StdEncoding.EncodeToString(buf.Bytes()) +} + +type PlaywrightCodeBundleResource struct { + ID string + Data *PlaywrightCodeBundleData + SourceArchive *PlaywrightCodeBundleSourceArchiveAttribute +} + +func PlaywrightCodeBundleResourceFromResourceData( + d *schema.ResourceData, +) (PlaywrightCodeBundleResource, error) { + sourceArchiveAttr, err := PlaywrightCodeBundleSourceArchiveAttributeFromList(d.Get("source_archive").([]any)) + if err != nil { + return PlaywrightCodeBundleResource{}, err + } + + data, err := PlaywrightCodeBundleDataFromString(d.Get("data").(string)) + if err != nil { + return PlaywrightCodeBundleResource{}, err + } + + resource := PlaywrightCodeBundleResource{ + ID: d.Id(), + Data: data, + SourceArchive: sourceArchiveAttr, + } + + return resource, nil +} + +func PlaywrightCodeBundleResourceFromResourceDiff( + d *schema.ResourceDiff, +) (PlaywrightCodeBundleResource, error) { + sourceArchiveAttr, err := PlaywrightCodeBundleSourceArchiveAttributeFromList(d.Get("source_archive").([]any)) + if err != nil { + return PlaywrightCodeBundleResource{}, err + } + + data, err := PlaywrightCodeBundleDataFromString(d.Get("data").(string)) + if err != nil { + return PlaywrightCodeBundleResource{}, err + } + + resource := PlaywrightCodeBundleResource{ + ID: d.Id(), + Data: data, + SourceArchive: sourceArchiveAttr, + } + + return resource, nil +} + +type PlaywrightCodeBundleSourceArchiveAttribute struct { + File string +} + +func PlaywrightCodeBundleSourceArchiveAttributeFromList( + list []any, +) (*PlaywrightCodeBundleSourceArchiveAttribute, error) { + if len(list) == 0 { + return nil, nil + } + + m := list[0].(tfMap) + + a := PlaywrightCodeBundleSourceArchiveAttribute{ + File: m["file"].(string), + } + + return &a, nil +} + +func (a *PlaywrightCodeBundleSourceArchiveAttribute) ToList() []tfMap { + if a == nil { + return []tfMap{} + } + + return []tfMap{ + { + "file": a.File, + }, + } +} + +func (a *PlaywrightCodeBundleSourceArchiveAttribute) ChecksumSha256() (string, error) { + file, err := os.Open(a.File) + if err != nil { + return "", fmt.Errorf("failed to open archive file %q: %w", a.File, err) + } + defer file.Close() + + checksum := checksumSha256(file) + + return checksum, nil +} + +func (a *PlaywrightCodeBundleSourceArchiveAttribute) Upload( + ctx context.Context, + client checkly.Client, +) (*checkly.CodeBundle, error) { + stat, err := os.Stat(a.File) + if err != nil { + if os.IsNotExist(err) { + return nil, fmt.Errorf("source archive file %q does not exist", a.File) + } + + return nil, fmt.Errorf("failed to stat archive file %q: %w", a.File, err) + } + + checksum, err := a.ChecksumSha256() + if err != nil { + return nil, fmt.Errorf("failed to calculate checksum for archive file %q: %w", a.File, err) + } + + file, err := os.Open(a.File) + if err != nil { + return nil, fmt.Errorf("failed to open archive file %q: %w", a.File, err) + } + + codeBundle, err := client.UploadCodeBundle(ctx, file, stat.Size(), checkly.UploadCodeBundleOptions{ + ChecksumSha256: checksum, + }) + if err != nil { + return nil, fmt.Errorf("failed to upload code bundle %q: %w", a.File, err) + } + + return codeBundle, nil +} diff --git a/checkly/validation.go b/checkly/validation.go index 0933cf5..17a1da2 100644 --- a/checkly/validation.go +++ b/checkly/validation.go @@ -3,6 +3,7 @@ package checkly import ( "cmp" "fmt" + "os" "slices" ) @@ -25,3 +26,16 @@ func validateBetween[T cmp.Ordered](from, to T) func(val any, key string) (warns return warns, errs } } + +func validateFileExists() func(val any, key string) (warns []string, errs []error) { + return func(val any, key string) (warns []string, errs []error) { + v := val.(string) + + _, err := os.Stat(v) + if os.IsNotExist(err) { + errs = append(errs, fmt.Errorf("%q refers to a non-existing file %q: %w", key, v, err)) + } + + return warns, errs + } +} diff --git a/docs/resources/playwright_check_suite.md b/docs/resources/playwright_check_suite.md new file mode 100644 index 0000000..f58fa55 --- /dev/null +++ b/docs/resources/playwright_check_suite.md @@ -0,0 +1,218 @@ +--- +# generated by https://github.com/hashicorp/terraform-plugin-docs +page_title: "checkly_playwright_check_suite Resource - terraform-provider-checkly" +subcategory: "" +description: |- + Creates a DNS Monitor to check DNS record availability and response times. +--- + +# checkly_playwright_check_suite (Resource) + +Creates a DNS Monitor to check DNS record availability and response times. + +## Example Usage + +```terraform +data "archive_file" "playwright-bundle" { + type = "tar.gz" + output_path = "test-bundle.tar.gz" + source_dir = "${path.module}/" +} + +resource "checkly_playwright_code_bundle" "playwright-bundle" { + source_archive { + file = data.archive_file.playwright-bundle.output_path + } +} + +resource "checkly_playwright_check_suite" "example-playwright-check" { + name = "Example Playwright check" + activated = true + frequency = 2 + use_global_alert_settings = true + + locations = [ + "eu-west-1" + ] + + bundle { + id = checkly_playwright_code_bundle.playwright-bundle.id + data = checkly_playwright_code_bundle.playwright-bundle.data + } + + runtime { + steps { + install { + command = "pnpm i" + } + + test { + command = "pnpm playwright test" + } + } + + playwright { + version = "1.56.1" + + device { + type = "chromium" + } + } + } +} +``` + + +## Schema + +### Required + +- `activated` (Boolean) Determines whether the check will run periodically or not after being deployed. +- `bundle` (Block List, Min: 1, Max: 1) Attaches a code bundle to the check. (see [below for nested schema](#nestedblock--bundle)) +- `frequency` (Number) How often the check should run in minutes. Possible values are `1`, `2`, `5`, `10`, `15`, `30`, `60`, `120`, `180`, `360`, `720`, and `1440`. +- `name` (String) The name of the check. +- `runtime` (Block List, Min: 1, Max: 1) Configure the runtime environment of the Playwright check. (see [below for nested schema](#nestedblock--runtime)) + +### Optional + +- `alert_channel_subscription` (Block List) An array of channel IDs and whether they're activated or not. If you don't set at least one alert subscription for your check, we won't be able to alert you. (see [below for nested schema](#nestedblock--alert_channel_subscription)) +- `alert_settings` (Block List, Max: 1) Determines the alert escalation policy for the check. (see [below for nested schema](#nestedblock--alert_settings)) +- `group_id` (Number) The ID of the check group that this check is part of. +- `group_order` (Number) The position of the check in the check group. It determines in what order checks and monitors are run when a group is triggered from the API or from CI/CD. +- `locations` (Set of String) An array of one or more data center locations where to run the this check. +- `muted` (Boolean) Determines if any notifications will be sent out when the check fails and/or recovers. (Default `false`). +- `private_locations` (Set of String) An array of one or more private locations slugs. +- `run_parallel` (Boolean) Determines whether the check should run on all selected locations in parallel or round-robin. (Default `false`). +- `tags` (Set of String) A list of tags for organizing and filtering checks and monitors. +- `trigger_incident` (Block Set, Max: 1) Create and resolve an incident based on the alert configuration. Useful for status page automation. (see [below for nested schema](#nestedblock--trigger_incident)) +- `use_global_alert_settings` (Boolean) When true, the account level alert settings will be used, not the alert setting defined on this check. (Default `true`). + +### Read-Only + +- `id` (String) The ID of this resource. + + +### Nested Schema for `bundle` + +Required: + +- `data` (String) The auxiliary data of the code bundle. +- `id` (String) The ID of the code bundle. + + + +### Nested Schema for `runtime` + +Optional: + +- `playwright` (Block List, Max: 1) Configure the Playwright capabilities that should be made available to the runtime environment. (see [below for nested schema](#nestedblock--runtime--playwright)) +- `steps` (Block List, Max: 1) Customize the actions taken during test execution. (see [below for nested schema](#nestedblock--runtime--steps)) + + +### Nested Schema for `runtime.playwright` + +Optional: + +- `device` (Block Set) The list of devices that should be made available for Playwright. (see [below for nested schema](#nestedblock--runtime--playwright--device)) +- `version` (String) The Playwright version to use. + + +### Nested Schema for `runtime.playwright.device` + +Required: + +- `type` (String) The type of the device. + + + + +### Nested Schema for `runtime.steps` + +Optional: + +- `install` (Block List, Max: 1) Customize the install step, which is used to initialize the environment prior to starting the test run. (see [below for nested schema](#nestedblock--runtime--steps--install)) +- `test` (Block List, Max: 1) Customize the test step. (see [below for nested schema](#nestedblock--runtime--steps--test)) + + +### Nested Schema for `runtime.steps.install` + +Optional: + +- `command` (String) The command used to install dependencies prior to running Playwright. The default value is the appropriate install command for your package manager (e.g. `npm install` for `npm`). + + + +### Nested Schema for `runtime.steps.test` + +Optional: + +- `command` (String) The command used to run Playwright. The default value is the appropriate exec command for your package manager (e.g. `npx playwright test` for `npm`). + + + + + +### Nested Schema for `alert_channel_subscription` + +Required: + +- `activated` (Boolean) Whether an alert should be sent to this channel. +- `channel_id` (Number) The ID of the alert channel. + + + +### Nested Schema for `alert_settings` + +Optional: + +- `escalation_type` (String) Determines the type of escalation to use. Possible values are `RUN_BASED` and `TIME_BASED`. (Default `RUN_BASED`). +- `parallel_run_failure_threshold` (Block List) Configuration for parallel run failure threshold. (see [below for nested schema](#nestedblock--alert_settings--parallel_run_failure_threshold)) +- `reminders` (Block List) Defines how often to send reminder notifications after initial alert. (see [below for nested schema](#nestedblock--alert_settings--reminders)) +- `run_based_escalation` (Block List) Configuration for run-based escalation. (see [below for nested schema](#nestedblock--alert_settings--run_based_escalation)) +- `time_based_escalation` (Block List) Configuration for time-based escalation. (see [below for nested schema](#nestedblock--alert_settings--time_based_escalation)) + + +### Nested Schema for `alert_settings.parallel_run_failure_threshold` + +Optional: + +- `enabled` (Boolean) Whether parallel run failure threshold is enabled. Only applies if the check is scheduled for multiple locations in parallel. (Default `false`). +- `percentage` (Number) Percentage of runs that must fail to trigger alert. Possible values are `10`, `20`, `30`, `40`, `50`, `60`, `70`, `80`, `90`, and `100`. (Default `10`). + + + +### Nested Schema for `alert_settings.reminders` + +Optional: + +- `amount` (Number) Number of reminder notifications to send. Possible values are `0`, `1`, `2`, `3`, `4`, `5`, and `100000` (`0` to disable, `100000` for unlimited). (Default `0`). +- `interval` (Number) Interval between reminder notifications in minutes. Possible values are `5`, `10`, `15`, and `30`. (Default `5`). + + + +### Nested Schema for `alert_settings.run_based_escalation` + +Optional: + +- `failed_run_threshold` (Number) Send an alert notification after the given number of consecutive check runs have failed. Possible values are between `1` and `5`. (Default `1`). + + + +### Nested Schema for `alert_settings.time_based_escalation` + +Optional: + +- `minutes_failing_threshold` (Number) Send an alert notification after the check has been failing for the given amount of time (in minutes). Possible values are `5`, `10`, `15`, and `30`. (Default `5`). + + + + +### Nested Schema for `trigger_incident` + +Required: + +- `description` (String) A detailed description of the incident. +- `name` (String) The name of the incident. +- `notify_subscribers` (Boolean) Whether to notify subscribers when the incident is triggered. +- `service_id` (String) The status page service that this incident will be associated with. +- `severity` (String) The severity level of the incident. Possible values are `MINOR`, `MEDIUM`, `MAJOR`, and `CRITICAL`. diff --git a/docs/resources/playwright_code_bundle.md b/docs/resources/playwright_code_bundle.md new file mode 100644 index 0000000..427a7c8 --- /dev/null +++ b/docs/resources/playwright_code_bundle.md @@ -0,0 +1,52 @@ +--- +# generated by https://github.com/hashicorp/terraform-plugin-docs +page_title: "checkly_playwright_code_bundle Resource - terraform-provider-checkly" +subcategory: "" +description: |- + A managed code bundle which can be used in Playwright Check Suite resources. +--- + +# checkly_playwright_code_bundle (Resource) + +A managed code bundle which can be used in Playwright Check Suite resources. + +## Example Usage + +```terraform +data "archive_file" "playwright-bundle" { + type = "tar.gz" + output_path = "example-playwright-bundle.tar.gz" + source_dir = "${path.module}/" +} + +resource "checkly_playwright_code_bundle" "example-1" { + source_archive { + file = data.archive_file.playwright-bundle.output_path + } +} + +resource "checkly_playwright_code_bundle" "example-2" { + source_archive { + file = "${path.module}/existing-playwright-bundle.tar.gz" + } +} +``` + + +## Schema + +### Required + +- `source_archive` (Block List, Min: 1, Max: 1) (see [below for nested schema](#nestedblock--source_archive)) + +### Read-Only + +- `data` (String) An opaque, computed value containing auxiliary data of the code bundle. This value should be passed as-is to a check resource. +- `id` (String) The ID of this resource. + + +### Nested Schema for `source_archive` + +Required: + +- `file` (String) diff --git a/examples/resources/checkly_playwright_check_suite/resource.tf b/examples/resources/checkly_playwright_check_suite/resource.tf new file mode 100644 index 0000000..da0eb23 --- /dev/null +++ b/examples/resources/checkly_playwright_check_suite/resource.tf @@ -0,0 +1,47 @@ +data "archive_file" "playwright-bundle" { + type = "tar.gz" + output_path = "test-bundle.tar.gz" + source_dir = "${path.module}/" +} + +resource "checkly_playwright_code_bundle" "playwright-bundle" { + source_archive { + file = data.archive_file.playwright-bundle.output_path + } +} + +resource "checkly_playwright_check_suite" "example-playwright-check" { + name = "Example Playwright check" + activated = true + frequency = 2 + use_global_alert_settings = true + + locations = [ + "eu-west-1" + ] + + bundle { + id = checkly_playwright_code_bundle.playwright-bundle.id + data = checkly_playwright_code_bundle.playwright-bundle.data + } + + runtime { + steps { + install { + command = "pnpm i" + } + + test { + command = "pnpm playwright test" + } + } + + playwright { + version = "1.56.1" + + device { + type = "chromium" + } + } + } +} diff --git a/examples/resources/checkly_playwright_code_bundle/resource.tf b/examples/resources/checkly_playwright_code_bundle/resource.tf new file mode 100644 index 0000000..819210e --- /dev/null +++ b/examples/resources/checkly_playwright_code_bundle/resource.tf @@ -0,0 +1,17 @@ +data "archive_file" "playwright-bundle" { + type = "tar.gz" + output_path = "example-playwright-bundle.tar.gz" + source_dir = "${path.module}/" +} + +resource "checkly_playwright_code_bundle" "example-1" { + source_archive { + file = data.archive_file.playwright-bundle.output_path + } +} + +resource "checkly_playwright_code_bundle" "example-2" { + source_archive { + file = "${path.module}/existing-playwright-bundle.tar.gz" + } +} From f838f1758dd4d91ee04e0af2c81914947be819a6 Mon Sep 17 00:00:00 2001 From: Simo Kinnunen Date: Fri, 28 Nov 2025 22:43:28 +0900 Subject: [PATCH 2/9] refactor: rename bundle data attribute to metadata, which is more suitable --- checkly/resource_playwright_check_suite.go | 20 ++-- checkly/resource_playwright_code_bundle.go | 97 ++++++++++--------- docs/resources/playwright_check_suite.md | 6 +- docs/resources/playwright_code_bundle.md | 10 +- .../resource.tf | 4 +- 5 files changed, 71 insertions(+), 66 deletions(-) diff --git a/checkly/resource_playwright_check_suite.go b/checkly/resource_playwright_check_suite.go index 376460c..2f83421 100644 --- a/checkly/resource_playwright_check_suite.go +++ b/checkly/resource_playwright_check_suite.go @@ -115,8 +115,8 @@ func resourcePlaywrightCheckSuite() *schema.Resource { Type: schema.TypeString, Required: true, }, - "data": { - Description: "The auxiliary data of the code bundle.", + metadataAttributeName: { + Description: "The generated metadata of the code bundle.", Type: schema.TypeString, Required: true, }, @@ -343,7 +343,7 @@ func PlaywrightCheckSuiteResourceFromResourceData( // We may want to make this configurable in the future, but for now // this will do. - check.CacheHash = checksumSha256(strings.NewReader(bundleAttr.Data.ChecksumSha256)) + check.CacheHash = checksumSha256(strings.NewReader(bundleAttr.Metadata.ChecksumSha256)) } runtimeAttr, err := PlaywrightCheckSuiteRuntimeAttributeFromList(d.Get("runtime").([]any)) @@ -483,8 +483,8 @@ func (r *PlaywrightCheckSuiteResource) StoreResourceData( } type PlaywrightCheckSuiteBundleAttribute struct { - ID string - Data *PlaywrightCodeBundleData + ID string + Metadata *PlaywrightCodeBundleMetadata } func PlaywrightCheckSuiteBundleAttributeFromList( @@ -496,14 +496,14 @@ func PlaywrightCheckSuiteBundleAttributeFromList( m := list[0].(tfMap) - data, err := PlaywrightCodeBundleDataFromString(m["data"].(string)) + data, err := PlaywrightCodeBundleMetadataFromString(m[metadataAttributeName].(string)) if err != nil { return nil, err } a := PlaywrightCheckSuiteBundleAttribute{ - ID: m["id"].(string), - Data: data, + ID: m["id"].(string), + Metadata: data, } return &a, nil @@ -516,8 +516,8 @@ func (a *PlaywrightCheckSuiteBundleAttribute) ToList() []tfMap { return []tfMap{ { - "id": a.ID, - "data": a.Data.EncodeToString(), + "id": a.ID, + metadataAttributeName: a.Metadata.EncodeToString(), }, } } diff --git a/checkly/resource_playwright_code_bundle.go b/checkly/resource_playwright_code_bundle.go index 7340ff6..5c734bd 100644 --- a/checkly/resource_playwright_code_bundle.go +++ b/checkly/resource_playwright_code_bundle.go @@ -15,6 +15,11 @@ import ( "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" ) +const ( + prebuiltArchiveAttributeName = "prebuilt_archive" + metadataAttributeName = "metadata" +) + func resourcePlaywrightCodeBundle() *schema.Resource { return &schema.Resource{ CreateContext: resourcePlaywrightCodeBundleCreate, @@ -22,8 +27,8 @@ func resourcePlaywrightCodeBundle() *schema.Resource { DeleteContext: resourcePlaywrightCodeBundleDelete, Description: "A managed code bundle which can be used in Playwright Check Suite resources.", Schema: map[string]*schema.Schema{ - "source_archive": { - Description: "", + prebuiltArchiveAttributeName: { + Description: "A prebuilt archive containing the code bundle.", Type: schema.TypeList, Required: true, ForceNew: true, @@ -31,7 +36,7 @@ func resourcePlaywrightCodeBundle() *schema.Resource { Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ "file": { - Description: "", + Description: "Path to the archive file.", Type: schema.TypeString, Required: true, ForceNew: true, @@ -40,10 +45,10 @@ func resourcePlaywrightCodeBundle() *schema.Resource { }, }, }, - "data": { - Description: "An opaque, computed value containing auxiliary " + - "data of the code bundle. This value should be passed " + - "as-is to a check resource.", + metadataAttributeName: { + Description: "An opaque blob of generated metadata. The " + + "value is not intended to be user-consumable and should " + + "be passed as-is to a Playwright check resource.", Type: schema.TypeString, Computed: true, ForceNew: true, @@ -57,8 +62,8 @@ func resourcePlaywrightCodeBundle() *schema.Resource { } switch { - case bundle.SourceArchive != nil: - checksum, err := bundle.SourceArchive.ChecksumSha256() + case bundle.PrebuiltArchive != nil: + checksum, err := bundle.PrebuiltArchive.ChecksumSha256() if err != nil { return fmt.Errorf("failed to calculate source archive checksum: %v", err) } @@ -76,9 +81,9 @@ func resourcePlaywrightCodeBundle() *schema.Resource { bundle.Data.Version = 1 bundle.Data.ChecksumSha256 = checksum - err = diff.SetNew("data", bundle.Data.EncodeToString()) + err = diff.SetNew(metadataAttributeName, bundle.Data.EncodeToString()) if err != nil { - return fmt.Errorf("failed to set %q: %v", "data", err) + return fmt.Errorf("failed to set %q: %v", metadataAttributeName, err) } return nil @@ -104,22 +109,22 @@ func resourcePlaywrightCodeBundleCreate( } switch { - case bundle.SourceArchive != nil: - result, err := bundle.SourceArchive.Upload(ctx, client.(checkly.Client)) + case bundle.PrebuiltArchive != nil: + result, err := bundle.PrebuiltArchive.Upload(ctx, client.(checkly.Client)) if err != nil { return diag.Errorf("failed to upload source archive: %v", err) } d.SetId(base64.StdEncoding.EncodeToString([]byte(result.Key))) - err = d.Set("source_archive", bundle.SourceArchive.ToList()) + err = d.Set(prebuiltArchiveAttributeName, bundle.PrebuiltArchive.ToList()) if err != nil { - return diag.Errorf("failed to set %q state: %v", "source_archive", err) + return diag.Errorf("failed to set %q state: %v", prebuiltArchiveAttributeName, err) } - err = d.Set("data", bundle.Data.EncodeToString()) + err = d.Set(metadataAttributeName, bundle.Data.EncodeToString()) if err != nil { - return diag.Errorf("failed to set %q state: %v", "data", err) + return diag.Errorf("failed to set %q state: %v", metadataAttributeName, err) } return nil @@ -159,9 +164,9 @@ func resourcePlaywrightCodeBundleRead( if result.ChecksumSha256 != "" { bundle.Data.ChecksumSha256 = result.ChecksumSha256 - err = d.Set("data", bundle.Data.EncodeToString()) + err = d.Set(metadataAttributeName, bundle.Data.EncodeToString()) if err != nil { - return diag.Errorf("failed to set %q state: %v", "data", err) + return diag.Errorf("failed to set %q state: %v", metadataAttributeName, err) } } @@ -178,34 +183,34 @@ func resourcePlaywrightCodeBundleDelete( return diags } -type PlaywrightCodeBundleData struct { +type PlaywrightCodeBundleMetadata struct { Version int `json:"v"` ChecksumSha256 string `json:"s256"` } -func PlaywrightCodeBundleDataFromString(s string) (*PlaywrightCodeBundleData, error) { +func PlaywrightCodeBundleMetadataFromString(s string) (*PlaywrightCodeBundleMetadata, error) { if s == "" { - return new(PlaywrightCodeBundleData), nil + return new(PlaywrightCodeBundleMetadata), nil } b64, err := base64.StdEncoding.DecodeString(s) if err != nil { - return nil, fmt.Errorf("failed to decode code bundle data %q: %w", s, err) + return nil, fmt.Errorf("failed to decode code bundle metadata %q: %w", s, err) } dec := json.NewDecoder(bytes.NewReader(b64)) - var t PlaywrightCodeBundleData + var t PlaywrightCodeBundleMetadata err = dec.Decode(&t) if err != nil { - return nil, fmt.Errorf("failed to decode code bundle data %q: %w", s, err) + return nil, fmt.Errorf("failed to decode code bundle metadata %q: %w", s, err) } return &t, err } -func (t *PlaywrightCodeBundleData) EncodeToString() string { +func (t *PlaywrightCodeBundleMetadata) EncodeToString() string { buf := new(bytes.Buffer) enc := json.NewEncoder(buf) @@ -220,28 +225,28 @@ func (t *PlaywrightCodeBundleData) EncodeToString() string { } type PlaywrightCodeBundleResource struct { - ID string - Data *PlaywrightCodeBundleData - SourceArchive *PlaywrightCodeBundleSourceArchiveAttribute + ID string + Data *PlaywrightCodeBundleMetadata + PrebuiltArchive *PlaywrightCodeBundlePrebuiltArchiveAttribute } func PlaywrightCodeBundleResourceFromResourceData( d *schema.ResourceData, ) (PlaywrightCodeBundleResource, error) { - sourceArchiveAttr, err := PlaywrightCodeBundleSourceArchiveAttributeFromList(d.Get("source_archive").([]any)) + prebuiltArchiveAttr, err := PlaywrightCodeBundlePrebuiltArchiveAttributeFromList(d.Get(prebuiltArchiveAttributeName).([]any)) if err != nil { return PlaywrightCodeBundleResource{}, err } - data, err := PlaywrightCodeBundleDataFromString(d.Get("data").(string)) + data, err := PlaywrightCodeBundleMetadataFromString(d.Get(metadataAttributeName).(string)) if err != nil { return PlaywrightCodeBundleResource{}, err } resource := PlaywrightCodeBundleResource{ - ID: d.Id(), - Data: data, - SourceArchive: sourceArchiveAttr, + ID: d.Id(), + Data: data, + PrebuiltArchive: prebuiltArchiveAttr, } return resource, nil @@ -250,46 +255,46 @@ func PlaywrightCodeBundleResourceFromResourceData( func PlaywrightCodeBundleResourceFromResourceDiff( d *schema.ResourceDiff, ) (PlaywrightCodeBundleResource, error) { - sourceArchiveAttr, err := PlaywrightCodeBundleSourceArchiveAttributeFromList(d.Get("source_archive").([]any)) + prebuiltArchiveAttr, err := PlaywrightCodeBundlePrebuiltArchiveAttributeFromList(d.Get(prebuiltArchiveAttributeName).([]any)) if err != nil { return PlaywrightCodeBundleResource{}, err } - data, err := PlaywrightCodeBundleDataFromString(d.Get("data").(string)) + data, err := PlaywrightCodeBundleMetadataFromString(d.Get(metadataAttributeName).(string)) if err != nil { return PlaywrightCodeBundleResource{}, err } resource := PlaywrightCodeBundleResource{ - ID: d.Id(), - Data: data, - SourceArchive: sourceArchiveAttr, + ID: d.Id(), + Data: data, + PrebuiltArchive: prebuiltArchiveAttr, } return resource, nil } -type PlaywrightCodeBundleSourceArchiveAttribute struct { +type PlaywrightCodeBundlePrebuiltArchiveAttribute struct { File string } -func PlaywrightCodeBundleSourceArchiveAttributeFromList( +func PlaywrightCodeBundlePrebuiltArchiveAttributeFromList( list []any, -) (*PlaywrightCodeBundleSourceArchiveAttribute, error) { +) (*PlaywrightCodeBundlePrebuiltArchiveAttribute, error) { if len(list) == 0 { return nil, nil } m := list[0].(tfMap) - a := PlaywrightCodeBundleSourceArchiveAttribute{ + a := PlaywrightCodeBundlePrebuiltArchiveAttribute{ File: m["file"].(string), } return &a, nil } -func (a *PlaywrightCodeBundleSourceArchiveAttribute) ToList() []tfMap { +func (a *PlaywrightCodeBundlePrebuiltArchiveAttribute) ToList() []tfMap { if a == nil { return []tfMap{} } @@ -301,7 +306,7 @@ func (a *PlaywrightCodeBundleSourceArchiveAttribute) ToList() []tfMap { } } -func (a *PlaywrightCodeBundleSourceArchiveAttribute) ChecksumSha256() (string, error) { +func (a *PlaywrightCodeBundlePrebuiltArchiveAttribute) ChecksumSha256() (string, error) { file, err := os.Open(a.File) if err != nil { return "", fmt.Errorf("failed to open archive file %q: %w", a.File, err) @@ -313,7 +318,7 @@ func (a *PlaywrightCodeBundleSourceArchiveAttribute) ChecksumSha256() (string, e return checksum, nil } -func (a *PlaywrightCodeBundleSourceArchiveAttribute) Upload( +func (a *PlaywrightCodeBundlePrebuiltArchiveAttribute) Upload( ctx context.Context, client checkly.Client, ) (*checkly.CodeBundle, error) { diff --git a/docs/resources/playwright_check_suite.md b/docs/resources/playwright_check_suite.md index f58fa55..8353245 100644 --- a/docs/resources/playwright_check_suite.md +++ b/docs/resources/playwright_check_suite.md @@ -36,8 +36,8 @@ resource "checkly_playwright_check_suite" "example-playwright-check" { ] bundle { - id = checkly_playwright_code_bundle.playwright-bundle.id - data = checkly_playwright_code_bundle.playwright-bundle.data + key = checkly_playwright_code_bundle.playwright-bundle.key + metadata = checkly_playwright_code_bundle.playwright-bundle.metadata } runtime { @@ -96,8 +96,8 @@ resource "checkly_playwright_check_suite" "example-playwright-check" { Required: -- `data` (String) The auxiliary data of the code bundle. - `id` (String) The ID of the code bundle. +- `metadata` (String) The generated metadata of the code bundle. diff --git a/docs/resources/playwright_code_bundle.md b/docs/resources/playwright_code_bundle.md index 427a7c8..5e87120 100644 --- a/docs/resources/playwright_code_bundle.md +++ b/docs/resources/playwright_code_bundle.md @@ -37,16 +37,16 @@ resource "checkly_playwright_code_bundle" "example-2" { ### Required -- `source_archive` (Block List, Min: 1, Max: 1) (see [below for nested schema](#nestedblock--source_archive)) +- `prebuilt_archive` (Block List, Min: 1, Max: 1) A prebuilt archive containing the code bundle. (see [below for nested schema](#nestedblock--prebuilt_archive)) ### Read-Only -- `data` (String) An opaque, computed value containing auxiliary data of the code bundle. This value should be passed as-is to a check resource. - `id` (String) The ID of this resource. +- `metadata` (String) An opaque blob of generated metadata. The value is not intended to be user-consumable and should be passed as-is to a Playwright check resource. - -### Nested Schema for `source_archive` + +### Nested Schema for `prebuilt_archive` Required: -- `file` (String) +- `file` (String) Path to the archive file. diff --git a/examples/resources/checkly_playwright_check_suite/resource.tf b/examples/resources/checkly_playwright_check_suite/resource.tf index da0eb23..d4aff3b 100644 --- a/examples/resources/checkly_playwright_check_suite/resource.tf +++ b/examples/resources/checkly_playwright_check_suite/resource.tf @@ -21,8 +21,8 @@ resource "checkly_playwright_check_suite" "example-playwright-check" { ] bundle { - id = checkly_playwright_code_bundle.playwright-bundle.id - data = checkly_playwright_code_bundle.playwright-bundle.data + key = checkly_playwright_code_bundle.playwright-bundle.key + metadata = checkly_playwright_code_bundle.playwright-bundle.metadata } runtime { From c54a2427ee97d9040868f331f834359e21a71257 Mon Sep 17 00:00:00 2001 From: Simo Kinnunen Date: Fri, 28 Nov 2025 22:55:56 +0900 Subject: [PATCH 3/9] chore: update check suite resource for newly nullable attributes --- checkly/resource_playwright_check_suite.go | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/checkly/resource_playwright_check_suite.go b/checkly/resource_playwright_check_suite.go index 2f83421..2ce2be6 100644 --- a/checkly/resource_playwright_check_suite.go +++ b/checkly/resource_playwright_check_suite.go @@ -354,7 +354,7 @@ func PlaywrightCheckSuiteResourceFromResourceData( if runtimeAttr != nil { if runtimeAttr.Steps != nil { if runtimeAttr.Steps.Test != nil { - check.TestCommand = runtimeAttr.Steps.Test.Command + check.TestCommand = &runtimeAttr.Steps.Test.Command } if runtimeAttr.Steps.Install != nil { @@ -363,7 +363,7 @@ func PlaywrightCheckSuiteResourceFromResourceData( } if runtimeAttr.Playwright != nil { - check.PlaywrightVersion = runtimeAttr.Playwright.Version + check.PlaywrightVersion = &runtimeAttr.Playwright.Version var browsers []string for _, device := range *runtimeAttr.Playwright.Devices { @@ -397,7 +397,7 @@ func PlaywrightCheckSuiteResourceFromAPIModel( var runtimeAttr PlaywrightCheckSuiteRuntimeAttribute - if check.TestCommand != "" || check.InstallCommand != nil { + if check.TestCommand != nil || check.InstallCommand != nil { runtimeAttr.Steps = new(PlaywrightCheckSuiteRuntimeStepsAttribute) if check.InstallCommand != nil { @@ -406,18 +406,18 @@ func PlaywrightCheckSuiteResourceFromAPIModel( } } - if check.TestCommand != "" { + if check.TestCommand != nil { runtimeAttr.Steps.Test = &PlaywrightCheckSuiteRuntimeStepsTestAttribute{ - Command: check.TestCommand, + Command: *check.TestCommand, } } } - if len(check.Browsers) != 0 || check.PlaywrightVersion != "" { + if len(check.Browsers) != 0 || check.PlaywrightVersion != nil { runtimeAttr.Playwright = new(PlaywrightCheckSuiteRuntimePlaywrightAttribute) - if check.PlaywrightVersion != "" { - runtimeAttr.Playwright.Version = check.PlaywrightVersion + if check.PlaywrightVersion != nil { + runtimeAttr.Playwright.Version = *check.PlaywrightVersion } if len(check.Browsers) != 0 { From 6dfa61f8039ffee7900e190169820b063f806d4d Mon Sep 17 00:00:00 2001 From: Simo Kinnunen Date: Fri, 28 Nov 2025 22:59:43 +0900 Subject: [PATCH 4/9] feat: bump Go SDK to v1.18.0 which supports the necessary endpoints for PW checks --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 8c2547b..3f3b28e 100644 --- a/go.mod +++ b/go.mod @@ -4,7 +4,7 @@ go 1.24.0 require ( github.com/aws/aws-sdk-go v1.44.122 // indirect - github.com/checkly/checkly-go-sdk v1.17.0 + github.com/checkly/checkly-go-sdk v1.18.0 github.com/google/go-cmp v0.7.0 github.com/gruntwork-io/terratest v0.41.16 github.com/hashicorp/terraform-plugin-docs v0.19.4 diff --git a/go.sum b/go.sum index a06b37d..fdc18b7 100644 --- a/go.sum +++ b/go.sum @@ -251,8 +251,8 @@ github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghf github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= -github.com/checkly/checkly-go-sdk v1.17.0 h1:QjgzCzk93Mv37A9abQ7N2LXxXqC2D8KEQr0l2cB1j7o= -github.com/checkly/checkly-go-sdk v1.17.0/go.mod h1:Pd6tBOggAe41NnCU5KwqA8JvD6J20/IctszT2E0AvHo= +github.com/checkly/checkly-go-sdk v1.18.0 h1:zvegNiRPvGlrF/yHo6SsiS6vRpdv/XbO9DAmInBG8Ss= +github.com/checkly/checkly-go-sdk v1.18.0/go.mod h1:Pd6tBOggAe41NnCU5KwqA8JvD6J20/IctszT2E0AvHo= github.com/cheggaaa/pb v1.0.27/go.mod h1:pQciLPpbU0oxA0h+VJYYLxO+XeDQb5pZijXscXHm81s= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= From d2b3c79a5712387ddb245d981b57a37ad97faa3f Mon Sep 17 00:00:00 2001 From: Simo Kinnunen Date: Fri, 28 Nov 2025 23:05:01 +0900 Subject: [PATCH 5/9] chore: change source_archive to the new prebuilt_archive in docs --- docs/resources/playwright_check_suite.md | 2 +- docs/resources/playwright_code_bundle.md | 4 ++-- examples/resources/checkly_playwright_check_suite/resource.tf | 2 +- examples/resources/checkly_playwright_code_bundle/resource.tf | 4 ++-- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/docs/resources/playwright_check_suite.md b/docs/resources/playwright_check_suite.md index 8353245..d7d89ec 100644 --- a/docs/resources/playwright_check_suite.md +++ b/docs/resources/playwright_check_suite.md @@ -20,7 +20,7 @@ data "archive_file" "playwright-bundle" { } resource "checkly_playwright_code_bundle" "playwright-bundle" { - source_archive { + prebuilt_archive { file = data.archive_file.playwright-bundle.output_path } } diff --git a/docs/resources/playwright_code_bundle.md b/docs/resources/playwright_code_bundle.md index 5e87120..2e85ea0 100644 --- a/docs/resources/playwright_code_bundle.md +++ b/docs/resources/playwright_code_bundle.md @@ -20,13 +20,13 @@ data "archive_file" "playwright-bundle" { } resource "checkly_playwright_code_bundle" "example-1" { - source_archive { + prebuilt_archive { file = data.archive_file.playwright-bundle.output_path } } resource "checkly_playwright_code_bundle" "example-2" { - source_archive { + prebuilt_archive { file = "${path.module}/existing-playwright-bundle.tar.gz" } } diff --git a/examples/resources/checkly_playwright_check_suite/resource.tf b/examples/resources/checkly_playwright_check_suite/resource.tf index d4aff3b..e1d73f1 100644 --- a/examples/resources/checkly_playwright_check_suite/resource.tf +++ b/examples/resources/checkly_playwright_check_suite/resource.tf @@ -5,7 +5,7 @@ data "archive_file" "playwright-bundle" { } resource "checkly_playwright_code_bundle" "playwright-bundle" { - source_archive { + prebuilt_archive { file = data.archive_file.playwright-bundle.output_path } } diff --git a/examples/resources/checkly_playwright_code_bundle/resource.tf b/examples/resources/checkly_playwright_code_bundle/resource.tf index 819210e..f413482 100644 --- a/examples/resources/checkly_playwright_code_bundle/resource.tf +++ b/examples/resources/checkly_playwright_code_bundle/resource.tf @@ -5,13 +5,13 @@ data "archive_file" "playwright-bundle" { } resource "checkly_playwright_code_bundle" "example-1" { - source_archive { + prebuilt_archive { file = data.archive_file.playwright-bundle.output_path } } resource "checkly_playwright_code_bundle" "example-2" { - source_archive { + prebuilt_archive { file = "${path.module}/existing-playwright-bundle.tar.gz" } } From 1da5b8c68b5ffc5eca0a21e285cceb2131df34fc Mon Sep 17 00:00:00 2001 From: Simo Kinnunen Date: Mon, 1 Dec 2025 20:25:59 +0900 Subject: [PATCH 6/9] chore: make examples more complete --- docs/resources/playwright_check_suite.md | 8 ++++++-- docs/resources/playwright_code_bundle.md | 10 ++++++++-- .../checkly_playwright_check_suite/resource.tf | 8 ++++++-- .../checkly_playwright_code_bundle/resource.tf | 10 ++++++++-- 4 files changed, 28 insertions(+), 8 deletions(-) diff --git a/docs/resources/playwright_check_suite.md b/docs/resources/playwright_check_suite.md index d7d89ec..ec74fca 100644 --- a/docs/resources/playwright_check_suite.md +++ b/docs/resources/playwright_check_suite.md @@ -15,8 +15,12 @@ Creates a DNS Monitor to check DNS record availability and response times. ```terraform data "archive_file" "playwright-bundle" { type = "tar.gz" - output_path = "test-bundle.tar.gz" - source_dir = "${path.module}/" + output_path = "app-bundle.tar.gz" + source_dir = "${path.module}/app/" + excludes = [ + ".git", + "node_modules", + ] } resource "checkly_playwright_code_bundle" "playwright-bundle" { diff --git a/docs/resources/playwright_code_bundle.md b/docs/resources/playwright_code_bundle.md index 2e85ea0..458c149 100644 --- a/docs/resources/playwright_code_bundle.md +++ b/docs/resources/playwright_code_bundle.md @@ -13,10 +13,15 @@ A managed code bundle which can be used in Playwright Check Suite resources. ## Example Usage ```terraform +# Construct a new bundle from source files data "archive_file" "playwright-bundle" { type = "tar.gz" - output_path = "example-playwright-bundle.tar.gz" - source_dir = "${path.module}/" + output_path = "app-bundle.tar.gz" + source_dir = "${path.module}/app/" + excludes = [ + ".git", + "node_modules", + ] } resource "checkly_playwright_code_bundle" "example-1" { @@ -25,6 +30,7 @@ resource "checkly_playwright_code_bundle" "example-1" { } } +# Use an existing bundle archive resource "checkly_playwright_code_bundle" "example-2" { prebuilt_archive { file = "${path.module}/existing-playwright-bundle.tar.gz" diff --git a/examples/resources/checkly_playwright_check_suite/resource.tf b/examples/resources/checkly_playwright_check_suite/resource.tf index e1d73f1..a6a3a73 100644 --- a/examples/resources/checkly_playwright_check_suite/resource.tf +++ b/examples/resources/checkly_playwright_check_suite/resource.tf @@ -1,7 +1,11 @@ data "archive_file" "playwright-bundle" { type = "tar.gz" - output_path = "test-bundle.tar.gz" - source_dir = "${path.module}/" + output_path = "app-bundle.tar.gz" + source_dir = "${path.module}/app/" + excludes = [ + ".git", + "node_modules", + ] } resource "checkly_playwright_code_bundle" "playwright-bundle" { diff --git a/examples/resources/checkly_playwright_code_bundle/resource.tf b/examples/resources/checkly_playwright_code_bundle/resource.tf index f413482..f98d9df 100644 --- a/examples/resources/checkly_playwright_code_bundle/resource.tf +++ b/examples/resources/checkly_playwright_code_bundle/resource.tf @@ -1,7 +1,12 @@ +# Construct a new bundle from source files data "archive_file" "playwright-bundle" { type = "tar.gz" - output_path = "example-playwright-bundle.tar.gz" - source_dir = "${path.module}/" + output_path = "app-bundle.tar.gz" + source_dir = "${path.module}/app/" + excludes = [ + ".git", + "node_modules", + ] } resource "checkly_playwright_code_bundle" "example-1" { @@ -10,6 +15,7 @@ resource "checkly_playwright_code_bundle" "example-1" { } } +# Use an existing bundle archive resource "checkly_playwright_code_bundle" "example-2" { prebuilt_archive { file = "${path.module}/existing-playwright-bundle.tar.gz" From dcdcf9bc27f839c83870a84e3145b55afda267fc Mon Sep 17 00:00:00 2001 From: Simo Kinnunen Date: Mon, 1 Dec 2025 20:35:31 +0900 Subject: [PATCH 7/9] chore: update playwright check description --- checkly/resource_playwright_check_suite.go | 2 +- docs/resources/playwright_check_suite.md | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/checkly/resource_playwright_check_suite.go b/checkly/resource_playwright_check_suite.go index 2ce2be6..8425f62 100644 --- a/checkly/resource_playwright_check_suite.go +++ b/checkly/resource_playwright_check_suite.go @@ -21,7 +21,7 @@ func resourcePlaywrightCheckSuite() *schema.Resource { Importer: &schema.ResourceImporter{ StateContext: schema.ImportStatePassthroughContext, }, - Description: "Creates a DNS Monitor to check DNS record availability and response times.", + Description: "Creates a Playwright check from a code bundle.", Schema: map[string]*schema.Schema{ "name": { Description: "The name of the check.", diff --git a/docs/resources/playwright_check_suite.md b/docs/resources/playwright_check_suite.md index ec74fca..32b0a86 100644 --- a/docs/resources/playwright_check_suite.md +++ b/docs/resources/playwright_check_suite.md @@ -3,12 +3,12 @@ page_title: "checkly_playwright_check_suite Resource - terraform-provider-checkly" subcategory: "" description: |- - Creates a DNS Monitor to check DNS record availability and response times. + Creates a Playwright check from a code bundle. --- # checkly_playwright_check_suite (Resource) -Creates a DNS Monitor to check DNS record availability and response times. +Creates a Playwright check from a code bundle. ## Example Usage From 74124b01bfcc9b122d27f4b52e068d7a4c623701 Mon Sep 17 00:00:00 2001 From: Simo Kinnunen Date: Mon, 1 Dec 2025 20:41:48 +0900 Subject: [PATCH 8/9] chore: update check suite usage --- .../checkly_playwright_check_suite/resource.tf | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/examples/resources/checkly_playwright_check_suite/resource.tf b/examples/resources/checkly_playwright_check_suite/resource.tf index a6a3a73..4c98c4d 100644 --- a/examples/resources/checkly_playwright_check_suite/resource.tf +++ b/examples/resources/checkly_playwright_check_suite/resource.tf @@ -25,18 +25,14 @@ resource "checkly_playwright_check_suite" "example-playwright-check" { ] bundle { - key = checkly_playwright_code_bundle.playwright-bundle.key + id = checkly_playwright_code_bundle.playwright-bundle.id metadata = checkly_playwright_code_bundle.playwright-bundle.metadata } runtime { steps { - install { - command = "pnpm i" - } - test { - command = "pnpm playwright test" + command = "npx playwright test --config \"playwright.config.ts\"" } } @@ -46,6 +42,10 @@ resource "checkly_playwright_check_suite" "example-playwright-check" { device { type = "chromium" } + + device { + type = "firefox" + } } } } From 0da279602d610c4c77e36509e2dbe69d2375c2f2 Mon Sep 17 00:00:00 2001 From: Simo Kinnunen Date: Mon, 1 Dec 2025 20:44:55 +0900 Subject: [PATCH 9/9] chore: generate docs --- docs/resources/playwright_check_suite.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/docs/resources/playwright_check_suite.md b/docs/resources/playwright_check_suite.md index 32b0a86..55f02fc 100644 --- a/docs/resources/playwright_check_suite.md +++ b/docs/resources/playwright_check_suite.md @@ -40,18 +40,14 @@ resource "checkly_playwright_check_suite" "example-playwright-check" { ] bundle { - key = checkly_playwright_code_bundle.playwright-bundle.key + id = checkly_playwright_code_bundle.playwright-bundle.id metadata = checkly_playwright_code_bundle.playwright-bundle.metadata } runtime { steps { - install { - command = "pnpm i" - } - test { - command = "pnpm playwright test" + command = "npx playwright test --config \"playwright.config.ts\"" } } @@ -61,6 +57,10 @@ resource "checkly_playwright_check_suite" "example-playwright-check" { device { type = "chromium" } + + device { + type = "firefox" + } } } }