@crossdelta/platform-sdk 0.14.0 β†’ 0.16.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (26) hide show
  1. package/bin/cli.js +714 -169
  2. package/bin/templates/workspace/.github/README.md +70 -0
  3. package/bin/templates/workspace/.github/actions/check-image-tag-exists/action.yml +27 -0
  4. package/bin/templates/workspace/.github/actions/check-image-tag-exists/index.js +179 -0
  5. package/bin/templates/workspace/.github/actions/check-path-changes/action.yml +21 -0
  6. package/bin/templates/workspace/.github/actions/check-path-changes/index.js +192 -0
  7. package/bin/templates/workspace/.github/actions/detect-skipped-services/action.yml +38 -0
  8. package/bin/templates/workspace/.github/actions/generate-scope-matrix/action.yml +17 -0
  9. package/bin/templates/workspace/.github/actions/generate-scope-matrix/index.js +355 -0
  10. package/bin/templates/workspace/.github/actions/prepare-build-context/action.yml +49 -0
  11. package/bin/templates/workspace/.github/actions/resolve-scope-tags/action.yml +31 -0
  12. package/bin/templates/workspace/.github/actions/resolve-scope-tags/index.js +398 -0
  13. package/bin/templates/workspace/.github/actions/setup-bun-install/action.yml.hbs +57 -0
  14. package/bin/templates/workspace/.github/copilot-chat-configuration.json +49 -0
  15. package/bin/templates/workspace/.github/copilot-instructions.md.hbs +72 -0
  16. package/bin/templates/workspace/.github/dependabot.yml +18 -0
  17. package/bin/templates/workspace/.github/workflows/build-and-deploy.yml.hbs +232 -0
  18. package/bin/templates/workspace/.github/workflows/lint-and-tests.yml.hbs +32 -0
  19. package/bin/templates/workspace/.github/workflows/publish-packages.yml +188 -0
  20. package/bin/templates/workspace/apps/.gitkeep +0 -0
  21. package/bin/templates/workspace/docs/.gitkeep +0 -0
  22. package/bin/templates/workspace/infra/package.json.hbs +1 -1
  23. package/bin/templates/workspace/infra/services/.gitkeep +0 -0
  24. package/bin/templates/workspace/packages/.gitkeep +0 -0
  25. package/bin/templates/workspace/packages/contracts/package.json.hbs +1 -1
  26. package/package.json +2 -2
@@ -0,0 +1,232 @@
1
+ name: πŸš€ Build and Deploy
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ paths:
7
+ - 'apps/*/**'
8
+ - 'services/*/**'
9
+ - 'infra/**'
10
+ - 'bun.lock'
11
+ - '.github/workflows/**'
12
+ workflow_run:
13
+ workflows: ['πŸ“¦ Publish Packages']
14
+ types:
15
+ - completed
16
+
17
+ permissions:
18
+ contents: read
19
+ packages: write
20
+
21
+ concurrency:
22
+ group: deploy-$\{{ github.ref }}
23
+ cancel-in-progress: false
24
+
25
+ env:
26
+ SCOPE_ROOTS: apps,services
27
+ REGISTRY: ghcr.io/$\{{ github.repository_owner }}/$\{{ github.event.repository.name }}
28
+ PULUMI_STACK: $\{{ vars.PULUMI_STACK_BASE }}/$\{{ github.ref_name == 'main' && 'production' || github.ref_name }}
29
+ WORKFLOW_HEAD_SHA: $\{{ github.event_name == 'workflow_run' && github.event.workflow_run.head_sha || github.sha }}
30
+ WORKFLOW_BASE_SHA_INPUT: $\{{ github.event_name == 'workflow_run' && github.event.workflow_run.head_commit.id || github.event.before }}
31
+
32
+ jobs:
33
+ prepare-scopes:
34
+ name: πŸ§ͺ Prepare Scopes
35
+ runs-on: ubuntu-latest
36
+ if: github.event_name != 'workflow_run' || github.event.workflow_run.conclusion == 'success'
37
+ outputs:
38
+ scopes: $\{{ steps.scope-generator.outputs.scopes }}
39
+ scope_count: $\{{ steps.scope-generator.outputs.scopes_count }}
40
+ infrastructure_changed: $\{{ steps.infra-check.outputs.changed }}
41
+ steps:
42
+ - uses: actions/checkout@v4
43
+ with:
44
+ fetch-depth: 0
45
+ ref: $\{{ env.WORKFLOW_HEAD_SHA }}
46
+
47
+ - name: Set commit range
48
+ run: |
49
+ set -euo pipefail
50
+ HEAD_SHA="${WORKFLOW_HEAD_SHA}"
51
+ BASE_SHA="${WORKFLOW_BASE_SHA_INPUT}"
52
+ NULL_SHA="0000000000000000000000000000000000000000"
53
+ if [ -z "$BASE_SHA" ] || [ "$BASE_SHA" = "$NULL_SHA" ]; then
54
+ if git rev-parse "${HEAD_SHA}^" >/dev/null 2>&1; then
55
+ BASE_SHA=$(git rev-parse "${HEAD_SHA}^")
56
+ else
57
+ BASE_SHA="$HEAD_SHA"
58
+ fi
59
+ fi
60
+ echo "GITHUB_SHA=$HEAD_SHA" >> "$GITHUB_ENV"
61
+ echo "GITHUB_EVENT_BEFORE=$BASE_SHA" >> "$GITHUB_ENV"
62
+
63
+ - name: Check for infrastructure changes
64
+ id: infra-check
65
+ uses: dorny/paths-filter@v3
66
+ with:
67
+ filters: |
68
+ changed:
69
+ - 'infra/**'
70
+
71
+ - name: Generate scope matrix
72
+ id: scope-generator
73
+ uses: ./.github/actions/generate-scope-matrix
74
+ with:
75
+ scope-roots: $\{{ env.SCOPE_ROOTS }}
76
+
77
+ build:
78
+ if: needs.prepare-scopes.outputs.scope_count && needs.prepare-scopes.outputs.scope_count != '0'
79
+ needs: prepare-scopes
80
+ runs-on: ubuntu-latest
81
+ strategy:
82
+ matrix:
83
+ scope: $\{{ fromJson(needs.prepare-scopes.outputs.scopes) }}
84
+ name: 🐳 Build $\{{ matrix.scope.shortName }}
85
+ env:
86
+ DOCKER_BUILDKIT: 1
87
+ IMAGE_TAG: $\{{ github.sha }}
88
+
89
+ steps:
90
+ - uses: actions/checkout@v4
91
+ with:
92
+ fetch-depth: 2
93
+ ref: $\{{ env.WORKFLOW_HEAD_SHA }}
94
+
95
+ - name: Set scope metadata
96
+ run: |
97
+ echo "SCOPE_DIR=$\{{ matrix.scope.dir }}" >> $GITHUB_ENV
98
+ echo "scope_name=$\{{ matrix.scope.shortName }}" >> $GITHUB_OUTPUT
99
+
100
+ - name: Setup Bun and install dependencies
101
+ uses: ./.github/actions/setup-bun-install
102
+ with:
103
+ enable-cache: 'true'
104
+ cache-key: bun-$\{{ runner.os }}-$\{{ hashFiles('bun.lock') }}
105
+ cache-restore-keys: bun-$\{{ runner.os }}-
106
+ npm-token: $\{{ secrets.NPM_TOKEN }}
107
+
108
+ - name: Prune
109
+ run: |
110
+ bunx turbo prune --scope=$\{{ matrix.scope.name }} --docker --out-dir out/$\{{ matrix.scope.shortName }}
111
+
112
+ - name: Compute scope checksum
113
+ id: scope-checksum
114
+ run: |
115
+ set -euo pipefail
116
+ cd "out/$\{{ matrix.scope.shortName }}"
117
+ HASH=$(find . -type f -print0 | sort -z | xargs -0 sha256sum | sha256sum)
118
+ HASH=${HASH%% *}
119
+ echo "scope_hash=$HASH" >> $GITHUB_OUTPUT
120
+
121
+ - name: Use scope checksum as image tag
122
+ run: echo "IMAGE_TAG=$\{{ steps.scope-checksum.outputs.scope_hash }}" >> $GITHUB_ENV
123
+
124
+ - name: Check if image tag exists
125
+ id: tag-check
126
+ uses: ./.github/actions/check-image-tag-exists
127
+ with:
128
+ scope-short-name: $\{{ matrix.scope.shortName }}
129
+ image-tag: $\{{ env.IMAGE_TAG }}
130
+ github-token: $\{{ secrets.GITHUB_TOKEN }}
131
+
132
+ - name: Set up Docker Buildx
133
+ if: steps.tag-check.outputs.exists != 'true'
134
+ uses: docker/setup-buildx-action@v3
135
+
136
+ - name: Login to GitHub Packages (GHCR)
137
+ if: steps.tag-check.outputs.exists != 'true'
138
+ uses: docker/login-action@v3
139
+ with:
140
+ registry: ghcr.io
141
+ username: $\{{ github.actor }}
142
+ password: $\{{ secrets.GITHUB_TOKEN }}
143
+
144
+ - name: Prepare build context
145
+ if: steps.tag-check.outputs.exists != 'true'
146
+ uses: ./.github/actions/prepare-build-context
147
+ with:
148
+ scope-short-name: $\{{ matrix.scope.shortName }}
149
+ scope-dir: $\{{ matrix.scope.dir }}
150
+
151
+ - name: Build and push image
152
+ if: steps.tag-check.outputs.exists != 'true'
153
+ uses: docker/build-push-action@v5
154
+ env:
155
+ NPM_TOKEN: $\{{ secrets.NPM_TOKEN }}
156
+ with:
157
+ context: out/$\{{ matrix.scope.shortName }}/full
158
+ push: true
159
+ tags: |
160
+ $\{{ env.REGISTRY }}/$\{{ matrix.scope.shortName }}:$\{{ env.IMAGE_TAG }}
161
+ $\{{ env.REGISTRY }}/$\{{ matrix.scope.shortName }}:latest
162
+ secrets: |
163
+ NPM_TOKEN=$\{{ env.NPM_TOKEN }}
164
+
165
+ - name: Mark this scope as changed
166
+ run: |
167
+ mkdir -p .changed/$\{{ matrix.scope.shortName }}
168
+ echo "$\{{ matrix.scope.shortName }}" > .changed/$\{{ matrix.scope.shortName }}/scope.txt
169
+ printf '{"shortName":"%s","imageTag":"%s"}\n' "$\{{ matrix.scope.shortName }}" "$\{{ env.IMAGE_TAG }}" > .changed/$\{{ matrix.scope.shortName }}/metadata.json
170
+
171
+ - name: Upload change marker
172
+ uses: actions/upload-artifact@v4
173
+ with:
174
+ name: changed-$\{{ matrix.scope.shortName }}
175
+ path: .changed/$\{{ matrix.scope.shortName }}
176
+
177
+ deploy:
178
+ runs-on: ubuntu-latest
179
+ needs: [build, prepare-scopes]
180
+ if: |
181
+ always() &&
182
+ needs.prepare-scopes.result == 'success' &&
183
+ needs.build.result != 'failure' &&
184
+ (needs.prepare-scopes.outputs.scope_count != '0' || needs.prepare-scopes.outputs.infrastructure_changed == 'true')
185
+ name: 🌍 Deploy
186
+ steps:
187
+ - uses: actions/checkout@v4
188
+ with:
189
+ ref: $\{{ env.WORKFLOW_HEAD_SHA }}
190
+ - name: Download all change markers
191
+ uses: actions/download-artifact@v4
192
+ with:
193
+ path: .artifacts
194
+
195
+ - name: Detect skipped services
196
+ id: detect_skipped
197
+ uses: ./.github/actions/detect-skipped-services
198
+
199
+ - name: Resolve scope image tags
200
+ id: resolve_scope_tags
201
+ uses: ./.github/actions/resolve-scope-tags
202
+ with:
203
+ markers-dir: .artifacts
204
+ scope-roots: $\{{ env.SCOPE_ROOTS }}
205
+ repository-owner: $\{{ github.repository_owner }}
206
+ allow-missing-scopes: $\{{ steps.detect_skipped.outputs.skipped-services }}
207
+ github-token: $\{{ secrets.GITHUB_TOKEN }}
208
+
209
+ - name: Setup Bun and install dependencies
210
+ uses: ./.github/actions/setup-bun-install
211
+ with:
212
+ enable-cache: 'true'
213
+ cache-key: bun-$\{{ runner.os }}-$\{{ hashFiles('bun.lock') }}
214
+ cache-restore-keys: bun-$\{{ runner.os }}-
215
+ npm-token: $\{{ secrets.NPM_TOKEN }}
216
+
217
+ - name: Build infrastructure package
218
+ run: |
219
+ bun run --cwd packages/infrastructure build
220
+
221
+ - name: Pulumi up
222
+ uses: pulumi/actions@v6
223
+ with:
224
+ command: up
225
+ suppress-progress: true
226
+ comment-on-summary: true
227
+ stack-name: $\{{ env.PULUMI_STACK }}
228
+ work-dir: infra
229
+ env:
230
+ PULUMI_ACCESS_TOKEN: $\{{ secrets.PULUMI_ACCESS_TOKEN }}
231
+ DIGITALOCEAN_TOKEN: $\{{ secrets.DIGITALOCEAN_TOKEN }}
232
+ SCOPE_IMAGE_TAGS: $\{{ steps.resolve_scope_tags.outputs.scope_image_tags }}
@@ -0,0 +1,32 @@
1
+ name: βœ… Pull Request Checks
2
+
3
+ on:
4
+ pull_request:
5
+ branches:
6
+ - main
7
+
8
+ concurrency:
9
+ group: $\{{ github.workflow }}-$\{{ github.ref }}
10
+ cancel-in-progress: true
11
+
12
+ jobs:
13
+ lint-and-test:
14
+ runs-on: ubuntu-latest
15
+ env:
16
+
17
+ steps:
18
+ - name: Checkout code
19
+ uses: actions/checkout@v4
20
+
21
+ - name: Setup Bun and install dependencies
22
+ uses: ./.github/actions/setup-bun-install
23
+ with:
24
+ enable-cache: 'true'
25
+ cache-key: bun-$\{{ runner.os }}-$\{{ hashFiles('bun.lock') }}
26
+ cache-restore-keys: bun-$\{{ runner.os }}-
27
+
28
+ - name: Run Linter
29
+ run: bun run --if-present lint
30
+
31
+ - name: Run Tests
32
+ run: bun run --if-present test
@@ -0,0 +1,188 @@
1
+ name: πŸ“¦ Publish Packages
2
+
3
+ on:
4
+ push:
5
+ branches:
6
+ - main
7
+ paths:
8
+ - 'packages/*/**'
9
+ workflow_dispatch:
10
+ inputs:
11
+ package:
12
+ description: 'Package to publish (slug from packages/ directory, or "all")'
13
+ type: string
14
+ default: all
15
+ required: true
16
+
17
+ permissions:
18
+ contents: write
19
+
20
+ jobs:
21
+ determine-packages:
22
+ if: github.actor != 'github-actions[bot]'
23
+ runs-on: ubuntu-latest
24
+ outputs:
25
+ packages: ${{ steps.set-matrix.outputs.packages }}
26
+ count: ${{ steps.set-matrix.outputs.count }}
27
+ steps:
28
+ - name: Checkout repository
29
+ uses: actions/checkout@v4
30
+ with:
31
+ fetch-depth: 0
32
+
33
+ - name: Detect changed packages
34
+ id: changed
35
+ uses: tj-actions/changed-files@v45
36
+ with:
37
+ json: true
38
+ dir_names: true
39
+ dir_names_max_depth: 2
40
+ files: packages/*/**
41
+
42
+ - name: Build package matrix
43
+ id: set-matrix
44
+ env:
45
+ INPUT_PACKAGE: ${{ github.event.inputs.package || '' }}
46
+ CHANGED_DIRS: ${{ steps.changed.outputs.all_changed_files }}
47
+ run: |
48
+ declare -a packages=()
49
+ declare -A changed_packages
50
+
51
+ # Parse changed directories from JSON
52
+ if [ "${{ github.event_name }}" == "push" ] && [ -n "$CHANGED_DIRS" ]; then
53
+ for dir in $(echo "$CHANGED_DIRS" | jq -r '.[]'); do
54
+ if [[ $dir =~ ^packages/([^/]+)$ ]]; then
55
+ changed_packages["${BASH_REMATCH[1]}"]=1
56
+ fi
57
+ done
58
+ fi
59
+
60
+ # Iterate all packages
61
+ for dir in packages/*/; do
62
+ [ ! -f "$dir/package.json" ] && continue
63
+
64
+ slug=$(basename "$dir")
65
+ name=$(jq -r '.name // empty' "$dir/package.json")
66
+ is_private=$(jq -r '.private // false' "$dir/package.json")
67
+
68
+ [ "$is_private" = "true" ] && continue
69
+ [ -z "$name" ] && continue
70
+
71
+ # Include package?
72
+ should_include=false
73
+ if [ -n "$INPUT_PACKAGE" ]; then
74
+ [ "$INPUT_PACKAGE" = "all" ] || [ "$INPUT_PACKAGE" = "$slug" ] && should_include=true
75
+ else
76
+ [ -n "${changed_packages[$slug]}" ] && should_include=true
77
+ fi
78
+
79
+ [ "$should_include" = true ] && packages+=("{\"name\":\"$name\",\"dir\":\"$dir\"}")
80
+ done
81
+
82
+ # Output
83
+ if [ ${#packages[@]} -eq 0 ]; then
84
+ echo "packages=[]" >> "$GITHUB_OUTPUT"
85
+ echo "count=0" >> "$GITHUB_OUTPUT"
86
+ else
87
+ echo "packages=[$(IFS=,; echo "${packages[*]}")]" >> "$GITHUB_OUTPUT"
88
+ echo "count=${#packages[@]}" >> "$GITHUB_OUTPUT"
89
+ echo "πŸ“¦ Packages to publish: ${#packages[@]}"
90
+ fi
91
+
92
+ # Build all packages in dependency order using Turborepo
93
+ # This ensures infrastructure is built AFTER cloudevents (which it depends on)
94
+ build-all:
95
+ name: Build all packages
96
+ needs: determine-packages
97
+ if: needs.determine-packages.outputs.count != '0'
98
+ runs-on: ubuntu-latest
99
+ steps:
100
+ - uses: actions/checkout@v4
101
+ - uses: oven-sh/setup-bun@v2
102
+ - name: Install dependencies
103
+ run: bun install
104
+
105
+ - name: Build all packages
106
+ run: |
107
+ # Turborepo automatically builds in dependency order (see turbo.json)
108
+ # Example order: cloudevents -> infrastructure, telemetry, platform-sdk
109
+ bunx turbo run build --filter='./packages/*'
110
+
111
+ - name: Upload build artifacts
112
+ uses: actions/upload-artifact@v4
113
+ with:
114
+ name: dist-packages
115
+ path: packages/*/dist
116
+ retention-days: 1
117
+
118
+ # Publish packages sequentially (max-parallel: 1)
119
+ # Build artifacts are already available from build-all job
120
+ publish:
121
+ name: Publish ${{ matrix.package.name }}
122
+ needs: [determine-packages, build-all]
123
+ if: needs.determine-packages.outputs.count != '0'
124
+ runs-on: ubuntu-latest
125
+ strategy:
126
+ max-parallel: 1
127
+ matrix:
128
+ package: ${{ fromJson(needs.determine-packages.outputs.packages) }}
129
+ steps:
130
+ - uses: actions/checkout@v4
131
+ - uses: oven-sh/setup-bun@v2
132
+
133
+ - name: Install dependencies
134
+ run: bun install --frozen-lockfile
135
+
136
+ - name: Download build artifacts
137
+ uses: actions/download-artifact@v4
138
+ with:
139
+ name: dist-packages
140
+ path: packages/
141
+
142
+ - name: Verify build artifacts
143
+ run: |
144
+ if [ ! -d "${{ matrix.package.dir }}/dist" ]; then
145
+ echo "❌ Build artifacts missing for ${{ matrix.package.name }}"
146
+ exit 1
147
+ fi
148
+ echo "βœ… Build artifacts found for ${{ matrix.package.name }}"
149
+
150
+ - name: Bump version
151
+ id: bump
152
+ working-directory: ${{ matrix.package.dir }}
153
+ run: |
154
+ CURRENT=$(jq -r '.version' package.json)
155
+ PUBLISHED=$(npm view "${{ matrix.package.name }}" version 2>/dev/null || echo "0.0.0")
156
+
157
+ if [ "$CURRENT" = "$PUBLISHED" ]; then
158
+ # Auto-bump patch version
159
+ NEW="${CURRENT%.*}.$((${CURRENT##*.} + 1))"
160
+ jq --arg v "$NEW" '.version = $v' package.json > tmp && mv tmp package.json
161
+ echo "version=$NEW" >> "$GITHUB_OUTPUT"
162
+ echo "bumped=true" >> "$GITHUB_OUTPUT"
163
+ echo "πŸ“¦ Bumped: $CURRENT β†’ $NEW"
164
+ else
165
+ # Use manual version
166
+ echo "version=$CURRENT" >> "$GITHUB_OUTPUT"
167
+ echo "bumped=false" >> "$GITHUB_OUTPUT"
168
+ echo "πŸ“¦ Manual version: $CURRENT (npm: $PUBLISHED)"
169
+ fi
170
+
171
+ - name: Publish to npm
172
+ working-directory: ${{ matrix.package.dir }}
173
+ env:
174
+ NPM_CONFIG_TOKEN: ${{ secrets.NPM_TOKEN }}
175
+ run: |
176
+ echo "πŸ“¦ Publishing ${{ matrix.package.name }}@${{ steps.bump.outputs.version }}"
177
+ bun publish --access=public --provenance --tolerate-republish
178
+
179
+ - name: Commit version bump
180
+ if: steps.bump.outputs.bumped == 'true'
181
+ env:
182
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
183
+ run: |
184
+ git config user.name "github-actions[bot]"
185
+ git config user.email "github-actions[bot]@users.noreply.github.com"
186
+ git add "${{ matrix.package.dir }}/package.json"
187
+ git diff --cached --quiet || git commit -m "chore(release): ${{ matrix.package.name }}@${{ steps.bump.outputs.version }}"
188
+ git pull --rebase origin ${{ github.ref_name }} && git push || true
File without changes
File without changes
@@ -8,7 +8,7 @@
8
8
  },
9
9
  "dependencies": {
10
10
  "@crossdelta/cloudevents": "^0.5.3",
11
- "@crossdelta/infrastructure": "^0.5.2",
11
+ "@crossdelta/infrastructure": "^0.5.3",
12
12
  "{{scope}}/contracts": "workspace:*",
13
13
  "@pulumi/digitalocean": "^4.55.0",
14
14
  "@pulumi/kubernetes": "^4.21.0",
File without changes
@@ -12,7 +12,7 @@
12
12
  },
13
13
  "dependencies": {
14
14
  "@crossdelta/cloudevents": "^0.5.3",
15
- "@crossdelta/infrastructure": "^0.5.2",
15
+ "@crossdelta/infrastructure": "^0.5.3",
16
16
  "zod": "^4.0.0"
17
17
  },
18
18
  "devDependencies": {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@crossdelta/platform-sdk",
3
- "version": "0.14.0",
3
+ "version": "0.16.0",
4
4
  "description": "Platform toolkit for event-driven microservices β€” keeping code and infrastructure in lockstep.",
5
5
  "keywords": [
6
6
  "cli",
@@ -87,7 +87,7 @@
87
87
  "build:schematics:copy": "cp -R schematics/* dist/schematics && find dist/schematics -name '*.ts' -delete",
88
88
  "build:schematics": "npm run build:schematics:transpile && npm run build:schematics:copy",
89
89
  "build": "npm run build:cli && npm run build:schematics && npm run build:cli:copy",
90
- "prepublishOnly": "[ -n \"$CI_SKIP_BUILD\" ] || npm run build",
90
+ "prepublishOnly": "npm run build",
91
91
  "lint": "biome lint --fix",
92
92
  "test": "bun test",
93
93
  "test:watch": "bun test --watch"