Skip to content
Open
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
26 changes: 5 additions & 21 deletions .github/workflows/storybook-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,7 @@ on:
required: false
type: string

# Required for AWS OIDC authentication
permissions:
id-token: write
contents: read

jobs:
Expand Down Expand Up @@ -63,31 +61,17 @@ jobs:
continue-on-error: true
id: test_filtered

- name: 🔐 Configure AWS Credentials
if: always()
uses: aws-actions/configure-aws-credentials@7474bc4690e29a8392af63c5b98e7449536d5c3a # v4.3.1
with:
aws-region: ${{ secrets.TEST_ARTIFACTS_AWS_REGION }}
role-to-assume: arn:aws:iam::${{ secrets.TEST_ARTIFACTS_AWS_ACCOUNT_ID }}:role/${{ secrets.TEST_ARTIFACTS_POLICY_NAME}}
role-session-name: StorybookTestsSession

- name: 📤 Upload Test Screenshots to S3
if: always()
run: npx tsx scripts/upload-test-screenshots.ts
env:
GITHUB_RUN_NUMBER: ${{ github.run_number }}
GITHUB_REPOSITORY: ${{ github.repository }}
S3_BUCKET: ${{ secrets.TEST_ARTIFACTS_BUCKET_NAME }}
AWS_REGION: ${{ secrets.TEST_ARTIFACTS_AWS_REGION }}

- name: 📊 Upload JUnit test results
- name: 📊 Upload JUnit test results and screenshots
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
if: always()
with:
name: storybook-junit-results
# Ship the raw per-story screenshots alongside the JUnit report so the
# Zephyr report workflow can embed them as base64 <img> in each step's
# result (replaces the previous S3-upload + URL-in-comment path).
path: |
test-results/storybook-junit.xml
test-results/screenshot-urls.json
test-results/screenshots/
retention-days: 7

- name: 📸 Upload failure artifacts
Expand Down
27 changes: 24 additions & 3 deletions .github/workflows/zephyr-report-results.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,16 @@

jobs:
report:
# Run on workflow_run (when Storybook Tests completes) or workflow_dispatch (manual)
# Run on workflow_run (when Storybook Tests completes) or workflow_dispatch (manual).
# For the workflow_run path, require the triggering run to originate from THIS
# repository (not a fork). This job is privileged (holds ZEPHYR_TOKEN + JFrog
# secrets) and checks out `workflow_run.head_sha`; gating on the head repository
# ensures that checked-out ref is always trusted, never untrusted fork code.
if: >
github.event_name == 'workflow_dispatch' ||
github.event.workflow_run.conclusion == 'success' ||
github.event.workflow_run.conclusion == 'failure'
((github.event.workflow_run.conclusion == 'success' ||
github.event.workflow_run.conclusion == 'failure') &&
github.event.workflow_run.head_repository.full_name == github.repository)
runs-on: ubuntu-latest
steps:
- name: Checkout repository
Expand All @@ -51,6 +56,22 @@
- name: Install dependencies
run: yarn install --immutable

# ts-lib-zephyr-nodejs is published only to TetraScience's JFrog Artifactory
# and is deliberately kept OUT of package.json / yarn.lock so public and
# external-contributor `yarn install` stays on the public npm registry. The
# shared composite action fetches it as a leaf tarball into node_modules
# (its only transitive need, ts-morph, is already installed).
# NOTE: pinned to the action's PR branch for testing; switch to @main once
# tetrascience/ts-ci-cd-lib#29 merges.
- name: Install ts-lib-zephyr-nodejs (JFrog)

@darwinboersma darwinboersma Jul 2, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Were there blockers to publishing ts-lib-zephyr-nodejs publicly? It seems like all of this wiring + the other PR would be unnecessary if that is possible, and less code is almost always better

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good question. ts-lib-zephyr-nodejs is intentionally private: it's an internal test-infra lib that hardcodes TetraScience Zephyr/JFrog specifics and has no external audience, and its own repo (license: UNLICENSED, no publishConfig) publishes only to JFrog — so publishing it to public npm would be a decision (and maintenance/security commitment) owned by that repo's team, out of scope for this migration. The wiring here is the standard pattern other TS repos already use to consume it (data-app repos, ts-service-web), so #161 stays consistent with them rather than forking a new distribution model. If the zephyr-lib team does decide to publish it publicly later, this collapses to a normal package.json dep and we can drop the JFrog step + #29 — worth raising with them, but not a blocker for this PR.

🤖 Addressed by Claude Code

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Digging into this a bit — I don't think ts-lib-zephyr-nodejs is actually intentionally private. It's private because that's the org default, but there's no deliberate decision behind it: src/ has zero TetraScience/JFrog-specific code (the only TS references are in the README/CI/CODEOWNERS), and it's a generic Zephyr Scale Cloud reporter/provisioner — clear external audience. The UNLICENSED + JFrog-only publishing are cookiecutter leftovers, not a distribution choice.

And it's our team's library, so this is our call to make. Since we're now consuming it from a public repo, I'd rather publish it to public npm than carry the JFrog leaf-tarball wiring here — that also lets us drop this step and ts-ci-cd-lib#29 entirely (the "less code" win).

Could you fold that into the integration work? It's roughly:

  • license: UNLICENSEDApache-2.0 + committed LICENSE file (matches @tetrascience-npm/tetrascience-react-ui)
  • rename to @tetrascience-npm/ts-lib-zephyr-nodejs + publishConfig: { access: "public", registry: "https://registry.npmjs.org" }
  • point publish.yml at public npm (mirror the data-apps-client trusted-publishing setup; first version needs a manual bootstrap)
  • add the npmScopes block to .yarnrc.yml to avoid the JFrog __archiveUrl lockfile pinning

Then #161 collapses to a normal package.json dep.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fair — I overstated "intentionally private"; you're right that it's org-default + cookiecutter leftovers, the src/ is generic, and it's your team's call. Public npm is the cleaner end state and collapses #161 to a normal dep + drops #29. 👍

One thing to sequence so we don't fragment: a few repos already depend on the unscoped ts-lib-zephyr-nodejs from JFrog (ts-service-web, a couple of data-app repos, ts-desktop-apps). Renaming to @tetrascience-npm/ts-lib-zephyr-nodejs means those keep resolving the old name from JFrog until they migrate — so it's a coordinated cutover, and the library has to be published publicly first (the first-version manual bootstrap) before #161 can depend on it.

Confirming scope/ordering with @OWilliams now. If we green-light it, the plan is: (1) library PR — Apache-2.0 + LICENSE, scope rename, publishConfig public, publish.yml → public trusted-publishing (mirror data-apps-client) + bootstrap v-first; (2) rework #161 to a plain package.json dep + .yarnrc.yml npmScopes, reverting the JFrog step and the dynamic-import shim; (3) close #29. I'll hold this thread open until we lock the direction.

🤖 Addressed by Claude Code

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Library PR is up: tetrascience/ts-lib-zephyr-nodejs#14 — renames to @tetrascience-npm/ts-lib-zephyr-nodejs, Apache-2.0 + LICENSE, publishConfig public, and publish.yml → public npm via OIDC trusted publishing (mirrors this repo's publish-public.yml). yarn check + all 368 tests pass.

Sequencing from here: (1) merge #14 + the one-time bootstrap (register the repo as a trusted publisher on npmjs, ensure a PROD env, mint the first public version — called out in that PR); (2) once a version is live on public npm, I'll flip this PR to a plain package.json dep (reverting the JFrog step + dynamic-import shim) and close ts-ci-cd-lib#29. Keeping #161 on JFrog until then so it stays green/mergeable if needed.

🤖 Addressed by Claude Code

uses: tetrascience/ts-ci-cd-lib/install-jfrog-npm-package@install-jfrog-npm-package-action

Check warning

Code scanning / CodeQL

Unpinned tag for a non-immutable Action in workflow or composite action Medium

Unpinned 3rd party Action 'Report Test Results to Zephyr' step
Uses Step
uses 'tetrascience/ts-ci-cd-lib/install-jfrog-npm-package' with ref 'install-jfrog-npm-package-action', not a pinned commit hash
Comment thread
owilliams-tetrascience marked this conversation as resolved.
with:
package: ts-lib-zephyr-nodejs
version: "0.4.0"
# Read-only virtual registry URL — infra info, not a credential.
registry-url: https://tetrascience.jfrog.io/artifactory/api/npm/ts-npm-virtual/
auth: ${{ secrets.JFROG_ARTIFACTORY_READ_NPM_AUTH }}

- name: Download test results artifact
uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0
with:
Expand Down
16 changes: 16 additions & 0 deletions .github/workflows/zephyr-sync-storybook.yml
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,22 @@
- name: Install dependencies
run: yarn install --immutable

# ts-lib-zephyr-nodejs is published only to TetraScience's JFrog Artifactory
# and is deliberately kept OUT of package.json / yarn.lock so public and
# external-contributor `yarn install` stays on the public npm registry. The
# shared composite action fetches it as a leaf tarball into node_modules
# (its only transitive need, ts-morph, is already installed).
# NOTE: pinned to the action's PR branch for testing; switch to @main once
# tetrascience/ts-ci-cd-lib#29 merges.
- name: Install ts-lib-zephyr-nodejs (JFrog)
uses: tetrascience/ts-ci-cd-lib/install-jfrog-npm-package@install-jfrog-npm-package-action

Check warning

Code scanning / CodeQL

Unpinned tag for a non-immutable Action in workflow or composite action Medium

Unpinned 3rd party Action 'Sync Storybook to Zephyr' step
Uses Step
uses 'tetrascience/ts-ci-cd-lib/install-jfrog-npm-package' with ref 'install-jfrog-npm-package-action', not a pinned commit hash
Comment thread
owilliams-tetrascience marked this conversation as resolved.
with:
package: ts-lib-zephyr-nodejs
version: "0.4.0"
# Read-only virtual registry URL — infra info, not a credential.
registry-url: https://tetrascience.jfrog.io/artifactory/api/npm/ts-npm-virtual/
auth: ${{ secrets.JFROG_ARTIFACTORY_READ_NPM_AUTH }}

- name: Run Zephyr sync
env:
ZEPHYR_TOKEN: ${{ secrets.ZEPHYR_TOKEN }}
Expand Down
4 changes: 3 additions & 1 deletion AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,9 @@ Convention: uses [Conventional Commits](https://www.conventionalcommits.org/) fo

## Zephyr Integration

- Test results reported to Zephyr Scale via `scripts/zephyr/report-zephyr-results.ts`
- Zephyr HTTP is handled by a shared internal `ts-lib-zephyr-nodejs` library (`ZephyrClient` + helpers). The repo's scripts are thin wrappers around it — JUnit parsing, story parsing/write-back, cycle resolution, and folder mapping stay local.
- **Dependency source:** the library lives only on TetraScience's JFrog Artifactory and is deliberately kept **out of `package.json` / `yarn.lock`** so public/external-contributor `yarn install` stays on the public npm registry. CI installs it as a leaf tarball inside the two Zephyr workflows (see `Install ts-lib-zephyr-nodejs (JFrog)` steps; the read-only virtual registry URL is hardcoded and only the org-level `JFROG_ARTIFACTORY_READ_NPM_AUTH` token comes from a secret). For local script work, install it as a leaf: `npm pack ts-lib-zephyr-nodejs@0.4.0 --registry <jfrog-url>` then extract the tgz into `node_modules/ts-lib-zephyr-nodejs` (do **not** `npm install --no-save` — it corrupts the Yarn `node_modules`).
- Test results reported to Zephyr Scale via `scripts/zephyr/report-zephyr-results.ts`. Each story's screenshot is embedded (base64 `<img>`) into every step of the execution via the library's `buildStepsPayload` + `putExecutionSteps` — there is no S3 upload; CI ships `test-results/screenshots/**` in the `storybook-junit-results` artifact for the report job to read.
- Story-to-testcase sync handled by `scripts/zephyr/sync-storybook-zephyr.ts`
- Test case IDs live in story parameters: `parameters.zephyr.testCaseId`
- Do not manually invent, copy, reuse, or paste Zephyr test case IDs between stories.
Expand Down
2 changes: 2 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -282,6 +282,8 @@ export const MyStory: Story = {

#### Zephyr Integration

The Zephyr scripts are thin wrappers around a shared internal `ts-lib-zephyr-nodejs` library (installed from the internal registry only inside the Zephyr CI workflows — see `AGENTS.md`). Test results report per-story screenshots embedded directly into each Zephyr step.

Test cases are linked to Zephyr Scale via story parameters. These IDs are auto-generated by `sync-storybook-zephyr`:

```typescript
Expand Down
2 changes: 0 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -168,8 +168,6 @@
},
"devDependencies": {
"@aws-sdk/client-athena": "^3.975.0",
"@aws-sdk/client-s3": "^3.985.0",
"@aws-sdk/s3-request-presigner": "^3.985.0",
"@commitlint/cli": "^20.5.0",
"@commitlint/config-conventional": "^20.5.0",
"@databricks/sql": "^1.12.0",
Expand Down
214 changes: 0 additions & 214 deletions scripts/upload-test-screenshots.ts

This file was deleted.

Loading
Loading