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
210 changes: 210 additions & 0 deletions .github/workflows/cd-release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,210 @@
name: cd Release (capabilities-development)

on:
push:
branches:
- capabilities-development
paths-ignore:
- "**/*.md"
- ".github/**"
workflow_dispatch:
inputs:
dry_run:
description: "Run without publishing or pushing tags"
required: false
default: false
type: boolean

env:
BUN_VERSION: "1.2.21"

concurrency:
group: cd-release
cancel-in-progress: false

jobs:
cd-release:
runs-on: ubuntu-latest
permissions:
contents: write # for git tag push and gh release create
id-token: write # for npm provenance
environment: Publish
steps:
- name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2

Check warning on line 34 in .github/workflows/cd-release.yml

View workflow job for this annotation

GitHub Actions / Validate Workflow Changes

1. Trusted actions should use a major version tag, if available. (trusted-tag-ref / warning)
with:
ref: ${{ github.ref }}
fetch-depth: 0
submodules: recursive

- name: Configure git identity
run: |
git config user.name "github-actions[bot]"
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"

- name: Re-run guard (skip if HEAD already published)
run: |
if git describe --exact-match --match 'v*-cd' HEAD 2>/dev/null; then
echo "::notice::HEAD already has a cd tag; skipping."
echo "SKIP=true" >> $GITHUB_ENV
else
echo "SKIP=false" >> $GITHUB_ENV
fi

- name: Setup Bun
if: env.SKIP != 'true'
uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2.2.0
with:
bun-version: ${{ env.BUN_VERSION }}

- name: Setup Node.js for npm publish
if: env.SKIP != 'true'
uses: actions/setup-node@v4

Check warning on line 62 in .github/workflows/cd-release.yml

View workflow job for this annotation

GitHub Actions / Validate Workflow Changes

1. Action is using node20. Versions older than node24 are being deprecated. Use a newer version of the action if possible. (node-version / warning)
with:
node-version: "24"
registry-url: "https://registry.npmjs.org"

- name: Update npm
if: env.SKIP != 'true'
run: npm install -g npm@latest

- name: Compute next cd version
if: env.SKIP != 'true'
id: version
run: |
NEW_VERSION=$(bun scripts/cd-release/version.ts)
echo "Computed next version: $NEW_VERSION"
if [[ ! "$NEW_VERSION" =~ -cd$ ]]; then
echo "::error::L2 guard tripped: version '$NEW_VERSION' does not end in -cd"
exit 1
fi
echo "NEW_VERSION=$NEW_VERSION" >> $GITHUB_OUTPUT
# also compute prior tag for release notes
PRIOR_TAG=$(git tag -l 'v*-cd' | sort -V | tail -1)
echo "PRIOR_TAG=$PRIOR_TAG" >> $GITHUB_OUTPUT

- name: Install dependencies
if: env.SKIP != 'true'
run: bun install --frozen-lockfile

- name: Run helper unit tests
if: env.SKIP != 'true'
working-directory: scripts/cd-release
run: bun test

- name: Decide whether javy needs republishing
if: env.SKIP != 'true'
id: javy
run: |
PRIOR="${{ steps.version.outputs.PRIOR_TAG }}"
# query last published javy under cd dist-tag; empty string if none
LAST_JAVY_CD=$(npm view @chainlink/cre-sdk-javy-plugin@cd version 2>/dev/null || true)
echo "LAST_JAVY_CD=$LAST_JAVY_CD"
if [ -z "$LAST_JAVY_CD" ]; then
CHANGED=true
else
CHANGED=$(bun scripts/cd-release/javy-changed.ts "$PRIOR")
fi
echo "CHANGED=$CHANGED" >> $GITHUB_OUTPUT
echo "LAST_JAVY_CD=$LAST_JAVY_CD" >> $GITHUB_OUTPUT

- name: Publish javy plugin (if changed)
if: env.SKIP != 'true' && steps.javy.outputs.CHANGED == 'true'
working-directory: packages/cre-sdk-javy-plugin
run: |
NEW="${{ steps.version.outputs.NEW_VERSION }}"
bun ../../scripts/cd-release/pin-deps.ts package.json "$NEW"
if [ "${{ github.event.inputs.dry_run }}" = "true" ]; then
npm publish --dry-run --access public --tag cd --provenance --verbose
elif npm view "@chainlink/cre-sdk-javy-plugin@$NEW" version > /dev/null 2>&1; then
echo "::notice::@chainlink/cre-sdk-javy-plugin@$NEW already published — skipping publish (re-run idempotency)"
else
npm publish --access public --tag cd --provenance --verbose
fi

- name: Resolve effective javy version for sdk pin
if: env.SKIP != 'true'
id: javyver
run: |
if [ "${{ steps.javy.outputs.CHANGED }}" = "true" ]; then
echo "JAVY_VER=${{ steps.version.outputs.NEW_VERSION }}" >> $GITHUB_OUTPUT
else
echo "JAVY_VER=${{ steps.javy.outputs.LAST_JAVY_CD }}" >> $GITHUB_OUTPUT
fi

- name: Build cre-sdk
if: env.SKIP != 'true'
working-directory: packages/cre-sdk
run: bun run build

- name: Pin and publish cre-sdk
if: env.SKIP != 'true'
working-directory: packages/cre-sdk
run: |
NEW="${{ steps.version.outputs.NEW_VERSION }}"
JAVY="${{ steps.javyver.outputs.JAVY_VER }}"
bun ../../scripts/cd-release/pin-deps.ts package.json "$NEW" \
"@chainlink/cre-sdk-javy-plugin=$JAVY"
if [ "${{ github.event.inputs.dry_run }}" = "true" ]; then
npm publish --dry-run --access public --tag cd --provenance --verbose
elif npm view "@chainlink/cre-sdk@$NEW" version > /dev/null 2>&1; then
echo "::notice::@chainlink/cre-sdk@$NEW already published — skipping publish (re-run idempotency)"
else
npm publish --access public --tag cd --provenance --verbose
fi

- name: Pin cre-sdk-examples (no publish)
if: env.SKIP != 'true'
working-directory: packages/cre-sdk-examples
run: |
NEW="${{ steps.version.outputs.NEW_VERSION }}"
bun ../../scripts/cd-release/pin-deps.ts package.json "$NEW" \
"@chainlink/cre-sdk=$NEW"

- name: Create ephemeral release commit and tag
if: env.SKIP != 'true'
run: |
NEW="${{ steps.version.outputs.NEW_VERSION }}"
git add packages/cre-sdk/package.json \
packages/cre-sdk-examples/package.json \
packages/cre-sdk-javy-plugin/package.json
git commit -m "chore(release): v${NEW} [skip ci]"
git tag "v${NEW}"
if [ "${{ github.event.inputs.dry_run }}" = "true" ]; then
echo "DRY RUN: would push tag v${NEW}"
git tag -d "v${NEW}"
else
git push origin "v${NEW}"
fi

- name: Create GitHub prerelease
if: env.SKIP != 'true' && github.event.inputs.dry_run != 'true'
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
NEW="${{ steps.version.outputs.NEW_VERSION }}"
PRIOR="${{ steps.version.outputs.PRIOR_TAG }}"
gh release create "v${NEW}" \
--prerelease \
--latest=false \
--generate-notes \
--notes-start-tag "$PRIOR" \
--title "v${NEW}"

- name: Summary
if: env.SKIP != 'true'
run: |
NEW="${{ steps.version.outputs.NEW_VERSION }}"
{
echo "## 🟡 cd Release v${NEW}"
echo ""
echo "- npm dist-tag: \`cd\`"
echo "- javy republished: ${{ steps.javy.outputs.CHANGED }}"
echo "- dry run: ${{ github.event.inputs.dry_run }}"
echo ""
echo "### Install"
echo '```bash'
echo "bun add @chainlink/cre-sdk@cd"
echo "bun add @chainlink/cre-sdk@${NEW}"
echo '```'
} >> $GITHUB_STEP_SUMMARY
10 changes: 10 additions & 0 deletions .github/workflows/publish-cre-sdk-javy-plugin.yml
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,16 @@ jobs:
echo "Current commit: $(git rev-parse HEAD)"
echo "Current commit short: $(git rev-parse --short HEAD)"

- name: Reject cd-line tags
if: ${{ github.event.inputs.tag != '' }}
run: |
INPUT_TAG="${{ github.event.inputs.tag }}"
if [[ "$INPUT_TAG" == *-cd* ]]; then
echo "::error::Refusing to publish '$INPUT_TAG' through this workflow."
echo "::error::cd-line tags must be published via cd-release.yml, not the main-line publish workflow."
exit 1
fi

- name: Setup Bun
uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2.2.0
with:
Expand Down
10 changes: 10 additions & 0 deletions .github/workflows/publish-cre-sdk.yml
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,16 @@ jobs:
echo "Current commit: $(git rev-parse HEAD)"
echo "Current commit short: $(git rev-parse --short HEAD)"

- name: Reject cd-line tags
if: ${{ github.event.inputs.tag != '' }}
run: |
INPUT_TAG="${{ github.event.inputs.tag }}"
if [[ "$INPUT_TAG" == *-cd* ]]; then
echo "::error::Refusing to publish '$INPUT_TAG' through this workflow."
echo "::error::cd-line tags must be published via cd-release.yml, not the main-line publish workflow."
exit 1
fi

- name: Setup Bun
uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2.2.0
with:
Expand Down
1 change: 1 addition & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
[submodule "submodules/chainlink-protos"]
path = submodules/chainlink-protos
url = https://github.com/smartcontractkit/chainlink-protos.git
branch = capabilities-development
56 changes: 56 additions & 0 deletions PUBLISHING.md
Original file line number Diff line number Diff line change
Expand Up @@ -83,3 +83,59 @@ Once the pre-release has been validated:

1. Update `packages/cre-sdk/package.json` version to `1.1.3` (remove the pre-release suffix)
2. Follow the normal release process — the workflow will publish with `--tag latest`

## 🟡 capabilities-development continuous prereleases

The `capabilities-development` branch publishes a continuous prerelease line under the npm `cd` dist-tag. **No manual coordination is required** — every push to `capabilities-development` triggers `.github/workflows/cd-release.yml`, which:

1. Computes the next version by patch-bumping the highest existing `v*.*.*-cd` git tag.
2. Republishes `@chainlink/cre-sdk-javy-plugin` only if its source changed since the last cd release.
3. Pins `workspace:*` dependencies to the new concrete version inside the published tarball metadata.
4. Tags the release as `v0.0.N-cd` (without modifying the branch — the tag points at an ephemeral release commit).
5. Creates a GitHub prerelease with auto-generated notes.

### Version scheme

| Channel | Version pattern | Source | dist-tag |
|---|---|---|---|
| Stable | `1.6.0` | `main` via `publish-cre-sdk*.yml` | `latest` |
| Curated alpha / beta / rc | `1.6.1-alpha.1` etc. | release branches via `publish-cre-sdk*.yml` | `alpha` / `beta` / `rc` |
| Continuous capabilities-development | `0.0.N-cd` | `capabilities-development` via `cd-release.yml` | `cd` |

The cd line is intentionally rooted at `0.0.0` and only patch-bumps. Major / minor never advance — the cd line is alpha-quality and does not communicate semantic version meaning. Consumers should pin to specific versions (`0.0.7-cd`) for reproducibility, or use the `cd` dist-tag for "always latest dev":

```bash
bun add @chainlink/cre-sdk@cd
bun add @chainlink/cre-sdk@0.0.7-cd
```

### One-time seed

The cd line must be seeded once with the lowest tag the workflow should bump from:

```bash
git tag v0.0.0-cd
git push origin v0.0.0-cd
```

After that, the workflow runs hands-off. To restart the line at a new base (e.g., `v1.0.0-cd`) tag manually with the new base; the next automated run will continue from there.

### Guards

- **L1**: npm `latest` dist-tag is never assigned to cd versions because `npm publish --tag cd` is hard-coded in the workflow.
- **L2**: The workflow asserts the computed version ends in `-cd` and aborts if not.
- **L3**: The manual `publish-cre-sdk.yml` and `publish-cre-sdk-javy-plugin.yml` workflows reject any input tag matching `*-cd*`.

### Branch state

The `capabilities-development` branch is **never modified** by the workflow. `package.json` files always show `workspace:*`. Pinned versions exist only inside the ephemeral release commit that the git tag points to. To consume the released artifact verbatim, check out the tag:

```bash
git checkout v0.0.7-cd
cd packages/cre-sdk-examples
bun install # resolves @chainlink/cre-sdk@0.0.7-cd from npm
```

### Re-run safety

If `cd-release.yml` runs again on the same commit (e.g., manual dispatch retry), it short-circuits when the current `HEAD` already has a `*-cd` tag. To force a re-publish, delete the tag locally and on origin first.
50 changes: 50 additions & 0 deletions scripts/cd-release/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
# cd-release helpers

Pure-function helpers used by `.github/workflows/cd-release.yml` to publish prereleases of `@chainlink/cre-sdk` and `@chainlink/cre-sdk-javy-plugin` under the npm `cd` dist-tag whenever code lands on `capabilities-development`.

Each helper is unit-tested with `bun test` and ships a thin CLI entry point so the workflow can shell out without embedding logic in YAML.

## `version.ts`

Computes the next cd version from existing git tags. Always patch-bumps from the highest `v*.*.*-cd` tag.

```bash
bun scripts/cd-release/version.ts
# → 0.0.7-cd
```

If no `*-cd` tag exists, exits non-zero with a seed instruction. Seed once manually:

```bash
git tag v0.0.0-cd
git push origin v0.0.0-cd
```

## `javy-changed.ts`

Returns `true` / `false` on stdout. `true` when the Javy plugin source differs from the supplied last-released cd tag, or when no prior cd javy version was passed.

```bash
bun scripts/cd-release/javy-changed.ts v0.0.6-cd
# → true (or false)
```

## `pin-deps.ts`

Mutates a `package.json` in place: sets top-level `version`, replaces named `workspace:*` dependencies with concrete version strings.

```bash
bun scripts/cd-release/pin-deps.ts \
packages/cre-sdk/package.json \
0.0.7-cd \
@chainlink/cre-sdk-javy-plugin=0.0.7-cd
```

Throws if a named dep is missing or is not a `workspace:*` entry — defensive against silent drift.

## Tests

```bash
cd scripts/cd-release
bun test
```
Loading
Loading