Skip to content

Commit

Permalink
feat(sdk): generate an sdk with spec from npm
Browse files Browse the repository at this point in the history
  • Loading branch information
fpaul-1A committed Apr 19, 2024
1 parent 10bd5c0 commit 316cd7e
Show file tree
Hide file tree
Showing 18 changed files with 264 additions and 23 deletions.
6 changes: 4 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
"build:lint": "yarn nx run-many --target=build --projects=eslint-plugin --parallel $(yarn get:cpus-number)",
"build:swagger-gen": "yarn nx run-many --target=build-swagger --parallel $(yarn get:cpus-number)",
"prepare:publish": "yarn prepare-publish \"$(yarn workspaces:list)\" --append dist",
"publish": "yarn run prepare:publish && yarn nx run-many --target=publish --parallel $(yarn get:cpus-number) --nx-bail",
"publish": "yarn run prepare:publish && yarn nx run-many --target=publish --exclude=tag:private --parallel $(yarn get:cpus-number) --nx-bail",
"publish:extensions": "yarn nx run-many --target=publish-extension --parallel $(yarn get:cpus-number)",
"publish:extensions:affected": "yarn nx affected --target=publish-extension --parallel $(yarn get:cpus-number)",
"lint": "yarn nx run-many --target=lint --parallel $(yarn get:cpus-number)",
Expand All @@ -41,7 +41,8 @@
"verdaccio:start-persistent": "docker run -d -it --rm --name verdaccio -p 4873:4873 -v \"$(yarn get:current-dir)/.verdaccio/conf\":/verdaccio/conf -v \"$(yarn get:current-dir)/.verdaccio/storage\":/verdaccio/storage:z verdaccio/verdaccio",
"verdaccio:clean": "rimraf -g \".verdaccio/storage/@{o3r,ama-sdk,ama-terasu}\"",
"verdaccio:login": "yarn cpy --cwd=./.verdaccio/conf .npmrc . --rename=.npmrc-logged && npx --yes npm-cli-login -u verdaccio -p verdaccio -e test@test.com -r http://127.0.0.1:4873 --config-path \".verdaccio/conf/.npmrc-logged\"",
"verdaccio:publish": "yarn verdaccio:clean && yarn set:version 999.0.0 --include \"!**/!(dist)/package.json\" --include !package.json && yarn verdaccio:login && yarn run publish --userconfig \".verdaccio/conf/.npmrc-logged\" --tag=latest --@o3r:registry=http://127.0.0.1:4873 --@ama-sdk:registry=http://127.0.0.1:4873 --@ama-terasu:registry=http://127.0.0.1:4873",
"verdaccio:prepare-publish": "yarn verdaccio:clean && yarn set:version 999.0.0 --include \"!**/!(dist)/package.json\" --include !package.json && yarn verdaccio:login && replace-in-files --regex=\"private(.*)true\" --replacement=private\\$1false '**/dist/package.json' && yarn run prepare:publish",
"verdaccio:publish": "yarn run verdaccio:prepare-publish && yarn nx run-many --target=publish --parallel $(yarn get:cpus-number) --nx-bail --userconfig \".verdaccio/conf/.npmrc-logged\" --tag=latest --@o3r:registry=http://127.0.0.1:4873 --@ama-sdk:registry=http://127.0.0.1:4873 --@ama-terasu:registry=http://127.0.0.1:4873",
"verdaccio:stop": "docker container stop $(docker ps -a -q --filter=\"name=verdaccio\")",
"verdaccio:all": "yarn verdaccio:stop && yarn verdaccio:start && yarn verdaccio:publish",
"watch:vscode-extension": "yarn nx run vscode-extension:compile:watch",
Expand Down Expand Up @@ -238,6 +239,7 @@
"postcss-scss": "~4.0.9",
"react": "^18.0.0",
"react-dom": "^18.0.0",
"replace-in-files-cli": "^2.2.0",
"rimraf": "^5.0.1",
"sass": "~1.75.0",
"sass-loader": "^14.0.0",
Expand Down
18 changes: 18 additions & 0 deletions packages/@ama-sdk/core/cli/update-spec-from-npm.cts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
#!/usr/bin/env node

/*
* Update the OpenAPI spec from an NPM package
*/

import { copyFile } from 'node:fs/promises';

void (async () => {
const packageName = process.argv[2];
const packagePath = process.argv[3];

const specSourcePath = require.resolve(`${packageName}/${packagePath}`);
// TODO get actual path from openapitools.json
const specDestinationPath = './openapi.yml';

await copyFile(specSourcePath, specDestinationPath);
})();
3 changes: 2 additions & 1 deletion packages/@ama-sdk/core/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,7 @@
"schematics": "./collection.json",
"bin": {
"amasdk-clear-index": "./dist/cli/clear-index.cjs",
"amasdk-files-pack": "./dist/cli/files-pack.cjs"
"amasdk-files-pack": "./dist/cli/files-pack.cjs",
"amasdk-update-spec-from-npm": "./dist/cli/update-spec-from-npm.cjs"
}
}
7 changes: 6 additions & 1 deletion packages/@ama-sdk/create/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,5 +43,10 @@ npm create @ama-sdk typescript <project-name> -- --package-manager=yarn [...opti
- `--o3r-metrics`: Enable or disable the collection of anonymous data for Otter
- `--exact-o3r-version` : use a pinned version for [otter packages](https://github.com/AmadeusITGroup/otter/blob/main/docs/README.md).

- `--spec-package-name`: The npm package name where the spec file can be fetched
- `--spec-package-registry`: The npm registry where the spec file can be fetched
- `--spec-package-path`: The path inside the package where to find the spec file
- `--spec-package-version`: The version to target for the npm package where the spec file can be fetched

> [!NOTE]
> If the `--spec-path` is specified, the SDK will be generated based on this specification at the creation time.
> If `--spec-path` or `--spec-package-name` is specified, the SDK will be generated based on this specification at the creation time.
19 changes: 19 additions & 0 deletions packages/@ama-sdk/create/src/index.it.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,25 @@ describe('Create new sdk command', () => {
expect(existsSync(path.join(sdkPackagePath, 'src', 'models', 'base', 'pet', 'pet.reviver.ts'))).toBeTruthy();
});

test('should generate a full SDK when the specification is provided as npm dependency', () => {
expect(() =>
packageManagerCreate({
script: '@ama-sdk',
args: [
'typescript',
sdkPackageName,
'--package-manager', packageManager,
'--spec-package-name', '@ama-sdk/showcase-sdk',
'--spec-package-path', 'openapi.yml',
'--spec-package-version', o3rEnvironment.testEnvironment.o3rVersion,
'--spec-package-registry', o3rEnvironment.testEnvironment.packageManagerConfig.registry
]
}, execAppOptions)
).not.toThrow();
expect(() => packageManagerRun({script: 'build'}, { ...execAppOptions, cwd: sdkPackagePath })).not.toThrow();
expect(existsSync(path.join(sdkPackagePath, 'src', 'models', 'base', 'pet', 'pet.reviver.ts'))).toBeTruthy();
});

test('should generate an SDK with no package scope', () => {
const packageName = sdkPackageName.replace('@', '').split('/')[1];
const newSdkPackagePath = path.join(sdkFolderPath, packageName);
Expand Down
32 changes: 26 additions & 6 deletions packages/@ama-sdk/create/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,12 @@ const getYarnVersion = () => {
}
};

const schematicArgs = [
if (argv['spec-path'] && argv['spec-package-name']) {
console.error('--spec-path cannot be set with --spec-package-name');
process.exit(-4);
}

const commonSchematicArgs = [
argv.debug !== undefined ? `--debug=${argv.debug as string}` : '--debug=false', // schematics enable debug mode per default when using schematics with relative path
...(name ? ['--name', name] : []),
'--package', pck,
Expand All @@ -74,28 +79,43 @@ const resolveTargetDirectory = resolve(process.cwd(), targetDirectory);

const run = () => {
const isSpecRelativePath = !!argv['spec-path'] && !parse(argv['spec-path']).root;
const shellSchematicArgs = [
...commonSchematicArgs,
...(argv['spec-package-name'] ? ['--spec-package-name', argv['spec-package-name']] : []),
...(argv['spec-package-registry'] ? ['--spec-package-registry', argv['spec-package-registry']] : []),
...(argv['spec-package-path'] ? ['--spec-package-path', argv['spec-package-path']] : []),
...(argv['spec-package-version'] ? ['--spec-package-version', argv['spec-package-version']] : [])
];
const coreSchematicArgs = [
...commonSchematicArgs,
'--spec-path', argv['spec-package-name'] ? './openapi.yml' : isSpecRelativePath ? relative(resolveTargetDirectory, resolve(process.cwd(), argv['spec-path'])) : argv['spec-path']
];

const runner = process.platform === 'win32' ? `${packageManager}.cmd` : packageManager;
const steps: { args: string[]; cwd?: string; runner?: string }[] = [
{ args: [binPath, `${schematicsPackage}:typescript-shell`, ...schematicArgs, '--directory', targetDirectory] },
{ args: [binPath, `${schematicsPackage}:typescript-shell`, ...shellSchematicArgs, '--directory', targetDirectory] },
...(
packageManager === 'yarn'
? [{ runner, args: ['set', 'version', getYarnVersion()], cwd: resolveTargetDirectory }]
: []
),
...(argv['spec-path'] ? [{
...(argv['spec-package-name'] ? [{
runner,
args: ['exec', 'amasdk-update-spec-from-npm', argv['spec-package-name'], argv['spec-package-path']],
cwd: resolveTargetDirectory
}] : []),
...((argv['spec-path'] || argv['spec-package-name']) ? [{
args: [
binPath,
`${schematicsPackage}:typescript-core`,
...schematicArgs,
'--spec-path', isSpecRelativePath ? relative(resolveTargetDirectory, resolve(process.cwd(), argv['spec-path'])) : argv['spec-path']
...coreSchematicArgs
],
cwd: resolveTargetDirectory
}] : [])
];

const errors = steps
.map((step) => spawnSync(step.runner || process.execPath, step.args, { stdio: 'inherit', cwd: step.cwd || process.cwd(), shell: true }))
.map((step) => spawnSync(step.runner || `"${process.execPath}"`, step.args, { stdio: 'inherit', cwd: step.cwd || process.cwd(), shell: true }))
.filter(({error, status}) => (error || status !== 0));

if (errors.length > 0) {
Expand Down
22 changes: 22 additions & 0 deletions packages/@ama-sdk/schematics/schematics/typescript/shell/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,9 @@ function ngGenerateTypescriptSDKFn(options: NgGenerateTypescriptSDKShellSchemati
packageManager: getPackageManagerName(options.packageManager),
projectHosting: options.hosting,
exactO3rVersion: options.exactO3rVersion,
specPackageName: options.specPackageName,
specPackagePath: options.specPackagePath,
specPackageVersion: options.specPackageVersion,
sdkCoreRange: `${options.exactO3rVersion ? '' : '~'}${amaSdkSchematicsPackageJson.version}`,
sdkCoreVersion: amaSdkSchematicsPackageJson.version,
angularVersion: amaSdkSchematicsPackageJson.dependencies!['@angular-devkit/core'],
Expand All @@ -80,6 +83,7 @@ function ngGenerateTypescriptSDKFn(options: NgGenerateTypescriptSDKShellSchemati
};

const targetPath = options.directory || tree.root.path;
const specScope = options.specPackageName?.startsWith('@') ? options.specPackageName.substring(1).split('/')[0] : undefined;

if (properties.packageManager === 'yarn') {
const yarnrcPath = posix.join(targetPath, '.yarnrc.yml');
Expand All @@ -91,11 +95,29 @@ function ngGenerateTypescriptSDKFn(options: NgGenerateTypescriptSDKShellSchemati
'isomorphic-fetch': amaSdkSchematicsPackageJson.devDependencies!['isomorphic-fetch']
}
};
if (options.specPackageRegistry && specScope) {
yarnrc.npmScopes ||= {};
yarnrc.npmScopes[specScope] = {
npmRegistryServer: options.specPackageRegistry
};
}

if (tree.exists(yarnrcPath)) {
tree.overwrite(yarnrcPath, dump(yarnrc, {indent: 2}));
} else {
tree.create(yarnrcPath, dump(yarnrc, {indent: 2}));
}
} else if (properties.packageManager === 'npm') {
if (options.specPackageRegistry && specScope) {
const npmrcPath = posix.join(targetPath, '.npmrc');
let npmrc = tree.exists(npmrcPath) ? tree.readText(npmrcPath) : '';
npmrc += `\n@${specScope}:registry=${options.specPackageRegistry}\n`;
if (tree.exists(npmrcPath)) {
tree.overwrite(npmrcPath, npmrc);
} else {
tree.create(npmrcPath, npmrc);
}
}
}

const baseRule = mergeWith(apply(url('./templates/base'), [
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,24 @@
"type": "string",
"description": "Directory where to generate the SDK"
},
"specPackageName": {
"type": "string",
"description": "The npm package name where the spec file can be fetched"
},
"specPackageRegistry": {
"type": "string",
"description": "The npm registry where the spec file can be fetched"
},
"specPackagePath": {
"type": "string",
"description": "The path inside the package where to find the spec file",
"default": "openapi.yml"
},
"specPackageVersion": {
"type": "string",
"description": "The version to target for the npm package where the spec file can be fetched",
"default": "latest"
},
"skipInstall": {
"type": "boolean",
"description": "Skip NPM install",
Expand Down
12 changes: 12 additions & 0 deletions packages/@ama-sdk/schematics/schematics/typescript/shell/schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,18 @@ export interface NgGenerateTypescriptSDKShellSchematicsSchema extends SchematicO
/** Directory where to generate the SDK */
directory?: string | undefined;

/** The npm package name where the spec file can be fetched */
specPackageName?: string;

/** The npm registry where the spec file can be fetched */
specPackageRegistry?: string;

/** The path inside the package where to find the spec file */
specPackagePath: string;

/** The version to target for the npm package where the spec file can be fetched */
specPackageVersion?: string;

/** Package manager to be used in the generated SDK */
packageManager?: 'npm' | 'yarn' | undefined;

Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
{
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
"extends": [
"config:base",
"github>AmadeusITGroup/otter//tools/renovate/base",
"github>AmadeusITGroup/otter//tools/renovate/sdk",
"github>AmadeusITGroup/otter//tools/renovate/sdk-spec-upgrade(my-specification-package)"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
"resolve": "node -e 'process.stdout.write(require.resolve(process.argv[1]));'",
"generate": "schematics @ama-sdk/schematics:typescript-core",
"spec:regen": "<%=packageManager%> run generate <% if (packageManager === 'npm') {%>-- <%}%>--generator-key <%=projectName%>-<%=projectPackageName%> && amasdk-clear-index",
"spec:upgrade": "<% if (specPackageName) { %>amasdk-update-spec-from-npm <%=specPackageName%> <%=specPackagePath%> && <% } %><%=packageManager%> run spec:regen",
"files:pack": "amasdk-files-pack",
"test": "jest --passWithNoTests",
"publish:package": "npm publish ./dist",
Expand Down Expand Up @@ -106,7 +107,8 @@
"ts-jest": "<%= versions['ts-jest'] %>",
"typedoc": "~0.25.0",
"tsc-watch": "^6.0.0",
"typescript": "<%= versions['typescript'] %>"
"typescript": "<%= versions['typescript'] %>"<% if (specPackageName) { %>,
"<%=specPackageName%>": "<%=specPackageVersion%>"<% } %>
},<% if (exactO3rVersion) { %>
"<%= packageManager == 'yarn' ? 'resolutions' : 'overrides' %>": {
"@o3r/schematics": "<%= sdkCoreRange %>"
Expand Down
File renamed without changes.
2 changes: 1 addition & 1 deletion packages/@ama-sdk/showcase-sdk/openapitools.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
"ama-sdk-showcase-sdk": {
"generatorName": "typescriptFetch",
"output": ".",
"inputSpec": "./swagger-spec.yaml",
"inputSpec": "./openapi.yml",
"globalProperty": {
"stringifyDate": true
}
Expand Down
6 changes: 5 additions & 1 deletion packages/@ama-sdk/showcase-sdk/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,14 +27,17 @@
"typings": "./index.d.ts",
"import": "./esm2020/index.js",
"require": "./esm2020/index.js"
},
"./openapi.yml": {
"default": "./openapi.yml"
}
},
"scripts": {
"clean": "rimraf test/ test-dev/ dist/ dist-dev/ dist-test/ build/",
"lint:ci": "eslint '**/*[jt]s' --quiet --format junit --output-file ./dist-lint/result.xml",
"lint": "eslint '**/*[jt]s' --cache",
"start": "tsc-watch -b tsconfigs/esm2020 --noClear --onFirstSuccess \"yarn run files:pack --watch\"",
"build": "yarn run build:cjs && yarn run build:esm2015 && yarn run build:esm2020 && yarn run files:pack",
"build": "yarn run build:cjs && yarn run build:esm2015 && yarn run build:esm2020 && cpy openapi.yml ./dist && yarn run files:pack",
"build:cjs": "swc src -d dist/cjs -C module.type=commonjs -q",
"build:esm2015": "swc src -d dist/esm2015 -C module.type=es6 -q",
"build:esm2020": "tsc -b tsconfigs/esm2020",
Expand Down Expand Up @@ -83,6 +86,7 @@
"@typescript-eslint/eslint-plugin": "^7.2.0",
"@typescript-eslint/parser": "^7.2.0",
"chokidar": "^3.5.2",
"cpy-cli": "^5.0.0",
"eslint": "^8.57.0",
"eslint-plugin-jest": "~27.9.0",
"eslint-plugin-jsdoc": "~48.2.1",
Expand Down
8 changes: 7 additions & 1 deletion packages/@ama-sdk/showcase-sdk/project.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,13 @@
"packages/@ama-sdk/showcase-sdk/package.json"
]
}
},
"publish": {
"executor": "nx:run-commands",
"options": {
"command": "npm publish packages/@ama-sdk/showcase-sdk/dist"
}
}
},
"tags": ["showcase"]
"tags": ["private", "showcase"]
}
2 changes: 1 addition & 1 deletion tools/renovate/tasks/sdk-regenerate.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
"postUpgradeTasks": {
"commands": [
"{{arg0}} install",
"{{arg0}} run swagger:generate"
"{{arg0}} run spec:upgrade"
],
"fileFilters": [
"!**/.{npmrc,yarnrc*}"
Expand Down
2 changes: 1 addition & 1 deletion tools/renovate/tasks/sdk-spec-regenerate.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
"postUpgradeTasks": {
"commands": [
"{{arg0}} install",
"{{arg0}} run swagger:generate"
"{{arg0}} run spec:upgrade"
],
"executionMode": "branch",
"fileFilters": [
Expand Down

0 comments on commit 316cd7e

Please sign in to comment.