npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

oyacloud

v1.4.0

Published

OyaCloud CLI for uploading test results from CI/CD pipelines and standalone executions

Readme

oyacloud

OyaCloud CLI for uploading test results from CI/CD pipelines and local runs.

Installation

npm install -g oyacloud

Needs Node.js 14 or later and direct outbound HTTPS (port 443) to api.oyaplus.com and Amazon S3 (*.amazonaws.com). Uploads through a proxy (HTTPS_PROXY) aren't supported yet — if your CI must use one, contact [email protected].

Getting started

  1. Create your project — Log in to app.oyaplus.com, go to Projects, and click New project. Your project API key is generated automatically.

  2. Save your key (optional — skip if you'll always pass --api-key):

oyacloud config set-key YOUR_PROJECT_KEY
  1. Push your first results:
oyacloud upload \
  --framework playwright_ts \
  --environment staging \
  --results-dir test-results

Usage

oyacloud upload \
  --framework playwright_ts \
  --environment staging \
  --results-dir test-results \
  --api-key YOUR_PROJECT_KEY

Supported frameworks

| Value | Framework | Alias | |-------|-----------|-------| | playwright_ts | Playwright (TypeScript/JavaScript) | | | playwright_py | Playwright (Python) | | | testng_java | TestNG (Java) | testng | | junit_java | JUnit (Java) | junit | | pytest_python | pytest (Python) | pytest | | cypress_js | Cypress (JavaScript) | cypress |

Everything except playwright_ts and testng_java is read as JUnit XML — including playwright_py, since pytest is what actually runs and reports there.

Where your reports are

Point --results-dir at the folder your test run writes its report to — a folder holding only this run's files. The CLI looks inside it and uploads only the test reports for your framework.

| Framework | Report setting | --results-dir | |-----------|----------------|-----------------| | playwright_ts | add the JSON reporter, inside the results folder: reporter: [['html'], ['json', { outputFile: 'test-results/results.json' }]] | test-results | | playwright_py | pytest --junitxml=test-results/results.xml (add --screenshot only-on-failure for screenshots) | test-results | | pytest_python | pytest --junitxml=pytest-results/results.xml | pytest-results | | testng_java | Maven Surefire (default) | target/surefire-reports | | junit_java — Maven | Surefire / Failsafe (default) | target/surefire-reports | | junit_java — Gradle | default | app/build/test-results/test (or build/test-results/test) | | cypress_js | reporter: 'mocha-junit-reporter', mochaFile: 'cypress/results/results-[hash].xml', includePending: true | cypress/results |

Multi-module Maven builds have one reports folder per module — pass a pattern instead: --results '**/target/*-reports/TEST-*.xml' (quote it).

Clean the folder before each run wherever the workspace is reused (local runs, persistent CI agents): mvn clean test, ./gradlew clean test, rm -rf pytest-results, rm -rf cypress/results. Playwright clears test-results/ itself.

What gets uploaded

Only your test reports — the CLI reads each file and keeps it only if it is a report for the framework you named. Everything else stays on your machine and is listed in the log with the reason: HTML reports, pom.xml, fixtures, TestNG's extra copies of its own results, traces and videos.

OyaCloud · framework testng_java · 8 candidate files
  ✓ target/surefire-reports/testng-results.xml  test report
  – target/surefire-reports/TEST-TestSuite.xml  copy of testng-results.xml
  – target/surefire-reports/testng-failed.xml  rerun definition, not results
Uploading 1 report (3 KB zipped) …
✅ Uploaded · build 3acde10a-…

Screenshots: Playwright (TypeScript and Python) screenshots go along automatically when the report names them and they are inside --results-dir. For Selenium or Cypress screenshots, pass --attachments 'target/screenshots/*.png'. Screenshots over 5 MB are skipped.

Everything is sent as one zip in one upload, and processed in the background — the CLI doesn't wait for it. Counts, and anything that was merged or skipped during processing, are on the build in the app.

Run with --dry-run to see exactly what would be uploaded without uploading anything.

Exit codes

| Code | Meaning | |------|---------| | 0 | Uploaded | | 2 | Nothing uploaded — no report for this framework in the folder, the folder doesn't exist, or the files are another framework's (the message says what to change) | | 1 | Anything else — network, API key, plan limits, upload too large |

Limits

100 MB zipped, 200 MB unzipped and 2,000 files per upload, 50 MB per report, 5 MB per screenshot.

Options

| Option | Required | Description | |--------|----------|-------------| | --framework | Yes | Test framework (see table above) | | --environment | For post-merge and regression | Environment under test (e.g. staging, qa, prod). Optional for PR and local builds — leave it out when a PR run has no deployed environment | | --results-dir | Yes* | Folder holding this run's test reports (repeatable). Or --results | | --results | No | Report files by pattern, e.g. '**/target/*-reports/TEST-*.xml' (repeatable; quote it) | | --attachments | No | Screenshots the report doesn't name, e.g. 'target/screenshots/*.png' (repeatable; quote it) | | --dry-run | No | Show what would be uploaded; upload nothing | | --verbose | No | List every file that isn't uploaded, not just a summary | | --api-key | No | Project API key (*skip if set via oyacloud config set-key) | | --branch | No | Branch name | | --commit | No | Commit SHA | | --pr-number | No | PR or MR number | | --target-branch | No | Target branch for PR builds (e.g. main) | | --author | No | Author or user who triggered the run | | --suite-name | No | Suite name label | | --grep | No | Tag/pattern this run was filtered to (e.g. @smoke). Pass the same value you gave playwright test --grep — the report can't recover it afterwards. Auto-fills --suite-name when that isn't set. | | --build-type | No | Override build-type detection (advanced): pr, post-merge, regression, or local |

Pass --grep whenever you filter a run. Without it a filtered run is recorded as a full-suite run, and gets compared against full-suite runs of a completely different size.

CI/CD Integration

Pass your application's branch and commit — not the test automation repo's.

PR build

# GitHub Actions
- name: Upload test results
  run: |
    oyacloud upload \
      --framework playwright_ts \
      --environment staging \
      --results-dir test-results \
      --branch ${{ github.head_ref }} \
      --commit ${{ github.event.pull_request.head.sha }} \
      --pr-number ${{ github.event.pull_request.number }} \
      --target-branch ${{ github.base_ref }} \
      --api-key ${{ secrets.OYACLOUD_API_KEY }}
// Jenkins
sh """
  oyacloud upload \
    --framework playwright_ts \
    --environment staging \
    --results-dir test-results \
    --branch ${APP_BRANCH} \
    --commit ${APP_COMMIT} \
    --pr-number ${APP_PR_NUMBER} \
    --target-branch ${APP_TARGET_BRANCH} \
    --api-key ${OYACLOUD_API_KEY}
"""

Post-merge build

# GitHub Actions
- name: Upload test results
  run: |
    oyacloud upload \
      --framework playwright_ts \
      --environment staging \
      --results-dir test-results \
      --branch ${{ github.ref_name }} \
      --commit ${{ github.sha }} \
      --api-key ${{ secrets.OYACLOUD_API_KEY }}

Regression / nightly build

No branch or commit needed — just the environment you are testing against:

# GitHub Actions (scheduled)
- name: Upload test results
  run: |
    oyacloud upload \
      --framework playwright_ts \
      --environment prod \
      --results-dir test-results \
      --api-key ${{ secrets.OYACLOUD_API_KEY }}

Multi-framework pipeline

A single project key works for all frameworks in the same pipeline:

# JUnit unit tests
oyacloud upload \
  --framework junit_java \
  --environment staging \
  --results-dir target/surefire-reports \
  --api-key ${{ secrets.OYACLOUD_API_KEY }}

# Playwright UI tests
oyacloud upload \
  --framework playwright_ts \
  --environment staging \
  --results-dir test-results \
  --api-key ${{ secrets.OYACLOUD_API_KEY }}

Build type detection

OyaCloud classifies every build as pr, post-merge, regression or local — no configuration needed. The first of these that applies wins:

  1. --build-type, if you pass it.

  2. OYACLOUD_BUILD_TYPE, if that environment variable is set.

  3. Your CI platform's own trigger signal, when it's reliable:

    | Platform | PR | Post-merge | Regression | |----------|----|-----------|-----------| | GitHub Actions | pull_request | push | schedule | | GitLab CI | merge_request_event | push | schedule | | Azure DevOps | PullRequest | IndividualCI / BatchedCI | Schedule | | Jenkins · CircleCI · Bitbucket | PR detection only | — | — |

    GitLab runs merge_request_event pipelines only when your .gitlab-ci.yml has merge-request workflow rules (if: $CI_PIPELINE_SOURCE == "merge_request_event"); without them a branch with an open merge request runs a push pipeline and counts as post-merge.

    Jenkins: use a Multibranch Pipeline (branch, PR number, target branch) and set the Jenkins URL (Manage Jenkins → System) — the CLI recognises Jenkins by JENKINS_URL. Jenkins doesn't say whether a build was started by a timer; for nightly builds set OYACLOUD_BUILD_TYPE=regression. Freestyle jobs provide only the commit — pass --branch "${GIT_BRANCH#origin/}" on a push job, --build-type regression on a regression job. Execute shell runs with sh -xe, so to upload when tests fail and keep the result: status=0; <tests> || status=$?; oyacloud upload …; exit $status.

  4. The backend infers it from what you passed — a --pr-number means a PR build, --commit with --branch means post-merge, neither means regression.

Environment and build type go together. Post-merge and regression builds are compared against earlier runs in the same environment, so they need --environment; the upload is refused without one. PR and local builds may leave it out. If no build type is given or detected, the build counts as a regression and therefore needs an environment — pass --build-type pr or --build-type local if it is neither.

Manual and dispatch triggers (workflow_dispatch, GitLab web/api, Azure Manual) deliberately fall through to step 4: a manual re-run says nothing about whether code actually merged.

Project API keys

Each project has its own API key. Generate it when you create the project, or from Projects → Configure → API Key.

Project keys are scoped — they identify which project the results belong to, so no --project flag is needed in the CLI.

To rotate a key: go to Projects → Configure → API Key → Rotate key. Update your pipelines before rotating as the old key stops working immediately.

Commands

oyacloud config set-key <apiKey>

Save API key locally. Run once after getting your project key.

oyacloud config show

Show current saved configuration (API key is masked).

Help

oyacloud --help
oyacloud upload --help

License

Proprietary. Copyright (c) 2026 OyaPlus LLC. All rights reserved.

You may install and run the CLI to use the OyaCloud service. You may not redistribute or modify it. See LICENSE for the full terms.

Versions up to and including 1.3.0 were published under the MIT licence and remain available under it.