Skip to content

Commit

Permalink
chore: update workflows for release and version bump (#8)
Browse files Browse the repository at this point in the history
What's Changed:
1. Running `yarn build` will now automatically update the schema if any changes have been made that will impact it. Not all changes will. This is accomplished by adding the existing command `yarn update-schema` into the `pre-compile` step that is run within `yarn build`. It is also run in the `release` step to check for any unintentional changes and will fail the release if uncommitted changes are found (one intentional exception is listed below).
3. A new function `bump()` will check for any updates to the schema (generated by `pre-compile`). If there are any, it will update the minimum major version to release by a full major version based off the latest tag in the repository. If there are no changes to the schema, no updates will be made. This is accomplished by setting `bump()` as the value for `minMajorVersion`. If there are no changes to the schema, this field will remain undefined but if there are, it will increment the version. This change will not be committed and will be removed once the release has completed, similarly to how `unbump` works in `projen`
4. A new command `yarn pre-release` runs `update-schema` and `default`. Running `default` after `update-schema` accomplishes all of the above and re-synthesizes the `tasks.json` file with the new major version so that the `release` command will run on the updated task definition.

Any uncommitted changes other than the `minMajorVersion` update will cause the `release` command to fail.
  • Loading branch information
TheRealAmazonKendra authored Aug 5, 2024
1 parent 1461a06 commit 39892ad
Show file tree
Hide file tree
Showing 16 changed files with 221 additions and 134 deletions.
1 change: 0 additions & 1 deletion .eslintrc.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions .github/workflows/release.yml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

25 changes: 22 additions & 3 deletions .projen/tasks.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

41 changes: 34 additions & 7 deletions .projenrc.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import { JsonPatch, cdk, release } from 'projen';
import { JsonPatch, cdk } from 'projen';
import { Stability } from 'projen/lib/cdk';
import { TrailingComma } from 'projen/lib/javascript';
const project = new cdk.JsiiProject({
import { bump } from './projenrc';

export const project = new cdk.JsiiProject({
author: 'Amazon Web Services',
authorAddress: '',
authorOrganization: true,
Expand All @@ -17,6 +19,12 @@ const project = new cdk.JsiiProject({
docgen: false,
publishDryRun: true,
stability: Stability.STABLE,
releaseWorkflowSetupSteps: [
{
name: 'Pre-Release Setup',
run: 'npx projen pre-release',
},
],
jsiiVersion: '*',
keywords: ['aws', 'cdk'],
repositoryUrl: 'https://github.com/cdklabs/cloud-assembly-schema.git',
Expand Down Expand Up @@ -50,7 +58,8 @@ const project = new cdk.JsiiProject({
},
eslintOptions: {
prettier: true,
dirs: ['lib', 'test', 'scripts'],
dirs: ['lib'],
devdirs: ['test'],
},
jestOptions: {
jestConfig: {
Expand All @@ -65,12 +74,32 @@ const project = new cdk.JsiiProject({
description: 'Cloud Assembly Schema',
devDeps: ['@types/semver', 'mock-fs', 'typescript-json-schema'],
gitignore: ['.DS_Store', '**/*.d.ts', '**/*.js'],
minMajorVersion: bump(),
});

release.ReleaseTrigger;
project.addScripts({
'update-schema': 'ts-node --prefer-ts-exts -e "require(\'./projenrc/update.ts\').update()"',
});

const packageJson = project.tryFindObjectFile('package.json');
project.preCompileTask.exec('yarn update-schema');
project.addTask('pre-release', {
steps: [
{
exec: 'yarn update-schema',
},
{
exec: 'yarn default',
},
],
});

project.tasks
.tryFind('release')
?.updateStep(4, { exec: "git diff --ignore-space-at-eol ':!.projen/tasks.json'" });

project.tasks.tryFind('release')?.exec('git restore .projen/tasks.json');

const packageJson = project.tryFindObjectFile('package.json');
packageJson?.patch(
JsonPatch.add('/jsii/targets/python/classifiers', [
'Framework :: AWS CDK',
Expand All @@ -82,6 +111,4 @@ project.addPackageIgnore('*.ts');
project.addPackageIgnore('!*.d.ts');
project.addPackageIgnore('**/scripts');

project.addScripts({ 'update-schema': 'bash ./scripts/update-schema.sh' });

project.synth();
10 changes: 5 additions & 5 deletions lib/manifest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,16 +13,16 @@ import * as integ from './integ-tests';
// see exec.ts#createAssembly
export const VERSION_MISMATCH: string = 'Cloud assembly schema version mismatch';

const ASSETS_SCHEMA = require('../schema/assets.schema.json');
import ASSETS_SCHEMA = require('../schema/assets.schema.json');

const ASSEMBLY_SCHEMA = require('../schema/cloud-assembly.schema.json');
import ASSEMBLY_SCHEMA = require('../schema/cloud-assembly.schema.json');

import INTEG_SCHEMA = require('../schema/integ.schema.json');

/**
* Version is shared for both manifests
*/
const SCHEMA_VERSION = require('../schema/cloud-assembly.version.json').version;

const INTEG_SCHEMA = require('../schema/integ.schema.json');
const SCHEMA_VERSION = require('../package.json').version;

/**
* Options for the loadManifest operation
Expand Down
3 changes: 2 additions & 1 deletion package.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

29 changes: 29 additions & 0 deletions projenrc/bump.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import * as semver from 'semver';
import { schemasChanged } from './update-schema';
import { exec, log } from './util';

export function bump() {
try {
const tags = exec([
'git',
'ls-remote',
'--tags',
'[email protected]:cdklabs/cloud-assembly-schema.git',
]);

const oldVersion = tags.split('/v').pop()!.slice(0, -3);
const newVersion = schemasChanged() ? semver.inc(oldVersion, 'major')! : oldVersion;

if (newVersion !== oldVersion) {
log(`Updating schema version: ${oldVersion} -> ${newVersion}`);
return parseInt(newVersion);
}
return undefined;
} catch (e) {
/**
* If git cannot be reached, returning undefined is fine. This will never happen
* in the release workflow and may very well happen in any given build.
*/
return undefined;
}
}
2 changes: 2 additions & 0 deletions projenrc/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export * from './update';
export * from './bump';
52 changes: 52 additions & 0 deletions projenrc/schema-definition.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import * as path from 'path';
import { generatedPath, sourcePath } from './util';

export type SchemaDefinition = {
/**
* The name of the root type.
*/
rootTypeName: string;
/**
* Files loaded to generate the schema.
* Should be relative to `cloud-assembly-schema/lib`.
* Usually this is just the file containing the root type.
*/
sourceFile: string;
/**
* The location of the generated schema.
*/
generatedFile: string;
};

/**
* Where schemas are committed.
*/
export const SCHEMA_DIR = path.resolve(__dirname, '../schema');

const SCHEMA_DEFINITIONS: { [schemaName: string]: SchemaDefinition } = {
assets: {
rootTypeName: 'AssetManifest',
sourceFile: sourcePath('assets'),
generatedFile: generatedPath('assets'),
},
'cloud-assembly': {
rootTypeName: 'AssemblyManifest',
sourceFile: sourcePath('cloud-assembly'),
generatedFile: generatedPath('cloud-assembly'),
},
integ: {
rootTypeName: 'IntegManifest',
sourceFile: sourcePath('integ-tests'),
generatedFile: generatedPath('integ'),
},
};

export const SCHEMAS: string[] = Object.keys(SCHEMA_DEFINITIONS);

export function getSchemaDefinition(key: string): SchemaDefinition {
return SCHEMA_DEFINITIONS[key];
}

export function getGeneratedSchemaPaths(): string[] {
return Object.values(SCHEMA_DEFINITIONS).map((s) => s.generatedFile);
}
78 changes: 19 additions & 59 deletions scripts/update-schema.ts → projenrc/update-schema.ts
Original file line number Diff line number Diff line change
@@ -1,68 +1,31 @@
import * as fs from 'fs';
import * as path from 'path';
import * as semver from 'semver';
// eslint-disable-next-line import/no-extraneous-dependencies
import * as tjs from 'typescript-json-schema';

function log(message: string) {
// eslint-disable-next-line no-console
console.log(message);
}

/**
* Where schemas are committed.
*/
const SCHEMA_DIR = path.resolve(__dirname, '../schema');

const SCHEMA_DEFINITIONS: {
[schemaName: string]: {
/**
* The name of the root type.
*/
rootTypeName: string;
/**
* Files loaded to generate the schema.
* Should be relative to `cloud-assembly-schema/lib`.
* Usually this is just the file containing the root type.
*/
files: string[];
};
} = {
assets: {
rootTypeName: 'AssetManifest',
files: [path.join('assets', 'schema.ts')],
},
'cloud-assembly': {
rootTypeName: 'AssemblyManifest',
files: [path.join('cloud-assembly', 'schema.ts')],
},
integ: {
rootTypeName: 'IntegManifest',
files: [path.join('integ-tests', 'schema.ts')],
},
};

export const SCHEMAS = Object.keys(SCHEMA_DEFINITIONS);

export function update() {
for (const s of SCHEMAS) {
generateSchema(s);
}

bump();
}
import { SCHEMA_DIR, getGeneratedSchemaPaths, getSchemaDefinition } from './schema-definition';
import { exec, log } from './util';

export function bump() {
const versionFile = path.join(SCHEMA_DIR, 'cloud-assembly.version.json');
const tags = exec([
'git',
'ls-remote',
'--tags',
'[email protected]:cdklabs/cloud-assembly-schema.git',
]);

// eslint-disable-next-line @typescript-eslint/no-require-imports
const metadata = require(versionFile);
const oldVersion = tags.split('/v').pop()!.slice(0, -3);

const oldVersion = metadata.version;
const newVersion = semver.inc(oldVersion, 'major');
const newVersion = schemasChanged() ? semver.inc(oldVersion, 'major')! : oldVersion;
const versionFile = path.join(SCHEMA_DIR, 'cloud-assembly.version.json');

log(`Updating schema version: ${oldVersion} -> ${newVersion}`);
fs.writeFileSync(versionFile, JSON.stringify({ version: newVersion }));
return parseInt(newVersion);
}

export function schemasChanged(): boolean {
const changes = exec(['git', 'diff', '--name-only', 'origin/main']).split('\n');
return changes.filter((change) => getGeneratedSchemaPaths().includes(change)).length > 0;
}

/**
Expand All @@ -72,7 +35,7 @@ export function bump() {
* @param shouldBump writes a new version of the schema and bumps the major version
*/
export function generateSchema(schemaName: string, saveToFile: boolean = true) {
const spec = SCHEMA_DEFINITIONS[schemaName];
const spec = getSchemaDefinition(schemaName);
const out = saveToFile ? path.join(SCHEMA_DIR, `${schemaName}.schema.json`) : '';

const settings: Partial<tjs.Args> = {
Expand All @@ -87,10 +50,7 @@ export function generateSchema(schemaName: string, saveToFile: boolean = true) {
strictNullChecks: true,
};

const program = tjs.getProgramFromFiles(
spec.files.map((file) => path.join(__dirname, '..', 'lib', file)),
compilerOptions
);
const program = tjs.getProgramFromFiles([spec.sourceFile], compilerOptions);
const schema = tjs.generateSchema(program, spec.rootTypeName, settings);

augmentDescription(schema);
Expand Down
8 changes: 8 additions & 0 deletions projenrc/update.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { SCHEMAS } from './schema-definition';
import { generateSchema } from './update-schema';

export function update() {
for (const s of SCHEMAS) {
generateSchema(s);
}
}
Loading

0 comments on commit 39892ad

Please sign in to comment.