diff --git a/.github/actions/emsdk-install/action.yml b/.github/actions/emsdk-install/action.yml new file mode 100644 index 0000000..0672f60 --- /dev/null +++ b/.github/actions/emsdk-install/action.yml @@ -0,0 +1,38 @@ +name: "emsdk install" +description: "Install emsdk with cache enabled" +inputs: + version: + description: "Emscripten version" + default: "4.0.23" + cache-folder: + description: "Cache folder" + default: "emsdk-cache" +runs: + using: "composite" + steps: + - name: Set up swap space + if: runner.os == 'Linux' + uses: pierotofy/set-swap-space@v1.0 + with: + swap-size-gb: 10 + + - name: Cache rotation keys + id: cache-rotation + shell: bash + run: | + echo "YEAR_MONTH=$(/bin/date -u "+%Y%m")" >> $GITHUB_OUTPUT + + - name: Setup emsdk cache + uses: actions/cache@v4 + with: + path: ${{ inputs.cache-folder }} + key: ${{ runner.os }}-emsdk-cache-${{ steps.cache-rotation.outputs.YEAR_MONTH }}-${{ inputs.version }} + restore-keys: | + ${{ runner.os }}-emsdk-cache-${{ steps.cache-rotation.outputs.YEAR_MONTH }}- + + - name: Install emsdk + uses: pyodide/setup-emsdk@v15 + with: + version: ${{ inputs.version }} + actions-cache-folder: ${{ inputs.cache-folder }} + cache-key: ${{ runner.os }}-emsdk-cache-${{ steps.cache-rotation.outputs.YEAR_MONTH }}-${{ inputs.version }} diff --git a/utils/actions/src/pnpm-install/action.yml b/.github/actions/pnpm-install/action.yml similarity index 100% rename from utils/actions/src/pnpm-install/action.yml rename to .github/actions/pnpm-install/action.yml diff --git a/.github/actions/prepare/action.yml b/.github/actions/prepare/action.yml new file mode 100644 index 0000000..934fd47 --- /dev/null +++ b/.github/actions/prepare/action.yml @@ -0,0 +1,38 @@ +name: prepare +description: Prepare action +inputs: + node-install: + description: Install node + default: "true" + pnpm-install: + description: Install pnpm depedencies + default: "true" + emsdk-install: + description: Install emscriptens + default: "true" + build: + description: Build packages + default: "true" +runs: + using: composite + steps: + - if: inputs.node-install == 'true' + name: Install Node.js v24 + uses: actions/setup-node@v6 + with: + node-version: 24 + package-manager-cache: false + registry-url: https://registry.npmjs.org + + - if: inputs.pnpm-install == 'true' + name: Install dependencies + uses: ./.github/actions/pnpm-install + + - if: inputs.emsdk-install == 'true' + name: Install emsdk + uses: ./.github/actions/emsdk-install + + - if: inputs.build == 'true' + name: Build packages + shell: bash + run: pnpm run build diff --git a/.github/workflows/label-sync.yml b/.github/workflows/label-sync.yml index 5a05edb..acece33 100644 --- a/.github/workflows/label-sync.yml +++ b/.github/workflows/label-sync.yml @@ -1,7 +1,5 @@ name: "Label sync" on: - schedule: - - cron: "0 0 * * *" workflow_dispatch: push: branches: @@ -18,7 +16,7 @@ jobs: if: github.repository_owner == 'NanoForge-dev' steps: - name: Checkout repository - uses: actions/checkout@v5 + uses: actions/checkout@v6 - name: Label sync uses: crazy-max/ghaction-github-labeler@v5 diff --git a/.github/workflows/pre-release.yml b/.github/workflows/pre-release.yml new file mode 100644 index 0000000..ae1a34b --- /dev/null +++ b/.github/workflows/pre-release.yml @@ -0,0 +1,59 @@ +name: Pre-Release + +on: + workflow_dispatch: + inputs: + package: + description: "The published name of a single package to release" + type: choice + required: true + options: + - "@nanoforge-dev/actions" + - "@nanoforge-dev/asset-manager" + - "@nanoforge-dev/common" + - "@nanoforge-dev/config" + - "@nanoforge-dev/core" + - "@nanoforge-dev/docgen" + - "@nanoforge-dev/ecs-client" + - "@nanoforge-dev/ecs-lib" + - "@nanoforge-dev/ecs-server" + - "@nanoforge-dev/graphics-2d" + - "@nanoforge-dev/input" + - "@nanoforge-dev/music" + - "@nanoforge-dev/network-client" + - "@nanoforge-dev/network-server" + - "@nanoforge-dev/sound" + - "@nanoforge-dev/utils-eslint-config" + - "@nanoforge-dev/utils-prettier-config" + version: + description: "New version of the package (leave empty for auto generated version)" + type: string + required: false + dry_run: + description: Perform a dry run? + type: boolean + default: false + +permissions: + contents: write + +jobs: + create-release-pr: + name: Create release pr + runs-on: ubuntu-latest + if: github.repository_owner == 'NanoForge-dev' + steps: + - name: Checkout repository + uses: actions/checkout@v6 + + - name: Prepare + uses: ./.github/actions/prepare + + - name: Release packages + uses: ./utils/actions/dist/create-release-pr + with: + package: ${{ inputs.package }} + version: ${{ inputs.version }} + dry: ${{ inputs.dry_run }} + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/release-tag.yml b/.github/workflows/release-tag.yml new file mode 100644 index 0000000..fa9f1c2 --- /dev/null +++ b/.github/workflows/release-tag.yml @@ -0,0 +1,31 @@ +name: Release + +on: + pull_request: + types: + - closed + branches: + - main + +permissions: + contents: write + +jobs: + create-release-tag: + name: Create release tag + runs-on: ubuntu-latest + if: github.repository_owner == 'NanoForge-dev' && github.event.pull_request.merged == true && startsWith(github.head_ref, 'releases/') + steps: + - name: Checkout repository + uses: actions/checkout@v6 + + - name: Prepare + uses: ./.github/actions/prepare + + - name: Create release tag + uses: ./utils/actions/dist/create-release-tag + with: + commit: ${{ github.sha }} + branch: ${{ github.head_ref }} + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index c57872d..97a6393 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -35,9 +35,6 @@ on: type: boolean default: false -env: - EM_CACHE_FOLDER: "emsdk-cache" - permissions: contents: write @@ -50,23 +47,8 @@ jobs: - name: Checkout repository uses: actions/checkout@v6 - - name: Install Node.js v24 - uses: actions/setup-node@v6 - with: - node-version: 24 - package-manager-cache: false - registry-url: https://registry.npmjs.org/ - - - name: Install dependencies - uses: ./utils/actions/src/pnpm-install - - - name: "Install emscipten" - uses: "mymindstorm/setup-emsdk@v14" - with: - actions-cache-folder: ${{env.EM_CACHE_FOLDER}} - - - name: Build dependencies - run: pnpm run build + - name: Prepare + uses: ./.github/actions/prepare - name: Release packages uses: ./utils/actions/dist/release-packages diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 1ffa176..f36664c 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -4,38 +4,20 @@ on: pull_request: branches: - main - - dev + push: + branches: + - main workflow_dispatch: -env: - EM_CACHE_FOLDER: "emsdk-cache" - jobs: - checkout: + tests: runs-on: ubuntu-latest steps: - - name: Checkout - uses: actions/checkout@v5 - - - name: "Setup pnpm" - uses: pnpm/action-setup@v4 - - - name: "Setup node" - uses: actions/setup-node@v4 - with: - node-version: 24.11.0 - cache: "pnpm" - - - name: "Install dependencies" - run: pnpm install - - - name: "Install emscipten" - uses: "mymindstorm/setup-emsdk@v14" - with: - actions-cache-folder: ${{env.EM_CACHE_FOLDER}} + - name: Checkout repository + uses: actions/checkout@v6 - - name: "Run build" - run: pnpm build + - name: Prepare + uses: ./.github/actions/prepare - name: "Run tests" run: pnpm test:unit diff --git a/example/pong-network/pnpm-lock.yaml b/example/pong-network/pnpm-lock.yaml index 6d69cea..2235fa1 100644 --- a/example/pong-network/pnpm-lock.yaml +++ b/example/pong-network/pnpm-lock.yaml @@ -113,7 +113,7 @@ importers: version: 5.9.3 vitest: specifier: ^4.0.15 - version: 4.0.15(@types/node@24.10.1)(yaml@2.8.2) + version: 4.0.15(@types/node@24.10.1)(terser@5.44.1)(yaml@2.8.2) ../../packages/common: devDependencies: @@ -263,7 +263,7 @@ importers: version: 5.9.3 vitest: specifier: ^4.0.15 - version: 4.0.15(@types/node@24.10.1)(yaml@2.8.2) + version: 4.0.15(@types/node@24.10.1)(terser@5.44.1)(yaml@2.8.2) ../../packages/ecs-lib: dependencies: @@ -300,7 +300,7 @@ importers: version: 5.9.3 vitest: specifier: ^4.0.15 - version: 4.0.15(@types/node@24.10.1)(yaml@2.8.2) + version: 4.0.15(@types/node@24.10.1)(terser@5.44.1)(yaml@2.8.2) ../../packages/ecs-server: dependencies: @@ -346,7 +346,7 @@ importers: version: 5.9.3 vitest: specifier: ^4.0.15 - version: 4.0.15(@types/node@24.10.1)(yaml@2.8.2) + version: 4.0.15(@types/node@24.10.1)(terser@5.44.1)(yaml@2.8.2) ../../packages/graphics-2d: dependencies: @@ -383,7 +383,7 @@ importers: version: 5.9.3 vitest: specifier: ^4.0.15 - version: 4.0.15(@types/node@24.10.1)(yaml@2.8.2) + version: 4.0.15(@types/node@24.10.1)(terser@5.44.1)(yaml@2.8.2) ../../packages/input: dependencies: @@ -455,9 +455,6 @@ importers: '@nanoforge-dev/config': specifier: workspace:^ version: link:../config - '@nanoforge-dev/ecs-client': - specifier: workspace:^ - version: link:../ecs-client devDependencies: '@favware/cliff-jumper': specifier: ^6.0.0 @@ -495,9 +492,6 @@ importers: '@nanoforge-dev/config': specifier: workspace:^ version: link:../config - '@nanoforge-dev/ecs-server': - specifier: workspace:^ - version: link:../ecs-server wrtc: specifier: ^0.4.7 version: 0.4.7 @@ -564,11 +558,60 @@ importers: specifier: ^5.9.3 version: 5.9.3 + ../../utils/actions: + dependencies: + '@actions/core': + specifier: ^2.0.1 + version: 2.0.2 + '@actions/github': + specifier: ^6.0.1 + version: 6.0.1 + commander: + specifier: ^14.0.2 + version: 14.0.2 + devDependencies: + '@favware/cliff-jumper': + specifier: ^6.0.0 + version: 6.0.0 + '@nanoforge-dev/utils-eslint-config': + specifier: workspace:^ + version: link:../eslint-config + '@nanoforge-dev/utils-prettier-config': + specifier: workspace:^ + version: link:../prettier-config + '@npm/types': + specifier: ^2.1.0 + version: 2.1.0 + '@trivago/prettier-plugin-sort-imports': + specifier: ^6.0.0 + version: 6.0.0(prettier@3.7.4) + '@types/bun': + specifier: ^1.3.5 + version: 1.3.5 + eslint: + specifier: ^9.39.1 + version: 9.39.1 + prettier: + specifier: ^3.6.2 + version: 3.7.4 + terser: + specifier: ^5.44.1 + version: 5.44.1 + tsup: + specifier: ^8.5.1 + version: 8.5.1(postcss@8.5.6)(typescript@5.9.3)(yaml@2.8.2) + typescript: + specifier: ^5.9.3 + version: 5.9.3 + ../../utils/eslint-config: dependencies: '@eslint/js': specifier: ^9.39.1 version: 9.39.1 + '@favware/cliff-jumper': + specifier: ^6.0.0 + version: 6.0.0 eslint-config-prettier: specifier: ^10.1.8 version: 10.1.8(eslint@9.39.1) @@ -603,6 +646,9 @@ importers: ../../utils/prettier-config: devDependencies: + '@favware/cliff-jumper': + specifier: ^6.0.0 + version: 6.0.0 '@trivago/prettier-plugin-sort-imports': specifier: ^6.0.0 version: 6.0.0(prettier@3.7.4) @@ -612,6 +658,24 @@ importers: packages: + '@actions/core@2.0.2': + resolution: {integrity: sha512-Ast1V7yHbGAhplAsuVlnb/5J8Mtr/Zl6byPPL+Qjq3lmfIgWF1ak1iYfF/079cRERiuTALTXkSuEUdZeDCfGtA==} + + '@actions/exec@2.0.0': + resolution: {integrity: sha512-k8ngrX2voJ/RIN6r9xB82NVqKpnMRtxDoiO+g3olkIUpQNqjArXrCQceduQZCQj3P3xm32pChRLqRrtXTlqhIw==} + + '@actions/github@6.0.1': + resolution: {integrity: sha512-xbZVcaqD4XnQAe35qSQqskb3SqIAfRyLBrHMd/8TuL7hJSz2QtbDwnNM8zWx4zO5l2fnGtseNE3MbEvD7BxVMw==} + + '@actions/http-client@2.2.3': + resolution: {integrity: sha512-mx8hyJi/hjFvbPokCg4uRd4ZX78t+YyRPtnKWwIl+RzNaVuFpQHfmlGVfsKEJN8LwTCvL+DfVgAM04XaHkm6bA==} + + '@actions/http-client@3.0.1': + resolution: {integrity: sha512-SbGS8c/vySbNO3kjFgSW77n83C4MQx/Yoe+b1hAdpuvfHxnkHzDq2pWljUpAA56Si1Gae/7zjeZsV0CYjmLo/w==} + + '@actions/io@2.0.0': + resolution: {integrity: sha512-Jv33IN09XLO+0HS79aaODsvIRyduiF7NY/F6LYeK5oeUmrsz7aFdRphQjFoESF4jS7lMauDOttKALcpapVDIAg==} + '@angular-devkit/core@21.0.2': resolution: {integrity: sha512-ePttMRRua9kv7df6fu2i5jTVJr5bzqwrKBBEtdXnWqOrYLUnU0G6XIpyGYVM6SyqpTwkTPlVsXZo5e8Lq356tg==} engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0, npm: ^6.11.0 || ^7.5.6 || >=8.0.0, yarn: '>= 1.13.0'} @@ -1042,6 +1106,10 @@ packages: resolution: {integrity: sha512-43/qtrDUokr7LJqoF2c3+RInu/t4zfrpYdoSDfYyhg52rwLV6TnOvdG4fXm7IkSB3wErkcmJS9iEhjVtOSEjjA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@fastify/busboy@2.1.1': + resolution: {integrity: sha512-vBZP4NlzfOlerQTnba4aqZoMhE/a9HY7HRqoOPaETQcSQuWEIyZMHGfVu6w9wGtGK5fED5qRs2DteVCjOH60sA==} + engines: {node: '>=14'} + '@favware/cliff-jumper@6.0.0': resolution: {integrity: sha512-9uXg/fGHFLh4AnG3HCtlrrrmDvUnmr5vrbs7H9pet3WlUCsGGGqeNT0bFb8LG0M0GatYUi9RM/F60p1yn2ndEA==} engines: {node: '>=v18'} @@ -1221,6 +1289,9 @@ packages: resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==} engines: {node: '>=6.0.0'} + '@jridgewell/source-map@0.3.11': + resolution: {integrity: sha512-ZMp1V8ZFcPG5dIWnQLr3NSI1MiCU7UETdS/A0G8V/XWHvJv3ZsFqutJn1Y5RPmAPX6F3BiE397OqveU/9NCuIA==} + '@jridgewell/sourcemap-codec@1.5.5': resolution: {integrity: sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==} @@ -1237,26 +1308,38 @@ packages: engines: {node: 24.11.1} hasBin: true - '@nanoforge-dev/loader-client@1.0.1': - resolution: {integrity: sha512-dPGmvAOSD9/Ypge8BNRBRRNPEDSwvwIYZ8BVOiwcz7A0n9mKkUPL2WfXuFoYPl3FBiiASM/soWYPjAjPQdIIwQ==} + '@nanoforge-dev/loader-client@1.1.0': + resolution: {integrity: sha512-i0WCutvQMGjFWrl4KFUBpt9EOaOdXOqP3ULQSkexWR2GvoavsKmuYlyAhnv6WA9WEXj7zPZr/FEi/7n459vyUA==} engines: {node: 24.11.0} - '@nanoforge-dev/loader-server@1.0.0': - resolution: {integrity: sha512-ssXzg9D+pWq2RiaBTcSvfLWTJW11AaYX/KUYdw42iI3pgVASFK1IlzFpijrsHvkT2An7fk5dUYrQMgXKYuhdIw==} + '@nanoforge-dev/loader-server@1.1.0': + resolution: {integrity: sha512-U+AOZIzzCb3VPPkGR3OpUpAm97xEyndDXLHH/XA+XZMlPHx6h3n8hA7sJnN4szPqx5CQR8ssgnpwdgnI6lwNWQ==} engines: {node: 24.11.0} - '@nanoforge-dev/loader-website@1.0.0': - resolution: {integrity: sha512-0667VNh91NM7/3EhXitiuZ1rLljbjOkHU3fRLSCa9R9IIn9tpaoELh5Uj66jj1GQHsbFMSgGgysWf0SaeEdMeQ==} + '@nanoforge-dev/loader-website@1.1.0': + resolution: {integrity: sha512-6taExH65vAfUpIVrWSzPzLsGkdXcdREjOjvgY4vOwXet3JXRtA6+yHjqp2kVg9Yrp+OA3iUPNXOsLRXOrfNVJw==} engines: {node: 24.11.0} '@nanoforge-dev/schematics@1.0.2': resolution: {integrity: sha512-vQ/b6GvNJZGNzsQMbTSPeZqVlVoy2tr4N5ESMkifdW12yvolXGhJgrZ/gBXvLVISM5wPORDsdx0W2S8j3hvoBQ==} engines: {node: 24.11.1} + '@npm/types@2.1.0': + resolution: {integrity: sha512-humQVe2BrWR7Yum5hGDYBnIPnnZJvKSOH/I4QN1ZL2bdb4c4zQHaHupEJ3cOkSJ07G3YfN793ptbNh196BWLgA==} + engines: {node: '>=18.6.0'} + + '@octokit/auth-token@4.0.0': + resolution: {integrity: sha512-tY/msAuJo6ARbK6SPIxZrPBms3xPbfwBrulZe0Wtr/DIY9lje2HeV1uoebShn6mx7SjCHif6EjMvoREj+gZ+SA==} + engines: {node: '>= 18'} + '@octokit/auth-token@5.1.2': resolution: {integrity: sha512-JcQDsBdg49Yky2w2ld20IHAlwr8d/d8N6NiOXbtuoPCqzbsiJgF633mVUw3x4mo0H5ypataQIX7SFu3yy44Mpw==} engines: {node: '>= 18'} + '@octokit/core@5.2.2': + resolution: {integrity: sha512-/g2d4sW9nUDJOMz3mabVQvOGhVa4e/BN/Um7yca9Bb2XTzPPnfTWHWQg+IsEYO7M3Vx+EXvaM/I2pJWIMun1bg==} + engines: {node: '>= 18'} + '@octokit/core@6.1.6': resolution: {integrity: sha512-kIU8SLQkYWGp3pVKiYzA5OSaNF5EE03P/R8zEmmrG6XwOg5oBjXyQVVIauQ0dgau4zYhpZEhJrvIYt6oM+zZZA==} engines: {node: '>= 18'} @@ -1265,27 +1348,67 @@ packages: resolution: {integrity: sha512-OlYOlZIsfEVZm5HCSR8aSg02T2lbUWOsCQoPKfTXJwDzcHQBrVBGdGXb89dv2Kw2ToZaRtudp8O3ZIYoaOjKlA==} engines: {node: '>= 18'} + '@octokit/endpoint@9.0.6': + resolution: {integrity: sha512-H1fNTMA57HbkFESSt3Y9+FBICv+0jFceJFPWDePYlR/iMGrwM5ph+Dd4XRQs+8X+PUFURLQgX9ChPfhJ/1uNQw==} + engines: {node: '>= 18'} + + '@octokit/graphql@7.1.1': + resolution: {integrity: sha512-3mkDltSfcDUoa176nlGoA32RGjeWjl3K7F/BwHwRMJUW/IteSa4bnSV8p2ThNkcIcZU2umkZWxwETSSCJf2Q7g==} + engines: {node: '>= 18'} + '@octokit/graphql@8.2.2': resolution: {integrity: sha512-Yi8hcoqsrXGdt0yObxbebHXFOiUA+2v3n53epuOg1QUgOB6c4XzvisBNVXJSl8RYA5KrDuSL2yq9Qmqe5N0ryA==} engines: {node: '>= 18'} + '@octokit/openapi-types@20.0.0': + resolution: {integrity: sha512-EtqRBEjp1dL/15V7WiX5LJMIxxkdiGJnabzYx5Apx4FkQIFgAfKumXeYAqqJCj1s+BMX4cPFIFC4OLCR6stlnA==} + + '@octokit/openapi-types@24.2.0': + resolution: {integrity: sha512-9sIH3nSUttelJSXUrmGzl7QUBFul0/mB8HRYl3fOlgHbIWG+WnYDXU3v/2zMtAvuzZ/ed00Ei6on975FhBfzrg==} + '@octokit/openapi-types@25.1.0': resolution: {integrity: sha512-idsIggNXUKkk0+BExUn1dQ92sfysJrje03Q0bv0e+KPLrvyqZF8MnBpFz8UNfYDwB3Ie7Z0TByjWfzxt7vseaA==} + '@octokit/plugin-paginate-rest@9.2.2': + resolution: {integrity: sha512-u3KYkGF7GcZnSD/3UP0S7K5XUFT2FkOQdcfXZGZQPGv3lm4F2Xbf71lvjldr8c1H3nNbF+33cLEkWYbokGWqiQ==} + engines: {node: '>= 18'} + peerDependencies: + '@octokit/core': '5' + + '@octokit/plugin-rest-endpoint-methods@10.4.1': + resolution: {integrity: sha512-xV1b+ceKV9KytQe3zCVqjg+8GTGfDYwaT1ATU5isiUyVtlVAO3HNdzpS4sr4GBx4hxQ46s7ITtZrAsxG22+rVg==} + engines: {node: '>= 18'} + peerDependencies: + '@octokit/core': '5' + '@octokit/plugin-retry@7.2.1': resolution: {integrity: sha512-wUc3gv0D6vNHpGxSaR3FlqJpTXGWgqmk607N9L3LvPL4QjaxDgX/1nY2mGpT37Khn+nlIXdljczkRnNdTTV3/A==} engines: {node: '>= 18'} peerDependencies: '@octokit/core': '>=6' + '@octokit/request-error@5.1.1': + resolution: {integrity: sha512-v9iyEQJH6ZntoENr9/yXxjuezh4My67CBSu9r6Ve/05Iu5gNgnisNWOsoJHTP6k0Rr0+HQIpnH+kyammu90q/g==} + engines: {node: '>= 18'} + '@octokit/request-error@6.1.8': resolution: {integrity: sha512-WEi/R0Jmq+IJKydWlKDmryPcmdYSVjL3ekaiEL1L9eo1sUnqMJ+grqmC9cjk7CA7+b2/T397tO5d8YLOH3qYpQ==} engines: {node: '>= 18'} + '@octokit/request@8.4.1': + resolution: {integrity: sha512-qnB2+SY3hkCmBxZsR/MPCybNmbJe4KAlfWErXq+rBKkQJlbjdJeS85VI9r8UqeLYLvnAenU8Q1okM/0MBsAGXw==} + engines: {node: '>= 18'} + '@octokit/request@9.2.4': resolution: {integrity: sha512-q8ybdytBmxa6KogWlNa818r0k1wlqzNC+yNkcQDECHvQo8Vmstrg18JwqJHdJdUiHD2sjlwBgSm9kHkOKe2iyA==} engines: {node: '>= 18'} + '@octokit/types@12.6.0': + resolution: {integrity: sha512-1rhSOfRa6H9w4YwK0yrf5faDaDTb+yLyBUKOCV4xtCDB5VmIPqd/v9yr9o6SAzOAlRxMiRiCic6JVM1/kunVkw==} + + '@octokit/types@13.10.0': + resolution: {integrity: sha512-ifLaO34EbbPj0Xgro4G5lP5asESjwHracYJvVaPIyXMuiuXLlhic3S47cBdTb+jfODkTE5YtGCLt3Ay3+J97sA==} + '@octokit/types@14.1.0': resolution: {integrity: sha512-1y6DgTy8Jomcpu33N+p5w58l6xyt55Ar2I91RPiIA0xCJBXyUAhXCcmZaDWSANiha7R9a6qJJ2CRomGPZ6f46g==} @@ -1499,6 +1622,9 @@ packages: svelte: optional: true + '@types/bun@1.3.5': + resolution: {integrity: sha512-RnygCqNrd3srIPEWBd5LFeUYG7plCoH2Yw9WaZGyNmdTEei+gWaHqydbaIRkIkcbXwhBT94q78QljxN0Sk838w==} + '@types/chai@5.2.3': resolution: {integrity: sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA==} @@ -1687,6 +1813,9 @@ packages: balanced-match@1.0.2: resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} + before-after-hook@2.2.3: + resolution: {integrity: sha512-NzUnlZexiaH/46WDhANlyR2bXRopNg4F/zuSA3OpZnllCUgRaOF2znDioDWrmbNVsuZk6l9pMquQB38cfBZwkQ==} + before-after-hook@3.0.2: resolution: {integrity: sha512-Nik3Sc0ncrMK4UUdXQmAnRtzmNQTAAXmXIopizwZ1W1t8QmfJj+zL4OA2I7XPTPW5z5TDqv4hRo/JzouDJnX3A==} @@ -1703,6 +1832,12 @@ packages: resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} engines: {node: '>=8'} + buffer-from@1.1.2: + resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==} + + bun-types@1.3.5: + resolution: {integrity: sha512-inmAYe2PFLs0SUbFOWSVD24sg1jFlMPxOjOSSCYqUgn4Hsc3rDc7dFvfVYjFPNHtov6kgUeulV4SxbuIV/stPw==} + bun@1.3.4: resolution: {integrity: sha512-xV6KgD5ImquuKsoghzbWmYzeCXmmSgN6yJGz444hri2W+NGKNRFUNrEhy9+/rRXbvNA2qF0K0jAwqFNy1/GhBg==} cpu: [arm64, x64] @@ -1794,6 +1929,9 @@ packages: resolution: {integrity: sha512-TywoWNNRbhoD0BXs1P3ZEScW8W5iKrnbithIl0YH+uCmBd0QpPOA8yc82DS3BIE5Ma6FnBVUsJ7wVUDz4dvOWQ==} engines: {node: '>=20'} + commander@2.20.3: + resolution: {integrity: sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==} + commander@4.1.1: resolution: {integrity: sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==} engines: {node: '>= 6'} @@ -1842,6 +1980,9 @@ packages: deep-is@0.1.4: resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} + deprecation@2.3.1: + resolution: {integrity: sha512-xmHIy4F3scKVwMsQ4WnVaS8bHOx0DmVwRywosKhaILI0ywMDWPtBSku2HNxRvF7jtwDRsoEwYQSfbxj8b7RlJQ==} + detect-libc@2.1.2: resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==} engines: {node: '>=8'} @@ -2343,6 +2484,9 @@ packages: obug@2.1.1: resolution: {integrity: sha512-uTqF9MuPraAQ+IsnPf366RG4cP9RtUi7MLO1N3KEc+wb0a6yKpeL0lmk2IB1jY5KHPAlTc6T/JRdC/YqxHNwkQ==} + once@1.4.0: + resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} + onetime@7.0.0: resolution: {integrity: sha512-VXJjc87FScF88uafS3JllDgvAm+c/Slfz06lorj2uAY34rlUu0Nt+v8wreiImcrgAjjIHp1rXpTDlLOGw29WwQ==} engines: {node: '>=18'} @@ -2535,6 +2679,13 @@ packages: resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} engines: {node: '>=0.10.0'} + source-map-support@0.5.21: + resolution: {integrity: sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==} + + source-map@0.6.1: + resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==} + engines: {node: '>=0.10.0'} + source-map@0.7.6: resolution: {integrity: sha512-i5uvt8C3ikiWeNZSVZNWcfZPItFQOsYTUAOkcUPGd8DqDy1uOUikjt5dG+uRlwyvR108Fb9DOd4GvXfT0N2/uQ==} engines: {node: '>= 12'} @@ -2606,6 +2757,11 @@ packages: resolution: {integrity: sha512-7NyxrTE4Anh8km8iEy7o0QYPs+0JKBTj5ZaqHg6B39erLg0qYXN3BijtShwbsNSvQ+LN75+KV+C4QR/f6Gwnpg==} engines: {node: '>=18'} + terser@5.44.1: + resolution: {integrity: sha512-t/R3R/n0MSwnnazuPpPNVO60LX0SKL45pyl9YlvxIdkH0Of7D5qM2EVe+yASRIlY5pZ73nclYJfNANGWPwFDZw==} + engines: {node: '>=10'} + hasBin: true + thenify-all@1.6.0: resolution: {integrity: sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==} engines: {node: '>=0.8'} @@ -2673,6 +2829,10 @@ packages: typescript: optional: true + tunnel@0.0.6: + resolution: {integrity: sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg==} + engines: {node: '>=0.6.11 <=0.7.0 || >=0.7.3'} + type-check@0.4.0: resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} engines: {node: '>= 0.8.0'} @@ -2695,6 +2855,10 @@ packages: undici-types@7.16.0: resolution: {integrity: sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==} + undici@5.29.0: + resolution: {integrity: sha512-raqeBD6NQK4SkWhQzeYKd1KmIG6dllBOTt55Rmkt4HtI9mwdWtJljnrXjAFUBLTSN67HWrOIZ3EPF4kjUw80Bg==} + engines: {node: '>=14.0'} + unicode-emoji-modifier-base@1.0.0: resolution: {integrity: sha512-yLSH4py7oFH3oG/9K+XWrz1pSi3dfUrWEnInbxMfArOfc1+33BlGPQtLsOYwvdMy11AwUBetYuaRxSPqgkq+8g==} engines: {node: '>=4'} @@ -2703,6 +2867,9 @@ packages: resolution: {integrity: sha512-+QBBXBCvifc56fsbuxZQ6Sic3wqqc3WWaqxs58gvJrcOuN83HGTCwz3oS5phzU9LthRNE9VrJCFCLUgHeeFnfA==} engines: {node: '>=18'} + universal-user-agent@6.0.1: + resolution: {integrity: sha512-yCzhz6FN2wU1NiiQRogkTQszlQSlpWaw8SvVegAc+bDxbzHgh1vX8uIe8OYyMH6DwH+sdTJsgMl36+mSMdRJIQ==} + universal-user-agent@7.0.3: resolution: {integrity: sha512-TmnEAEAsBJVZM/AADELsK76llnwcf9vMKuPz8JflO1frO8Lchitr0fNaN9d+Ap0BjKtqWqd/J17qeDnXh8CL2A==} @@ -2818,6 +2985,9 @@ packages: resolution: {integrity: sha512-42AtmgqjV+X1VpdOfyTGOYRi0/zsoLqtXQckTmqTeybT+BDIbM/Guxo7x3pE2vtpr1ok6xRqM9OpBe+Jyoqyww==} engines: {node: '>=18'} + wrappy@1.0.2: + resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} + wrtc@0.4.7: resolution: {integrity: sha512-P6Hn7VT4lfSH49HxLHcHhDq+aFf/jd9dPY7lDHeFhZ22N3858EKuwm2jmnlPzpsRGEPaoF6XwkcxY5SYnt4f/g==} engines: {node: ^8.11.2 || >=10.0.0} @@ -2863,6 +3033,37 @@ packages: snapshots: + '@actions/core@2.0.2': + dependencies: + '@actions/exec': 2.0.0 + '@actions/http-client': 3.0.1 + + '@actions/exec@2.0.0': + dependencies: + '@actions/io': 2.0.0 + + '@actions/github@6.0.1': + dependencies: + '@actions/http-client': 2.2.3 + '@octokit/core': 5.2.2 + '@octokit/plugin-paginate-rest': 9.2.2(@octokit/core@5.2.2) + '@octokit/plugin-rest-endpoint-methods': 10.4.1(@octokit/core@5.2.2) + '@octokit/request': 8.4.1 + '@octokit/request-error': 5.1.1 + undici: 5.29.0 + + '@actions/http-client@2.2.3': + dependencies: + tunnel: 0.0.6 + undici: 5.29.0 + + '@actions/http-client@3.0.1': + dependencies: + tunnel: 0.0.6 + undici: 5.29.0 + + '@actions/io@2.0.0': {} + '@angular-devkit/core@21.0.2(chokidar@4.0.3)': dependencies: ajv: 8.17.1 @@ -3161,6 +3362,8 @@ snapshots: '@eslint/core': 0.17.0 levn: 0.4.1 + '@fastify/busboy@2.1.1': {} + '@favware/cliff-jumper@6.0.0': dependencies: '@favware/colorette-spinner': 1.0.1 @@ -3344,6 +3547,11 @@ snapshots: '@jridgewell/resolve-uri@3.1.2': {} + '@jridgewell/source-map@0.3.11': + dependencies: + '@jridgewell/gen-mapping': 0.3.13 + '@jridgewell/trace-mapping': 0.3.31 + '@jridgewell/sourcemap-codec@1.5.5': {} '@jridgewell/trace-mapping@0.3.31': @@ -3369,8 +3577,8 @@ snapshots: '@angular-devkit/schematics': 21.0.2(chokidar@4.0.3) '@angular-devkit/schematics-cli': 21.0.2(@types/node@24.10.1)(chokidar@4.0.3) '@inquirer/prompts': 7.10.1(@types/node@24.10.1) - '@nanoforge-dev/loader-client': 1.0.1 - '@nanoforge-dev/loader-server': 1.0.0 + '@nanoforge-dev/loader-client': 1.1.0 + '@nanoforge-dev/loader-server': 1.1.0 '@nanoforge-dev/schematics': 1.0.2(chokidar@4.0.3) ansis: 4.2.0 chokidar: 4.0.3 @@ -3384,14 +3592,14 @@ snapshots: transitivePeerDependencies: - '@types/node' - '@nanoforge-dev/loader-client@1.0.1': + '@nanoforge-dev/loader-client@1.1.0': dependencies: - '@nanoforge-dev/loader-website': 1.0.0 + '@nanoforge-dev/loader-website': 1.1.0 bun: 1.3.4 - '@nanoforge-dev/loader-server@1.0.0': {} + '@nanoforge-dev/loader-server@1.1.0': {} - '@nanoforge-dev/loader-website@1.0.0': {} + '@nanoforge-dev/loader-website@1.1.0': {} '@nanoforge-dev/schematics@1.0.2(chokidar@4.0.3)': dependencies: @@ -3400,8 +3608,22 @@ snapshots: transitivePeerDependencies: - chokidar + '@npm/types@2.1.0': {} + + '@octokit/auth-token@4.0.0': {} + '@octokit/auth-token@5.1.2': {} + '@octokit/core@5.2.2': + dependencies: + '@octokit/auth-token': 4.0.0 + '@octokit/graphql': 7.1.1 + '@octokit/request': 8.4.1 + '@octokit/request-error': 5.1.1 + '@octokit/types': 13.10.0 + before-after-hook: 2.2.3 + universal-user-agent: 6.0.1 + '@octokit/core@6.1.6': dependencies: '@octokit/auth-token': 5.1.2 @@ -3417,14 +3639,39 @@ snapshots: '@octokit/types': 14.1.0 universal-user-agent: 7.0.3 + '@octokit/endpoint@9.0.6': + dependencies: + '@octokit/types': 13.10.0 + universal-user-agent: 6.0.1 + + '@octokit/graphql@7.1.1': + dependencies: + '@octokit/request': 8.4.1 + '@octokit/types': 13.10.0 + universal-user-agent: 6.0.1 + '@octokit/graphql@8.2.2': dependencies: '@octokit/request': 9.2.4 '@octokit/types': 14.1.0 universal-user-agent: 7.0.3 + '@octokit/openapi-types@20.0.0': {} + + '@octokit/openapi-types@24.2.0': {} + '@octokit/openapi-types@25.1.0': {} + '@octokit/plugin-paginate-rest@9.2.2(@octokit/core@5.2.2)': + dependencies: + '@octokit/core': 5.2.2 + '@octokit/types': 12.6.0 + + '@octokit/plugin-rest-endpoint-methods@10.4.1(@octokit/core@5.2.2)': + dependencies: + '@octokit/core': 5.2.2 + '@octokit/types': 12.6.0 + '@octokit/plugin-retry@7.2.1(@octokit/core@6.1.6)': dependencies: '@octokit/core': 6.1.6 @@ -3432,10 +3679,23 @@ snapshots: '@octokit/types': 14.1.0 bottleneck: 2.19.5 + '@octokit/request-error@5.1.1': + dependencies: + '@octokit/types': 13.10.0 + deprecation: 2.3.1 + once: 1.4.0 + '@octokit/request-error@6.1.8': dependencies: '@octokit/types': 14.1.0 + '@octokit/request@8.4.1': + dependencies: + '@octokit/endpoint': 9.0.6 + '@octokit/request-error': 5.1.1 + '@octokit/types': 13.10.0 + universal-user-agent: 6.0.1 + '@octokit/request@9.2.4': dependencies: '@octokit/endpoint': 10.1.4 @@ -3444,6 +3704,14 @@ snapshots: fast-content-type-parse: 2.0.1 universal-user-agent: 7.0.3 + '@octokit/types@12.6.0': + dependencies: + '@octokit/openapi-types': 20.0.0 + + '@octokit/types@13.10.0': + dependencies: + '@octokit/openapi-types': 24.2.0 + '@octokit/types@14.1.0': dependencies: '@octokit/openapi-types': 25.1.0 @@ -3575,6 +3843,10 @@ snapshots: transitivePeerDependencies: - supports-color + '@types/bun@1.3.5': + dependencies: + bun-types: 1.3.5 + '@types/chai@5.2.3': dependencies: '@types/deep-eql': 4.0.2 @@ -3704,13 +3976,13 @@ snapshots: chai: 6.2.1 tinyrainbow: 3.0.3 - '@vitest/mocker@4.0.15(vite@7.2.7(@types/node@24.10.1)(yaml@2.8.2))': + '@vitest/mocker@4.0.15(vite@7.2.7(@types/node@24.10.1)(terser@5.44.1)(yaml@2.8.2))': dependencies: '@vitest/spy': 4.0.15 estree-walker: 3.0.3 magic-string: 0.30.21 optionalDependencies: - vite: 7.2.7(@types/node@24.10.1)(yaml@2.8.2) + vite: 7.2.7(@types/node@24.10.1)(terser@5.44.1)(yaml@2.8.2) '@vitest/pretty-format@4.0.15': dependencies: @@ -3788,6 +4060,8 @@ snapshots: balanced-match@1.0.2: {} + before-after-hook@2.2.3: {} + before-after-hook@3.0.2: {} bottleneck@2.19.5: {} @@ -3805,6 +4079,12 @@ snapshots: dependencies: fill-range: 7.1.1 + buffer-from@1.1.2: {} + + bun-types@1.3.5: + dependencies: + '@types/node': 24.10.1 + bun@1.3.4: optionalDependencies: '@oven/bun-darwin-aarch64': 1.3.4 @@ -3886,6 +4166,8 @@ snapshots: commander@14.0.2: {} + commander@2.20.3: {} + commander@4.1.1: {} concat-map@0.0.1: {} @@ -3922,6 +4204,8 @@ snapshots: deep-is@0.1.4: {} + deprecation@2.3.1: {} + detect-libc@2.1.2: {} domexception@1.0.1: @@ -4441,6 +4725,10 @@ snapshots: obug@2.1.1: {} + once@1.4.0: + dependencies: + wrappy: 1.0.2 + onetime@7.0.0: dependencies: mimic-function: 5.0.1 @@ -4617,6 +4905,13 @@ snapshots: source-map-js@1.2.1: {} + source-map-support@0.5.21: + dependencies: + buffer-from: 1.1.2 + source-map: 0.6.1 + + source-map@0.6.1: {} + source-map@0.7.6: {} stackback@0.0.2: {} @@ -4689,6 +4984,13 @@ snapshots: minizlib: 3.1.0 yallist: 5.0.0 + terser@5.44.1: + dependencies: + '@jridgewell/source-map': 0.3.11 + acorn: 8.15.0 + commander: 2.20.3 + source-map-support: 0.5.21 + thenify-all@1.6.0: dependencies: thenify: 3.3.1 @@ -4754,6 +5056,8 @@ snapshots: - tsx - yaml + tunnel@0.0.6: {} + type-check@0.4.0: dependencies: prelude-ls: 1.2.1 @@ -4775,10 +5079,16 @@ snapshots: undici-types@7.16.0: {} + undici@5.29.0: + dependencies: + '@fastify/busboy': 2.1.1 + unicode-emoji-modifier-base@1.0.0: {} unicorn-magic@0.3.0: {} + universal-user-agent@6.0.1: {} + universal-user-agent@7.0.3: {} uri-js@4.4.1: @@ -4787,7 +5097,7 @@ snapshots: validator@13.15.23: {} - vite@7.2.7(@types/node@24.10.1)(yaml@2.8.2): + vite@7.2.7(@types/node@24.10.1)(terser@5.44.1)(yaml@2.8.2): dependencies: esbuild: 0.25.12 fdir: 6.5.0(picomatch@4.0.3) @@ -4798,12 +5108,13 @@ snapshots: optionalDependencies: '@types/node': 24.10.1 fsevents: 2.3.3 + terser: 5.44.1 yaml: 2.8.2 - vitest@4.0.15(@types/node@24.10.1)(yaml@2.8.2): + vitest@4.0.15(@types/node@24.10.1)(terser@5.44.1)(yaml@2.8.2): dependencies: '@vitest/expect': 4.0.15 - '@vitest/mocker': 4.0.15(vite@7.2.7(@types/node@24.10.1)(yaml@2.8.2)) + '@vitest/mocker': 4.0.15(vite@7.2.7(@types/node@24.10.1)(terser@5.44.1)(yaml@2.8.2)) '@vitest/pretty-format': 4.0.15 '@vitest/runner': 4.0.15 '@vitest/snapshot': 4.0.15 @@ -4820,7 +5131,7 @@ snapshots: tinyexec: 1.0.2 tinyglobby: 0.2.15 tinyrainbow: 3.0.3 - vite: 7.2.7(@types/node@24.10.1)(yaml@2.8.2) + vite: 7.2.7(@types/node@24.10.1)(terser@5.44.1)(yaml@2.8.2) why-is-node-running: 2.3.0 optionalDependencies: '@types/node': 24.10.1 @@ -4870,6 +5181,8 @@ snapshots: string-width: 7.2.0 strip-ansi: 7.1.2 + wrappy@1.0.2: {} + wrtc@0.4.7: optionalDependencies: domexception: 1.0.1 diff --git a/utils/actions/src/create-release-pr/action.yml b/utils/actions/src/create-release-pr/action.yml new file mode 100644 index 0000000..7e092f1 --- /dev/null +++ b/utils/actions/src/create-release-pr/action.yml @@ -0,0 +1,20 @@ +name: "Create release PR" +description: "Create a PR for releasing a package" +inputs: + dry: + description: "Perform a dry run that skips pr creation and outputs logs indicating what would have happened" + default: "false" + package: + description: "The published name of the package to release" + version: + description: "New version of the package" +runs: + using: composite + steps: + - uses: oven-sh/setup-bun@v2 + - run: bun $GITHUB_ACTION_PATH/index.js + shell: bash + env: + INPUT_DRY: ${{ inputs.dry }} + INPUT_PACKAGE: ${{ inputs.package }} + INPUT_VERSION: ${{ inputs.version }} diff --git a/utils/actions/src/create-release-pr/functions.ts b/utils/actions/src/create-release-pr/functions.ts new file mode 100644 index 0000000..86a073a --- /dev/null +++ b/utils/actions/src/create-release-pr/functions.ts @@ -0,0 +1,83 @@ +import { context, getOctokit } from "@actions/github"; +import { $, file, write } from "bun"; +import process from "node:process"; +import { join } from "path"; + +import { type IPkg } from "./types"; + +let octokit: ReturnType | undefined; + +if (process.env.GITHUB_TOKEN) { + octokit = getOctokit(process.env.GITHUB_TOKEN); +} + +export const resolvePackage = async (name: string): Promise => { + const pkgs: IPkg[] = + await $`pnpm list --filter ${name} --recursive --only-projects --prod --json`.json(); + if (pkgs.length <= 0) throw new Error("Package not found"); + return pkgs[0] as IPkg; +}; + +export const resolveChangelog = async ( + path: string, + name: string, + version: string, +): Promise => { + const changelogFile = await file(join(path, "CHANGELOG.md")).text(); + let changelogLines: string[] = []; + let foundChangelog = false; + + for (const line of changelogFile.split("\n")) { + if (line.startsWith("# [")) { + if (foundChangelog) { + if (changelogLines.at(-1) === "") changelogLines = changelogLines.slice(2, -1); + break; + } + if (!line.startsWith(`# [${name}@${version}]`)) break; + foundChangelog = true; + } + if (foundChangelog) changelogLines.push(line); + } + + return `${changelogLines.join("\n").replace(/^\s+|\s+$/g, "")}\n`; +}; + +export const resolveVersion = async (name: string): Promise => { + const regex = new RegExp(`^📦 Bumped ${name}@(\\d+\\.\\d+\\.\\d+)$`); + const res = await $`pnpm --filter=${name} run release --dry-run`.text(); + for (const line of res.split("\n")) { + const match = regex.exec(line); + if (match) return match[1] as string; + } + throw new Error("Could not find the version"); +}; + +export const checkoutToReleaseBranch = async (name: string, version: string): Promise => { + const branchName = `releases/${name.replace("@nanoforge-dev/", "")}@${version}`; + await $`git checkout -b ${branchName}`; + return branchName; +}; + +export const updateVersion = async (path: string, version: string): Promise => { + const fullPath = join(path, "package.json"); + const pkg = await file(fullPath).json(); + pkg.version = version; + await write(fullPath, JSON.stringify(pkg)); +}; + +export const runRelease = async (name: string): Promise => { + await $`pnpm --filter=${name} run release --skip-automatic-bump --skip-tag`; +}; + +export const pushRelease = async (branch: string): Promise => { + await $`git push origin refs/heads/${branch}:${branch}`; +}; + +export const createPR = async (branchName: string): Promise => { + await octokit?.rest.pulls.create({ + ...context.repo, + base: "main", + head: branchName, + title: await $`git show -s --format=%s`.text(), + }); +}; diff --git a/utils/actions/src/create-release-pr/index.ts b/utils/actions/src/create-release-pr/index.ts new file mode 100644 index 0000000..2655b3b --- /dev/null +++ b/utils/actions/src/create-release-pr/index.ts @@ -0,0 +1,66 @@ +import { getBooleanInput, getInput, summary } from "@actions/core"; +import { program } from "commander"; + +import { + checkoutToReleaseBranch, + createPR, + pushRelease, + resolveChangelog, + resolvePackage, + resolveVersion, + runRelease, + updateVersion, +} from "./functions"; + +const createSummary = async (name: string, dry: boolean) => { + const pkg = await resolvePackage(name); + const changelog = await resolveChangelog(pkg.path, pkg.name, pkg.version); + + const result = summary.addHeading("Pre-Release summary"); + + if (dry) { + result.addRaw("\n\n> [!NOTE]\n> This is a dry run.\n\n"); + } + + result.addHeading(`${pkg.name} pre-released`, 2); + + result.addRaw(`> Version : ${pkg.version}\n`); + result.addSeparator(); + result.addRaw("> Changelog :\n"); + result.addBreak(); + result.addCodeBlock(changelog); + + await result.write(); +}; + +const bootstrap = async () => { + program + .name("create release pr") + .description("pre-releases monorepo packages with proper sequencing") + .argument( + "[package]", + "release a specific package (and it's dependencies)", + getInput("package"), + ) + .option("--dry", "skips actual publishing and outputs logs instead", getBooleanInput("dry")) + .option("--version ", "new version of the package", getInput("version")) + .parse(); + + const { dry, version: baseVersion } = program.opts<{ dry: boolean; version: string }>(); + const [packageName] = program.processedArgs as [string]; + + const pkg = await resolvePackage(packageName); + const version = baseVersion || (await resolveVersion(packageName)); + + const branchName = await checkoutToReleaseBranch(pkg.name, version); + await updateVersion(pkg.path, version); + await runRelease(pkg.name); + if (!dry) { + await pushRelease(branchName); + await createPR(branchName); + } + + await createSummary(packageName, dry); +}; + +bootstrap().then(); diff --git a/utils/actions/src/create-release-pr/types.ts b/utils/actions/src/create-release-pr/types.ts new file mode 100644 index 0000000..370f19d --- /dev/null +++ b/utils/actions/src/create-release-pr/types.ts @@ -0,0 +1,6 @@ +export interface IPkg { + name: string; + version: string; + path: string; + private: boolean; +} diff --git a/utils/actions/src/create-release-tag/action.yml b/utils/actions/src/create-release-tag/action.yml new file mode 100644 index 0000000..fea0d64 --- /dev/null +++ b/utils/actions/src/create-release-tag/action.yml @@ -0,0 +1,16 @@ +name: "Create release tag" +description: "Create a tag the package release" +inputs: + commit: + description: "Commit sha to put the tag on" + branch: + description: "Head branch name" +runs: + using: composite + steps: + - uses: oven-sh/setup-bun@v2 + - run: bun $GITHUB_ACTION_PATH/index.js + shell: bash + env: + INPUT_COMMIT: ${{ inputs.commit }} + INPUT_BRANCH: ${{ inputs.branch }} diff --git a/utils/actions/src/create-release-tag/index.ts b/utils/actions/src/create-release-tag/index.ts new file mode 100644 index 0000000..e2d881a --- /dev/null +++ b/utils/actions/src/create-release-tag/index.ts @@ -0,0 +1,31 @@ +import { getInput } from "@actions/core"; +import { context, getOctokit } from "@actions/github"; +import { program } from "commander"; +import process from "node:process"; + +let octokit: ReturnType | undefined; + +if (process.env.GITHUB_TOKEN) { + octokit = getOctokit(process.env.GITHUB_TOKEN); +} + +const bootstrap = async () => { + program + .name("create release tag") + .description("create release tag for monorepo packages with proper sequencing") + .option("--commit ", "commit sha of ythe last commit", getInput("commit")) + .option("--branch ", "head branch of the merged pr", getInput("branch")) + .parse(); + + const { commit, branch } = program.opts<{ commit: string; branch: string }>(); + + const pkg = branch.replace("releases/", "@nanoforge-dev/"); + + await octokit?.rest.git.createRef({ + ...context.repo, + ref: `refs/tags/${pkg}`, + sha: commit, + }); +}; + +bootstrap().then(); diff --git a/utils/actions/src/release-packages/release-package.ts b/utils/actions/src/release-packages/release-package.ts index 4f161ab..dc32e84 100644 --- a/utils/actions/src/release-packages/release-package.ts +++ b/utils/actions/src/release-packages/release-package.ts @@ -24,13 +24,10 @@ async function gitTagAndRelease(release: ReleaseEntry, dry: boolean) { return; } - const commitHash = (await $`git rev-parse HEAD`.text()).trim(); - try { await octokit?.rest.repos.createRelease({ ...context.repo, tag_name: tagName, - target_commitish: commitHash, name: tagName, body: release.changelog ?? "", generate_release_notes: release.changelog === undefined, diff --git a/utils/actions/tsup.config.ts b/utils/actions/tsup.config.ts index dc0b410..29b1448 100644 --- a/utils/actions/tsup.config.ts +++ b/utils/actions/tsup.config.ts @@ -11,4 +11,8 @@ const createConfig = (name: string, entries: string[] = []) => { }); }; -export default [createConfig("pnpm-install"), createConfig("release-packages", ["index.ts"])]; +export default [ + createConfig("create-release-pr", ["index.ts"]), + createConfig("create-release-tag", ["index.ts"]), + createConfig("release-packages", ["index.ts"]), +];