Skip to content
Merged
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
57 changes: 47 additions & 10 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -61,25 +61,62 @@ jobs:
- name: Install dependencies
run: bun install --frozen-lockfile

# On Bun 1.4.3 (pinned in mise.toml), `bun pm pack` takes the version it
# writes for a `workspace:*` dep from the workspace entry in bun.lock, not
# from that package's package.json. release-please bumps package.json
# only, and `--frozen-lockfile` does not flag the drift, so the lock still
# carries the previous versions. That shipped @pleaseai/emulate@0.4.0
# pinned to 0.3.1/0.3.0 deps, two of which were never published. A
# non-frozen install rewrites only those version entries.
- name: Sync workspace versions into bun.lock
run: bun install

- name: Build
run: bun run build

- name: Publish released packages
# bash runs with pipefail, so a failed jq fails the step instead of
# publishing nothing
- name: Pack and verify released packages
# bash runs with -e and pipefail, so a failed jq, tar or pack fails the
# step instead of packing nothing
shell: bash
env:
# release-please emits the dirs it released as a JSON array, e.g.
# ["packages/asana","packages/emulate"].
PATHS_RELEASED: ${{ needs.release-please.outputs.paths_released }}
run: |
echo "$PATHS_RELEASED" | jq -r '.[]' | while read -r pkg; do
echo "::group::publish $pkg"
pkgs="$(echo "$PATHS_RELEASED" | jq -r '.[]')"
# name -> version of every workspace package, from package.json
versions="$(jq -n '[inputs | {(.name): .version}] | add' packages/*/package.json)"
: > "$RUNNER_TEMP/tarballs"
failed=0
while read -r pkg; do
[ -n "$pkg" ] || continue
# `bun pm pack` rewrites `workspace:*` deps to the concrete version
# in the tarball (npm pack/publish on its own would not). npm then
# publishes that tarball, authenticating via OIDC (Trusted Publisher
# configured on npmjs.com) and attaching provenance automatically.
# in the tarball (npm pack/publish on its own would not).
tarball="$(cd "$pkg" && bun pm pack --quiet)"
npm publish "$pkg/$tarball" --access public
# Every in-repo dep in the packed manifest must equal the version in
# that package's package.json. All tarballs are checked before the
# publish step runs, so a mismatch publishes nothing.
mismatches="$(tar -xOzf "$pkg/$tarball" package/package.json | jq -r --argjson want "$versions" '
[.dependencies, .optionalDependencies] | add // {} | to_entries[]
| select(.key | in($want))
| select((.value | ltrimstr("^") | ltrimstr("~")) != $want[.key])
| "\(.key): packed \(.value), package.json \($want[.key])"')"
if [ -n "$mismatches" ]; then
echo "::error::$pkg/$tarball pins workspace deps that differ from their package.json versions"
echo "$mismatches"
failed=1
fi
echo "$pkg/$tarball" >> "$RUNNER_TEMP/tarballs"
done <<< "$pkgs"
exit "$failed"

- name: Publish released packages
shell: bash
run: |
while read -r tarball; do
echo "::group::publish $tarball"
# npm authenticates via OIDC (Trusted Publisher configured on
# npmjs.com) and attaches provenance automatically.
npm publish "$tarball" --access public
echo "::endgroup::"
done
done < "$RUNNER_TEMP/tarballs"
56 changes: 56 additions & 0 deletions packages/emulate/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
# @pleaseai/emulate

Local drop-in replacement services for CI and no-network sandboxes — the
`emulate` CLI and programmatic API that run every `@pleaseai/emulate-*`
service emulator.

**Documentation: [emulate.pleaseai.dev](https://emulate.pleaseai.dev)**

## Install

```bash
npm install --save-dev @pleaseai/emulate
```

Install 0.4.1 or later. 0.4.0 and 0.3.1 depend on service package versions
that were never published, so they fail to install.

## Start

```bash
# Start every service (ports assigned sequentially from 4000)
npx @pleaseai/emulate

# Start specific services only
npx @pleaseai/emulate --service kakao,tosspayments

# Generate a seed config file
npx @pleaseai/emulate init
```

When an `emulate.config.yaml` (or `--seed <file>`) is present, the emulators
start pre-seeded with app keys, users, and table data. `--service` chooses
which services start. Without it, the services named in the config start;
if the config names no recognized services, every service starts.

## Programmatic use in tests

```ts
import { createEmulator } from '@pleaseai/emulate'

const emulator = await createEmulator({
service: 'supabase',
port: 4004,
seed: {
supabase: {
anon_key: 'test-anon-key',
tables: { todos: [{ id: 1, title: 'Buy groceries', completed: false }] },
},
},
})

// ... run your tests. emulator.reset() restores seeded state, emulator.close() shuts down.
```

See the [repository README](https://github.com/pleaseai/emulate#readme) for
the list of supported services and their default ports.
4 changes: 3 additions & 1 deletion release-please-config.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,9 @@
"packages": {
"packages/asana": {},
"packages/autumn": {},
"packages/emulate": {},
"packages/emulate": {
"release-as": "0.4.1"
},
"packages/firebase": {},
"packages/gitlab": {},
"packages/jira": {},
Expand Down
Loading