diff --git a/.github/workflows/sync_renovate-changesets.yaml b/.github/workflows/sync_renovate-changesets.yaml new file mode 100644 index 000000000..301a2dffd --- /dev/null +++ b/.github/workflows/sync_renovate-changesets.yaml @@ -0,0 +1,104 @@ +name: Sync Renovate changeset +on: + pull_request_target: + paths: + - '.github/workflows/sync_renovate-changesets.yml' + - '**/yarn.lock' + +jobs: + generate-changeset: + runs-on: ubuntu-latest + if: github.actor == 'renovate[bot]' && github.repository == 'kadel/backstage-showcase' + steps: + # - name: Generate token + # if: steps.command.outputs.command-name + # id: generate_token + # uses: tibdex/github-app-token@0d49dd721133f900ebd5e0dff2810704e8defbc6 # v1 + # with: + # app_id: ${{ vars.JANUS_IDP_GITHUB_APP_ID }} + # private_key: ${{ secrets.JANUS_IDP_GITHUB_APP_PRIVATE_KEY }} + - name: Checkout + uses: actions/checkout@v3 + with: + fetch-depth: 2 + ref: ${{ github.head_ref }} + #token: ${{ steps.generate_token.outputs.token }} + - name: Configure Git + run: | + git config --global user.email 139477802+janus-idp[bot]@users.noreply.github.com + git config --global user.name 'Janus IDP' + - name: Generate changeset + uses: actions/github-script@v6 + with: + script: | + const { promises: fs } = require("fs"); + // Parses package.json files and returns the package names + async function getPackagesNames(files) { + const names = []; + for (const file of files) { + const 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 (const [pkg, bump] of packageBumps) { + message = message + `Updated dependency \`${pkg}\` to \`${bump}\`.\n`; + } + + const pkgs = packages.map((pkg) => `'${pkg}': patch`).join("\n"); + const body = `---\n${pkgs}\n---\n\n${message.trim()}\n`; + await fs.writeFile(fileName, body); + } + + async function getBumps(files) { + const bumps = new Map(); + for (const file of files) { + const { stdout: changes } = await exec.getExecOutput("git", [ + "show", + file, + ]); + for (const change of changes.split("\n")) { + if (!change.startsWith("+ ")) { + continue; + } + const match = change.match(/"(.*?)"/g); + bumps.set(match[0].replace(/"/g, ""), match[1].replace(/"/g, "")); + } + } + return bumps; + } + + const branch = await exec.getExecOutput("git branch --show-current"); + if (!branch.stdout.startsWith("renovate/")) { + console.log("Not a renovate branch, skipping"); + return; + } + const diffOutput = await exec.getExecOutput("git diff --name-only HEAD~1"); + const diffFiles = diffOutput.stdout.split("\n"); + if (diffFiles.find((f) => f.startsWith(".changeset"))) { + console.log("Changeset already exists, skipping"); + return; + } + const files = diffFiles + .filter((file) => file !== "package.json") // skip root package.json + .filter((file) => file.includes("package.json")); + const packageNames = await getPackagesNames(files); + if (!packageNames.length) { + console.log("No package.json changes to published packages, skipping"); + return; + } + const { stdout: shortHash } = await exec.getExecOutput( + "git rev-parse --short HEAD" + ); + const fileName = `.changeset/renovate-${shortHash.trim()}.md`; + + const 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 push --force");