in projenrc/build-workflow.ts [26:317]
public constructor(project: typescript.TypeScriptProject, opts: BuildWorkflowOptions = {}) {
const wf = project.github!.addWorkflow('build');
wf.on({
mergeGroup: {},
pullRequest: {},
workflowDispatch: {},
});
if (opts.defaultBranch !== null) {
wf.on({
push: {
branches: [opts.defaultBranch ?? 'main', 'maintenance/*'],
},
});
}
const nodeVersion = project.minNodeVersion?.split('.', 1).at(0) ?? 'lts/*';
wf.addJobs({
'build': {
env: { CI: 'true' },
outputs: {
'self-mutation-needed': {
stepId: 'self-mutation',
outputName: 'needed',
},
},
permissions: { contents: github.workflows.JobPermission.READ },
runsOn: ['ubuntu-latest'],
steps: [
{
name: 'Checkout',
uses: 'actions/checkout@v4',
},
{
name: 'Setup Node.js',
uses: 'actions/setup-node@v4',
with: {
'node-version': nodeVersion,
'cache': 'yarn',
},
},
{
name: 'Cache build outputs',
if: "github.event_name == 'pull_request'",
uses: 'actions/cache@v3',
with: {
'key':
"build-outputs-${{ hashFiles('tsconfig.json', 'build-tools/**/*.ts', 'src/**/*.ts', 'package.json', 'yarn.lock') }}",
'path': ['tsconfig.tsbuildinfo', 'lib/**/*'].join('\n'),
'restore-keys': 'build-outputs-',
},
},
{
name: 'Install dependencies',
run: 'yarn install --check-files',
},
{
name: 'compile',
run: ['npx projen', 'npx projen pre-compile', 'npx projen compile', 'npx projen post-compile'].join(' && '),
},
// Run tests to allow self-mutation to be performed if needed...
{ name: 'test', run: 'npx projen test' },
{
name: 'Find mutations',
id: 'self-mutation',
run: [
'git add .',
'git diff --staged --patch --exit-code > .repo.patch || echo "needed=true" >> $GITHUB_OUTPUT',
].join('\n'),
},
{
name: 'Upload patch',
if: 'steps.self-mutation.outputs.needed',
uses: 'actions/upload-artifact@v4.3.6',
with: {
name: '.repo.patch',
path: '.repo.patch',
overwrite: true,
},
},
{
name: 'Fail if self-mutation is needed',
if: 'steps.self-mutation.outputs.needed',
run: [
'echo "::error::Files were changed during build (see build log). If this was triggered from a fork, you will need to update your branch."',
'cat .repo.patch',
'exit 1',
].join('\n'),
},
{
name: 'Upload artifact',
uses: 'actions/upload-artifact@v4.3.6',
with: {
name: 'build-output',
path: [
'${{ github.workspace }}',
// Exclude node_modules to reduce artifact size (we won't use those anyway)...
'!${{ github.workspace }}/node_modules',
'!${{ github.workspace }}/fixtures/node_modules',
].join('\n'),
overwrite: true,
},
},
],
},
'self-mutation': {
env: { CI: 'true' },
needs: ['build'],
runsOn: ['ubuntu-latest'],
permissions: { contents: github.workflows.JobPermission.WRITE },
if: "always() && (github.event_name == 'pull_request') && needs.build.outputs.self-mutation-needed && (github.event.pull_request.head.repo.full_name == github.repository)",
steps: [
{
name: 'Checkout',
uses: 'actions/checkout@v4',
with: {
ref: '${{ github.event.pull_request.head.ref }}',
repository: '${{ github.event.pull_request.head.repo.full_name }}',
token: '${{ secrets.PROJEN_GITHUB_TOKEN }}',
},
},
{
name: 'Download patch',
uses: 'actions/download-artifact@v4',
with: {
name: '.repo.patch',
path: '${{ runner.temp }}',
},
},
{
name: 'Apply patch',
run: '[ -s ${{ runner.temp }}/.repo.patch ] && git apply ${{ runner.temp }}/.repo.patch || echo "Empty patch. Skipping."',
},
{
name: 'Set git identity',
run: ['git config user.name "github-actions"', 'git config user.email "github-actions@github.com"'].join(
'\n',
),
},
{
name: 'Push changes',
run: [
'git add .',
'git commit -s -m "chore: self-mutation"',
'git push origin HEAD:${{ github.event.pull_request.head.ref }}',
].join('\n'),
},
],
},
'matrix-test': {
env: { CI: 'true' },
if: 'success()',
strategy: {
failFast: false,
matrix: {
domain: {
'node-version': NodeRelease.ALL_RELEASES.flatMap((release) => {
if (!release.supported || isOdd(release.majorVersion)) {
return [];
}
return [`${release.majorVersion}.x`];
}),
},
},
},
name: 'test (node ${{ matrix.node-version }})',
needs: ['build'],
permissions: {},
runsOn: ['ubuntu-latest'],
steps: [
{
name: 'Download artifact',
uses: 'actions/download-artifact@v4',
with: { name: 'build-output', path: '${{ github.workspace }}' },
},
{
name: 'Setup Node.js',
uses: 'actions/setup-node@v4',
with: {
'node-version': '${{ matrix.node-version }}',
'cache': 'yarn',
},
},
{
name: 'Install dependencies',
run: 'yarn install --frozen-lockfile',
},
// Re-run post-compile to ensure /fixtures/ symlinks are correctly present...
{
name: 'Re-run post-compile',
run: 'npx projen post-compile',
},
{ name: 'Test', run: 'npx projen test' },
{
name: 'Assert clean working directory',
run: 'git diff --staged --exit-code',
},
],
},
'matrix-clear': {
// This is a simple "join target" to simplify branch protection rules.
env: { CI: 'true' },
name: 'Unit Tests',
needs: ['matrix-test'],
permissions: {},
runsOn: ['ubuntu-latest'],
if: 'always()',
steps: [
{
name: 'Build result',
run: 'echo ${{needs.matrix-test.result}}',
},
{
if: "${{ needs.matrix-test.result != 'success' }}",
name: 'Set status based on matrix build',
run: 'exit 1',
},
],
},
'package': {
env: { CI: 'true' },
name: 'package',
needs: ['build'],
permissions: {},
runsOn: ['ubuntu-latest'],
steps: [
{
name: 'Download artifact',
uses: 'actions/download-artifact@v4',
with: { name: 'build-output', path: '${{ github.workspace }}' },
},
{
name: 'Setup Node.js',
uses: 'actions/setup-node@v4',
with: {
'node-version': nodeVersion,
'cache': 'yarn',
},
},
{
name: 'Install dependencies',
run: 'yarn install --frozen-lockfile',
},
{
name: 'Package',
run: 'npx projen package',
},
{
name: 'Upload artifact',
uses: 'actions/upload-artifact@v4.3.6',
with: {
name: 'release-package',
path: '${{ github.workspace }}/dist',
overwrite: true,
},
},
],
},
});
if (opts.autoMerge ?? true) {
const autoMerge = project.github!.addWorkflow('auto-merge');
autoMerge.runName = 'Enable "Merge when ready" on PR #${{ github.event.number }}';
autoMerge.on({
pullRequestTarget: {
types: ['opened', 'reopened', 'ready_for_review'],
},
});
autoMerge.addJob('enable-auto-merge', {
env: { CI: 'true' },
name: 'Enable "Merge when ready" for this PR',
permissions: {
pullRequests: github.workflows.JobPermission.WRITE,
contents: github.workflows.JobPermission.WRITE,
},
runsOn: ['ubuntu-latest'],
steps: [
{
uses: 'peter-evans/enable-pull-request-automerge@v2',
with: {
'token': '${{ secrets.PROJEN_GITHUB_TOKEN }}',
'pull-request-number': '${{ github.event.number }}',
'merge-method': 'squash',
},
},
],
});
}
}