Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 10 additions & 38 deletions .github/workflows/go-integration-tests.yml
Original file line number Diff line number Diff line change
@@ -1,23 +1,21 @@
name: Go integration tests

# Language-specific workflow: only runs for the Go client. Triggers on PRs to master that
# touch Go client, test, or example code, and can be dispatched manually from any branch.
# Runs for changes to Go code, docs, or this workflow, and can be dispatched from any branch.
on:
pull_request:
branches: [master]
paths:
- '**/*.go'
- 'go.mod'
- 'go.sum'
# The "Test examples" step validates the in-documentation snippets, so doc changes must
# re-run the workflow even though Markdown is not Go code.
# The "Test examples" step checks the snippets of the docs.
- 'docs/**'
- 'README.md'
- '.github/workflows/go-integration-tests.yml'
- '.github/scripts/assert-tests-ran.sh'
workflow_dispatch:

# Avoid concurrent runs of the same ref racing on the shared test account.
# Runs of one ref share the test account, so they must not overlap.
concurrency:
group: go-integration-${{ github.ref }}
cancel-in-progress: true
Expand All @@ -32,8 +30,7 @@ jobs:
- name: Set up Go
uses: actions/setup-go@v5
with:
# Patched toolchain (Go 1.26.10+): earlier releases still trust the compromised
# intermediate CA certificates. Keep in step with the `toolchain` line in go.mod.
# Earlier releases trust compromised CA certificates. Keep in step with go.mod.
go-version: '1.26.10'
cache: true

Expand All @@ -49,13 +46,8 @@ jobs:
- name: Vet
run: go vet ./...

# The idiomatic Go linter. `go vet` only catches a narrow set of correctness issues;
# golangci-lint bundles staticcheck and other analyzers, satisfying the coding-rules
# mandate that linting/type-checking run in CI. Config lives in .golangci.yml.
- name: Lint (golangci-lint)
# Use the v7 action and pin a golangci-lint v2 release: .golangci.yml uses the
# v2 config schema, which the v6 action's v1.x binary rejects ("additional
# properties 'version'/'default' not allowed").
# .golangci.yml uses the v2 schema, which needs the v7 action.
uses: golangci/golangci-lint-action@v7
with:
version: v2.15.0
Expand All @@ -64,13 +56,10 @@ jobs:
run: go build ./...

- name: Unit tests
# The unit tests are offline (mock HTTP backend) and prove the retry/error/signature
# logic without hitting the API.
# Offline tests with a mock HTTP backend.
run: go test . -v

# Fail fast if the integration-test secret is missing or empty. Without this guard the
# integration tests silently "pass" (they skip when APIFY_TOKEN is unset), so a green
# run would not prove the API logic actually executed.
# Without the token the integration tests skip and the run would be green.
- name: Require APIFY_TOKEN secret
env:
APIFY_TOKEN: ${{ secrets.APIFY_TOKEN }}
Expand All @@ -82,36 +71,19 @@ jobs:

- name: Integration tests
env:
# The integration-test token is stored as a repository secret.
APIFY_TOKEN: ${{ secrets.APIFY_TOKEN }}
# Limit parallelism to be gentle on the shared test account. The documentation example
# programs (TestExample*) and the in-documentation snippet checks (TestDocSnippets*) are
# exercised by the standalone "Test examples" step below, so they are skipped here to
# keep the two concerns separate.
#
# -json is parsed by assert-tests-ran.sh so the step fails if zero tests actually ran or
# every test skipped (a filter that matches nothing, a package with no test functions,
# or an all-skip run would otherwise exit green and hide that the API logic never ran).
# The example and snippet tests run in "Test examples". assert-tests-ran.sh fails the step
# if no test ran or all were skipped.
run: |
set -o pipefail
go test ./tests/ -json -timeout 900s -p 1 -parallel 4 -skip '^(TestExample|TestDocSnippets)' \
| tee integration.jsonl
./.github/scripts/assert-tests-ran.sh integration.jsonl "Integration tests"

# Standalone CI step that verifies the documentation examples actually work. It runs the
# example programs in examples/ end-to-end against the live API (via the TestExample*
# smoke tests in tests/examples_test.go, each of which executes `go run ./examples/<name>`)
# and checks that every in-documentation code snippet is valid, runnable, and gofmt-
# formatted (the TestDocSnippets* tests, which extract every ```go block from the README
# and docs/ and compile each one). Both are required by the documentation requirements:
# each documentation example has a CI test that actually runs the code, and each snippet
# must be valid, runnable and properly formatted.
# Runs the programs in examples/ against the live API and compiles the snippets of the docs.
- name: Test examples
env:
APIFY_TOKEN: ${{ secrets.APIFY_TOKEN }}
# Match the integration-test thread cap so the example programs (which hit the live
# account) stay gentle on the shared test account. As above, -json is asserted so the
# step fails if the example/snippet tests did not actually run or all skipped.
run: |
set -o pipefail
go test ./tests/ -json -timeout 900s -p 1 -parallel 4 -run '^(TestExample|TestDocSnippets)' \
Expand Down
44 changes: 13 additions & 31 deletions .github/workflows/go-publish.yml
Original file line number Diff line number Diff line change
@@ -1,13 +1,7 @@
name: Publish Go client

# Language-specific publish workflow for the Go client. Go has no central package registry to
# upload an archive to: a module is "published" by pushing a semver git tag (vX.Y.Z), after which
# the Go module proxy (proxy.golang.org) and pkg.go.dev pick it up on first request. This workflow
# is therefore the language-specific distribution standard for Go.
#
# It is triggered manually only (workflow_dispatch) so a maintainer deliberately decides when a
# release is cut. The version is taken from the single source of truth (the ClientVersion constant
# in version.go) so the published tag can never disagree with the in-code client version.
# Publishes the Go client by pushing the tag v<ClientVersion>, which the Go module proxy and
# pkg.go.dev pick up. It runs only when a maintainer triggers it.
on:
workflow_dispatch:
inputs:
Expand All @@ -16,14 +10,12 @@ on:
type: boolean
default: false

# Never allow two publish runs to race; pushing two release tags concurrently is hard to undo.
# Two release tags pushed at once are hard to undo.
concurrency:
group: go-publish
cancel-in-progress: false

# The default GITHUB_TOKEN needs write access to push the tag and create the release. No other
# credentials are required: the Go module proxy reads the public repo directly, so there is no
# registry token to configure.
# The GITHUB_TOKEN pushes the tag and creates the release. No other credentials are needed.
permissions:
contents: write

Expand All @@ -34,12 +26,10 @@ jobs:
- name: Checkout
uses: actions/checkout@v4
with:
# Full history so the tag points at the real commit and `git describe`-style tooling works.
# Full history, so that the tag points at the real commit.
fetch-depth: 0

# A release tag is immutable once the Go module proxy has fetched it, so a release must only
# ever be cut from master. Refuse to run from any other ref, even when dispatched manually,
# so a maintainer cannot accidentally publish an unmerged feature-branch commit as a version.
# A tag is immutable once the module proxy has fetched it, so release from master only.
- name: Require master branch
run: |
if [ "${GITHUB_REF}" != "refs/heads/master" ]; then
Expand All @@ -50,12 +40,11 @@ jobs:
- name: Set up Go
uses: actions/setup-go@v5
with:
# Patched toolchain (Go 1.26.10+): earlier releases still trust the compromised
# intermediate CA certificates. Keep in step with the `toolchain` line in go.mod.
# Earlier releases trust compromised CA certificates. Keep in step with go.mod.
go-version: '1.26.10'
cache: true

# Gate the release on the same quality bar as CI so a broken build can never be tagged.
# The checks of CI.
- name: Check formatting
run: |
unformatted=$(gofmt -l .)
Expand All @@ -77,12 +66,10 @@ jobs:
run: go build ./...

- name: Unit tests
# Offline (mock HTTP backend) tests; prove the retry/error/signature logic without the API.
# Offline tests with a mock HTTP backend.
run: go test . -v

# Derive the release tag from the single source of truth (version.go). Keeping the tag in lock
# step with the in-code ClientVersion means consumers who read the constant and consumers who
# `go get` a tag always see the same version.
# The tag is the ClientVersion of version.go.
- name: Resolve version from version.go
id: version
run: |
Expand All @@ -98,8 +85,7 @@ jobs:
echo "tag=v${version}" >> "$GITHUB_OUTPUT"
echo "Resolved release tag: v${version}"

# Fail early (before creating any tag) if this version was already released, so a publish run
# can never silently no-op or clobber an existing release.
# Fail before creating anything if the version was released already.
- name: Ensure tag does not already exist
env:
TAG: ${{ steps.version.outputs.tag }}
Expand All @@ -123,8 +109,6 @@ jobs:
git tag -a "${TAG}" -m "Release ${TAG}"
git push origin "${TAG}"

# Create a GitHub release for the tag. Uses the default GITHUB_TOKEN from repository secrets;
# no personal access token or registry credential is needed.
- name: Create GitHub release
if: ${{ github.event.inputs.dry_run != 'true' }}
env:
Expand All @@ -135,16 +119,14 @@ jobs:
--title "${TAG}" \
--notes "Apify Go client ${TAG}. See CHANGELOG.md for details."

# Prompt the public Go module proxy to fetch the new version. This is what makes the release
# discoverable on pkg.go.dev; it requires no authentication because the repository is public.
# Asks the Go module proxy to fetch the version, which lists it on pkg.go.dev.
- name: Trigger Go module proxy indexing
if: ${{ github.event.inputs.dry_run != 'true' }}
env:
TAG: ${{ steps.version.outputs.tag }}
run: |
module=$(go list -m)
echo "Requesting ${module}@${TAG} from the Go module proxy to trigger indexing."
# Best-effort: the proxy may take a moment to see the freshly pushed tag, so a failure here
# is not fatal — the module is still published via the tag and will be indexed on first use.
# The proxy may not see the tag yet. That is not fatal, since the tag publishes the module.
curl -fsSL "https://proxy.golang.org/${module}/@v/${TAG}.info" || \
echo "::warning::Proxy did not return the version yet; pkg.go.dev will index it on first request."
20 changes: 20 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,26 @@ 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.16.0] - 2026-11-10

### Added

- `RequestCompressionZstd` for `WithRequestCompression` and `ActorServerRequestOptions.Compression`.
- `ActorServerRequestOptions.ParentRequestID`, sent as the `X-Actor-Request-ID` header, so that a
Server Actor calling another one passes its caller's pricing tier on.
- `zstd` in the documented `Content-Encoding` values of `SetRecordRawWithEncoding`.
- `RequestQueueClient.BatchAddRequestsWithOptions` and `BatchAddRequestsOptions`.
- `RequestQueueOperationInfo.UniqueKey`, set by batch add results.

### Changed

- `BatchAddRequests` retries the requests that the API did not process, up to 3 times by default,
and sends up to 5 batches at once. A batch that fails with an API or transport error leaves its
requests that were not added in `UnprocessedRequests`, and it is not an error of the call. An
undecodable response or an ended context is still an error.
- Shortened and corrected the documentation and code comments.
- Bumped `APISpecVersion` to `v2-2026-11-09T143926Z` and `ClientVersion` to `0.16.0`.

## [0.15.0] - 2026-11-06

### Added
Expand Down
Loading
Loading