diff --git a/.github/actions/setup/action.yml b/.github/actions/setup/action.yml index 16babab1c9a..58c96a86e5b 100644 --- a/.github/actions/setup/action.yml +++ b/.github/actions/setup/action.yml @@ -14,10 +14,6 @@ inputs: description: Node version to install. Empty keeps the runner's preinstalled Node, for jobs that only ever ran Bun. required: false default: '24' - registry-url: - description: npm registry to write an .npmrc for, so `npm publish` reads NODE_AUTH_TOKEN. Empty writes none. - required: false - default: '' # Sticky disk keys are scoped by event name, and fork PRs get their own namespace on # top: untrusted fork runs must never share a cache with push runs (whose caches @@ -43,7 +39,6 @@ runs: uses: actions/setup-node@949feb2413d6458794dcd2491c4babbbce0c15c1 # v6 with: node-version: ${{ inputs.node-version }} - registry-url: ${{ inputs.registry-url }} - name: Mount Bun cache if: inputs.provider == '' || inputs.provider == 'blacksmith' diff --git a/.github/workflows/publish-cli.yml b/.github/workflows/publish-cli.yml index a6696c27926..5eef3cc7e1a 100644 --- a/.github/workflows/publish-cli.yml +++ b/.github/workflows/publish-cli.yml @@ -15,10 +15,13 @@ concurrency: cancel-in-progress: false jobs: - publish: - name: publish + build: + name: build runs-on: ${{ (vars.CI_PROVIDER == '' || vars.CI_PROVIDER == 'blacksmith') && 'blacksmith-4vcpu-ubuntu-2404' || 'ubuntu-latest' }} timeout-minutes: 15 + outputs: + version: ${{ steps.package_version.outputs.version }} + exists: ${{ steps.version_check.outputs.exists }} steps: - name: Checkout repository uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v6 @@ -30,7 +33,6 @@ jobs: with: provider: ${{ vars.CI_PROVIDER }} node-version: '22' - registry-url: https://registry.npmjs.org/ - name: Build package working-directory: packages/cli @@ -39,7 +41,7 @@ jobs: - name: Get package version id: package_version working-directory: packages/cli - run: echo "version=$(node -p "require('./package.json').version")" >> $GITHUB_OUTPUT + run: echo "version=$(node -p "require('./package.json').version")" >> "$GITHUB_OUTPUT" - name: Check if version already exists id: version_check @@ -47,20 +49,59 @@ jobs: VERSION: ${{ steps.package_version.outputs.version }} run: | if npm view "simstudio@$VERSION" version &> /dev/null; then - echo "exists=true" >> $GITHUB_OUTPUT + echo "exists=true" >> "$GITHUB_OUTPUT" else - echo "exists=false" >> $GITHUB_OUTPUT + echo "exists=false" >> "$GITHUB_OUTPUT" fi - - name: Publish to npm + # Bun packs because it rewrites `workspace:` ranges to real versions, + # which `npm pack` would publish verbatim. + - name: Pack package if: steps.version_check.outputs.exists == 'false' working-directory: packages/cli - run: npm publish --access=public - env: - NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} + run: bun pm pack --ignore-scripts --filename "$RUNNER_TEMP/package.tgz" --quiet + + - name: Upload package + if: steps.version_check.outputs.exists == 'false' + uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2 + with: + name: package + path: ${{ runner.temp }}/package.tgz + if-no-files-found: error + retention-days: 1 - name: Log skipped publish if: steps.version_check.outputs.exists == 'true' env: VERSION: ${{ steps.package_version.outputs.version }} - run: echo "Skipped publishing because version $VERSION already exists on npm" \ No newline at end of file + run: echo "Skipped publishing because version $VERSION already exists on npm" + + # npm trusted publishing trades this job's OIDC token for a short-lived npm + # credential, so no npm token is stored anywhere. npm accepts the token only + # from GitHub-hosted runners, and only this job can mint one: it runs no + # repository code, it publishes the tarball the build job packed. npm runs no + # lifecycle scripts for a tarball, so nothing is rebuilt here, and provenance + # is attached automatically. + publish: + name: publish + needs: build + if: needs.build.outputs.exists == 'false' + runs-on: ubuntu-latest + timeout-minutes: 10 + permissions: + id-token: write + steps: + # Node 24 bundles npm 11.5.1+, which trusted publishing requires. + - name: Setup Node + uses: actions/setup-node@949feb2413d6458794dcd2491c4babbbce0c15c1 # v6 + with: + node-version: '24' + + - name: Download package + uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8.0.2 + with: + name: package + path: ${{ runner.temp }} + + - name: Publish to npm + run: npm publish "$RUNNER_TEMP/package.tgz" --access public diff --git a/.github/workflows/publish-sim-cli.yml b/.github/workflows/publish-sim-cli.yml index 591748b1606..2d87aa6bd92 100644 --- a/.github/workflows/publish-sim-cli.yml +++ b/.github/workflows/publish-sim-cli.yml @@ -19,10 +19,13 @@ concurrency: cancel-in-progress: false jobs: - publish: - name: publish + build: + name: build runs-on: ${{ (vars.CI_PROVIDER == '' || vars.CI_PROVIDER == 'blacksmith') && 'blacksmith-4vcpu-ubuntu-2404' || 'ubuntu-latest' }} timeout-minutes: 15 + outputs: + version: ${{ steps.release.outputs.version }} + tag: ${{ steps.release.outputs.tag }} steps: - name: Checkout repository uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v6 @@ -37,11 +40,6 @@ jobs: provider: ${{ vars.CI_PROVIDER }} node-version: '22' - - name: Verify npm authentication - env: - NPM_CONFIG_TOKEN: ${{ secrets.NPM_TOKEN }} - run: bun pm whoami - - name: Auto-bump package version run: bun run bump:npm-packages sim-cli @@ -54,9 +52,10 @@ jobs: run: bun run type-check # The usage-reporting destination is baked into the bundle at build time - # (docs/cli/usage-data), so only the two steps that build it get the - # token. Every other step, the tests above in particular, runs without - # it: a test that runs a real command must never report to production. + # (docs/cli/usage-data), so only this step gets the token, and the + # tarball packed from its output is what ships. Every other step, the + # tests above in particular, runs without it: a test that runs a real + # command must never report to production. - name: Build package working-directory: packages/sim-cli env: @@ -107,23 +106,28 @@ jobs: echo "tag=$TAG" } >> "$GITHUB_OUTPUT" + # Bun packs because it rewrites `workspace:` ranges to real versions, + # which `npm pack` would publish verbatim. The smoke test below and the + # publish job both use this one tarball, so what was tested is what ships. + - name: Pack package + working-directory: packages/sim-cli + run: bun pm pack --ignore-scripts --filename "$RUNNER_TEMP/package.tgz" --quiet + - name: Setup Node 20 for the bundle smoke test uses: actions/setup-node@949feb2413d6458794dcd2491c4babbbce0c15c1 # v6 with: node-version: '20' - name: Smoke-test packed Node bundle - working-directory: packages/sim-cli + env: + VERSION: ${{ steps.release.outputs.version }} run: | set -euo pipefail SMOKE_DIR="$(mktemp -d "$RUNNER_TEMP/sim-cli-smoke.XXXXXX")" - PACKAGE_PATH="$SMOKE_DIR/sim-cli.tgz" - bun pm pack --ignore-scripts --filename "$PACKAGE_PATH" --quiet - tar -xzf "$PACKAGE_PATH" -C "$SMOKE_DIR" - "$SMOKE_DIR/package/dist/index.js" --version + tar -xzf "$RUNNER_TEMP/package.tgz" -C "$SMOKE_DIR" + test "$("$SMOKE_DIR/package/dist/index.js" --version)" = "$VERSION" - name: Verify version is unpublished - working-directory: packages/sim-cli env: VERSION: ${{ steps.release.outputs.version }} run: | @@ -132,19 +136,47 @@ jobs: exit 1 fi - # `bun publish` runs `prepublishOnly`, which rebuilds `dist`, and that - # rebuild is what ships, so it needs the token as well. + - name: Upload package + uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2 + with: + name: package + path: ${{ runner.temp }}/package.tgz + if-no-files-found: error + retention-days: 1 + + # npm trusted publishing trades this job's OIDC token for a short-lived npm + # credential, so no npm token is stored anywhere. npm accepts the token only + # from GitHub-hosted runners, and only this job can mint one: it runs no + # repository code, it publishes the tarball the build job tested. npm runs no + # lifecycle scripts for a tarball, so nothing is rebuilt here, and provenance + # is attached automatically. + publish: + name: publish + needs: build + runs-on: ubuntu-latest + timeout-minutes: 10 + permissions: + id-token: write + steps: + # Node 24 bundles npm 11.5.1+, which trusted publishing requires. + - name: Setup Node + uses: actions/setup-node@949feb2413d6458794dcd2491c4babbbce0c15c1 # v6 + with: + node-version: '24' + + - name: Download package + uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8.0.2 + with: + name: package + path: ${{ runner.temp }} + - name: Publish to npm - working-directory: packages/sim-cli env: - NPM_CONFIG_TOKEN: ${{ secrets.NPM_TOKEN }} - NPM_TAG: ${{ steps.release.outputs.tag }} - SIM_CLI_TELEMETRY_KEY: ${{ vars.SIM_CLI_TELEMETRY_KEY }} - SIM_CLI_TELEMETRY_HOST: ${{ vars.SIM_CLI_TELEMETRY_HOST }} - run: bun publish --access public --tag "$NPM_TAG" --no-save + NPM_TAG: ${{ needs.build.outputs.tag }} + run: npm publish "$RUNNER_TEMP/package.tgz" --access public --tag "$NPM_TAG" - name: Summarize release env: - VERSION: ${{ steps.release.outputs.version }} - NPM_TAG: ${{ steps.release.outputs.tag }} + VERSION: ${{ needs.build.outputs.version }} + NPM_TAG: ${{ needs.build.outputs.tag }} run: echo "Published sim@$VERSION with the '$NPM_TAG' tag." diff --git a/.github/workflows/publish-sim-setup.yml b/.github/workflows/publish-sim-setup.yml index 2bcedc4b5db..3356f40ed9f 100644 --- a/.github/workflows/publish-sim-setup.yml +++ b/.github/workflows/publish-sim-setup.yml @@ -10,6 +10,8 @@ on: - 'packages/utils/**' - 'docker-compose.prod.yml' - 'bun.lock' + # A change to how the package is built or published has to republish it. + - '.github/workflows/publish-sim-setup.yml' permissions: contents: read @@ -19,10 +21,13 @@ concurrency: cancel-in-progress: false jobs: - publish: - name: publish + build: + name: build runs-on: ${{ (vars.CI_PROVIDER == '' || vars.CI_PROVIDER == 'blacksmith') && 'blacksmith-4vcpu-ubuntu-2404' || 'ubuntu-latest' }} timeout-minutes: 15 + outputs: + version: ${{ steps.release.outputs.version }} + tag: ${{ steps.release.outputs.tag }} steps: - name: Checkout repository uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v6 @@ -37,11 +42,6 @@ jobs: provider: ${{ vars.CI_PROVIDER }} node-version: '22' - - name: Verify npm authentication - env: - NPM_CONFIG_TOKEN: ${{ secrets.NPM_TOKEN }} - run: bun pm whoami - - name: Auto-bump package version run: bun run bump:npm-packages sim-setup @@ -104,21 +104,27 @@ jobs: echo "tag=$TAG" } >> "$GITHUB_OUTPUT" + # Bun packs because it rewrites `workspace:` ranges to real versions, + # which `npm pack` would publish verbatim. The smoke test below and the + # publish job both use this one tarball, so what was tested is what ships. + - name: Pack package + working-directory: packages/sim-setup + run: bun pm pack --ignore-scripts --filename "$RUNNER_TEMP/package.tgz" --quiet + - name: Setup Node 20 for the bundle smoke test uses: actions/setup-node@949feb2413d6458794dcd2491c4babbbce0c15c1 # v6 with: node-version: '20' - name: Smoke-test packed Node bundle - working-directory: packages/sim-setup + env: + VERSION: ${{ steps.release.outputs.version }} run: | set -euo pipefail SMOKE_DIR="$(mktemp -d "$RUNNER_TEMP/sim-setup-smoke.XXXXXX")" - PACKAGE_PATH="$SMOKE_DIR/sim-setup.tgz" - bun pm pack --ignore-scripts --filename "$PACKAGE_PATH" --quiet - tar -xzf "$PACKAGE_PATH" -C "$SMOKE_DIR" + tar -xzf "$RUNNER_TEMP/package.tgz" -C "$SMOKE_DIR" - if tar -tzf "$PACKAGE_PATH" | grep -Eq '^package/(apps|docker|helm|packages|scripts)/'; then + if tar -tzf "$RUNNER_TEMP/package.tgz" | grep -Eq '^package/(apps|docker|helm|packages|scripts)/'; then echo 'Packed setup package contains repository source directories.' >&2 exit 1 fi @@ -130,7 +136,7 @@ jobs: fi cd "$SMOKE_DIR" - node package/dist/index.js --version + test "$(node package/dist/index.js --version)" = "$VERSION" node package/dist/index.js --help for command in config add doctor start stop restart update status logs down reset; do node package/dist/index.js "$command" --help > /dev/null @@ -146,7 +152,6 @@ jobs: fi - name: Verify version is unpublished - working-directory: packages/sim-setup env: VERSION: ${{ steps.release.outputs.version }} run: | @@ -155,15 +160,47 @@ jobs: exit 1 fi + - name: Upload package + uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2 + with: + name: package + path: ${{ runner.temp }}/package.tgz + if-no-files-found: error + retention-days: 1 + + # npm trusted publishing trades this job's OIDC token for a short-lived npm + # credential, so no npm token is stored anywhere. npm accepts the token only + # from GitHub-hosted runners, and only this job can mint one: it runs no + # repository code, it publishes the tarball the build job tested. npm runs no + # lifecycle scripts for a tarball, so nothing is rebuilt here, and provenance + # is attached automatically. + publish: + name: publish + needs: build + runs-on: ubuntu-latest + timeout-minutes: 10 + permissions: + id-token: write + steps: + # Node 24 bundles npm 11.5.1+, which trusted publishing requires. + - name: Setup Node + uses: actions/setup-node@949feb2413d6458794dcd2491c4babbbce0c15c1 # v6 + with: + node-version: '24' + + - name: Download package + uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8.0.2 + with: + name: package + path: ${{ runner.temp }} + - name: Publish to npm - working-directory: packages/sim-setup env: - NPM_CONFIG_TOKEN: ${{ secrets.NPM_TOKEN }} - NPM_TAG: ${{ steps.release.outputs.tag }} - run: bun publish --access public --tag "$NPM_TAG" --no-save + NPM_TAG: ${{ needs.build.outputs.tag }} + run: npm publish "$RUNNER_TEMP/package.tgz" --access public --tag "$NPM_TAG" - name: Summarize release env: - VERSION: ${{ steps.release.outputs.version }} - NPM_TAG: ${{ steps.release.outputs.tag }} + VERSION: ${{ needs.build.outputs.version }} + NPM_TAG: ${{ needs.build.outputs.tag }} run: echo "Published sim-setup@$VERSION with the '$NPM_TAG' tag." diff --git a/.github/workflows/publish-ts-sdk.yml b/.github/workflows/publish-ts-sdk.yml index 1c5e7e35e40..8a3c9c15b5e 100644 --- a/.github/workflows/publish-ts-sdk.yml +++ b/.github/workflows/publish-ts-sdk.yml @@ -7,7 +7,7 @@ on: - 'packages/ts-sdk/**' permissions: - contents: write + contents: read # A newer push waits for the running publish rather than racing its version check. concurrency: @@ -15,10 +15,13 @@ concurrency: cancel-in-progress: false jobs: - publish: - name: publish + build: + name: build runs-on: ${{ (vars.CI_PROVIDER == '' || vars.CI_PROVIDER == 'blacksmith') && 'blacksmith-4vcpu-ubuntu-2404' || 'ubuntu-latest' }} timeout-minutes: 15 + outputs: + version: ${{ steps.package_version.outputs.version }} + exists: ${{ steps.version_check.outputs.exists }} steps: - name: Checkout repository uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v6 @@ -30,7 +33,6 @@ jobs: with: provider: ${{ vars.CI_PROVIDER }} node-version: '22' - registry-url: https://registry.npmjs.org/ - name: Run tests working-directory: packages/ts-sdk @@ -43,7 +45,7 @@ jobs: - name: Get package version id: package_version working-directory: packages/ts-sdk - run: echo "version=$(node -p "require('./package.json').version")" >> $GITHUB_OUTPUT + run: echo "version=$(node -p "require('./package.json').version")" >> "$GITHUB_OUTPUT" - name: Check if version already exists id: version_check @@ -51,17 +53,26 @@ jobs: VERSION: ${{ steps.package_version.outputs.version }} run: | if npm view "simstudio-ts-sdk@$VERSION" version &> /dev/null; then - echo "exists=true" >> $GITHUB_OUTPUT + echo "exists=true" >> "$GITHUB_OUTPUT" else - echo "exists=false" >> $GITHUB_OUTPUT + echo "exists=false" >> "$GITHUB_OUTPUT" fi - - name: Publish to npm + # Bun packs because it rewrites `workspace:` ranges to real versions, + # which `npm pack` would publish verbatim. + - name: Pack package if: steps.version_check.outputs.exists == 'false' working-directory: packages/ts-sdk - run: npm publish --access=public - env: - NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} + run: bun pm pack --ignore-scripts --filename "$RUNNER_TEMP/package.tgz" --quiet + + - name: Upload package + if: steps.version_check.outputs.exists == 'false' + uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2 + with: + name: package + path: ${{ runner.temp }}/package.tgz + if-no-files-found: error + retention-days: 1 - name: Log skipped publish if: steps.version_check.outputs.exists == 'true' @@ -69,25 +80,62 @@ jobs: VERSION: ${{ steps.package_version.outputs.version }} run: echo "Skipped publishing because version $VERSION already exists on npm" + # npm trusted publishing trades this job's OIDC token for a short-lived npm + # credential, so no npm token is stored anywhere. npm accepts the token only + # from GitHub-hosted runners, and only this job can mint one: it runs no + # repository code, it publishes the tarball the build job tested. npm runs no + # lifecycle scripts for a tarball, so nothing is rebuilt here, and provenance + # is attached automatically. + publish: + name: publish + needs: build + if: needs.build.outputs.exists == 'false' + runs-on: ubuntu-latest + timeout-minutes: 10 + permissions: + id-token: write + steps: + # Node 24 bundles npm 11.5.1+, which trusted publishing requires. + - name: Setup Node + uses: actions/setup-node@949feb2413d6458794dcd2491c4babbbce0c15c1 # v6 + with: + node-version: '24' + + - name: Download package + uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8.0.2 + with: + name: package + path: ${{ runner.temp }} + + - name: Publish to npm + run: npm publish "$RUNNER_TEMP/package.tgz" --access public + + release: + name: release + needs: [build, publish] + runs-on: ubuntu-latest + timeout-minutes: 5 + permissions: + contents: write + steps: - name: Create GitHub Release - if: steps.version_check.outputs.exists == 'false' uses: softprops/action-gh-release@efb35369e0ad2afab669f228072c1b0d510eae64 # v3.0.3 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: - tag_name: typescript-sdk-v${{ steps.package_version.outputs.version }} - name: TypeScript SDK v${{ steps.package_version.outputs.version }} + tag_name: typescript-sdk-v${{ needs.build.outputs.version }} + name: TypeScript SDK v${{ needs.build.outputs.version }} body: | - ## TypeScript SDK v${{ steps.package_version.outputs.version }} - - Published simstudio-ts-sdk@${{ steps.package_version.outputs.version }} to npm. - + ## TypeScript SDK v${{ needs.build.outputs.version }} + + Published simstudio-ts-sdk@${{ needs.build.outputs.version }} to npm. + ### Installation ```bash - npm install simstudio-ts-sdk@${{ steps.package_version.outputs.version }} + npm install simstudio-ts-sdk@${{ needs.build.outputs.version }} ``` - + ### Documentation See the [README](https://github.com/simstudioai/sim/tree/main/packages/ts-sdk) or the [docs](https://docs.sim.ai/sdks/typescript) for more information. draft: false - prerelease: false \ No newline at end of file + prerelease: false diff --git a/packages/cli/package.json b/packages/cli/package.json index 34e245b7b1d..3975d34a98c 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -35,6 +35,11 @@ ], "author": "Sim", "license": "Apache-2.0", + "repository": { + "type": "git", + "url": "git+https://github.com/simstudioai/sim.git", + "directory": "packages/cli" + }, "engines": { "node": ">=18" },