Skip to content

Commit 7a00a9f

Browse files
committed
Update to support v3 platformatic
1 parent 8dc02f8 commit 7a00a9f

File tree

14 files changed

+6111
-381
lines changed

14 files changed

+6111
-381
lines changed

.github/workflows/ci.yml

Lines changed: 9 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -8,18 +8,13 @@ on:
88
- main
99
- 'releases/**'
1010

11-
env:
12-
CARGO_NET_GIT_FETCH_WITH_CLI: 'true'
13-
# GIT_SSH_COMMAND: 'ssh -o UserKnownHostsFile=/github/home/.ssh/known_hosts -o StrictHostKeyChecking=yes'
14-
1511
jobs:
1612
ci:
1713
name: CI - Node.js ${{ matrix.node-version }} & Python ${{ matrix.python-version }}
1814
runs-on: ubuntu-latest
1915
strategy:
2016
matrix:
2117
node-version:
22-
- '20'
2318
- '22'
2419
- '24'
2520
python-version:
@@ -38,40 +33,23 @@ jobs:
3833
with:
3934
ssh-private-key: |
4035
${{ secrets.SSH_PRIVATE_KEY }}
41-
${{ secrets.HTTP_HANDLER_ACCESS_TOKEN }}
42-
${{ secrets.HTTP_REWRITER_ACCESS_TOKEN }}
43-
- uses: actions/setup-node@v5
44-
with:
45-
node-version: ${{ matrix.node-version }}
4636
- uses: actions/setup-python@v6
4737
with:
4838
python-version: ${{ matrix.python }}
49-
- uses: actions/cache@v4
50-
with:
51-
path: ~/.pnpm-store
52-
key: node-modules-${{ hashFiles('package.json') }}
5339
- uses: pnpm/action-setup@v4
5440
with:
5541
version: latest
42+
- uses: actions/setup-node@v5
43+
with:
44+
node-version: ${{ matrix.node-version }}
45+
cache: pnpm
46+
registry-url: https://registry.npmjs.org
47+
- name: Authenticate with private NPM package
48+
run: echo "//registry.npmjs.org/:_authToken=${{ secrets.PYTHON_NODE_NPM_TOKEN }}" > ~/.npmrc
5649
- name: Install dependencies
5750
run: pnpm install
58-
- uses: dtolnay/rust-toolchain@stable
59-
with:
60-
toolchain: stable
61-
# TODO: replace with `pnpm install` when using published dependency
62-
- name: Build python-node manually
63-
run: |
64-
# Configure git to use SSH host aliases for private repos (needed by cargo)
65-
git config --global url."ssh://git@github.com-http-handler/platformatic/http-handler".insteadOf "ssh://git@github.com/platformatic/http-handler"
66-
git config --global url."ssh://git@github.com-http-handler/platformatic/http-handler.git".insteadOf "ssh://git@github.com/platformatic/http-handler.git"
67-
git config --global url."ssh://git@github.com-http-rewriter/platformatic/http-rewriter".insteadOf "ssh://git@github.com/platformatic/http-rewriter"
68-
git config --global url."ssh://git@github.com-http-rewriter/platformatic/http-rewriter.git".insteadOf "ssh://git@github.com/platformatic/http-rewriter.git"
69-
70-
cd node_modules/@platformatic/python-node
71-
pnpm install --ignore-scripts
72-
pnpm run build
73-
pnpm run build:wasm
74-
pnpm run build:fix
51+
env:
52+
NODE_AUTH_TOKEN: ${{ secrets.PYTHON_NODE_NPM_TOKEN }}
7553
- name: Run Full Test Suite
7654
shell: bash
7755
run: pnpm test
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
name: Publish release
2+
3+
on:
4+
workflow_dispatch:
5+
inputs:
6+
version:
7+
description: "The version number to tag and release"
8+
required: true
9+
type: string
10+
prerelease:
11+
description: "Release as pre-release"
12+
required: false
13+
type: boolean
14+
default: false
15+
16+
jobs:
17+
release-npm:
18+
runs-on: ubuntu-latest
19+
environment: main
20+
permissions:
21+
contents: write
22+
id-token: write
23+
steps:
24+
- name: Checkout
25+
uses: actions/checkout@v4
26+
- name: Use supported Node.js Version
27+
uses: actions/setup-node@v4
28+
with:
29+
node-version: 22
30+
- name: Restore cached dependencies
31+
uses: actions/cache@v4
32+
with:
33+
path: ~/.pnpm-store
34+
key: node-modules-${{ hashFiles('package.json') }}
35+
- name: Setup pnpm
36+
uses: pnpm/action-setup@v4
37+
with:
38+
version: latest
39+
- name: Install dependencies
40+
run: pnpm install --frozen-lockfile
41+
- name: Bump version and push commit
42+
run: |
43+
pnpm version ${{ inputs.version }} --no-git-tag-version
44+
git config --global user.name "${{ github.actor }}"
45+
git config --global user.email "${{ github.actor }}@users.noreply.github.com"
46+
git commit -a -m "Bumped v${{ inputs.version }}"
47+
git push origin HEAD:${{ github.ref }}
48+
- name: Publish new version
49+
run: |
50+
npm install npm -g
51+
npm publish --access public --tag ${{ inputs.prerelease == true && 'next' || 'latest' }}
52+
- name: Create release notes
53+
run: |
54+
npx @matteo.collina/release-notes -a ${{ secrets.GITHUB_TOKEN }} -t v${{ inputs.version }} -r ${{ github.repository }} ${{ github.event.inputs.prerelease == 'true' && '-p' || '' }} -c ${{ github.ref }}

.gitignore

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -140,5 +140,4 @@ plt-python
140140
wordpress
141141

142142
package-lock.json
143-
pnpm-lock.yaml
144143
yarn.lock

config.d.ts

Lines changed: 21 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -164,32 +164,14 @@ export interface PlatformaticPythonConfiguration {
164164
plugins?: {
165165
[k: string]: unknown;
166166
};
167-
metrics?:
168-
| boolean
169-
| {
170-
port?: number | string;
171-
hostname?: string;
172-
endpoint?: string;
173-
server?: "own" | "parent" | "hide";
174-
defaultMetrics?: {
175-
enabled: boolean;
176-
};
177-
auth?: {
178-
username: string;
179-
password: string;
180-
};
181-
labels?: {
182-
[k: string]: string;
183-
};
184-
};
185167
telemetry?: {
186168
enabled?: boolean | string;
187169
/**
188-
* The name of the service. Defaults to the folder name if not specified.
170+
* The name of the application. Defaults to the folder name if not specified.
189171
*/
190-
serviceName: string;
172+
applicationName: string;
191173
/**
192-
* The version of the service (optional)
174+
* The version of the application (optional)
193175
*/
194176
version?: string;
195177
/**
@@ -271,6 +253,7 @@ export interface PlatformaticPythonConfiguration {
271253
| string;
272254
$schema?: string;
273255
module?: string;
256+
application?: {};
274257
service?: {
275258
openapi?:
276259
| {
@@ -324,21 +307,14 @@ export interface PlatformaticPythonConfiguration {
324307
};
325308
};
326309
};
327-
clients?: {
328-
serviceId?: string;
329-
name?: string;
330-
type?: "openapi" | "graphql";
331-
path?: string;
332-
schema?: string;
333-
url?: string;
334-
fullResponse?: boolean;
335-
fullRequest?: boolean;
336-
validateResponse?: boolean;
337-
}[];
338310
runtime?: {
339311
preload?: string | string[];
340312
basePath?: string;
313+
services?: {
314+
[k: string]: unknown;
315+
}[];
341316
workers?: number | string;
317+
workersRestartDelay?: number | string;
342318
logger?: {
343319
level: (
344320
| ("fatal" | "error" | "warn" | "info" | "debug" | "trace" | "silent")
@@ -423,9 +399,10 @@ export interface PlatformaticPythonConfiguration {
423399
};
424400
startTimeout?: number;
425401
restartOnError?: boolean | number;
402+
exitOnUnhandledErrors?: boolean;
426403
gracefulShutdown?: {
427404
runtime: number | string;
428-
service: number | string;
405+
application: number | string;
429406
};
430407
health?: {
431408
enabled?: boolean | string;
@@ -435,7 +412,7 @@ export interface PlatformaticPythonConfiguration {
435412
maxELU?: number | string;
436413
maxHeapUsed?: number | string;
437414
maxHeapTotal?: number | string;
438-
maxYoungGeneration?: number;
415+
maxYoungGeneration?: number | string;
439416
};
440417
undici?: {
441418
agentOptions?: {
@@ -512,6 +489,10 @@ export interface PlatformaticPythonConfiguration {
512489
labels?: {
513490
[k: string]: string;
514491
};
492+
/**
493+
* The label name to use for the application identifier in metrics (e.g., applicationId, serviceId)
494+
*/
495+
applicationLabel?: string;
515496
readiness?:
516497
| boolean
517498
| {
@@ -538,17 +519,16 @@ export interface PlatformaticPythonConfiguration {
538519
body?: string;
539520
};
540521
};
541-
additionalProperties?: never;
542-
[k: string]: unknown;
522+
plugins?: string[];
543523
};
544524
telemetry?: {
545525
enabled?: boolean | string;
546526
/**
547-
* The name of the service. Defaults to the folder name if not specified.
527+
* The name of the application. Defaults to the folder name if not specified.
548528
*/
549-
serviceName: string;
529+
applicationName: string;
550530
/**
551-
* The version of the service (optional)
531+
* The version of the application (optional)
552532
*/
553533
version?: string;
554534
/**
@@ -624,7 +604,8 @@ export interface PlatformaticPythonConfiguration {
624604
watchDisabled?: boolean;
625605
[k: string]: unknown;
626606
};
627-
serviceTimeout?: number | string;
607+
applicationTimeout?: number | string;
608+
messagingTimeout?: number | string;
628609
env?: {
629610
[k: string]: string;
630611
};

lib/generator.js

Lines changed: 7 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { Generator as ServiceGenerator } from '@platformatic/service'
22
import { readFile } from 'node:fs/promises'
3-
import { basename, resolve, join } from 'node:path'
3+
import { join } from 'node:path'
4+
import { packageJson } from '../lib/schema.js'
45

56
export class Generator extends ServiceGenerator {
67
constructor (opts = {}) {
@@ -31,7 +32,6 @@ export class Generator extends ServiceGenerator {
3132
}
3233

3334
async _getConfigFileContents () {
34-
const packageJson = await this._getStackablePackageJson()
3535
const { server, watch } = await super._getConfigFileContents()
3636

3737
return {
@@ -52,8 +52,6 @@ export class Generator extends ServiceGenerator {
5252
delete this.config.env.PLT_TYPESCRIPT
5353
delete this.config.defaultEnv.PLT_TYPESCRIPT
5454

55-
const packageJson = await this._getStackablePackageJson()
56-
5755
this.config.dependencies = {
5856
[packageJson.name]: `^${packageJson.version}`
5957
}
@@ -64,15 +62,11 @@ export class Generator extends ServiceGenerator {
6462
delete this.files['.gitignore']
6563

6664
if (!this.config.isUpdating) {
67-
this.addFile({ path: 'public', file: 'main.py', contents: await readFile(join(import.meta.dirname, 'main.py'), 'utf-8') })
65+
this.addFile({
66+
path: 'public',
67+
file: 'main.py',
68+
contents: await readFile(join(import.meta.dirname, 'main.py'), 'utf-8')
69+
})
6870
}
6971
}
70-
71-
async _getStackablePackageJson () {
72-
if (!this._packageJson) {
73-
this._packageJson = JSON.parse(await readFile(resolve(import.meta.dirname, '../package.json'), 'utf-8'))
74-
}
75-
76-
return this._packageJson
77-
}
7872
}

lib/index.js

Lines changed: 13 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,19 @@
1-
import { buildStackable } from '@platformatic/service'
2-
import { Generator as _Generator } from './generator.js'
1+
import { create as createService, platformaticService } from '@platformatic/service'
32
import { plugin } from './plugin.js'
4-
import { packageJson, schema } from './schema.js'
3+
import { schema } from './schema.js'
54

6-
export async function stackable (fastify, opts) {
7-
await fastify.register(plugin, opts)
5+
export async function python (app, capability) {
6+
await platformaticService(app, capability)
7+
await app.register(plugin, capability)
88
}
99

10-
stackable.Generator = _Generator
11-
stackable.configType = 'python'
12-
stackable.schema = schema
13-
stackable.configManagerConfig = {
14-
schemaOptions: {
15-
useDefaults: true,
16-
coerceTypes: true,
17-
allErrors: true,
18-
strict: false
19-
}
10+
export async function create (configOrRoot, sourceOrConfig, context) {
11+
return createService(configOrRoot, sourceOrConfig, {
12+
schema,
13+
applicationFactory: python,
14+
...context
15+
})
2016
}
2117

22-
export const Generator = _Generator
23-
24-
export default {
25-
configType: 'python',
26-
configManagerConfig: stackable.configManagerConfig,
27-
/* c8 ignore next 3 */
28-
async buildStackable (opts) {
29-
return buildStackable(opts, stackable)
30-
},
31-
schema,
32-
version: packageJson.version
33-
}
18+
export { Generator } from './generator.js'
19+
export { packageJson, schema, schemaComponents, version } from './schema.js'

lib/plugin.js

Lines changed: 11 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,17 @@
1-
import { readFile } from 'node:fs/promises'
2-
import { basename } from 'node:path'
1+
import fp from 'fastify-plugin'
32

43
const HTTP_METHODS = ['GET', 'POST', 'PUT', 'DELETE', 'PATCH', 'OPTIONS', 'TRACE']
54

6-
const capitalizeHeaders = header => header.replace(/(^|-)([a-z])/g, (_, dash, letter) => dash + letter.toUpperCase());
5+
const capitalizeHeaders = header => header.replace(/(^|-)([a-z])/g, (_, dash, letter) => dash + letter.toUpperCase())
76

8-
export async function plugin (server, opts) {
7+
// A full URL string is needed for PHP, but Node.js splits that across a bunch of places.
8+
function urlForRequest (req) {
9+
const proto = req.raw.protocol ?? 'http:'
10+
const host = req.headers.host ?? 'localhost'
11+
return new URL(req.url, `${proto}//${host}`)
12+
}
13+
14+
export async function pythonPlugin (server, opts) {
915
// We import this dynically to provide better error reporting in case
1016
// this module fails to load one of the native bindings
1117
const { Python, Request } = await import('@platformatic/python-node')
@@ -95,17 +101,4 @@ export async function plugin (server, opts) {
95101
})
96102
}
97103

98-
// A full URL string is needed for Python, but Node.js splits that across a bunch of places.
99-
function urlForRequest(req) {
100-
const proto = req.raw.protocol ?? 'http:'
101-
const host = req.headers.host ?? 'localhost'
102-
return new URL(req.url, `${proto}//${host}`)
103-
}
104-
105-
// Currently header values must be arrays. Need to make it support single values too.
106-
function fixHeaders (headers) {
107-
return Object.fromEntries(
108-
Object.entries(headers)
109-
.map(([key, value]) => [key, [value]])
110-
)
111-
}
104+
export const plugin = fp(pythonPlugin)

0 commit comments

Comments
 (0)