Skip to content
Draft
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
232 changes: 196 additions & 36 deletions .github/workflows/publish-stable-release.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@ env:
HUSKY: "0"
NPM_CONFIG_PROVENANCE: "true"

# Replace the sdk-actions ref below with the final commit SHA containing the
# manifest-driven publish action before using this workflow for production.

jobs:
validate-release-sha:
runs-on: ubuntu-latest
Expand Down Expand Up @@ -69,18 +72,20 @@ jobs:
echo "Diff to latest release: $diff_url"
} | tee -a "$GITHUB_STEP_SUMMARY"

publish-stable:
build-package-artifacts:
needs:
- validate-release-sha
- print-changelog-links
runs-on: ubuntu-latest
timeout-minutes: 30
permissions:
contents: write
issues: write
contents: read
id-token: write
pull-requests: read
environment: npm-publish
attestations: write
outputs:
has_work: ${{ steps.detect.outputs.has_work }}
markdown: ${{ steps.detect.outputs.markdown }}
release_sha: ${{ needs.validate-release-sha.outputs.release_sha }}
steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
Expand Down Expand Up @@ -113,23 +118,185 @@ jobs:
- name: Build packages
if: steps.detect.outputs.needs_publish == 'true'
run: pnpm run build
- name: Publish stable packages to npm
- name: Pack packages and generate SBOMs
if: steps.detect.outputs.needs_publish == 'true'
run: node scripts/release/pack-publishable-packages.mjs --manifest .release-manifest.json --output-dir artifacts/release-packages --report artifacts/release-packages/pack-report.json
- name: Read release artifact paths
id: artifact_paths
if: steps.detect.outputs.needs_publish == 'true'
run: |
set -euo pipefail

emit_paths() {
local output_prefix="$1"
local package_name="$2"
local tarball sbom
tarball="$(jq -r --arg name "$package_name" '.packages[]? | select(.name == $name) | .tarball_asset // empty' .release-manifest.json)"
sbom="$(jq -r --arg name "$package_name" '.packages[]? | select(.name == $name) | .sbom_asset // empty' .release-manifest.json)"

if [ -n "$tarball" ]; then
echo "${output_prefix}_tarball=artifacts/release-packages/$tarball" >> "$GITHUB_OUTPUT"
echo "${output_prefix}_sbom=artifacts/release-packages/$sbom" >> "$GITHUB_OUTPUT"
fi
}

emit_paths braintrust "braintrust"
emit_paths braintrust_browser "@braintrust/browser"
emit_paths braintrust_langchain_js "@braintrust/langchain-js"
emit_paths braintrust_openai_agents "@braintrust/openai-agents"
emit_paths braintrust_otel "@braintrust/otel"
emit_paths braintrust_templates_nunjucks_js "@braintrust/templates-nunjucks-js"
emit_paths braintrust_temporal "@braintrust/temporal"
emit_paths braintrust_vercel_ai_sdk "@braintrust/vercel-ai-sdk"
- name: Attest tarball build provenance
if: steps.detect.outputs.needs_publish == 'true'
uses: actions/attest-build-provenance@0f67c3f4856b2e3261c31976d6725780e5e4c373 # v4.1.1
with:
subject-path: artifacts/release-packages/*.tgz
- name: Attest braintrust SBOM
if: steps.artifact_paths.outputs.braintrust_tarball != ''
uses: actions/attest@a1948c3f048ba23858d222213b7c278aabede763 # v4.1.1
with:
subject-path: ${{ steps.artifact_paths.outputs.braintrust_tarball }}
sbom-path: ${{ steps.artifact_paths.outputs.braintrust_sbom }}
- name: Attest @braintrust/browser SBOM
if: steps.artifact_paths.outputs.braintrust_browser_tarball != ''
uses: actions/attest@a1948c3f048ba23858d222213b7c278aabede763 # v4.1.1
with:
subject-path: ${{ steps.artifact_paths.outputs.braintrust_browser_tarball }}
sbom-path: ${{ steps.artifact_paths.outputs.braintrust_browser_sbom }}
- name: Attest @braintrust/langchain-js SBOM
if: steps.artifact_paths.outputs.braintrust_langchain_js_tarball != ''
uses: actions/attest@a1948c3f048ba23858d222213b7c278aabede763 # v4.1.1
with:
subject-path: ${{ steps.artifact_paths.outputs.braintrust_langchain_js_tarball }}
sbom-path: ${{ steps.artifact_paths.outputs.braintrust_langchain_js_sbom }}
- name: Attest @braintrust/openai-agents SBOM
if: steps.artifact_paths.outputs.braintrust_openai_agents_tarball != ''
uses: actions/attest@a1948c3f048ba23858d222213b7c278aabede763 # v4.1.1
with:
subject-path: ${{ steps.artifact_paths.outputs.braintrust_openai_agents_tarball }}
sbom-path: ${{ steps.artifact_paths.outputs.braintrust_openai_agents_sbom }}
- name: Attest @braintrust/otel SBOM
if: steps.artifact_paths.outputs.braintrust_otel_tarball != ''
uses: actions/attest@a1948c3f048ba23858d222213b7c278aabede763 # v4.1.1
with:
subject-path: ${{ steps.artifact_paths.outputs.braintrust_otel_tarball }}
sbom-path: ${{ steps.artifact_paths.outputs.braintrust_otel_sbom }}
- name: Attest @braintrust/templates-nunjucks-js SBOM
if: steps.artifact_paths.outputs.braintrust_templates_nunjucks_js_tarball != ''
uses: actions/attest@a1948c3f048ba23858d222213b7c278aabede763 # v4.1.1
with:
subject-path: ${{ steps.artifact_paths.outputs.braintrust_templates_nunjucks_js_tarball }}
sbom-path: ${{ steps.artifact_paths.outputs.braintrust_templates_nunjucks_js_sbom }}
- name: Attest @braintrust/temporal SBOM
if: steps.artifact_paths.outputs.braintrust_temporal_tarball != ''
uses: actions/attest@a1948c3f048ba23858d222213b7c278aabede763 # v4.1.1
with:
subject-path: ${{ steps.artifact_paths.outputs.braintrust_temporal_tarball }}
sbom-path: ${{ steps.artifact_paths.outputs.braintrust_temporal_sbom }}
- name: Attest @braintrust/vercel-ai-sdk SBOM
if: steps.artifact_paths.outputs.braintrust_vercel_ai_sdk_tarball != ''
uses: actions/attest@a1948c3f048ba23858d222213b7c278aabede763 # v4.1.1
with:
subject-path: ${{ steps.artifact_paths.outputs.braintrust_vercel_ai_sdk_tarball }}
sbom-path: ${{ steps.artifact_paths.outputs.braintrust_vercel_ai_sdk_sbom }}
- name: Upload release package artifacts
if: steps.detect.outputs.needs_publish == 'true'
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: stable-release-packages
path: |
.release-manifest.json
artifacts/release-packages/
retention-days: 1
if-no-files-found: error

request-approval:
needs:
- build-package-artifacts
if: needs.build-package-artifacts.outputs.has_work == 'true'
runs-on: ubuntu-latest
timeout-minutes: 5
permissions: {}
steps:
- name: Post release approval summary
env:
NODE_AUTH_TOKEN: ""
NPM_TOKEN: ""
run: node scripts/release/publish-release-manifest.mjs --manifest .release-manifest.json
RELEASE_SHA: ${{ needs.build-package-artifacts.outputs.release_sha }}
PACKAGES: ${{ needs.build-package-artifacts.outputs.markdown }}
run: |
{
echo "## Stable release awaiting approval"
echo
echo "**Release SHA:** \`$RELEASE_SHA\`"
echo
echo "### Packages"
echo "$PACKAGES"
} >> "$GITHUB_STEP_SUMMARY"
- name: Post approval request to Slack
uses: slackapi/slack-github-action@af78098f536edbc4de71162a307590698245be95 # v3.0.1
with:
method: chat.postMessage
token: ${{ secrets.SLACK_BOT_TOKEN }}
payload: |
channel: C0ABHT0SWA2
text: "⏳ Stable release awaiting approval"
blocks:
- type: "header"
text:
type: "plain_text"
text: "⏳ Stable release awaiting approval"
- type: "section"
text:
type: "mrkdwn"
text: "*Release SHA:* `${{ needs.build-package-artifacts.outputs.release_sha }}`\n\n*Packages:*\n${{ needs.build-package-artifacts.outputs.markdown }}\n\n<${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}|View Run>"

publish-stable:
needs:
- build-package-artifacts
- request-approval
if: |
always() &&
needs.build-package-artifacts.outputs.has_work == 'true' &&
needs.request-approval.result == 'success'
runs-on: ubuntu-latest
timeout-minutes: 30
permissions:
contents: write
issues: write
id-token: write
pull-requests: read
attestations: read
environment: npm-publish
steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
fetch-depth: 0
ref: ${{ needs.build-package-artifacts.outputs.release_sha }}
- name: Download release package artifacts
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with:
name: stable-release-packages
path: release-artifacts
- name: Publish stable package tarballs
uses: braintrustdata/sdk-actions/actions/release/lang/js/publish-tarballs@release_custom_build_actions
with:
manifest: release-artifacts/.release-manifest.json
tarballs: release-artifacts/artifacts/release-packages/*.tgz
repo: ${{ github.repository }}
slack_token: ${{ secrets.SLACK_BOT_TOKEN }}
slack_channel: C0ABHT0SWA2
- name: Push Changesets release tags
if: steps.detect.outputs.has_work == 'true'
run: |
set -euo pipefail

git config user.name "github-actions[bot]"
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"

target_commit="$(jq -r '.commit // empty' .release-manifest.json)"
manifest="release-artifacts/.release-manifest.json"
target_commit="$(jq -r '.commit // empty' "$manifest")"
mapfile -t tags < <(
jq -r '.packages[]? | .tag // "\(.name)@\(.version)"' .release-manifest.json
jq -r '.packages[]? | .tag // "\(.name)@\(.version)"' "$manifest"
)

if [ "${#tags[@]}" -eq 0 ]; then
Expand Down Expand Up @@ -174,44 +341,37 @@ jobs:

git push origin "${to_push[@]}"
- name: Create GitHub Releases
if: steps.detect.outputs.has_work == 'true'
env:
GITHUB_TOKEN: ${{ github.token }}
run: node scripts/release/create-github-releases.mjs --manifest .release-manifest.json
uses: braintrustdata/sdk-actions/actions/release/create-package-releases@release_custom_build_actions
with:
manifest: release-artifacts/.release-manifest.json
repo: ${{ github.repository }}
- name: Attach package SBOMs to GitHub Releases
uses: braintrustdata/sdk-actions/actions/release/upload-package-sboms@release_custom_build_actions
with:
manifest: release-artifacts/.release-manifest.json
sboms: release-artifacts/artifacts/release-packages/*.sbom.json
repo: ${{ github.repository }}
- name: Comment on issues closed by released PRs
if: steps.detect.outputs.has_work == 'true'
env:
GITHUB_TOKEN: ${{ github.token }}
run: node scripts/release/comment-release-issues.mjs
- name: Post stable release to Slack
if: steps.detect.outputs.has_work == 'true'
uses: slackapi/slack-github-action@af78098f536edbc4de71162a307590698245be95 # v3.0.1
with:
method: chat.postMessage
token: ${{ secrets.SLACK_BOT_TOKEN }}
payload: |
channel: C0ABHT0SWA2
text: "✅ Packages published"
blocks:
- type: "header"
text:
type: "plain_text"
text: "✅ Packages published"
- type: "section"
text:
type: "mrkdwn"
text: "*Release SHA:* `${{ needs.validate-release-sha.outputs.release_sha }}`\n\n*Packages:*\n${{ steps.detect.outputs.markdown }}\n\n<${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}|View Run>"
run: |
cp release-artifacts/.release-manifest.json .release-manifest.json
node scripts/release/comment-release-issues.mjs

notify-failure:
needs:
- validate-release-sha
- print-changelog-links
- build-package-artifacts
- request-approval
- publish-stable
if: |
always() &&
(
needs.validate-release-sha.result == 'failure' ||
needs.print-changelog-links.result == 'failure' ||
needs.build-package-artifacts.result == 'failure' ||
needs.request-approval.result == 'failure' ||
needs.publish-stable.result == 'failure'
)
runs-on: ubuntu-latest
Expand Down
2 changes: 1 addition & 1 deletion .tool-versions
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
nodejs 24.15.0
npm 11.12.1
pnpm 10.33.0
pnpm 11.9.0
deno 2.7.6
29 changes: 1 addition & 28 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -56,32 +56,5 @@
"lint-staged": {
"**/*.{js,jsx,ts,tsx,mjs,cjs,css,md,mdx,html,yaml,yml,json}": "prettier --write"
},
"packageManager": "pnpm@10.33.0",
"pnpm": {
"overrides": {
"handlebars": "^4.7.9",
"protobufjs": "^7.5.8",
"esbuild": "0.27.4",
"uuid": "11.1.1",
"router@2.2.0>path-to-regexp": "8.4.0",
"express@5.2.1>qs": "6.15.2",
"qs@>=6.7.0 <6.15.2": "^6.15.2",
"tar@>=7.0.0 <7.5.11": "^7.5.11",
"tar@>=6.0.0 <7.0.0": "^6.2.1",
"hono@>=4.0.0 <4.12.18": "^4.12.18",
"flatted@<3.4.2": "^3.4.2",
"markdown-it@>=13.0.0 <14.1.1": "^14.1.1",
"ip-address@<10.1.1": "^10.1.1",
"js-yaml@>=4.0.0 <4.1.1": "^4.1.1",
"js-yaml@<3.14.2": "^3.14.2",
"@mikro-orm/knex@>=6.0.0 <6.6.14": "^6.6.14",
"glob@>=10.2.0 <10.5.0": "^10.5.0"
},
"ignoredBuiltDependencies": [
"@swc/core",
"esbuild",
"msw",
"protobufjs"
]
}
"packageManager": "pnpm@11.9.0"
}
22 changes: 11 additions & 11 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading
Loading