Documentation

CLI Reference

Upload test results to OyaCloud from any CI/CD pipeline or your local machine.

Sign-ups open shortly

The CLI is already published on npm — npm install -g oyacloud works today, and this reference is current. Steps 1 and 2 below need an OyaCloud account, which unlocks when the app goes live. Get notified.

Quick setup

  1. 1. Get access

    No account yet? Sign up — new accounts go through a quick manual approval before the dashboard unlocks.

  2. 2. Create a project and get your API key

  3. 3. Install the CLI

    Requires Node.js 14 or later.

    npm install -g oyacloud
  4. 4. Choose your test framework

    Pick the one you actually use — steps 5 and 7 below change to match it.

  5. 5. Configure your reporter

    Pick a framework in step 4 above to see this step.

  6. 6. Save your API key

    Running on CI? Set a secret/variable named exactly OYACLOUD_API_KEY in your CI platform, and every future command needs no --api-key flag at all.

    • GitLab CI / CircleCI — that's the whole thing, both expose it to your job automatically
    • GitHub Actions / Jenkins — needs one extra line to map it in, pick your platform below to see it

    Repo secrets aren’t auto-exposed as env vars — map it explicitly, once, in the workflow:

    env:
      OYACLOUD_API_KEY: ${{ secrets.OYACLOUD_API_KEY }}

    Not setting up a CI secret at all? Just pass --api-key YOUR_KEY directly on the command instead — or, for local/manual runs, save it once:

    oyacloud config set-key YOUR_PROJECT_API_KEY
  7. 7. Upload your results

    oyacloud upload --framework <framework> --environment staging --results-dir <results-dir>

    Pick a framework in step 4 above to fill in the exact command.

    A green 🎉 Upload completed successfully! here means the file was received and queued — it doesn't mean it was parsed correctly. Processing happens afterward, asynchronously; if the build doesn't show up looking right, your OyaCloud dashboard is the real source of truth, not this terminal output.

    Two things worth knowing before you rely on this data:

    • Every build is auto-classified as PR / post-merge / regression from your CI trigger on most platforms — see Automatic build-type detection below for exactly how, or what to do if your platform isn't one of them.
    • Running a scoped/filtered subset of your suite (a tag filter, a specific folder) rather than the full thing? Pass --suite-name, or it silently merges into your full-suite history — see the --suite-name guide below.

Automatic build-type detection

OyaCloud figures out whether a run is a PR, a post-merge build, or a scheduled/regression run directly from your CI platform’s own trigger signal — not by guessing from branch names. How much of that is automatic depends on which platform you’re on:

Tier 1

Zero config

GitHub Actions · GitLab CI · Azure DevOps

PR, post-merge, and scheduled runs are all auto-detected from your CI platform’s own trigger signal — nothing to set.

Tier 2

PR + post-merge auto-detected

Jenkins · CircleCI · Bitbucket

Scheduled/cron runs need one line: OYACLOUD_BUILD_TYPE=regression — none of these platforms expose a trigger-source signal reliable enough to detect a schedule automatically.

Tier 3

Explicit only

Everything else

Pass --build-type explicitly — an unrecognized platform is never guessed at.

Passing --build-type or setting OYACLOUD_BUILD_TYPE always overrides detection, on any platform.

The three build types

The same command works for every scenario below and every supported CI platform:

  • Branch, commit, PR number, and author are all auto-detected (see "What gets auto-detected" below)
  • build_type is detected too, on most platforms — see the tiers above
  • --environment is the one flag that's genuinely yours to set — point it at whatever CI variable your own pipeline already uses (shown here as $ENVIRONMENT, illustrative — use your own variable name)
oyacloud upload \
  --framework <framework> \
  --environment $ENVIRONMENT \
  --results-dir <results-dir>

<framework> and <results-dir> are whatever you picked in Quick setup steps 4-5 above. No --api-key shown — see Quick setup step 6 above for how that gets picked up automatically.

PR / Feature branch

pr

Tests run on every pull request. OyaCloud compares your results against the latest post-merge baseline on the target branch, and the dashboard shows which tests newly failed, newly passed, or became flaky in this PR.

Post-merge / Main branch

post-merge

Tests run after a PR merges. These become the health baseline — pass-rate trends, flaky detection, and every future PR comparison are measured against the most recent post-merge run on the target branch.

Standalone regression

regression

Scheduled or on-demand runs not tied to a specific commit or PR — nightly suites, environment health checks. Tracked in their own trend line, separate from PR and post-merge history.

What gets auto-detected

Different from build_type detection above — this is the underlying data (branch, commit, PR number, target branch, author) the CLI reads directly from your CI platform's own environment variables and attaches to every build:

  • Nothing to configure — pulled straight from real environment variables
  • Nothing ever guessed — a field with no real source (marked below) is just left blank, exactly like omitting the flag
  • Passing the flag explicitly always overrides whatever was detected
FieldGitHub ActionsGitLab CICircleCIJenkinsAzure DevOpsBitbucket
BranchMultibranch only
Commit
PR numberusually*Multibranch only
Target branchMultibranch only
Author
  • GitHub Actions — PR number detection covers both pull_request and pull_request_target events.
  • CircleCI* — PR number isn't always populated for same-repo (non-fork) PRs, depending on project settings. CircleCI's own documented limitation, not something OyaCloud's CLI can work around.
  • Jenkins — only gets branch/PR-number/target-branch on a Multibranch Pipeline job configured with PR discovery. A plain freestyle job has none of these (commit still works, via the Git plugin).

Reference

All flags

FlagRequiredDescription
--frameworkYesOne of: playwright_ts · playwright_py · testng_java · pytest_python · junit_java · cypress_js
--environmentYesWhere tests ran — a free-form label (staging, qa, prod, whatever you use). Not validated against a fixed list.
--results-dirYesPath to the folder containing your result files
--api-keyYes*

Project API key.

On CI: set it once as OYACLOUD_API_KEY instead (see Quick setup step 6) and skip this flag entirely.

--build-typeNo*

post-merge · pr · regression · local

If omitted, inferred from branch/commit/PR context — see the note below the table.

--branchNo

Auto-detected on GitHub Actions, GitLab CI, CircleCI, and Jenkins Multibranch Pipelines.

Pass explicitly to override, or on an unsupported CI — see "What gets auto-detected" below.

--commitNoSame auto-detection as --branch.
--target-branchNo

Same auto-detection as --branch.

Gap: CircleCI has no target-branch equivalent at all — pass it explicitly there if PR-comparison accuracy matters to you.

--pr-numberNoSame auto-detection as --branch.
--suite-nameNo

Display label for partial/scoped runs — see the guide below.

Optional for every build type (PR, post-merge, regression, local) equally.

--grepNo

Tag/pattern this run was filtered to, e.g. @smoke — matches whatever you passed to playwright test --grep.

Auto-fills --suite-name when that flag isn't set explicitly. Playwright's own JSON report has no reliable way to recover this value after the fact, so it has to be passed here too — without it, a tag-filtered run is scoped as a full run and gets compared/flaky-tracked against runs of a completely different size.

--authorNoAuto-detected everywhere via git log — doesn't need any CI-specific variable, works identically on every platform and locally.

How build_type actually gets resolved if you don't pass --build-type, in order:

  1. --build-type flag, if passed — always wins, on every platform
  2. else OYACLOUD_BUILD_TYPE environment variable, if set
  3. else your CI platform's own trigger signal, detected automatically with zero config on GitHub Actions, GitLab CI, and Azure DevOps (see the tiers above)
  4. last resort, only if none of the above apply — the backend infers it from whatever branch/commit/PR-number it has:
    1. --pr-number present (explicit or auto-detected) → pr
    2. else --commit present and --branch is main/master/develop (or matches your project's configured base branch) → post-merge
    3. otherwise → regression

In practice, step 3 resolves it correctly before it ever reaches the backend's inference at all, on most platforms — pass --build-type explicitly only if you want to be certain, or your branch naming doesn't match your project's configured base branch.

Network requirements

On a self-hosted CI runner behind a firewall, allowlist outbound HTTPS to both of these — uploads use both on every run:

api.oyaplus.com — build metadata (create build, request upload URLs)
*.s3.amazonaws.com — the actual report files, via short-lived presigned upload URLs

Proxy environments aren't supported yet. The CLI doesn't read HTTPS_PROXY/HTTP_PROXY/NO_PROXY — on a runner that requires an outbound proxy (not just an allowlisted firewall), uploads won't get through no matter how the proxy itself is configured.

Supported frameworks

--framework valueToolTypical results path
playwright_tsPlaywright (TypeScript/JS)test-results/
playwright_pyPlaywright (Python)test-results/ (pytest --junitxml output)
testng_javaTestNG (Java)target/surefire-reports/
pytest_pythonpytest (Python)pytest-results/ (varies by --junitxml config)
junit_javaJUnit (Java)build/test-results/test/ (Gradle) · target/surefire-reports/ (Maven)
cypress_jsCypresscypress/results/ (requires mocha-junit-reporter — see note below)

Cypress note: Cypress's own test runner doesn't produce OyaCloud-readable output directly — add mocha-junit-reporter (the standard way to get CI-consumable output from Cypress, since Mocha is its test runner underneath) and point --results-dir at wherever it writes its XML.

Short aliases: testng, pytest, junit, and cypress also work as shorthand for testng_java, pytest_python, junit_java, and cypress_js.

--suite-name guide

--suite-name sets the display label shown in the dashboard and becomes the run scope — the key used to group and compare builds over time. It's equally optional across every build type (PR, post-merge, regression, local) — nothing about build type makes it required.

Use it when…

  • TestNG group runs-Dgroups=smoke without a named testng.xml writes the generic "Surefire suite" name, which gets grouped with full runs unless you set this.
  • Playwright folder runs — running a subfolder with no --grep filter has no self-describing scope; it'll show as "Full Execution" unless you set this.
  • Named test groups — e.g. separate "Payments Suite" from "Auth Suite" trends.
  • Playwright tag runs--grep @smoke filtering isn't visible in Playwright's JSON report, so pass --suite-name explicitly or your scoped run gets merged into the full-suite scope.

Skip it when…

  • Full suite runs — scope defaults to "Full Execution".
  • TestNG suite XML — a real, named testng.xml suite name is read automatically.

Troubleshooting

What you seeWhat it means
API key requiredNo --api-key flag, no OYACLOUD_API_KEY env var, and no key saved via oyacloud config set-key. Run oyacloud config show to check what's saved locally.
API Error 401: Invalid or expired API keyThe key is wrong, revoked, or mistyped. Double-check it against Settings → API Keys.
API Error 401: CLI uploads require a project keyYou're using a company-level key instead of a project key — generate a project-scoped one from that project's settings.
Results directory not found--results-dir doesn't exist relative to where the command ran — a very common CI issue when the working directory isn't what you expect. Try an absolute path.
No supported files found in results directoryThe directory exists but nothing in it (recursively) matches .json .xml .html .png .jpg .jpeg .log .txt — usually means your reporter wrote somewhere else, or hasn't run yet.
Skipping oversized fileNot an error — a warning. Any single file over 10MB (a chatty test's embedded stdout/stderr is the usual cause) is skipped and not uploaded; everything else in your results directory still uploads normally.
Total upload size too large / No files left to upload after skipping oversized filesYour total upload (after any oversized files are skipped) is still over 100MB, or every file in the directory was too large to upload — try uploading a smaller/scoped results directory.
Too many files: max 500 per buildYour results directory (recursively) has more than 500 files matching the supported extensions — scope --results-dir to a narrower directory.
File type not allowed: …A file the CLI selected isn't one of the supported extensions after all — this is a backend-side check distinct from the CLI's own (silent) skip of unsupported files; if you see this, it's worth a report to support@oyaplus.com.
getaddrinfo ENOTFOUND / connection errorsThe runner can't reach api.oyaplus.com or the S3 upload host — check the Network requirements above against your firewall. If your runner requires an outbound proxy rather than a firewall allowlist, see the proxy note above — that's not yet supported.
Invalid JSON response containing HTML markupThe request was blocked before it ever reached the API — a firewall, proxy, or WAF returned an HTML error page instead. Check your network/proxy configuration (same guidance as the ENOTFOUND row above), not an API bug.
API Error 403: trial expired / subscription cancelled or suspendedYour account's subscription status is blocking uploads — the exact message (trial expired, cancelled, or a failed payment) tells you which. Contact support@oyaplus.com or check Settings → Billing.
API Error 429: Build limit reached for this periodYou've hit your plan's monthly build limit — the message includes your current usage (e.g. 50/50). Contact support@oyaplus.com to upgrade.
Not shown by the CLI — appears as the build's error on your dashboardDeclared framework '…' but no uploaded file matches that format--framework doesn't match what your reporter actually produced — e.g. passing testng_java for plain JUnit XML output. The CLI itself still prints a green success message either way (see step 7's note above) — this only ever shows up as a failed build on the dashboard.