-
Notifications
You must be signed in to change notification settings - Fork 4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
chore: add "gen" target as a pre build script #10648
Conversation
packages/@aws-cdk/core/package.json
Outdated
}, | ||
"cdk-build": { | ||
"cloudformation": "AWS::CloudFormation", | ||
"cfn2ts-core-import": ".", | ||
"pre": [ | ||
"rm -rf test/fs/fixtures && cd test/fs && tar -xzf fixtures.tar.gz" | ||
"rm -rf test/fs/fixtures && cd test/fs && tar -xzf fixtures.tar.gz && npm run gen" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@rix0rrr since pre
is an array I assumed I can simply add npm run gen
as a separate item in the array:
"pre": [
"rm -rf test/fs/fixtures && cd test/fs && tar -xzf fixtures.tar.gz",
"npm run gen"
]
This does not work in cdk-build
as the array of commands is concatenated without an &&
:
rm -rf test/fs/fixtures && cd test/fs && tar -xzf fixtures.tar.gz npm run gen
Which fails. Is this a bug?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh yes, that sounds like a big bad bug.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So, this is by design, we might still want to change it, but first let me describe the current API. The shell
function accepts an array of strings, and assumes that commands[0]
includes the actual command, and the rest of the elements in the array are the args to that command:
aws-cdk/packages/aws-cdk/lib/os.ts
Lines 17 to 20 in 37fdc94
const child = child_process.spawn(command[0], command.slice(1), { | |
...options, | |
stdio: ['ignore', 'pipe', 'inherit'], | |
}); |
This is leveraged in several locations in the code, for example, in cdk-watch:
await shell(packageCompiler({ jsii: args.jsii, tsc: args.tsc }).concat(['-w'])); |
Usage:
aws-cdk/tools/cdk-build-tools/lib/package-info.ts
Lines 84 to 90 in 37fdc94
export function packageCompiler(compilers: CompilerOverrides): string[] { | |
if (isJsii()) { | |
return [compilers.jsii || require.resolve('jsii/bin/jsii'), '--silence-warnings=reserved-word']; | |
} else { | |
return [compilers.tsc || require.resolve('typescript/bin/tsc'), '--build']; | |
} | |
} |
It feels unintuitive, but maybe it is? I think we can keep shell
as is, but change pre
to accept a string instead of an array. Call for suggestions!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
aws-cdk/tools/cdk-build-tools/lib/os.ts
Lines 22 to 24 in d412bb6
const child = child_process.spawn(command[0], command.slice(1), { | |
// Need this for Windows where we want .cmd and .bat to be found as well. | |
shell: true, |
I see that the implementation of shell
is a little weird, probably because Node.js is just slightly different from other programming languages that have similar interfaces. Normally it's:
- Run a command through the shell, argument should be a string (string can contain special shell characters like
&
,>
and they will have their usual shell meaning) - Run a command directly, argument should be an array (shell is not involved,
&
,>
and
However, in inimitable "I'll try to do the best I can" Node.js fashion, the underlying child_process.spawn
function takes an array yet runs it through the shell, and it's fine if the whole string is in command[0]
. I guess in an attempt to be broadly compatible, it just won't escape command[0]
but it will escape command[1..]
. Something we need to verify.
I consider that flavor of API to be a feature! It's much easier to get wrong by accidentally having shell metacharacters
interpreted, or having to quote arguments (maybe there are filenames with spaces), etc. If I can, I will always design
my subprocess API to take an array instead of a string. You can still get the original behavior by calling
subprocess(['bash', '-c', originalCommandStringWithSpecialCharacters])
, so it's not a loss of functionality.
It's a pity it's so confusing here.
In any case, knowing what we're knowing, and even leaving the API of the shell
function unchanged, we can change the API exposed via the package.json
file easily. If we detect that package['cdk-build'].pre
is an array, we can either run multiple shells, or just join everything together with a &&
before we run it through the shell.
await shell(options.pre, { timers, env }); |
if (Array.isArray(options.pre)) {
for (const cmd of options.pre) {
await shell(cmd, { timers, env });
}
} else {
await shell(options.pre, { timers, env });
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I didn't see the change to cfn2ts in here?
(Which is great, because I don't want it anyway :) )
@@ -50,11 +50,15 @@ | |||
"cfn2ts": "cfn2ts", | |||
"build+test+package": "npm run build+test && npm run package", | |||
"build+test": "npm run build && npm test", | |||
"compat": "cdk-compat" | |||
"compat": "cdk-compat", | |||
"gen": "cfn2ts" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why don't we put the arguments to cfn2ts here as well? Let's make this
"gen": "cfn2ts" | |
"gen": "cfn2ts --scope=Alexa::Ask" |
etc.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We don't need it, cfn2ts
already gets this from the pacakge.json
file:
aws-cdk/tools/cfn2ts/bin/cfn2ts.ts
Lines 43 to 46 in bc096f0
async function tryAutoDetectScope(pkg: any): Promise<undefined | string[]> { | |
const value = pkg['cdk-build'] && pkg['cdk-build'].cloudformation; | |
return value && (typeof value === 'string' ? [value] : value); | |
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I know, but it gets it from the cdk-build
section. Don't you agree that's kinda confusing because we're not using cdk-build
to invoke cfn2ts
anymore?
In any case, fine.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree it's confusing, as evident by having to read through cfn2ts
code to understand why calling it without the scope name even works. I think we can add it to the gen
directive for clarity, not sure about removing the logic from cfn2ts
, it is a private package so technically we wont be breaking anyone.
}, | ||
"cdk-build": { | ||
"cloudformation": "Alexa::ASK", | ||
"jest": true, | ||
"pre": [ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This feels unnecessary. We can just code knowledge of the gen
target into cdk-build
, and get rid of cdk-build.pre
altogether.
(Yes, that means moving everything that's currently in cdk-build.pre
into scripts.gen
. If you don't want to that, I'm okay with leaving cdk-build.pre
in, but I'd still prefer that the tool knows about gen
ning so we don't have to repeat this in every package file).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good call. I removed npm run gen
from all pre
directive. cdk-build
will now execute gen
unless --skip-gen
was provided.
I moved all code generation logic to gen
, this include code generation commands in non cfn modules as well. I didn't remove pre
completely since there are cases in which it is used for things like cleaning folders, which are not code generation related.
packages/@aws-cdk/cfnspec/build-tools/create-missing-libraries.ts
Outdated
Show resolved
Hide resolved
packages/@aws-cdk/core/package.json
Outdated
}, | ||
"cdk-build": { | ||
"cloudformation": "AWS::CloudFormation", | ||
"cfn2ts-core-import": ".", | ||
"pre": [ | ||
"rm -rf test/fs/fixtures && cd test/fs && tar -xzf fixtures.tar.gz" | ||
"rm -rf test/fs/fixtures && cd test/fs && tar -xzf fixtures.tar.gz && npm run gen" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh yes, that sounds like a big bad bug.
packages/@aws-cdk/core/package.json
Outdated
}, | ||
"cdk-build": { | ||
"cloudformation": "AWS::CloudFormation", | ||
"cfn2ts-core-import": ".", | ||
"pre": [ | ||
"rm -rf test/fs/fixtures && cd test/fs && tar -xzf fixtures.tar.gz" | ||
"rm -rf test/fs/fixtures && cd test/fs && tar -xzf fixtures.tar.gz && npm run gen" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So, this is by design, we might still want to change it, but first let me describe the current API. The shell
function accepts an array of strings, and assumes that commands[0]
includes the actual command, and the rest of the elements in the array are the args to that command:
aws-cdk/packages/aws-cdk/lib/os.ts
Lines 17 to 20 in 37fdc94
const child = child_process.spawn(command[0], command.slice(1), { | |
...options, | |
stdio: ['ignore', 'pipe', 'inherit'], | |
}); |
This is leveraged in several locations in the code, for example, in cdk-watch:
await shell(packageCompiler({ jsii: args.jsii, tsc: args.tsc }).concat(['-w'])); |
Usage:
aws-cdk/tools/cdk-build-tools/lib/package-info.ts
Lines 84 to 90 in 37fdc94
export function packageCompiler(compilers: CompilerOverrides): string[] { | |
if (isJsii()) { | |
return [compilers.jsii || require.resolve('jsii/bin/jsii'), '--silence-warnings=reserved-word']; | |
} else { | |
return [compilers.tsc || require.resolve('typescript/bin/tsc'), '--build']; | |
} | |
} |
It feels unintuitive, but maybe it is? I think we can keep shell
as is, but change pre
to accept a string instead of an array. Call for suggestions!
@@ -24,22 +24,22 @@ async function main() { | |||
desc: 'Specify a different eslint executable', | |||
defaultDescription: 'eslint provided by node dependencies', | |||
}) | |||
.option('skip-gen', { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Note to self(and to the interested reviewer): NEVER EVER use no-something
for a boolean argument when using yargs, it will be interrupted as something=false
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yep. Every boolean argument you can pass like this on the command line:
$ command --flag
$ command --no-flag
So if you call your option gen
and default it to true
, you can call it with:
$ cdk-build --no-gen
Which seems excellent.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I guess it was only a surprise to me :) If that's the case I'll change it to gen
if ! [ -x "$(command -v yarn)" ]; then | ||
echo "yarn is not installed. Install it from here- https://yarnpkg.com/en/docs/install." | ||
exit 1 | ||
fi | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hoisted this check so it will happen before executing yarn install
@@ -13,4 +13,5 @@ for file in ${files}; do | |||
cp $src/$file . | |||
done | |||
|
|||
npx rewrite-imports "**/*.ts" | |||
NAME=${1:-} | |||
npx rewrite-imports "**/*.ts" ${NAME} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Probably could have done "$@"
here?
* Return the command defined in scripts.gen if exists | ||
*/ | ||
export function genScript(): string | undefined { | ||
return currentPackageJson().scripts.gen; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
return currentPackageJson().scripts.gen; | |
return currentPackageJson().scripts?.gen; |
Not likely but possible that scripts
is empty.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Excited about this change. Provisional approval to give you a chance to consider some final tweaks, other than that: ship it!
* cdk-build.pre now support array of commands
Thank you for contributing! Your pull request will be updated from master and then merged automatically (do not update manually, and be sure to allow changes to be pushed to your fork). |
Thank you for contributing! Your pull request will be updated from master and then merged automatically (do not update manually, and be sure to allow changes to be pushed to your fork). |
AWS CodeBuild CI Report
Powered by github-codebuild-logs, available on the AWS Serverless Application Repository |
What's new?
.scripts/gen.sh
- execute this to executegen
all modules, for cfn modules this will usually executecfn2ts
. This also means that you can use it to generate all required files to buildmonocdk
:cdk-build
will now execute the command specified in the packagescript.gen
directive.cdk-build.pre
- The commands in thepre
array are now concatenated using&&
.This PR includes changes to many files the majority of them are
package.json
files. Summary of changes:gen
as an npm script target to all cfn modules. Thegen
target is already used in our repo as a convention for executing pre build command for code generation. This change extends it to include executingcfn2ts
. Prior to this change we were executing thepre
commands incdk-build
, followed by executingcfn2ts
on cfn modules.cdk-build
now executegen
unless--skip-gen
is passed.cfn2ts
) were moved frompre
incdk-build
togen
. The only remainingpre
directives are those unrelated to code generation such as cleaning commands.Why?
This will allow us to execute
lerna run --stream gen
to execute all required code generation scripts on all modules.cfn2ts
script already includes the ability to auto detect the CloudFormation scope fromcdk-build
clause in thepackage.json
:aws-cdk/tools/cfn2ts/bin/cfn2ts.ts
Lines 43 to 46 in bc096f0
which makes it redundant to execute
cfn2ts --scope=scope
.gen
directive is now required in all cfn module, it was added tocfnspec
so it will be added to every new module.gen.sh
script inscripts
, executing it will buildcfn2ts
and then executelerna gen
. This is useful if one wants to only get the.generated
files without running a full build.This PR originally included the changes require to split the monocdk build, these were removed from this PR to make it easier to review. The monocdk build related changes will be submitted in a different PR.
By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license