feat(providers): add providerMeta (#59)#198
Conversation
Add detectProviderMetadata() / providerMetadata exposing normalized git and build metadata (repo, branch, commit SHA, PR number, deployment environment, build URL, run id, actor, event, workflow) for the detected provider. Extractors live in a separate module (src/provider-metadata.ts) and reuse detectProvider() as the single source of truth for the provider name, so importing only isCI/provider tree-shakes the metadata engine out. Adapted from @varlock/ci-env-info.
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
📝 WalkthroughWalkthroughThis PR adds a new provider metadata module, exports it from the package entrypoint, documents the API, and adds tests for provider-specific metadata extraction. ChangesProvider Metadata Feature
Estimated code review effort: 3 (Moderate) | ~25 minutes 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 4
🧹 Nitpick comments (1)
test/provider-metadata.test.ts (1)
62-85: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winConsider adding a
workflowNameassertion to the GitHub Actions push test.
GITHUB_WORKFLOWis listed inenvKeys(line 17) andworkflowNameis a documented metadata field, but no test asserts it. Adding a stub and assertion to the existing GitHub Actions push test would close this coverage gap with minimal effort.🧪 Suggested addition
vi.stubEnv("GITHUB_ACTOR", "octocat"); + vi.stubEnv("GITHUB_WORKFLOW", "CI"); expect(detectProviderMetadata()).toMatchObject({ name: "github_actions", repo: { owner: "unjs", name: "std-env" }, repoSlug: "unjs/std-env", branch: "main", commitSha: "abcdef1234567890", commitShaShort: "abcdef1", isPR: false, runId: "42", buildUrl: "https://github.com/unjs/std-env/actions/runs/42", actor: "octocat", eventName: "push", + workflowName: "CI", });🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@test/provider-metadata.test.ts` around lines 62 - 85, The GitHub Actions push metadata test in detectProviderMetadata is missing coverage for the documented workflowName field even though GITHUB_WORKFLOW is included in envKeys. Update the existing GitHub Actions push case to stub GITHUB_WORKFLOW and assert the returned metadata includes workflowName, using detectProviderMetadata and the same toMatchObject block so the coverage stays aligned with the other GitHub Actions fields.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@src/provider-metadata.ts`:
- Line 162: The buildUrl mapping in the provider metadata is double-prefixing
Netlify deploy URLs with https://, which produces invalid URLs. Update the
buildUrl handler in provider-metadata to use env.DEPLOY_URL directly when it is
present, and keep the undefined fallback unchanged so Netlify’s already
fully-qualified URL is returned as-is.
- Around line 142-143: The GitLab merge-request number mapping in provider
metadata is using the instance-wide ID instead of the user-facing MR IID. Update
the `provider-metadata` mapping for `prNumber` to use `CI_MERGE_REQUEST_IID`
while keeping `isPR` unchanged unless you intentionally want to align it too;
the relevant symbols to adjust are the merge-request fields in the provider
metadata object.
- Line 128: The prNumber resolver in provider metadata is reading the wrong
GitHub Actions variable, so PR builds never resolve a number. Update the
prNumber mapping in the provider-metadata logic to use env.GITHUB_REF with
parsePrNumber, since that helper already understands the pull ref format; keep
the change localized to the prNumber callback and ensure no other callers still
rely on GITHUB_EVENT_NUMBER.
In `@test/provider-metadata.test.ts`:
- Around line 116-130: Handle Netlify DEPLOY_URL values without double-prefixing
the scheme. In detectProviderMetadata, update the Netlify URL normalization so
the buildUrl logic checks whether DEPLOY_URL already starts with https:// before
prepending it; only add the scheme when it is missing. Keep the behavior covered
by the existing provider metadata test for the Netlify deploy-preview case.
---
Nitpick comments:
In `@test/provider-metadata.test.ts`:
- Around line 62-85: The GitHub Actions push metadata test in
detectProviderMetadata is missing coverage for the documented workflowName field
even though GITHUB_WORKFLOW is included in envKeys. Update the existing GitHub
Actions push case to stub GITHUB_WORKFLOW and assert the returned metadata
includes workflowName, using detectProviderMetadata and the same toMatchObject
block so the coverage stays aligned with the other GitHub Actions fields.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: aba0544a-432e-43b4-a65f-1011a240b56a
📒 Files selected for processing (5)
AGENTS.mdREADME.mdsrc/index.tssrc/provider-metadata.tstest/provider-metadata.test.ts
Address CodeRabbit review and an independent audit of every provider's env vars against official docs: - github: parse prNumber from GITHUB_REF (refs/pull/<n>), only on pull refs; prefer GITHUB_REF_NAME for the branch fallback - gitlab: use CI_MERGE_REQUEST_IID (user-facing MR number) not the instance-wide CI_MERGE_REQUEST_ID - netlify: DEPLOY_URL is already fully-qualified — don't re-prefix https:// - azure: prefer SYSTEM_PULLREQUEST_PULLREQUESTNUMBER over the internal PULLREQUESTID for GitHub-based PRs - bitbucket: BITBUCKET_REPO_OWNER is deprecated — use BITBUCKET_WORKSPACE - semaphore: PULL_REQUEST_NUMBER does not exist — use SEMAPHORE_GIT_PR_NUMBER - bitrise: add repo via BITRISEIO_GIT_REPOSITORY_OWNER/SLUG - note target-vs-source branch on PR builds (travis, appveyor, semaphore) Add Semaphore test and workflowName coverage; fix Netlify test URL.
|
Pushed fixes for the review, plus an independent audit of every provider's env vars against official docs. From the CodeRabbit review
From the docs audit (beyond the bot's findings)
Known, documented caveatFor Travis / AppVeyor / Semaphore, on PR builds the Confirmed correct and unchanged: Vercel ( All green: 33 tests, typecheck, lint, build. Still a draft pending direction on naming/shape. |
…mmitShaShort - Derive `isPR` from the parsed PR number when a provider signals a PR via the same env var it uses for the number (9 providers), instead of repeating that var in both the `isPR` and `prNumber` tuple slots. Semantics unchanged, including the `isPR: false` case on non-PR builds. - Drop the `commitShaShort` field and its `shortSha` helper: it duplicated data already in `commitSha` and is a one-liner (`commitSha.slice(0, 7)`) for consumers that want it. Full-bundle dist: 9653 -> 9368 B raw, 3898 -> 3858 B gzip. Metadata engine still tree-shakes to zero for consumers that don't import it. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…eld name Add a `/* branch */`, `/* commitSha */`, ... comment in front of every element of each provider's extractor tuple — values and elided `,` holes alike — so the positional table reads clearly without cross-referencing the tuple order. oxfmt strips comments off bare sparse-array holes, so the table is frozen with a statement-level `// oxfmt-ignore` and hand-aligned. Comments are dropped in minification: dist is byte-identical (9368 B raw / 3858 B gzip). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Shorter, consistent naming across the whole module: - src/provider-metadata.ts -> src/provider-meta.ts (+ test file) - ProviderMetadata -> ProviderMeta - providerMetadata -> providerMeta - detectProviderMetadata -> detectProviderMeta - README + AGENTS docs updated to match Public API rename (exports change), all tests green. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
providerMeta (#59)
`repoSlug` was unconditionally `${repo.owner}/${repo.name}` — fully derived
from `repo` and never divergent, so it duplicated state the caller already has.
Consumers that want the slug can join it in one expression. Mirrors the earlier
`commitShaShort` removal. The `parseRepoSlug` normalization helper stays.
dist: 9360 -> 9326 B raw, 3854 -> 3836 B gzip.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
`mapEnvironment` had exactly one caller (`runEnvironment`'s EnvironmentMap branch); fold it in. Terser already inlined it at minify time, so dist is unchanged (9326 B raw); the win is one fewer module-local helper to follow. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
detectProviderMeta() called detectProvider() unconditionally, so a bundle retaining both `provider*` and `providerMeta` scanned the provider table twice at module init. Split the body into `extractProviderMeta(name)`: - detectProviderMeta() still passes a fresh detectProvider().name (re-run semantics for callers). - the eager `providerMeta` singleton reuses the already-computed `providerInfo.name`, so detection runs once at init. The singleton is a `#__PURE__` IIFE (same pattern as `provider`) so the `providerInfo.name` property access stays inside the closure — a bare property-access argument would defeat the annotation and re-pin the provider table into every consumer (caught by test/bundle.test.ts). All 13 tree-shaking guards + 46 unit tests pass. dist: 9326 -> 9362 B raw. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…lit-var providers Vercel, Bitbucket, and Drone all expose canonical split owner/name env vars, so their inline `parseRepoSlug(...)` fallbacks were dead or duplicative: - vercel: the fallback parsed VERCEL_GIT_REPO_SLUG, which is only the repo name (no `/`), so parseRepoSlug always returned undefined there — dead code. - bitbucket: use BITBUCKET_WORKSPACE + BITBUCKET_REPO_SLUG directly instead of splitting BITBUCKET_REPO_FULL_NAME. - drone: use DRONE_REPO_OWNER + DRONE_REPO_NAME instead of parsing DRONE_REPO. parseRepoSlug stays: it's the default parser for the 10 string-valued `repo` slots, four of which pass full git/https URLs (netlify, codebuild, buildkite, circle) that need its URL handling. dist: 9362 -> 9192 B raw, 3831 -> 3784 B gzip. All tests green. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…ad ref branch - Add `// Docs: <url>` comments citing each provider's official env-var reference, verified against vendor docs. - Netlify: extract `prNumber` from `REVIEW_ID` (documented to match the deploy-preview number). - CodeBuild: recognize `PULL_REQUEST_MERGED`/`PULL_REQUEST_CLOSED` webhook events and extract `prNumber` from `CODEBUILD_WEBHOOK_TRIGGER`. - Jenkins: prefer `CHANGE_ID` (maintained GitHub Branch Source plugin) over `ghprbPullId` (deprecated PR builder plugin) when both are set. - refToBranch: remove the `refs/head/` (singular) branch — not a real git ref format, so it was unreachable dead code. - Note Azure's branch-name leaf-truncation and CircleCI's PR-var deprecation caveats inline for future reference. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
… edge cases Adds dedicated cases for previously-untested providers (Cloudflare Workers, Azure Pipelines, Bitbucket, Buildkite, Jenkins, Render, Travis, AppVeyor, Bitrise, Cirrus, Codefresh, Drone) plus edge cases surfaced while verifying provider docs: case-insensitive environment mapping, malformed/`.git`-suffix repo URLs, GitLab single-segment project paths, and the new Netlify/CodeBuild prNumber extraction. Raises provider-meta.ts coverage from ~80%/64% to ~97%/90% (statements/branches). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…Url (live app) `buildUrl` conflated two different concepts: a link to the CI run's logs (GitHub Actions, GitLab pipeline, CircleCI, Buildkite) vs. the live, publicly-reachable deployment URL (Vercel, Netlify, Cloudflare Pages, Render). Splitting them fixes two real gaps found while auditing against official docs: Render exposed no URL at all despite having `RENDER_EXTERNAL_URL`, and GitLab only captured the pipeline log URL, never its opt-in `CI_ENVIRONMENT_URL` deploy URL. - Add `deployUrl` as a new (appended, non-reordering) tuple slot. - Move Netlify/Vercel/Cloudflare Pages' existing URL extraction to `deployUrl`. - Add Render (`RENDER_EXTERNAL_URL`) and GitLab (`CI_ENVIRONMENT_URL`) `deployUrl` extraction. - Update README/AGENTS.md and add test coverage for the new field. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Closes #59 (partially — the git/build metadata half).
Obviously feel free to adapt as necessary. The important parts (all the provider specific detection and vars) should be easy to reuse however you see fit.
This comes from well worn code in varlock - although I highly doubt we've had users on all the more obscure providers.
What
Adds
detectProviderMetadata()/providerMetadata, exposing normalized git and build metadata for the detected CI/CD or deployment provider:Fields:
name,repo {owner,name},repoSlug,branch,commitSha,commitShaShort,isPR,prNumber,environment,buildUrl,runId,actor,eventName,workflowName. All optional exceptname— availability depends on the provider and event.The extraction logic and per-provider env var mappings are adapted from
@varlock/ci-env-info. It shows no npm downloads because while it is usable on its own, it's an internal package that ships inside Varlock, where this metadata powers builtin variables and is used to automatically infer the current environment (production / preview / development) from the CI/deploy context. So the mappings here are already battle-tested across real CI providers, not net-new.Design notes
src/provider-metadata.ts), out of the detection hot path.providers.tsstays free of per-provider extractor closures, so importing onlyisCI/providerdoesn't pull in the metadata engine. Verified with esbuild — a{ isCI, provider }bundle contains zero metadata extractors; the module is side-effect-free (Side effects: 0 B).detectProviderMetadata()calls the existingdetectProvider()for the provider name, then looks up extractors in aPartial<Record<ProviderName, ProviderExtractors>>keyed by the same lowercase names. No parallel detection list.envproxy (no bareprocess), lazy/* #__PURE__ */singleton,.tsimports.{ name }.Open questions for review
providerMetadata/detectProviderMetadataalongsideproviderInfo. Happy to rename or reshape — e.g. folding intoproviderInfo, though that reintroduces the tree-shaking cost the split avoids.docsUrl/raw/isCIfrom the upstream varlock shape (std-env already hasisCI; the others felt out of scope). Easy to add back.Checklist
pnpm lint/pnpm typecheck/pnpm testpass (8 new tests)pnpm buildsucceeds; new exports present indistSummary by CodeRabbit
providerMetadataanddetectProviderMetadata.