Collection of Projen project types for use with Pulumi
projen doesn't need to be installed. You will be using npx to run projen which takes care of all required setup steps.
To create a new project, run the following command and follow the instructions:
$ mkdir my-project
$ cd my-project
$ npx projen new --from @hallcor/pulumi-projen-project-types PROJECT-TYPE
🤖 Synthesizing project...
...Once your project is created, you can configure your project by editing
.projenrc.ts or .projenrc.py and re-running npx projen to synthesize again.
The files generated by projen are considered an "implementation detail" and projen protects them from being manually edited (most files are marked read-only, and an "anti tamper" check is configured in the CI build workflow to ensure that files are not updated during build).
For the TypeScript based projects the project commands can be viewed an run
using the package manager (e.g. yarn build, yarn package, etc). For
non-TypeScript based projects (i.e. Python) you can use projen to view and run
project commands.
Projen is built around a standard build process for all projects. Each project will have these standard tasks.
default: The "default" task that executes projen and synthesizes the projectpre-compile: Task that runs prior tocompilecompile: Compiles the project (e.g.tsc --buildfor TypeScript projects)post-compile: Task that runs aftercompiletest: Task that runs the project testspackage: Task that runs steps to package the project for publishing
There is also a standard build task the chains the above 6 tasks in order.
There is a great [tasks guide] where you can find more information on adding new tasks, editing existing tasks, etc.
List available commands
$ npx projen --help
projen [command]
Commands:
projen new [PROJECT-TYPE-NAME] [OPTIONS] Creates a new projen project
For a complete list of the available options for a specific project type, run:
projen new [PROJECT-TYPE-NAME] --help
projen build Full release build
projen bump Bumps version based on latest git tag and generates a changelog entry
projen clobber hard resets to HEAD of origin and cleans the local repo
projen compile Only compile
projen default Synthesize project files
projen dist
projen eject Remove projen from the project
projen install Install and upgrade dependencies
projen package Creates the distribution package
projen post-compile Runs after successful compilation
projen pre-compile Prepare the project for compilation
projen publish:git Prepends the release changelog onto the project changelog, creates a release commit, and tags the release
projen release Prepare a release from "main" branch
projen test Run tests
projen unbump Restores version to 0.0.0
projen completion generate completion script
Options:
--post Run post-synthesis steps such as installing dependencies. Use --no-post to skip [boolean] [default: true]
-w, --watch Keep running and resynthesize when projenrc changes [boolean] [default: false]
--debug Debug logs [boolean] [default: false]
--rc path to .projenrc.js file [deprecated] [string] [default: "/Users/chall/personal/pulumi-lambda-builders/.projenrc.js"]
--help Show help [boolean]
--version Show version number
Run a specific command
$ npx projen buildInspect a specific command
$ npx projen build -i
description: Full release build
- default
description: Synthesize project files
- exec: python .projenrc.py
- pre-compile
description: Prepare the project for compilation
- compile
description: Only compile
- post-compile
description: Runs after successful compilation
- test
description: Run tests
- exec: npm ci
- exec: pytest
- package
description: Creates the distribution package
- dist
- exec: mkdir -p dist
- exec: cp version.json dist/
- exec: git checkout version.jsonCurrently supported project types
PythonComponent: Creates a Pulumi Python Component projectTypeScriptComponent: Creates a Pulumi TypeScript Component project
$ mkdir my-python-component
$ cd my-python-component
$ npx projen new --from @hallcor/pulumi-projen-project-types python_componentfrom hallcor.pulumi_projen_project_types import PythonComponent
project = PythonComponent(
module_name="pulumi_lambda_builders",
component_name="lambda-builders",
name="pulumi-lambda-builders",
version="0.1.0",
deps=[
"aws_lambda_builders",
],
dev_deps=[
"pyfakefs",
"numpy",
"hallcor.pulumi-projen-project-types",
],
)
project.synth()- componentName
By default the
nameof the of the Pulumi component will be taken from the projectname. This can be overridden by using thecomponentNameproperty.
For a full list of input properties supported see the Input Property Reference
- pulumi_python_options
This can be used to override some of the default Pulumi options. For example you
can specify a specific version of
pulumito use.
project = PythonComponent(
...,
pulumi_python_options=PulumiPythonOptions(
pulumi_version=">=3.159 <4.0" # this is the default value
),
)For publishing related options see the publishing section
$ mkdir my-python-component
$ cd my-python-component
$ npx projen new --from @hallcor/pulumi-projen-project-types type_script_component --name my-componentimport { TypeScriptComponent } from '@hallcor/pulumi-projen-project-types';
const project = new TypeScriptComponent({
defaultReleaseBranch: 'main',
devDeps: [
'@hallcor/pulumi-projen-project-types',
],
name: 'my-component',
projenrcTs: true,
// deps: [], /* Runtime dependencies of this module. */
// description: undefined, /* The description is just a string that helps people understand the purpose of the package. */
// packageName: undefined, /* The "name" in package.json. */
});
project.synth();- TODO
The Pulumi Component project types also setup publishing workflows to publish git tags and GitHub releases. By default these will
Important
The publishing workflows rely on commit-and-tag-version which means your commits must follow Conventional Commits
- Create an annotated tag on push to the
mainbranch - Create a GitHub release for the tag when the tag is created
By default the project will publish a new tag on every commit to the main
branch. This can be configured via the releaseTrigger option.
scheduled: Run the release workflow on a schedulemanual: Creates a publish task which can be run locally to publish a tagcontinuous: Run the release workflow on every commit to themainbranch
On a schedule
new TypeScriptComponent({
...,
releaseTrigger: ReleaseTrigger.scheduled({ schedule: '0 0 * * 2' }), // run every tuesday
});Manual
new TypeScriptComponent({
...,
releaseTrigger: ReleaseTrigger.manual(),
});For the release workflow to create tags, specific credentials are needed.
By default it expects a GitHub secret variable named PROJEN_GITHUB_TOKEN with
read/write access to contents. A separate token from the builtin ${{ secrets.GITHUB_TOKEN }}
is needed in order to trigger the downstream release-github workflow.
This can be customized using the projenCredentials option.
From a different secret
new TypeScriptComponent({
...,
projenCredentials: GithubCredentials.fromPersonalAccessToken({ secret: 'MY_GITHUB_TOKEN' }),
});From a GitHub app
new TypeScriptComponent({
...,
projenCredentials: GithubCredentials.fromApp({
privateKeySecret: 'MY_GITHUB_APP_PRIVATE_KEY',
clientIdSecret: 'MY_GITHUB_APP_ID',
}),
});From a GitHub app via Pulumi ESC
new TypeScriptComponent({
...,
projenCredentials: GithubCredentials.fromApp({
clientIdSecret: 'MY_GITHUB_APP_ID',
privateKeySecret: 'MY_GITHUB_APP_PRIVATE_KEY',
pulumiEscSetup: PulumiEscSetup.fromOidcAuth({
environment: 'imports/github-secrets',
organization: 'pulumi',
requestedToken: PulumiToken.fromOrgToken(),
}),
}),
});When pulumiEscSetup is supplied to GithubCredentials.fromApp(...), the generated
GitHub App token step reads app-id and private-key from ESC step outputs using
the clientIdSecret and privateKeySecret names as output keys.
Use the PulumiEscSetup helper to add the pulumi/esc-action to generated workflows and control which secrets are exported. The helper keeps the step id stable (esc) so you can safely reference the action outputs from later steps.
Mapped exportEnvironmentVariables values are passed to the ESC action as a comma-delimited string.
exportEnvironmentVariables→export-environment-variablesversion→versioncloudUrl→cloud-urlkeys(deprecated) →keysand automatically setsexport-environment-variablestotruefor backward compatibility
Export specific mappings with passthrough
import { ExportEnvironmentVariables, PulumiEscSetup } from '@hallcor/pulumi-projen-project-types';
const esc = PulumiEscSetup.fromPersonalAccessToken({
environment: 'acme/catalog/prod',
exportEnvironmentVariables: ExportEnvironmentVariables.fromMapping([
'AWS_ACCESS_KEY_ID', // direct mapping
'CD_TOKEN=DEPLOY_TOKEN', // remap the ESC secret DEPLOY_TOKEN to CD_TOKEN
'*', // passthrough any remaining secrets
]),
});
project.github?.addWorkflow('deploy').addJobs({
deploy: {
runsOn: ['ubuntu-latest'],
steps: [
{ uses: 'actions/checkout@v4' },
...esc.setupSteps,
{ run: `echo "Deploy token is ${esc.output('CD_TOKEN')}"` },
],
},
});Pin ESC CLI version and use a custom Pulumi Cloud URL
const esc = PulumiEscSetup.fromPersonalAccessToken({
environment: 'acme/catalog/prod',
version: '0.10.0',
cloudUrl: 'https://api.enterprise.pulumi.com',
});Native OIDC authentication
import { JobPermission } from 'projen/lib/github/workflows-model';
const esc = PulumiEscSetup.fromOidcAuth({
environment: 'acme/catalog/prod',
organization: 'acme',
});
project.github?.addWorkflow('ci').addJobs({
build: {
permissions: { idToken: JobPermission.WRITE, contents: JobPermission.READ },
runsOn: ['ubuntu-latest'],
steps: [
{ uses: 'actions/checkout@v4' },
...esc.setupSteps,
{ run: 'echo "Pulumi token is available via esc outputs"' },
],
},
});Note
ESC step outputs are available as ${{ steps.esc.outputs.<KEY> }} or via PulumiEscSetup.output('<KEY>') when the helper is used. Existing workflows that still rely on the deprecated keys option continue to work, though new workflows should prefer exportEnvironmentVariables for fine-grained control.