diff --git a/.carson/workspace.snapshot b/.carson/workspace.snapshot index 57ea6f04c..b18924edb 100644 Binary files a/.carson/workspace.snapshot and b/.carson/workspace.snapshot differ diff --git a/.changeset/brown-bananas-fry.md b/.changeset/brown-bananas-fry.md new file mode 100644 index 000000000..9b11ed553 --- /dev/null +++ b/.changeset/brown-bananas-fry.md @@ -0,0 +1,5 @@ +--- +'@jakubmazanec/carson-templates': minor +--- + +Adds support for Renovate bot to the GitHub workflows in `workspace` template. diff --git a/.github/workflows/pull-request.yaml b/.github/workflows/pull-request.yaml index 38aa48faa..bf6592e25 100644 --- a/.github/workflows/pull-request.yaml +++ b/.github/workflows/pull-request.yaml @@ -6,7 +6,8 @@ on: - development jobs: - pull_request_check: + check_pull_request: + name: Check pull request runs-on: ubuntu-latest timeout-minutes: 15 steps: @@ -15,6 +16,11 @@ jobs: token: ${{secrets.GITHUB_TOKEN}} fetch-depth: 0 + - name: Configure git + run: | + git config user.email "bot@mazanec.dev" + git config user.name "Bot" + - uses: actions/setup-node@v3 with: node-version: 16 @@ -23,6 +29,7 @@ jobs: run: npm ci - name: Check for changes + if: "github.actor != 'renovate[bot]'" run: | git config core.filemode false git_status=$(git status --porcelain) @@ -40,6 +47,7 @@ jobs: run: npm test - name: Check for changes + if: "github.actor != 'renovate[bot]'" run: | git config core.filemode false git_status=$(git status --porcelain) @@ -54,4 +62,5 @@ jobs: git config --unset core.filemode - name: Check for changesets + if: "github.actor != 'renovate[bot]'" run: npx changeset status --since=origin/development diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index cc4531a6c..5438df4ba 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -3,7 +3,7 @@ name: Release on: [push, workflow_dispatch] jobs: - main_branch_release: + release_main_branch: name: Main branch release runs-on: ubuntu-latest timeout-minutes: 15 @@ -39,7 +39,7 @@ jobs: if [[ -n $git_status ]]; then echo "You have uncommitted changes!" - git status --porcelain + git diff git config --unset core.filemode exit 1 fi @@ -56,7 +56,7 @@ jobs: if [[ -n $git_status ]]; then echo "You have uncommitted changes!" - git status --porcelain + git diff git config --unset core.filemode exit 1 fi @@ -127,7 +127,7 @@ jobs: git merge main --no-verify git push -u origin development --no-verify - development_branch_release: + release_development_branch: name: Development branch release runs-on: ubuntu-latest timeout-minutes: 15 @@ -163,7 +163,7 @@ jobs: if [[ -n $git_status ]]; then echo "You have uncommitted changes!" - git status --porcelain + git diff git config --unset core.filemode exit 1 fi @@ -180,7 +180,7 @@ jobs: if [[ -n $git_status ]]; then echo "You have uncommitted changes!" - git status --porcelain + git diff git config --unset core.filemode exit 1 fi @@ -220,11 +220,13 @@ jobs: NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} NPM_TOKEN: ${{ secrets.NPM_TOKEN }} - feature_branch_release: + release_feature_branch: name: Feature branch release runs-on: ubuntu-latest timeout-minutes: 15 - if: "github.ref_name != 'main' && github.ref_name != 'development'" + if: + "github.ref_name != 'main' && github.ref_name != 'development' && github.actor != + 'renovate[bot]'" steps: - name: Cancel previous runs uses: styfle/cancel-workflow-action@0.11.0 @@ -256,7 +258,7 @@ jobs: if [[ -n $git_status ]]; then echo "You have uncommitted changes!" - git status --porcelain + git diff git config --unset core.filemode exit 1 fi @@ -273,7 +275,7 @@ jobs: if [[ -n $git_status ]]; then echo "You have uncommitted changes!" - git status --porcelain + git diff git config --unset core.filemode exit 1 fi diff --git a/.github/workflows/generate-changeset.yaml b/.github/workflows/update-pull-request.yaml similarity index 76% rename from .github/workflows/generate-changeset.yaml rename to .github/workflows/update-pull-request.yaml index d366950ea..d317f0f42 100644 --- a/.github/workflows/generate-changeset.yaml +++ b/.github/workflows/update-pull-request.yaml @@ -1,29 +1,21 @@ -name: Generate changeset +name: Update pull request on: - workflow_dispatch: pull_request_target: - paths: - - '.github/workflows/renovate.yaml' - - '**/package.json' - - '**/package-lock.json' + branches: + - development jobs: - generate-changeset: - name: Generate changeset + update_pull_request: + name: Update pull request + if: github.actor == 'renovate[bot]' runs-on: ubuntu-latest timeout-minutes: 15 - if: github.actor == 'renovate[bot]' steps: - - name: Cancel previous runs - uses: styfle/cancel-workflow-action@0.11.0 - with: - access_token: ${{ secrets.GITHUB_TOKEN }} - - uses: actions/checkout@v3 with: ref: ${{ github.head_ref }} - token: ${{secrets.PAT}} + token: ${{secrets.GITHUB_TOKEN}} fetch-depth: 0 - name: Configure git @@ -31,8 +23,16 @@ jobs: git config user.email "bot@mazanec.dev" git config user.name "Bot" + - uses: actions/setup-node@v3 + with: + node-version: 16 + + - name: Install packages + run: npm ci + - name: Generate changeset uses: actions/github-script@v6 + if: ${{ github.actor == 'renovate[bot]' }} with: script: | let { promises: fs } = require('fs'); @@ -86,14 +86,6 @@ jobs: return bumps; } - let branch = await exec.getExecOutput('git branch --show-current'); - - if (!branch.stdout.startsWith('renovate/')) { - console.log('Not a renovate branch, skipping...'); - - return; - } - let diffOutput = await exec.getExecOutput('git diff --name-only HEAD~1'); let diffFiles = diffOutput.stdout.split('\n'); @@ -111,6 +103,11 @@ jobs: if (!packageNames.length) { console.log('No package.json changes to published packages, skipping...'); + await exec.exec('npx', ['changeset', '--empty']); + await exec.exec('git', ['add', './changeset/**', '--all']); + await exec.exec('git commit -m"Add changeset [skip actions]"'); + await exec.exec('git push --force'); + return; } @@ -121,6 +118,14 @@ jobs: let packageBumps = await getBumps(files); await createChangeset(fileName, packageBumps, packageNames); - await exec.exec('git', ['add', fileName]); - await exec.exec('git commit -C HEAD --amend --no-edit'); + await exec.exec('git', ['add', './changeset/**', '--all']); + await exec.exec('git commit -m"Add changeset [skip actions]"'); await exec.exec('git push --force'); + + - name: Update Carson + if: ${{ github.actor == 'renovate[bot]' }} + run: | + npm install + git add . --all + git commit -m"Run Carson update [skip actions]" + git push --force diff --git a/packages/carson-templates/templates/workspace/.github/workflows/pull-request.yaml.ejs b/packages/carson-templates/templates/workspace/.github/workflows/pull-request.yaml.ejs index 89e72e0d1..d855b2554 100644 --- a/packages/carson-templates/templates/workspace/.github/workflows/pull-request.yaml.ejs +++ b/packages/carson-templates/templates/workspace/.github/workflows/pull-request.yaml.ejs @@ -10,7 +10,8 @@ on: - development jobs: - pull_request_check: + check_pull_request: + name: Check pull request runs-on: ubuntu-latest timeout-minutes: 15 steps: @@ -19,6 +20,11 @@ jobs: token: ${{secrets.GITHUB_TOKEN}} fetch-depth: 0 + - name: Configure git + run: | + git config user.email "bot@mazanec.dev" + git config user.name "Bot" + - uses: actions/setup-node@v3 with: node-version: 16 @@ -27,6 +33,7 @@ jobs: run: npm ci - name: Check for changes + if: "github.actor != 'renovate[bot]'" run: | git config core.filemode false git_status=$(git status --porcelain) @@ -44,6 +51,7 @@ jobs: run: npm test - name: Check for changes + if: "github.actor != 'renovate[bot]'" run: | git config core.filemode false git_status=$(git status --porcelain) @@ -58,4 +66,5 @@ jobs: git config --unset core.filemode - name: Check for changesets - run: npx changeset status --since=origin/development + if: "github.actor != 'renovate[bot]'" + run: npx changeset status --since=origin/<%- getDevelopmentBranch(workspace) %> diff --git a/packages/carson-templates/templates/workspace/.github/workflows/release.yaml.ejs b/packages/carson-templates/templates/workspace/.github/workflows/release.yaml.ejs index 030cad65a..829f8502d 100644 --- a/packages/carson-templates/templates/workspace/.github/workflows/release.yaml.ejs +++ b/packages/carson-templates/templates/workspace/.github/workflows/release.yaml.ejs @@ -7,7 +7,7 @@ name: Release on: [push, workflow_dispatch] jobs: - main_branch_release: + release_main_branch: name: Main branch release runs-on: ubuntu-latest timeout-minutes: 15 @@ -43,7 +43,7 @@ jobs: if [[ -n $git_status ]]; then echo "You have uncommitted changes!" - git status --porcelain + git diff git config --unset core.filemode exit 1 fi @@ -60,7 +60,7 @@ jobs: if [[ -n $git_status ]]; then echo "You have uncommitted changes!" - git status --porcelain + git diff git config --unset core.filemode exit 1 fi @@ -131,7 +131,7 @@ jobs: git merge <%- getMainBranch(workspace) %> --no-verify git push -u origin <%- getDevelopmentBranch(workspace) %> --no-verify - development_branch_release: + release_development_branch: name: Development branch release runs-on: ubuntu-latest timeout-minutes: 15 @@ -167,7 +167,7 @@ jobs: if [[ -n $git_status ]]; then echo "You have uncommitted changes!" - git status --porcelain + git diff git config --unset core.filemode exit 1 fi @@ -184,7 +184,7 @@ jobs: if [[ -n $git_status ]]; then echo "You have uncommitted changes!" - git status --porcelain + git diff git config --unset core.filemode exit 1 fi @@ -224,11 +224,11 @@ jobs: NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} NPM_TOKEN: ${{ secrets.NPM_TOKEN }} - feature_branch_release: + release_feature_branch: name: Feature branch release runs-on: ubuntu-latest timeout-minutes: 15 - if: "github.ref_name != '<%- getMainBranch(workspace) %>' && github.ref_name != '<%- getDevelopmentBranch(workspace) %>'" + if: "github.ref_name != '<%- getMainBranch(workspace) %>' && github.ref_name != '<%- getDevelopmentBranch(workspace) %>' && github.actor != 'renovate[bot]'" steps: - name: Cancel previous runs uses: styfle/cancel-workflow-action@0.11.0 @@ -260,7 +260,7 @@ jobs: if [[ -n $git_status ]]; then echo "You have uncommitted changes!" - git status --porcelain + git diff git config --unset core.filemode exit 1 fi @@ -277,7 +277,7 @@ jobs: if [[ -n $git_status ]]; then echo "You have uncommitted changes!" - git status --porcelain + git diff git config --unset core.filemode exit 1 fi diff --git a/packages/carson-templates/templates/workspace/.github/workflows/update-pull-request.yaml.ejs b/packages/carson-templates/templates/workspace/.github/workflows/update-pull-request.yaml.ejs new file mode 100644 index 000000000..f2f6b9ed4 --- /dev/null +++ b/packages/carson-templates/templates/workspace/.github/workflows/update-pull-request.yaml.ejs @@ -0,0 +1,135 @@ +--- +to: '.github/workflows/update-pull-request.yaml' +strategy: overwrite +--- +name: Update pull request + +on: + pull_request_target: + branches: + - development + +jobs: + update_pull_request: + name: Update pull request + if: github.actor == 'renovate[bot]' + runs-on: ubuntu-latest + timeout-minutes: 15 + steps: + - uses: actions/checkout@v3 + with: + ref: ${{ github.head_ref }} + token: ${{secrets.GITHUB_TOKEN}} + fetch-depth: 0 + + - name: Configure git + run: | + git config user.email "bot@mazanec.dev" + git config user.name "Bot" + + - uses: actions/setup-node@v3 + with: + node-version: 16 + + - name: Install packages + run: npm ci + + - name: Generate changeset + uses: actions/github-script@v6 + if: ${{ github.actor == 'renovate[bot]' }} + with: + script: | + let { promises: fs } = require('fs'); + + async function getPackagesNames(files) { + let names = []; + + for (let file of files) { + let data = JSON.parse(await fs.readFile(file, 'utf8')); + + if (!data.private) { + names.push(data.name); + } + } + + return names; + } + + async function createChangeset(fileName, packageBumps, packages) { + let message = ''; + + for (let [packageName, bump] of packageBumps) { + message = + message + `Dependency \`${packageName}\` updated to \`${bump}\`.\n`; + } + + let header = packages + .map((packageName) => `'${packageName}': patch`) + .join('\n'); + + await fs.writeFile(fileName, `---\n${header}\n---\n${message.trim()}\n`); + } + + async function getBumps(files) { + let bumps = new Map(); + + for (let file of files) { + let { stdout: changes } = await exec.getExecOutput('git', ['show', file]); + + for (let change of changes.split('\n')) { + if (!change.startsWith('+ ')) { + continue; + } + + let match = change.match(/"(.*?)"/g); + + bumps.set(match[0].replace(/"/g, ''), match[1].replace(/"/g, '')); + } + } + + return bumps; + } + + let diffOutput = await exec.getExecOutput('git diff --name-only HEAD~1'); + let diffFiles = diffOutput.stdout.split('\n'); + + if (diffFiles.find((diffFile) => diffFile.startsWith('.changeset'))) { + console.log('Changeset already exists, skipping...'); + + return; + } + + let files = diffFiles + .filter((file) => file !== 'package.json') // skip root package.json + .filter((file) => file.includes('package.json')); + let packageNames = await getPackagesNames(files); + + if (!packageNames.length) { + console.log('No package.json changes to published packages, skipping...'); + + await exec.exec('npx', ['changeset', '--empty']); + await exec.exec('git', ['add', './changeset/**', '--all']); + await exec.exec('git commit -m"Add changeset [skip actions]"'); + await exec.exec('git push --force'); + + return; + } + + let { stdout: shortHash } = await exec.getExecOutput( + 'git rev-parse --short HEAD', + ); + let fileName = `.changeset/renovate-${shortHash.trim()}.md`; + let packageBumps = await getBumps(files); + + await createChangeset(fileName, packageBumps, packageNames); + await exec.exec('git', ['add', './changeset/**', '--all']); + await exec.exec('git commit -m"Add changeset [skip actions]"'); + await exec.exec('git push --force'); + + - name: Update Carson + if: ${{ github.actor == 'renovate[bot]' }} + run: | + npm install + git add . --all + git commit -m"Run Carson update [skip actions]" + git push --force