diff --git a/CHANGELOG.md b/CHANGELOG.md index 2a7dd99..5f5ae10 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,36 @@ All notable changes to the Apify Go client are documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [0.4.0] - 2026-06-26 + +Updated to Apify OpenAPI specification `v2-2026-06-25T142310Z` (previously +`v2-2026-06-24T105326Z`). An operation- and parameter-level audit against the new specification +found no changes to the in-scope API surface; the spec update itself is a version bump only. This +release adds an `origin` filter to the last-run convenience accessors (additively, with no +breaking change) for parity with the `apify-client-js` reference, and cleans up stale in-code +comments. + +### Added + +- `ActorClient.LastRunWithOptions` and `TaskClient.LastRunWithOptions` accept a `LastRunOptions` + with `Status` and `Origin` filters, matching the reference client's `lastRun({ status, origin })`. + The existing `LastRun(status string)` accessors are unchanged (they delegate to the new methods + with only `Status` set), so this is a purely additive, non-breaking change. `Origin` is a + reference-client convenience threaded to the same `runs/last` endpoint; the OpenAPI spec does not + document it as a query parameter. + +### Changed + +- Bumped `API_SPEC_VERSION` to `v2-2026-06-25T142310Z`. +- Bumped `CLIENT_VERSION` to `0.4.0` (minor bump per SemVer for the additive `LastRunWithOptions` + API). + +### Fixed + +- Cleaned up stale in-code comments around the `isAtHome` User-Agent flag that quoted the older, + capitalized requirement wording; the comments now match the current lowercase requirement text. + No behavior change — the flag already rendered lowercase (`true`/`false`). + ## [0.3.0] - 2026-06-25 Updated to Apify OpenAPI specification `v2-2026-06-24T105326Z` (previously diff --git a/actor.go b/actor.go index 4f7533b..609b91a 100644 --- a/actor.go +++ b/actor.go @@ -212,11 +212,18 @@ func (c *ActorClient) ValidateInputForBuild(ctx context.Context, input any, buil // LastRun returns a client for the last run of this Actor, optionally filtered by status // (e.g. "SUCCEEDED"). Pass an empty status for no filter. +// +// To also filter by run origin, use LastRunWithOptions. func (c *ActorClient) LastRun(status string) *RunClient { + return c.LastRunWithOptions(LastRunOptions{Status: status}) +} + +// LastRunWithOptions returns a client for the last run of this Actor, optionally filtered by +// status and/or origin. See LastRunOptions. Mirrors the reference client's +// lastRun({ status, origin }). +func (c *ActorClient) LastRunWithOptions(options LastRunOptions) *RunClient { client := newRunClient(c.root, c.ctx.http, c.ctx.subURL(""), "runs", "last") - if status != "" { - client.setStatusParam(status) - } + client.setLastRunParams(options) return client } diff --git a/client.go b/client.go index 83e0549..0811ea8 100644 --- a/client.go +++ b/client.go @@ -129,7 +129,7 @@ func withIsAtHomeFn(fn func() bool) Option { // Environment variable that signals the client is running on the Apify platform. // // Per client_requirements.md the flag is based solely on APIFY_IS_AT_HOME ("based on the -// environment variable `APIFY_IS_AT_HOME`, `False` if env variable is missing"), which also +// environment variable `APIFY_IS_AT_HOME`, `false` if env variable is missing"), which also // matches the JS reference (it reads only APIFY_IS_AT_HOME via @apify/consts). const envIsAtHome = "APIFY_IS_AT_HOME" diff --git a/common.go b/common.go index dfb731c..dfd33be 100644 --- a/common.go +++ b/common.go @@ -213,16 +213,8 @@ type PaginationList[T any] struct { // `ApifyClient/{version} ({os}; {language version}); isAtHome/{isAtHome}`. // // isAtHome is driven solely by the platform's APIFY_IS_AT_HOME environment variable (matching -// the requirements and the reference JS client, which reads it via @apify/consts); it is set to -// any non-empty value when the client runs on the Apify platform. -// -// Casing note (deliberate): the flag is rendered lowercase (true/false). The requirements' -// worked example shows the capitalized form (isAtHome/True | isAtHome/False), but that example -// is Python-specific (Python's str(bool) is "True"/"False"). The "consistent with the JS -// reference" requirement is same-priority, and the JS client interpolates a JS boolean, which -// stringifies lowercase; the Rust sibling client emits lowercase too. Lowercase is therefore the -// cross-client-consistent choice, and the literal capitalized example is treated as illustrative -// rather than normative. See CHANGELOG.md. +// the requirements and the reference JS client, which reads it via @apify/consts) and is +// rendered lowercase (true/false), consistent with the JS and Rust sibling clients. func BuildUserAgent(suffix string, isAtHomeFn func() bool) string { atHome := "false" if isAtHomeFn() { diff --git a/docs/actors.md b/docs/actors.md index 9d83206..37675c9 100644 --- a/docs/actors.md +++ b/docs/actors.md @@ -86,6 +86,7 @@ The `Actor` value returned by `Get`/`Create`/`Update` and listed by `List`: | `ValidateInput(ctx, input any) (json.RawMessage, error)` | Validate input against the `latest` build's schema. | | `ValidateInputForBuild(ctx, input any, build string) (json.RawMessage, error)` | Validate input against a specific build's schema (tag or number). | | `LastRun(status string) *RunClient` | Client for the last run (optional status filter). | +| `LastRunWithOptions(options LastRunOptions) *RunClient` | Client for the last run, filtered by status and/or origin. | | `Builds() *BuildCollectionClient` | This Actor's builds. | | `Runs() *RunCollectionClient` | This Actor's runs. | | `Version(n) *ActorVersionClient` / `Versions() *ActorVersionCollectionClient` | Versions. | @@ -96,6 +97,30 @@ omits the parameter, so the API validates against the build tagged `latest` (per specification). Both return the raw JSON validation result from the API — a JSON object reporting whether the input is valid and, if not, the schema violations. +`LastRun(status)` returns the Actor's most recent run, optionally narrowed to a status. Use +`LastRunWithOptions` to also narrow by origin (how the run was started). Both return a +`RunClient` for the resolved run, so you can chain `.Get(ctx)`, `.Dataset()`, etc. + +`LastRunOptions` (all fields optional; an empty field leaves that filter unset): + +| Field | Type | Meaning | +|---|---|---| +| `Status` | `string` | Filter by run status (e.g. `SUCCEEDED`, `FAILED`, `RUNNING`). | +| `Origin` | `string` | Filter by how the run was started: `DEVELOPMENT`, `WEB`, `API`, `SCHEDULER`, `TEST`, `WEBHOOK`, `ACTOR`, `CLI`, `CI`, `STANDBY`, `MCP`. | + +```go +// Most recent run that both SUCCEEDED and was started via the API. +lastRun, ok, err := client.Actor("apify/hello-world"). + LastRunWithOptions(apify.LastRunOptions{Status: "SUCCEEDED", Origin: "API"}). + Get(ctx) +if err != nil { + log.Fatal(err) +} +if ok { + fmt.Printf("last API run: %s (%s)\n", lastRun.ID, lastRun.Status) +} +``` + ```go // Validate input against a specific build's input schema. result, err := client.Actor("apify/hello-world").ValidateInputForBuild(ctx, @@ -153,6 +178,14 @@ run, err := client.Actor("apify/hello-world").Call(ctx, | `Version(n).EnvVars().List(ctx)` / `.Create(ctx, ActorEnvVar)` | List/create env vars. | | `Version(n).EnvVar(name).Get/Update/Delete(ctx)` | Manage a single env var. | +`ActorEnvVar` fields: + +| Field | Type | Meaning | +|---|---|---| +| `Name` | `string` | The environment variable name (required). | +| `Value` | `string` | The environment variable value. | +| `IsSecret` | `*bool` | Whether the value is stored as a secret (encrypted at rest). | + ```go v := client.Actor(actorID).Version("0.0") _, err := v.EnvVars().Create(ctx, apify.ActorEnvVar{Name: "API_KEY", Value: "secret", IsSecret: apify.Ptr(true)}) diff --git a/docs/tasks.md b/docs/tasks.md index 6806ec4..7aaabf9 100644 --- a/docs/tasks.md +++ b/docs/tasks.md @@ -35,6 +35,7 @@ A task is a pre-configured Actor run with stored input. Access the task collecti | `GetInput(ctx) (json.RawMessage, bool, error)` | Fetch the stored input. | | `UpdateInput(ctx, input any) (json.RawMessage, error)` | Replace the stored input. | | `LastRun(status string) *RunClient` | Client for the last run (optional status filter). | +| `LastRunWithOptions(options LastRunOptions) *RunClient` | Client for the last run, filtered by status and/or origin. | | `Runs() *RunCollectionClient` | This task's runs. | | `Webhooks() *WebhookCollectionClient` | This task's webhooks. | @@ -54,3 +55,20 @@ run, err := client.Task(task.ID).Call(ctx, nil, apify.TaskStartOptions{}, apify. `TaskStartOptions` mirrors `ActorStartOptions` (see [actors.md](actors.md)) but omits the Actor-only `ContentType` and `ForcePermissionLevel`, which the task run endpoint does not accept. + +`LastRun(status)` / `LastRunWithOptions(LastRunOptions{Status, Origin})` resolve the task's most +recent run, optionally narrowed by status and/or origin. `LastRunOptions` is the same type used +by the Actor client — see [actors.md](actors.md#single-actor) for its field reference. + +```go +// Most recent task run that SUCCEEDED. +lastRun, ok, err := client.Task("my-task-id"). + LastRunWithOptions(apify.LastRunOptions{Status: "SUCCEEDED"}). + Get(ctx) +if err != nil { + log.Fatal(err) +} +if ok { + fmt.Printf("last run: %s (%s)\n", lastRun.ID, lastRun.Status) +} +``` diff --git a/run.go b/run.go index 711d697..665c402 100644 --- a/run.go +++ b/run.go @@ -62,10 +62,28 @@ func newRunClient(root *ApifyClient, hc *httpClient, baseURL, resourcePath, id s } } -// setStatusParam pins a `status` query parameter inherited by all calls on this client. -// Used by ActorClient.LastRun / TaskClient.LastRun to filter the "last" run by status. -func (c *RunClient) setStatusParam(status string) { - c.ctx.baseParams.addRaw("status", status) +// LastRunOptions filters which "last" run the ActorClient.LastRunWithOptions / +// TaskClient.LastRunWithOptions accessors resolve to. An empty field leaves that filter unset. +// +// Origin is an Apify-platform convenience exposed by the reference client (lastRun({ origin })) +// but not documented as a query parameter in the OpenAPI spec; it is included for parity with the +// reference, which threads it to the same runs/last endpoint. +type LastRunOptions struct { + // Status filters by run status (e.g. "SUCCEEDED", "FAILED", "RUNNING"). + Status string + // Origin filters by how the run was started (e.g. "DEVELOPMENT", "WEB", "API", "SCHEDULER"). + Origin string +} + +// setLastRunParams pins the `status` and/or `origin` query parameters inherited by all calls on +// this client. Empty values are skipped so they leave the corresponding filter unset. +func (c *RunClient) setLastRunParams(options LastRunOptions) { + if options.Status != "" { + c.ctx.baseParams.addRaw("status", options.Status) + } + if options.Origin != "" { + c.ctx.baseParams.addRaw("origin", options.Origin) + } } // Get fetches the run object. The bool reports whether it exists. diff --git a/task.go b/task.go index df83f4a..b64d384 100644 --- a/task.go +++ b/task.go @@ -119,11 +119,18 @@ func (c *TaskClient) UpdateInput(ctx context.Context, input any) (json.RawMessag // LastRun returns a client for the last run of this task, optionally filtered by status // (e.g. "SUCCEEDED"). Pass an empty status for no filter. +// +// To also filter by run origin, use LastRunWithOptions. func (c *TaskClient) LastRun(status string) *RunClient { + return c.LastRunWithOptions(LastRunOptions{Status: status}) +} + +// LastRunWithOptions returns a client for the last run of this task, optionally filtered by +// status and/or origin. See LastRunOptions. Mirrors the reference client's +// lastRun({ status, origin }). +func (c *TaskClient) LastRunWithOptions(options LastRunOptions) *RunClient { client := newRunClient(c.root, c.ctx.http, c.ctx.subURL(""), "runs", "last") - if status != "" { - client.setStatusParam(status) - } + client.setLastRunParams(options) return client } diff --git a/tests/actor_run_test.go b/tests/actor_run_test.go index 22dc627..cb59a89 100644 --- a/tests/actor_run_test.go +++ b/tests/actor_run_test.go @@ -70,4 +70,15 @@ func TestLastRunAccess(t *testing.T) { if lastRun.Status != "SUCCEEDED" { t.Fatalf("expected last succeeded run, got %q", lastRun.Status) } + + // The run was started via the API, so filtering the last run by both status and origin + // must still resolve it. This exercises the origin filter on LastRunWithOptions. + lastRunByOrigin, ok, err := client.Actor("apify/hello-world"). + LastRunWithOptions(apify.LastRunOptions{Status: "SUCCEEDED", Origin: "API"}).Get(ctx) + if err != nil || !ok { + t.Fatalf("last run by origin: ok=%v err=%v", ok, err) + } + if lastRunByOrigin.Status != "SUCCEEDED" { + t.Fatalf("expected last succeeded run filtered by origin, got %q", lastRunByOrigin.Status) + } } diff --git a/version.go b/version.go index 756fcfe..bfb9ce9 100644 --- a/version.go +++ b/version.go @@ -4,10 +4,10 @@ package apify // // It follows Semantic Versioning (https://semver.org/). Changes to the public // interface (other than additive ones) are considered breaking changes. -const CLIENT_VERSION = "0.3.0" +const CLIENT_VERSION = "0.4.0" // API_SPEC_VERSION is the version of the Apify OpenAPI specification that this // client was generated and verified against. // // It corresponds to the `info.version` field of the Apify OpenAPI document. -const API_SPEC_VERSION = "v2-2026-06-24T105326Z" +const API_SPEC_VERSION = "v2-2026-06-25T142310Z"