watchfor 0.10.0 → 0.12.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 4922ce5a8ab3f8757d67110dd6705ec23cd07190e2ce12fb8e3a76b0bef72cd7
4
- data.tar.gz: 53ae8a93fb27b7e96ca47cd7383fbbbc1207c1cadc597316429b6b4f43232521
3
+ metadata.gz: b3d7fc66146ff02aa81bb3517188f14d8ce8c04b9b643b869aba9793610560b6
4
+ data.tar.gz: 19c2c8f08062072d54a90fe7d848b30ae24b5997a6179ba3aac6ddd5e31008be
5
5
  SHA512:
6
- metadata.gz: a6fcfeb516a7621f6aa6b8dc18eb0492b928052158aee32cd51319344d06e210006527303927f5453f1b0106fcfe4dafeb10f18ea3b1584670b6532b8049f714
7
- data.tar.gz: 37a2e3ad2df077d130609042d0c61cb2aabb8bacb1d9f56c2fff503f819f09d5847f5d6e33334c3267342d91f504f5e3811888c336e447a91341d6cf8386510d
6
+ metadata.gz: c53ae17ddbc628f745c8099df3d1425627c1da778e616fd2a4cfc8bfca0680b56ff188881383d8f1f6cc10b68f42f53264b1cbc3ebf5f33cc4f8fb069045a703
7
+ data.tar.gz: b2214618bce3e48a10c5c8bbac5c4ee60f79281445472bde3fe225e82606297b21c7e087d12da41f68a0e20c15d8e6863846608165064add64511a8562940dd2
data/README.md CHANGED
@@ -43,6 +43,11 @@ wf.monitors.reset(mon["id"])
43
43
  # Page integrity: after a deploy, accept what the newest check saw as the new baseline
44
44
  wf.monitors.accept_baseline(integrity_monitor_id)
45
45
 
46
+ # Browser checks: try a Playwright script once (nothing saved), then read the result
47
+ run = wf.playwright.test_run(script: script, target: "https://shop.example.com")
48
+ wf.playwright.get_test_run(run["id"]) # status: queued | running | done | error
49
+ wf.variables.put("LOGIN_PASSWORD", value: password, secret: true)
50
+
46
51
  # Older checks: pass next_cursor back as cursor (keep the same hours/success)
47
52
  page = wf.monitors.checks(mon["id"], hours: 24, limit: 100)
48
53
  wf.monitors.checks(mon["id"], hours: 24, limit: 100, cursor: page["next_cursor"]) if page["next_cursor"]
@@ -85,6 +90,14 @@ Namespaces: `wf.monitors`, `wf.alert_rules`, `wf.incidents`,
85
90
  `wf.incident_stats(period)`, `wf.notifications`, `wf.activity`. Errors raise
86
91
  `Watchfor::Error` with `#status`, `#code`, `#message`.
87
92
 
93
+ ## Prometheus metrics (Pro plan and above)
94
+
95
+ ```ruby
96
+ text = wf.metrics(tag: "production") # Prometheus text format
97
+ ```
98
+
99
+ Usually you point Prometheus at `https://watchfor.io/api/v1/metrics` directly; this is for scripts and one-off checks. See https://watchfor.io/docs/api/prometheus.
100
+
88
101
  ## CLI
89
102
 
90
103
  ```bash
data/exe/watchfor CHANGED
@@ -36,8 +36,13 @@ begin
36
36
  cursor = args.include?("--cursor") ? args[args.index("--cursor") + 1] : nil
37
37
  wf.monitors.checks(monitor_id, cursor: cursor)
38
38
  when "report" then wf.report(period: args.include?("--period") ? args[args.index("--period") + 1] : nil)
39
+ when "metrics"
40
+ tag = args.include?("--tag") ? args[args.index("--tag") + 1] : nil
41
+ type = args.include?("--type") ? args[args.index("--type") + 1] : nil
42
+ print wf.metrics(tag: tag, type: type)
43
+ exit 0
39
44
  else
40
- warn "Usage: watchfor [summary|plan|monitors|locations|monitor-types|incidents|checks <monitor_id> [--cursor c]|report [--period 7d|30d]]"
45
+ warn "Usage: watchfor [summary|plan|monitors|locations|monitor-types|incidents|checks <monitor_id> [--cursor c]|report [--period 7d|30d]|metrics [--tag t] [--type t]]"
41
46
  exit 2
42
47
  end
43
48
  puts JSON.pretty_generate(result)
@@ -27,7 +27,7 @@ module Watchfor
27
27
  class Client
28
28
  attr_reader :monitors, :alert_rules, :incidents, :hosts, :status_pages, :on_call, :notification_channels,
29
29
  :maintenance_windows, :contacts, :contact_groups,
30
- :diagnostics
30
+ :diagnostics, :playwright, :variables
31
31
 
32
32
  def initialize(api_key:, base_url: DEFAULT_BASE_URL, timeout: 30)
33
33
  raise ArgumentError, "api_key is required" if api_key.nil? || api_key.empty?
@@ -46,10 +46,12 @@ module Watchfor
46
46
  @contacts = Contacts.new(self)
47
47
  @contact_groups = ContactGroups.new(self)
48
48
  @diagnostics = Diagnostics.new(self)
49
+ @playwright = Playwright.new(self)
50
+ @variables = Variables.new(self)
49
51
  end
50
52
 
51
53
  # Core request. +query+ and +body+ are optional hashes.
52
- def request(method, path, query: nil, body: nil, idempotency_key: nil)
54
+ def request(method, path, query: nil, body: nil, idempotency_key: nil, text: false)
53
55
  uri = URI("#{@base_url}#{path}")
54
56
  unless query.nil? || query.empty?
55
57
  cleaned = query.reject { |_, v| v.nil? || v == "" }
@@ -63,7 +65,7 @@ module Watchfor
63
65
  }.fetch(method)
64
66
  req = klass.new(uri)
65
67
  req["Authorization"] = "Bearer #{@api_key}"
66
- req["Accept"] = "application/json"
68
+ req["Accept"] = text ? "text/plain, application/json" : "application/json"
67
69
  req["User-Agent"] = "watchfor-ruby/#{Watchfor::VERSION}"
68
70
  req["Idempotency-Key"] = idempotency_key if idempotency_key
69
71
  unless body.nil?
@@ -78,6 +80,8 @@ module Watchfor
78
80
  end
79
81
 
80
82
  raw = res.body.to_s
83
+ return raw if text && res.code.to_i.between?(200, 299)
84
+
81
85
  parsed = raw.empty? ? nil : (JSON.parse(raw) rescue nil)
82
86
  unless res.code.to_i.between?(200, 299)
83
87
  err = parsed.is_a?(Hash) ? (parsed["error"] || {}) : {}
@@ -90,6 +94,14 @@ module Watchfor
90
94
  # Top-level reads
91
95
  def me = request("GET", "/me")
92
96
  def summary = request("GET", "/summary")
97
+
98
+ # The organization in Prometheus text format (Pro plan and above):
99
+ # status, uptime, response times, expiry, heartbeats, hosts. Cached 60 s.
100
+ def metrics(tag: nil, type: nil, monitor_id: nil, include_hosts: nil)
101
+ query = { tag: tag, type: type, monitor_id: monitor_id,
102
+ include_hosts: include_hosts.nil? ? nil : include_hosts.to_s }
103
+ request("GET", "/metrics", query: query, text: true)
104
+ end
93
105
  def plan = request("GET", "/plan")
94
106
  def incident_stats(period = nil) = request("GET", "/incidents/stats", query: { period: period })
95
107
 
@@ -141,6 +153,14 @@ module Watchfor
141
153
  end
142
154
  # One check in full detail (redacted).
143
155
  def check_detail(id, run_id) = @c.request("GET", "/monitors/#{id}/checks/#{run_id}")
156
+ # Browser checks: runs, newest first (status: "failed" | "flaky").
157
+ def runs(id, status: nil, limit: nil, cursor: nil)
158
+ @c.request("GET", "/monitors/#{id}/runs", query: { status: status, limit: limit, cursor: cursor })
159
+ end
160
+ # Browser checks: one run — steps, errors, Web Vitals, screenshots, trace link.
161
+ def run(id, run_id) = @c.request("GET", "/monitors/#{id}/runs/#{run_id}")
162
+ def script_versions(id) = @c.request("GET", "/monitors/#{id}/script/versions")
163
+ def script_version(id, version) = @c.request("GET", "/monitors/#{id}/script/versions/#{version}")
144
164
  # Page integrity monitors: the accepted baseline of every watched page.
145
165
  def baseline(id) = @c.request("GET", "/monitors/#{id}/baseline")
146
166
  # Page integrity monitors: accept what the newest check saw as the new
@@ -152,6 +172,23 @@ module Watchfor
152
172
  end
153
173
  end
154
174
 
175
+ # Browser checks: run a Playwright script once without saving it.
176
+ class Playwright < Namespace
177
+ def test_run(body) = @c.request("POST", "/playwright/test-runs", body: body)
178
+ def get_test_run(id) = @c.request("GET", "/playwright/test-runs/#{id}")
179
+ end
180
+
181
+ # Org variables and secrets (process.env.NAME); secrets are write-only.
182
+ class Variables < Namespace
183
+ def list = @c.request("GET", "/variables")
184
+ def put(name, value: nil, secret: false)
185
+ body = { secret: secret }
186
+ body[:value] = value unless value.nil?
187
+ @c.request("PUT", "/variables/#{name}", body: body)
188
+ end
189
+ def delete(name) = @c.request("DELETE", "/variables/#{name}")
190
+ end
191
+
155
192
  class AlertRules < Namespace
156
193
  def list(monitor_id) = @c.request("GET", "/monitors/#{monitor_id}/alert-rules")
157
194
  def get(monitor_id, rule_id) = @c.request("GET", "/monitors/#{monitor_id}/alert-rules/#{rule_id}")
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Watchfor
4
- VERSION = "0.10.0"
4
+ VERSION = "0.12.0"
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: watchfor
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.10.0
4
+ version: 0.12.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - WatchFor
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2026-09-25 00:00:00.000000000 Z
11
+ date: 2026-10-01 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: Zero-dependency Ruby client for the WatchFor REST API (monitors, alert
14
14
  rules, incidents, maintenance windows) plus a `watchfor` CLI.