diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 21e4db42a..db306b4d6 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -3,7 +3,9 @@ name: Node.js CI -on: [pull_request] +on: + pull_request: + workflow_call: permissions: contents: read diff --git a/.github/workflows/keyboard_plugin_test.yml b/.github/workflows/keyboard_plugin_test.yml deleted file mode 100644 index e64efe983..000000000 --- a/.github/workflows/keyboard_plugin_test.yml +++ /dev/null @@ -1,66 +0,0 @@ -# Workflow for running the keyboard navigation plugin's automated tests. - -name: Keyboard Navigation Automated Tests - -on: - workflow_dispatch: - pull_request: - push: - branches: - - main - -permissions: - contents: read - -jobs: - webdriverio_tests: - name: WebdriverIO tests - timeout-minutes: 10 - runs-on: ${{ matrix.os }} - - strategy: - fail-fast: false - matrix: - os: [ubuntu-latest] - - steps: - - name: Checkout core Blockly - uses: actions/checkout@v5 - with: - path: core-blockly - - - name: Checkout keyboard navigation plugin - uses: actions/checkout@v5 - with: - repository: 'google/blockly-keyboard-experimentation' - ref: 'main' - path: blockly-keyboard-experimentation - - - name: Use Node.js 20.x - uses: actions/setup-node@v5 - with: - node-version: 20.x - - - name: NPM install - run: | - cd core-blockly - npm install - cd .. - cd blockly-keyboard-experimentation - npm install - cd .. - - - name: Link latest core main with plugin - run: | - cd core-blockly/packages/blockly - npm run package - cd dist - npm link - cd ../../../../blockly-keyboard-experimentation - npm link blockly - cd .. - - - name: Run keyboard navigation plugin tests - run: | - cd blockly-keyboard-experimentation - npm run test diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml new file mode 100644 index 000000000..0f403f447 --- /dev/null +++ b/.github/workflows/publish.yml @@ -0,0 +1,137 @@ +name: Publish to npm + +on: + workflow_dispatch: + inputs: + dry_run: + description: 'Dry run - print the version that would be published, but do not commit or publish anything.' + required: false + default: false + type: boolean + skip_versioning: + description: > + Skip version bump - use the version already in the repo + (e.g. retry after npm publish failed but the release commit is already pushed). + required: false + default: false + type: boolean + +permissions: + contents: write + id-token: write + +jobs: + ci: + uses: ./.github/workflows/build.yml + + version: + needs: ci + runs-on: ubuntu-latest + timeout-minutes: 30 + outputs: + version: ${{ steps.version.outputs.version }} + steps: + - name: Checkout + uses: actions/checkout@v5 + with: + fetch-depth: 0 + + - name: Setup Node.js + uses: actions/setup-node@v5 + with: + node-version: 24.x + registry-url: 'https://registry.npmjs.org' + + - name: Install dependencies + if: ${{ !inputs.skip_versioning }} + run: npm ci + + - name: Determine version bump + id: bump + if: ${{ !inputs.skip_versioning }} + working-directory: packages/blockly + run: | + RELEASE_TYPE=$(npx conventional-recommended-bump --preset conventionalcommits -t blockly-) + echo "release_type=$RELEASE_TYPE" >> "$GITHUB_OUTPUT" + echo "Recommended bump: $RELEASE_TYPE" + + - name: Apply version bump + if: ${{ !inputs.skip_versioning }} + working-directory: packages/blockly + run: npm version ${{ steps.bump.outputs.release_type }} --no-git-tag-version + + - name: Read package version + id: version + working-directory: packages/blockly + run: | + VERSION=$(node -p "require('./package.json').version") + echo "version=$VERSION" >> "$GITHUB_OUTPUT" + echo "Version: $VERSION" + + - name: Upload versioned files + if: ${{ !inputs.skip_versioning }} + uses: actions/upload-artifact@v4 + with: + name: versioned-files + path: | + packages/blockly/package.json + package-lock.json + + publish: + needs: version + runs-on: ubuntu-latest + if: ${{ !inputs.dry_run }} + environment: release + steps: + - name: Checkout + uses: actions/checkout@v5 + with: + fetch-depth: 0 + ssh-key: ${{ secrets.DEPLOY_PRIVATE_KEY }} + + - name: Download versioned files + if: ${{ !inputs.skip_versioning }} + uses: actions/download-artifact@v4 + with: + name: versioned-files + + - name: Commit and push version bump + if: ${{ !inputs.skip_versioning }} + run: | + git config user.name "github-actions[bot]" + git config user.email "41898282+github-actions[bot]@users.noreply.github.com" + git add packages/blockly/package.json package-lock.json + git commit -m "release: v${{ needs.version.outputs.version }}" + git push + + - name: Setup Node.js + uses: actions/setup-node@v5 + with: + node-version: 24.x + registry-url: 'https://registry.npmjs.org' + + - name: Install dependencies + run: npm ci + + - name: Build package + working-directory: packages/blockly + run: npm run package + + - name: Publish to npm + working-directory: packages/blockly/dist + run: npm publish --verbose + + - name: Create tarball + working-directory: packages/blockly + run: npm pack ./dist + + - name: Create GitHub release + working-directory: packages/blockly + env: + GH_TOKEN: ${{ github.token }} + run: | + TARBALL="blockly-${{ needs.version.outputs.version }}.tgz" + gh release create "blockly-v${{ needs.version.outputs.version }}" "$TARBALL" \ + --repo "$GITHUB_REPOSITORY" \ + --title "blockly-v${{ needs.version.outputs.version }}" \ + --generate-notes diff --git a/.github/workflows/update-gh-pages.yml b/.github/workflows/update-gh-pages.yml new file mode 100644 index 000000000..e45aca688 --- /dev/null +++ b/.github/workflows/update-gh-pages.yml @@ -0,0 +1,36 @@ +# Manual workflow to update GitHub Pages from a chosen source branch. +# The gulp updateGithubPages task builds the repo and force-pushes to gh-pages. + +name: Update GitHub Pages + +on: + workflow_dispatch: + inputs: + source_branch: + description: 'Source branch to build and deploy to GitHub Pages' + required: true + type: string + default: main + +permissions: + contents: write + +jobs: + update-gh-pages: + timeout-minutes: 15 + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@v5 + with: + ref: ${{ inputs.source_branch }} + fetch-depth: 0 + + - name: Use Node.js + uses: actions/setup-node@v5 + with: + node-version: 24.x + + - name: Update GitHub Pages + working-directory: ./packages/blockly + run: npm run updateGithubPages:staging diff --git a/package-lock.json b/package-lock.json index a02898fb6..0a4f05b47 100644 --- a/package-lock.json +++ b/package-lock.json @@ -18,15 +18,11 @@ }, "node_modules/@acemir/cssom": { "version": "0.9.31", - "resolved": "https://registry.npmjs.org/@acemir/cssom/-/cssom-0.9.31.tgz", - "integrity": "sha512-ZnR3GSaH+/vJ0YlHau21FjfLYjMpYVIzTD8M8vIEQvIGxeOXyXdzCI140rrCY862p/C/BbzWsjc1dgnM9mkoTA==", "dev": true, "license": "MIT" }, "node_modules/@asamuzakjp/css-color": { "version": "4.1.2", - "resolved": "https://registry.npmjs.org/@asamuzakjp/css-color/-/css-color-4.1.2.tgz", - "integrity": "sha512-NfBUvBaYgKIuq6E/RBLY1m0IohzNHAYyaJGuTK79Z23uNwmz2jl1mPsC5ZxCCxylinKhT1Amn5oNTlx1wN8cQg==", "dev": true, "license": "MIT", "dependencies": { @@ -39,8 +35,6 @@ }, "node_modules/@asamuzakjp/css-color/node_modules/lru-cache": { "version": "11.2.7", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.2.7.tgz", - "integrity": "sha512-aY/R+aEsRelme17KGQa/1ZSIpLpNYYrhcrepKTZgE+W3WM16YMCaPwOHLHsmopZHELU0Ojin1lPVxKR0MihncA==", "dev": true, "license": "BlueOak-1.0.0", "engines": { @@ -49,8 +43,6 @@ }, "node_modules/@asamuzakjp/dom-selector": { "version": "6.8.1", - "resolved": "https://registry.npmjs.org/@asamuzakjp/dom-selector/-/dom-selector-6.8.1.tgz", - "integrity": "sha512-MvRz1nCqW0fsy8Qz4dnLIvhOlMzqDVBabZx6lH+YywFDdjXhMY37SmpV1XFX3JzG5GWHn63j6HX6QPr3lZXHvQ==", "dev": true, "license": "MIT", "dependencies": { @@ -63,8 +55,6 @@ }, "node_modules/@asamuzakjp/dom-selector/node_modules/lru-cache": { "version": "11.2.7", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.2.7.tgz", - "integrity": "sha512-aY/R+aEsRelme17KGQa/1ZSIpLpNYYrhcrepKTZgE+W3WM16YMCaPwOHLHsmopZHELU0Ojin1lPVxKR0MihncA==", "dev": true, "license": "BlueOak-1.0.0", "engines": { @@ -73,8 +63,6 @@ }, "node_modules/@asamuzakjp/nwsapi": { "version": "2.3.9", - "resolved": "https://registry.npmjs.org/@asamuzakjp/nwsapi/-/nwsapi-2.3.9.tgz", - "integrity": "sha512-n8GuYSrI9bF7FFZ/SjhwevlHc8xaVlb/7HmHelnc/PZXBD2ZR49NnN9sMMuDdEGPeeRQ5d0hqlSlEpgCX3Wl0Q==", "dev": true, "license": "MIT" }, @@ -458,8 +446,6 @@ }, "node_modules/@csstools/color-helpers": { "version": "6.0.2", - "resolved": "https://registry.npmjs.org/@csstools/color-helpers/-/color-helpers-6.0.2.tgz", - "integrity": "sha512-LMGQLS9EuADloEFkcTBR3BwV/CGHV7zyDxVRtVDTwdI2Ca4it0CCVTT9wCkxSgokjE5Ho41hEPgb8OEUwoXr6Q==", "dev": true, "funding": [ { @@ -478,8 +464,6 @@ }, "node_modules/@csstools/css-calc": { "version": "3.1.1", - "resolved": "https://registry.npmjs.org/@csstools/css-calc/-/css-calc-3.1.1.tgz", - "integrity": "sha512-HJ26Z/vmsZQqs/o3a6bgKslXGFAungXGbinULZO3eMsOyNJHeBBZfup5FiZInOghgoM4Hwnmw+OgbJCNg1wwUQ==", "dev": true, "funding": [ { @@ -502,8 +486,6 @@ }, "node_modules/@csstools/css-color-parser": { "version": "4.0.2", - "resolved": "https://registry.npmjs.org/@csstools/css-color-parser/-/css-color-parser-4.0.2.tgz", - "integrity": "sha512-0GEfbBLmTFf0dJlpsNU7zwxRIH0/BGEMuXLTCvFYxuL1tNhqzTbtnFICyJLTNK4a+RechKP75e7w42ClXSnJQw==", "dev": true, "funding": [ { @@ -530,8 +512,6 @@ }, "node_modules/@csstools/css-parser-algorithms": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/@csstools/css-parser-algorithms/-/css-parser-algorithms-4.0.0.tgz", - "integrity": "sha512-+B87qS7fIG3L5h3qwJ/IFbjoVoOe/bpOdh9hAjXbvx0o8ImEmUsGXN0inFOnk2ChCFgqkkGFQ+TpM5rbhkKe4w==", "dev": true, "funding": [ { @@ -553,8 +533,6 @@ }, "node_modules/@csstools/css-syntax-patches-for-csstree": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@csstools/css-syntax-patches-for-csstree/-/css-syntax-patches-for-csstree-1.1.1.tgz", - "integrity": "sha512-BvqN0AMWNAnLk9G8jnUT77D+mUbY/H2b3uDTvg2isJkHaOufUE2R3AOwxWo7VBQKT1lOdwdvorddo2B/lk64+w==", "dev": true, "funding": [ { @@ -578,8 +556,6 @@ }, "node_modules/@csstools/css-tokenizer": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/@csstools/css-tokenizer/-/css-tokenizer-4.0.0.tgz", - "integrity": "sha512-QxULHAm7cNu72w97JUNCBFODFaXpbDg+dP8b/oWFAZ2MTRppA3U00Y2L1HqaS4J6yBqxwa/Y3nMBaxVKbB/NsA==", "dev": true, "funding": [ { @@ -598,8 +574,6 @@ }, "node_modules/@exodus/bytes": { "version": "1.15.0", - "resolved": "https://registry.npmjs.org/@exodus/bytes/-/bytes-1.15.0.tgz", - "integrity": "sha512-UY0nlA+feH81UGSHv92sLEPLCeZFjXOuHhrIo0HQydScuQc8s0A7kL/UdgwgDq8g8ilksmuoF35YVTNphV2aBQ==", "dev": true, "license": "MIT", "engines": { @@ -732,8 +706,6 @@ }, "node_modules/bidi-js": { "version": "1.0.3", - "resolved": "https://registry.npmjs.org/bidi-js/-/bidi-js-1.0.3.tgz", - "integrity": "sha512-RKshQI1R3YQ+n9YJz2QQ147P66ELpa1FQEg20Dk8oW9t2KgLbpDLLp9aGZ7y8WHSshDknG0bknqGw5/tyCs5tw==", "dev": true, "license": "MIT", "dependencies": { @@ -891,8 +863,6 @@ }, "node_modules/css-tree": { "version": "3.2.1", - "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-3.2.1.tgz", - "integrity": "sha512-X7sjQzceUhu1u7Y/ylrRZFU2FS6LRiFVp6rKLPg23y3x3c3DOKAwuXGDp+PAGjh6CSnCjYeAul8pcT8bAl+lSA==", "dev": true, "license": "MIT", "dependencies": { @@ -905,8 +875,6 @@ }, "node_modules/cssstyle": { "version": "5.3.7", - "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-5.3.7.tgz", - "integrity": "sha512-7D2EPVltRrsTkhpQmksIu+LxeWAIEk6wRDMJ1qljlv+CKHJM+cJLlfhWIzNA44eAsHXSNe3+vO6DW1yCYx8SuQ==", "dev": true, "license": "MIT", "dependencies": { @@ -932,8 +900,6 @@ }, "node_modules/data-urls": { "version": "6.0.1", - "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-6.0.1.tgz", - "integrity": "sha512-euIQENZg6x8mj3fO6o9+fOW8MimUI4PpD/fZBhJfeioZVy9TUpM4UY7KjQNVZFlqwJ0UdzRDzkycB997HEq1BQ==", "dev": true, "license": "MIT", "dependencies": { @@ -946,8 +912,6 @@ }, "node_modules/data-urls/node_modules/whatwg-mimetype": { "version": "5.0.0", - "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-5.0.0.tgz", - "integrity": "sha512-sXcNcHOC51uPGF0P/D4NVtrkjSU2fNsm9iog4ZvZJsL3rjoDAzXZhkm2MWt1y+PUdggKAYVoMAIYcs78wJ51Cw==", "dev": true, "license": "MIT", "engines": { @@ -972,8 +936,6 @@ }, "node_modules/decimal.js": { "version": "10.6.0", - "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.6.0.tgz", - "integrity": "sha512-YpgQiITW3JXGntzdUmyUR1V812Hn8T1YVXhCu+wO3OpS4eU9l4YdD3qjyiKdV6mvV29zapkMeD390UVEf2lkUg==", "dev": true, "license": "MIT" }, @@ -1074,6 +1036,24 @@ "node": ">=16" } }, + "node_modules/git-semver-tags": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/git-semver-tags/-/git-semver-tags-7.0.1.tgz", + "integrity": "sha512-NY0ZHjJzyyNXHTDZmj+GG7PyuAKtMsyWSwh07CR2hOZFa+/yoTsXci/nF2obzL8UDhakFNkD9gNdt/Ed+cxh2Q==", + "deprecated": "This package is no longer maintained. For the JavaScript API, please use @conventional-changelog/git-client instead.", + "dev": true, + "license": "MIT", + "dependencies": { + "meow": "^12.0.1", + "semver": "^7.5.2" + }, + "bin": { + "git-semver-tags": "cli.mjs" + }, + "engines": { + "node": ">=16" + } + }, "node_modules/glob": { "version": "13.0.0", "dev": true, @@ -1113,14 +1093,14 @@ } }, "node_modules/google-closure-compiler": { - "version": "20260315.0.0", - "resolved": "https://registry.npmjs.org/google-closure-compiler/-/google-closure-compiler-20260315.0.0.tgz", - "integrity": "sha512-z+Zdkth5+bdt+bSy3HuYRgjSAgx4WncBZ0Rd+/1Hf3wFemkkTxXGXpG7A5Y8n5WrTsPd1n/fxVuD5xfFL6s5Dw==", + "version": "20260330.0.0", + "resolved": "https://registry.npmjs.org/google-closure-compiler/-/google-closure-compiler-20260330.0.0.tgz", + "integrity": "sha512-USY3fekBavIfAkzHEooo6FcuTT/+z6FbfMRK3l3nsgsKB2oJ4baPPz2XYGSivHNstB8l10CcPvWh5FwlWZpzvQ==", "dev": true, "license": "Apache-2.0", "dependencies": { "chalk": "^2.0.0 || ^3.0.0 || ^4.0.0 || ^5.0.0 <5.6.1 || ^5.6.2 >5.6.1", - "google-closure-compiler-java": "^20260315.0.0", + "google-closure-compiler-java": "^20260330.0.0", "minimist": "^1.0.0", "vinyl": "^3.0.1", "vinyl-sourcemaps-apply": "^0.2.0" @@ -1132,23 +1112,23 @@ "node": ">=18" }, "optionalDependencies": { - "google-closure-compiler-linux": "^20260315.0.0", - "google-closure-compiler-linux-arm64": "^20260315.0.0", - "google-closure-compiler-macos": "^20260315.0.0", - "google-closure-compiler-windows": "^20260315.0.0" + "google-closure-compiler-linux": "^20260330.0.0", + "google-closure-compiler-linux-arm64": "^20260330.0.0", + "google-closure-compiler-macos": "^20260330.0.0", + "google-closure-compiler-windows": "^20260330.0.0" } }, "node_modules/google-closure-compiler-java": { - "version": "20260315.0.0", - "resolved": "https://registry.npmjs.org/google-closure-compiler-java/-/google-closure-compiler-java-20260315.0.0.tgz", - "integrity": "sha512-3CYSN3x7S7xCc/7Yx9vmH4pOc/8tkJdPjftUV1tUt2/tYKYEeH9mGv5dtrs22Uf6qXdIqlEBGg+ZQXX13xVpww==", + "version": "20260330.0.0", + "resolved": "https://registry.npmjs.org/google-closure-compiler-java/-/google-closure-compiler-java-20260330.0.0.tgz", + "integrity": "sha512-wc+HpQlNvS5mquzVjpOjhVlgYgvxnOyqPDCJJN2k7+5dVE7mbzZya7mIEfsPaRZ39KbPVvNrDpMEAahKiuNtjA==", "dev": true, "license": "Apache-2.0" }, "node_modules/google-closure-compiler-linux": { - "version": "20260315.0.0", - "resolved": "https://registry.npmjs.org/google-closure-compiler-linux/-/google-closure-compiler-linux-20260315.0.0.tgz", - "integrity": "sha512-jXUnyY3Cr5kmBDmGuxw3HULjzX69AeXVRcIpI+YuFGfo8qX1dIbkOpNK7JHWtJ7qE01foGmCwjnx5WOSrplYyg==", + "version": "20260330.0.0", + "resolved": "https://registry.npmjs.org/google-closure-compiler-linux/-/google-closure-compiler-linux-20260330.0.0.tgz", + "integrity": "sha512-BWEknhsCj/zero4Zk0/FtbAM1eO3QQA34xGQa4HeREV36trs/zmVCSVRqYCYcEAAEBiMjj97wMPdhFSkm72k8g==", "cpu": [ "x32", "x64" @@ -1161,9 +1141,9 @@ ] }, "node_modules/google-closure-compiler-linux-arm64": { - "version": "20260315.0.0", - "resolved": "https://registry.npmjs.org/google-closure-compiler-linux-arm64/-/google-closure-compiler-linux-arm64-20260315.0.0.tgz", - "integrity": "sha512-e0dSgFEg/bE9gscw+u2Roy/FkJOQ/6MvG3nBCPR8IqAkJ+ibBAQKnYOSK1sAUp1bXJROiUJy6a+GTJ312FKS+A==", + "version": "20260330.0.0", + "resolved": "https://registry.npmjs.org/google-closure-compiler-linux-arm64/-/google-closure-compiler-linux-arm64-20260330.0.0.tgz", + "integrity": "sha512-7C9khLgtZEUfZ/xCkjLVTC5vRJt5CmfWwiAk/u3+pPzsDubngHwKE1e0UTPqNwJEXo8VVXM4OdvrY7hzwR4MZg==", "cpu": [ "arm64" ], @@ -1175,9 +1155,9 @@ ] }, "node_modules/google-closure-compiler-macos": { - "version": "20260315.0.0", - "resolved": "https://registry.npmjs.org/google-closure-compiler-macos/-/google-closure-compiler-macos-20260315.0.0.tgz", - "integrity": "sha512-yhY46Mdbqs7HAPsYAhXlt9Q2rROLZfaZrTFZZqyVo/uufEmGH3vOyxshTbBQWhaJQHkELWsc/XKSVfvX4rcoYA==", + "version": "20260330.0.0", + "resolved": "https://registry.npmjs.org/google-closure-compiler-macos/-/google-closure-compiler-macos-20260330.0.0.tgz", + "integrity": "sha512-3mGI7eYwIZYAZFdMwpS4wXB5+q/kKbl936FtvRIIgRtFhSX7m6kwsyXqGP62ZvuOCcPcW14dC6k7g6l7eS2Fgw==", "cpu": [ "arm64" ], @@ -1189,9 +1169,9 @@ ] }, "node_modules/google-closure-compiler-windows": { - "version": "20260315.0.0", - "resolved": "https://registry.npmjs.org/google-closure-compiler-windows/-/google-closure-compiler-windows-20260315.0.0.tgz", - "integrity": "sha512-EpIPPU6vQ5EzuzKQMe3vhEWLqqXY4SKNoLjXrr4GWXoses9h7xT6nkHDuDe/7x5MWZOMRv4qmlW3PzLCsx98qg==", + "version": "20260330.0.0", + "resolved": "https://registry.npmjs.org/google-closure-compiler-windows/-/google-closure-compiler-windows-20260330.0.0.tgz", + "integrity": "sha512-dqMKvjzdAlgERhHKHG12dKrOcL2ASNeKP1c3doCQn3vwZizz1xV2Ns6m711tb6pfNXFstfR6VJAoMuv/BjmdYQ==", "cpu": [ "x32", "x64" @@ -1333,8 +1313,6 @@ }, "node_modules/jsdom": { "version": "27.4.0", - "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-27.4.0.tgz", - "integrity": "sha512-mjzqwWRD9Y1J1KUi7W97Gja1bwOOM5Ug0EZ6UDK3xS7j7mndrkwozHtSblfomlzyB4NepioNt+B2sOSzczVgtQ==", "dev": true, "license": "MIT", "dependencies": { @@ -1373,8 +1351,6 @@ }, "node_modules/jsdom/node_modules/entities": { "version": "6.0.1", - "resolved": "https://registry.npmjs.org/entities/-/entities-6.0.1.tgz", - "integrity": "sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==", "dev": true, "license": "BSD-2-Clause", "engines": { @@ -1386,8 +1362,6 @@ }, "node_modules/jsdom/node_modules/html-encoding-sniffer": { "version": "6.0.0", - "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-6.0.0.tgz", - "integrity": "sha512-CV9TW3Y3f8/wT0BRFc1/KAVQ3TUHiXmaAb6VW9vtiMFf7SLoMd1PdAc4W3KFOFETBJUb90KatHqlsZMWV+R9Gg==", "dev": true, "license": "MIT", "dependencies": { @@ -1399,8 +1373,6 @@ }, "node_modules/jsdom/node_modules/parse5": { "version": "8.0.0", - "resolved": "https://registry.npmjs.org/parse5/-/parse5-8.0.0.tgz", - "integrity": "sha512-9m4m5GSgXjL4AjumKzq1Fgfp3Z8rsvjRNbnkVwfu2ImRqE5D0LnY2QfDen18FSY9C573YU5XxSapdHZTZ2WolA==", "dev": true, "license": "MIT", "dependencies": { @@ -1503,8 +1475,6 @@ }, "node_modules/mdn-data": { "version": "2.27.1", - "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.27.1.tgz", - "integrity": "sha512-9Yubnt3e8A0OKwxYSXyhLymGW4sCufcLG6VdiDdUGVkPhpqLxlvP5vl1983gQjJl3tqbrM731mjaZaP68AgosQ==", "dev": true, "license": "CC0-1.0" }, @@ -1668,6 +1638,20 @@ "node": ">=v12.22.7" } }, + "node_modules/semver": { + "version": "7.5.4", + "dev": true, + "license": "ISC", + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/source-map": { "version": "0.5.7", "dev": true, @@ -1678,8 +1662,6 @@ }, "node_modules/source-map-js": { "version": "1.2.1", - "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", - "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", "dev": true, "license": "BSD-3-Clause", "engines": { @@ -1772,8 +1754,6 @@ }, "node_modules/tldts": { "version": "7.0.26", - "resolved": "https://registry.npmjs.org/tldts/-/tldts-7.0.26.tgz", - "integrity": "sha512-WiGwQjr0qYdNNG8KpMKlSvpxz652lqa3Rd+/hSaDcY4Uo6SKWZq2LAF+hsAhUewTtYhXlorBKgNF3Kk8hnjGoQ==", "dev": true, "license": "MIT", "dependencies": { @@ -1785,15 +1765,11 @@ }, "node_modules/tldts-core": { "version": "7.0.26", - "resolved": "https://registry.npmjs.org/tldts-core/-/tldts-core-7.0.26.tgz", - "integrity": "sha512-5WJ2SqFsv4G2Dwi7ZFVRnz6b2H1od39QME1lc2y5Ew3eWiZMAeqOAfWpRP9jHvhUl881406QtZTODvjttJs+ew==", "dev": true, "license": "MIT" }, "node_modules/tough-cookie": { "version": "6.0.1", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-6.0.1.tgz", - "integrity": "sha512-LktZQb3IeoUWB9lqR5EWTHgW/VTITCXg4D21M+lvybRVdylLrRMnqaIONLVb5mav8vM19m44HIcGq4qASeu2Qw==", "dev": true, "license": "BSD-3-Clause", "dependencies": { @@ -1805,8 +1781,6 @@ }, "node_modules/tr46": { "version": "6.0.0", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-6.0.0.tgz", - "integrity": "sha512-bLVMLPtstlZ4iMQHpFHTR7GAGj2jxi8Dg0s2h2MafAE4uSWF98FC/3MomU51iQAMf8/qDUbKWf5GxuvvVcXEhw==", "dev": true, "license": "MIT", "dependencies": { @@ -1867,8 +1841,6 @@ }, "node_modules/webidl-conversions": { "version": "8.0.1", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-8.0.1.tgz", - "integrity": "sha512-BMhLD/Sw+GbJC21C/UgyaZX41nPt8bUTg+jWyDeg7e7YN4xOM05YPSIXceACnXVtqyEw/LMClUQMtMZ+PGGpqQ==", "dev": true, "license": "BSD-2-Clause", "engines": { @@ -1885,8 +1857,6 @@ }, "node_modules/whatwg-url": { "version": "15.1.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-15.1.0.tgz", - "integrity": "sha512-2ytDk0kiEj/yu90JOAp44PVPUkO9+jVhyf+SybKlRHSDlvOOZhdPIrr7xTH64l4WixO2cP+wQIcgujkGBPPz6g==", "dev": true, "license": "MIT", "dependencies": { @@ -1980,7 +1950,7 @@ } }, "packages/blockly": { - "version": "12.4.1", + "version": "12.5.1", "hasInstallScript": true, "license": "Apache-2.0", "devDependencies": { @@ -1995,6 +1965,8 @@ "async-done": "^2.0.0", "chai": "^6.0.1", "concurrently": "^9.0.1", + "conventional-changelog-conventionalcommits": "^7.0.2", + "conventional-recommended-bump": "^9.0.0", "eslint": "^9.15.0", "eslint-config-google": "^0.14.0", "eslint-config-prettier": "^10.1.1", @@ -2003,16 +1975,13 @@ "eslint-plugin-prettier": "^5.2.1", "glob": "^11.0.1", "globals": "^16.0.0", - "google-closure-compiler": "^20260315.0.0", + "google-closure-compiler": "^20260330.0.0", "gulp": "^5.0.0", "gulp-concat": "^2.6.1", "gulp-gzip": "^1.4.2", "gulp-header": "^2.0.9", - "gulp-insert": "^0.5.0", "gulp-rename": "^2.0.0", "gulp-replace": "^1.0.0", - "gulp-series": "^1.0.2", - "gulp-shell": "^0.8.0", "gulp-sourcemaps": "^3.0.0", "gulp-umd": "^2.0.0", "http-server": "^14.0.0", @@ -4698,6 +4667,47 @@ "node": ">= 0.6" } }, + "packages/blockly/node_modules/conventional-changelog-preset-loader": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/conventional-changelog-preset-loader/-/conventional-changelog-preset-loader-4.1.0.tgz", + "integrity": "sha512-HozQjJicZTuRhCRTq4rZbefaiCzRM2pr6u2NL3XhrmQm4RMnDXfESU6JKu/pnKwx5xtdkYfNCsbhN5exhiKGJA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=16" + } + }, + "packages/blockly/node_modules/conventional-commits-filter": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/conventional-commits-filter/-/conventional-commits-filter-4.0.0.tgz", + "integrity": "sha512-rnpnibcSOdFcdclpFwWa+pPlZJhXE7l+XK04zxhbWrhgpR96h33QLz8hITTXbcYICxVr3HZFtbtUAQ+4LdBo9A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=16" + } + }, + "packages/blockly/node_modules/conventional-recommended-bump": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/conventional-recommended-bump/-/conventional-recommended-bump-9.0.0.tgz", + "integrity": "sha512-HR1yD0G5HgYAu6K0wJjLd7QGRK8MQDqqj6Tn1n/ja1dFwBCE6QmV+iSgQ5F7hkx7OUR/8bHpxJqYtXj2f/opPQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "conventional-changelog-preset-loader": "^4.1.0", + "conventional-commits-filter": "^4.0.0", + "conventional-commits-parser": "^5.0.0", + "git-raw-commits": "^4.0.0", + "git-semver-tags": "^7.0.0", + "meow": "^12.0.1" + }, + "bin": { + "conventional-recommended-bump": "cli.mjs" + }, + "engines": { + "node": ">=16" + } + }, "packages/blockly/node_modules/convert-source-map": { "version": "1.8.0", "dev": true, @@ -6525,36 +6535,6 @@ "xtend": "~4.0.1" } }, - "packages/blockly/node_modules/gulp-insert": { - "version": "0.5.0", - "dev": true, - "license": "MIT", - "dependencies": { - "readable-stream": "^1.0.26-4", - "streamqueue": "0.0.6" - } - }, - "packages/blockly/node_modules/gulp-insert/node_modules/isarray": { - "version": "0.0.1", - "dev": true, - "license": "MIT" - }, - "packages/blockly/node_modules/gulp-insert/node_modules/readable-stream": { - "version": "1.1.14", - "dev": true, - "license": "MIT", - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.1", - "isarray": "0.0.1", - "string_decoder": "~0.10.x" - } - }, - "packages/blockly/node_modules/gulp-insert/node_modules/string_decoder": { - "version": "0.10.31", - "dev": true, - "license": "MIT" - }, "packages/blockly/node_modules/gulp-rename": { "version": "2.1.0", "dev": true, @@ -6578,48 +6558,6 @@ "node": ">=10" } }, - "packages/blockly/node_modules/gulp-series": { - "version": "1.0.2", - "dev": true, - "license": "MIT" - }, - "packages/blockly/node_modules/gulp-shell": { - "version": "0.8.0", - "dev": true, - "license": "MIT", - "dependencies": { - "chalk": "^3.0.0", - "fancy-log": "^1.3.3", - "lodash.template": "^4.5.0", - "plugin-error": "^1.0.1", - "through2": "^3.0.1", - "tslib": "^1.10.0" - }, - "engines": { - "node": ">=10.0.0" - } - }, - "packages/blockly/node_modules/gulp-shell/node_modules/chalk": { - "version": "3.0.0", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=8" - } - }, - "packages/blockly/node_modules/gulp-shell/node_modules/through2": { - "version": "3.0.2", - "dev": true, - "license": "MIT", - "dependencies": { - "inherits": "^2.0.4", - "readable-stream": "2 || 3" - } - }, "packages/blockly/node_modules/gulp-sourcemaps": { "version": "3.0.0", "dev": true, @@ -9075,37 +9013,6 @@ "any-promise": "^1.1.0" } }, - "packages/blockly/node_modules/streamqueue": { - "version": "0.0.6", - "dev": true, - "dependencies": { - "readable-stream": "^1.0.26-2" - }, - "engines": { - "node": ">= 0.10.0" - } - }, - "packages/blockly/node_modules/streamqueue/node_modules/isarray": { - "version": "0.0.1", - "dev": true, - "license": "MIT" - }, - "packages/blockly/node_modules/streamqueue/node_modules/readable-stream": { - "version": "1.1.14", - "dev": true, - "license": "MIT", - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.1", - "isarray": "0.0.1", - "string_decoder": "~0.10.x" - } - }, - "packages/blockly/node_modules/streamqueue/node_modules/string_decoder": { - "version": "0.10.31", - "dev": true, - "license": "MIT" - }, "packages/blockly/node_modules/string_decoder": { "version": "1.1.1", "dev": true, @@ -9339,11 +9246,6 @@ "typescript": ">=4.8.4" } }, - "packages/blockly/node_modules/tslib": { - "version": "1.14.1", - "dev": true, - "license": "0BSD" - }, "packages/blockly/node_modules/type": { "version": "1.2.0", "dev": true, diff --git a/packages/blockly/core/connection.ts b/packages/blockly/core/connection.ts index a55c25059..a79b7b9b1 100644 --- a/packages/blockly/core/connection.ts +++ b/packages/blockly/core/connection.ts @@ -291,10 +291,7 @@ export class Connection { } let event; - if ( - eventUtils.isEnabled() && - !childConnection.getSourceBlock().isDeadOrDying() - ) { + if (eventUtils.isEnabled()) { event = new (eventUtils.get(EventType.BLOCK_MOVE))( childConnection.getSourceBlock(), ) as BlockMove; diff --git a/packages/blockly/core/css.ts b/packages/blockly/core/css.ts index c664d25f8..0384f719f 100644 --- a/packages/blockly/core/css.ts +++ b/packages/blockly/core/css.ts @@ -98,14 +98,7 @@ const content = ` .blocklyBlockCanvas.blocklyCanvasTransitioning, .blocklyBubbleCanvas.blocklyCanvasTransitioning { - transition: transform .15s; -} - -@media (prefers-reduced-motion) { - .blocklyBlockCanvas.blocklyCanvasTransitioning, - .blocklyBubbleCanvas.blocklyCanvasTransitioning { - transition: none; - } + transition: transform .5s; } .blocklyEmboss { @@ -466,17 +459,14 @@ input[type=number] { } /* State: selected/checked. */ -.blocklyMenuItemCheckbox { - height: 16px; - position: absolute; - width: 16px; -} - .blocklyMenuItemSelected .blocklyMenuItemCheckbox { background: url(<<>>/sprites.svg) no-repeat -48px -16px; float: left; margin-left: -24px; + width: 16px; + height: 16px; position: static; /* Scroll with the menu. */ + display: block; } .blocklyMenuItemRtl .blocklyMenuItemCheckbox { diff --git a/packages/blockly/core/layer_manager.ts b/packages/blockly/core/layer_manager.ts index 7d253b110..1142bcf58 100644 --- a/packages/blockly/core/layer_manager.ts +++ b/packages/blockly/core/layer_manager.ts @@ -73,11 +73,11 @@ export class LayerManager { * @internal */ appendToAnimationLayer(elem: IRenderedElement) { - const currentTransform = this.dragLayer?.style.transform; + const currentTransform = this.dragLayer?.getAttribute('transform'); // Only update the current transform when appending, so animations don't // move if the workspace moves. - if (currentTransform && this.animationLayer) { - this.animationLayer.style.transform = currentTransform; + if (currentTransform) { + this.animationLayer?.setAttribute('transform', currentTransform); } this.animationLayer?.appendChild(elem.getSvgRoot()); } @@ -88,12 +88,10 @@ export class LayerManager { * @internal */ translateLayers(newCoord: Coordinate, newScale: number) { - const translation = `translate(${newCoord.x}px, ${newCoord.y}px) scale(${newScale})`; - if (this.dragLayer) { - this.dragLayer.style.transform = translation; - } + const translation = `translate(${newCoord.x}, ${newCoord.y}) scale(${newScale})`; + this.dragLayer?.setAttribute('transform', translation); for (const [_, layer] of this.layers) { - layer.style.transform = translation; + layer.setAttribute('transform', translation); } } diff --git a/packages/blockly/core/toolbox/toolbox.ts b/packages/blockly/core/toolbox/toolbox.ts index 28861f231..67bb0fc84 100644 --- a/packages/blockly/core/toolbox/toolbox.ts +++ b/packages/blockly/core/toolbox/toolbox.ts @@ -11,7 +11,6 @@ */ // Former goog.module ID: Blockly.Toolbox -// Unused import preserved for side-effects. Remove if unneeded. import {BlockSvg} from '../block_svg.js'; import * as browserEvents from '../browser_events.js'; import * as common from '../common.js'; @@ -199,7 +198,7 @@ export class Toolbox aria.setRole(this.contentsDiv_, aria.Role.TREE); container.appendChild(this.contentsDiv_); - svg.parentNode!.insertBefore(container, svg); + svg.parentNode?.insertBefore(container, svg); this.attachEvents_(container, this.contentsDiv_); return container; @@ -288,7 +287,7 @@ export class Toolbox const itemId = (targetElement as Element).getAttribute('id'); if (itemId) { const item = this.getToolboxItemById(itemId); - if (item!.isSelectable()) { + if (item?.isSelectable()) { this.setSelectedItem(item); (item as ISelectableToolboxItem).onClick(e); } @@ -380,7 +379,7 @@ export class Toolbox const toolboxItemDef = toolboxDef[i]; this.createToolboxItem(toolboxItemDef, fragment); } - this.contentsDiv_!.appendChild(fragment); + this.contentsDiv_?.appendChild(fragment); } /** @@ -419,9 +418,7 @@ export class Toolbox } // Adds the ID to the HTML element that can receive a click. // This is used in onClick_ to find the toolboxItem that was clicked. - if (toolboxItem.getClickTarget()) { - toolboxItem.getClickTarget()!.setAttribute('id', toolboxItem.getId()); - } + toolboxItem.getClickTarget()?.setAttribute('id', toolboxItem.getId()); } } @@ -706,7 +703,7 @@ export class Toolbox this.width_ = toolboxDiv.offsetWidth; this.height_ = workspaceMetrics.viewHeight; } - this.flyout!.position(); + this.flyout?.position(); } /** @@ -715,10 +712,11 @@ export class Toolbox * @internal */ handleToolboxItemResize() { + if (!this.HtmlDiv) return; // Reposition the workspace so that (0,0) is in the correct position // relative to the new absolute edge (ie toolbox edge). const workspace = this.workspace_; - const rect = this.HtmlDiv!.getBoundingClientRect(); + const rect = this.HtmlDiv.getBoundingClientRect(); const flyout = this.getFlyout(); const newX = this.toolboxPosition === toolbox.Position.LEFT @@ -770,7 +768,7 @@ export class Toolbox this.selectedItem_.isSelectable() && this.selectedItem_.getContents().length ) { - this.flyout!.show(this.selectedItem_.getContents()); + this.flyout?.show(this.selectedItem_.getContents()); } } @@ -784,7 +782,9 @@ export class Toolbox return; } - this.HtmlDiv!.style.display = isVisible ? 'block' : 'none'; + if (this.HtmlDiv) { + this.HtmlDiv.style.display = isVisible ? 'block' : 'none'; + } this.isVisible_ = isVisible; // Invisible toolbox is ignored as drag targets and must have the drag // target updated. @@ -928,10 +928,10 @@ export class Toolbox (oldItem === newItem && !newItem.isCollapsible()) || !newItem.getContents().length ) { - this.flyout!.hide(); + this.flyout?.hide(); } else { - this.flyout!.show(newItem.getContents()); - this.flyout!.scrollToStart(); + this.flyout?.show(newItem.getContents()); + this.flyout?.scrollToStart(); } } @@ -968,8 +968,8 @@ export class Toolbox private toggleSelectedItem(expanded: boolean): boolean { if ( isCollapsibleToolboxItem(this.selectedItem_) && - this.selectedItem_.isCollapsible() && - this.selectedItem_.isExpanded() !== expanded + this.selectedItem_?.isCollapsible() && + this.selectedItem_?.isExpanded() !== expanded ) { this.selectedItem_.toggleExpanded(); return true; @@ -981,7 +981,7 @@ export class Toolbox /** Disposes of this toolbox. */ dispose() { this.workspace_.getComponentManager().removeComponent('toolbox'); - this.flyout!.dispose(); + this.flyout?.dispose(); this.contents.forEach((item) => item.dispose()); for (let j = 0; j < this.boundEvents_.length; j++) { diff --git a/packages/blockly/core/zoom_controls.ts b/packages/blockly/core/zoom_controls.ts index 6bd119423..4f14b73be 100644 --- a/packages/blockly/core/zoom_controls.ts +++ b/packages/blockly/core/zoom_controls.ts @@ -373,10 +373,8 @@ export class ZoomControls implements IPositionable { * @param e A mouse down event. */ private zoom(amount: number, e: PointerEvent) { - this.workspace.beginCanvasTransition(); this.workspace.markFocused(); this.workspace.zoomCenter(amount); - setTimeout(this.workspace.endCanvasTransition.bind(this.workspace), 150); this.fireZoomEvent(); Touch.clearTouchIdentifier(); // Don't block future drags. e.stopPropagation(); // Don't start a workspace scroll. @@ -461,7 +459,7 @@ export class ZoomControls implements IPositionable { this.workspace.zoomCenter(amount); this.workspace.scrollCenter(); - setTimeout(this.workspace.endCanvasTransition.bind(this.workspace), 150); + setTimeout(this.workspace.endCanvasTransition.bind(this.workspace), 500); this.fireZoomEvent(); Touch.clearTouchIdentifier(); // Don't block future drags. e.stopPropagation(); // Don't start a workspace scroll. diff --git a/packages/blockly/gulpfile.mjs b/packages/blockly/gulpfile.mjs index ad61bcb51..378d6ce5e 100644 --- a/packages/blockly/gulpfile.mjs +++ b/packages/blockly/gulpfile.mjs @@ -33,18 +33,9 @@ import { tsc, } from './scripts/gulpfiles/build_tasks.mjs'; import {docs} from './scripts/gulpfiles/docs_tasks.mjs'; -import { - createRC, - syncDevelop, - syncMaster, - updateGithubPages, -} from './scripts/gulpfiles/git_tasks.mjs'; +import {updateGithubPages} from './scripts/gulpfiles/git_tasks.mjs'; import {cleanReleaseDir, pack} from './scripts/gulpfiles/package_tasks.mjs'; -import { - publish, - publishBeta, - recompile, -} from './scripts/gulpfiles/release_tasks.mjs'; +import {publish, publishBeta} from './scripts/gulpfiles/release_tasks.mjs'; import { generators, interactiveMocha, @@ -72,7 +63,7 @@ export { prepareDemos, deployDemosBeta, deployDemos, - updateGithubPages as gitUpdateGithubPages, + updateGithubPages, } // Manually-invokable targets that also invoke prerequisites where @@ -86,15 +77,5 @@ export { generators as testGenerators, interactiveMocha, buildAdvancedCompilationTest, - createRC as gitCreateRC, docs, } - -// Legacy targets, to be deleted. -// -// prettier-ignore -export { - recompile, - syncDevelop as gitSyncDevelop, - syncMaster as gitSyncMaster, -} diff --git a/packages/blockly/package.json b/packages/blockly/package.json index 5ab927b43..7f6d53970 100644 --- a/packages/blockly/package.json +++ b/packages/blockly/package.json @@ -1,16 +1,16 @@ { "name": "blockly", - "version": "12.4.1", + "version": "12.5.1", "description": "Blockly is a library for building visual programming editors.", "keywords": [ "blockly" ], "repository": { "type": "git", - "url": "git+https://github.com/google/blockly.git" + "url": "git+https://github.com/RaspberryPiFoundation/blockly.git" }, "bugs": { - "url": "https://github.com/google/blockly/issues" + "url": "https://github.com/RaspberryPiFoundation/blockly/issues" }, "homepage": "https://developers.google.com/blockly/", "author": { @@ -41,8 +41,6 @@ "prepareDemos": "gulp prepareDemos", "publish": "npm ci && gulp publish", "publish:beta": "npm ci && gulp publishBeta", - "recompile": "gulp recompile", - "release": "gulp gitCreateRC", "start": "npm run build && concurrently -n tsc,server \"tsc --watch --preserveWatchOutput --outDir \"build/src\" --declarationDir \"build/declarations\"\" \"http-server ./ -s -o /tests/playground.html -c-1\"", "tsc": "gulp tsc", "test": "gulp test", @@ -50,7 +48,8 @@ "test:generators": "gulp testGenerators", "test:mocha:interactive": "npm run build && concurrently -n tsc,server \"tsc --watch --preserveWatchOutput --outDir \"build/src\" --declarationDir \"build/declarations\"\" \"gulp interactiveMocha\"", "test:compile:advanced": "gulp buildAdvancedCompilationTest --debug", - "updateGithubPages": "npm ci && gulp gitUpdateGithubPages" + "updateGithubPages": "npm ci && gulp updateGithubPages --upstream", + "updateGithubPages:staging": "npm ci && gulp updateGithubPages --use-local" }, "exports": { ".": { @@ -114,6 +113,8 @@ "async-done": "^2.0.0", "chai": "^6.0.1", "concurrently": "^9.0.1", + "conventional-changelog-conventionalcommits": "^7.0.2", + "conventional-recommended-bump": "^9.0.0", "eslint": "^9.15.0", "eslint-config-google": "^0.14.0", "eslint-config-prettier": "^10.1.1", @@ -122,16 +123,13 @@ "eslint-plugin-prettier": "^5.2.1", "glob": "^11.0.1", "globals": "^16.0.0", - "google-closure-compiler": "^20260315.0.0", + "google-closure-compiler": "^20260330.0.0", "gulp": "^5.0.0", "gulp-concat": "^2.6.1", "gulp-gzip": "^1.4.2", "gulp-header": "^2.0.9", - "gulp-insert": "^0.5.0", "gulp-rename": "^2.0.0", "gulp-replace": "^1.0.0", - "gulp-series": "^1.0.2", - "gulp-shell": "^0.8.0", "gulp-sourcemaps": "^3.0.0", "gulp-umd": "^2.0.0", "http-server": "^14.0.0", diff --git a/packages/blockly/scripts/gulpfiles/git_tasks.mjs b/packages/blockly/scripts/gulpfiles/git_tasks.mjs index 2b08e16b3..6a68b54be 100644 --- a/packages/blockly/scripts/gulpfiles/git_tasks.mjs +++ b/packages/blockly/scripts/gulpfiles/git_tasks.mjs @@ -8,17 +8,36 @@ * @fileoverview Git-related gulp tasks for Blockly. */ + import * as gulp from 'gulp'; import {execSync} from 'child_process'; +import yargs from 'yargs'; +import { hideBin } from 'yargs/helpers'; import * as buildTasks from './build_tasks.mjs'; import * as packageTasks from './package_tasks.mjs'; -const UPSTREAM_URL = 'https://github.com/google/blockly.git'; +const UPSTREAM_URL = 'git@github.com:RaspberryPiFoundation/blockly.git'; + +// Use yargs to parse --remote argument +const argv = yargs(hideBin(process.argv)).option('remote', { + type: 'string', + describe: 'Remote to push gh-pages to', + demandOption: false +}).option('upstream', { + type: 'boolean', + describe: 'Push to RaspberryPiFoundation/blockly instead of origin', + demandOption: false +}).option('use-local', { + type: 'boolean', + describe: 'Build and push from current branch instead of syncing with main', + demandOption: false +}).help().argv; +const remoteToUse = argv.upstream ? UPSTREAM_URL : resolveRemote(argv.remote); /** * Extra paths to include in the gh_pages branch (beyond the normal - * contents of master / develop). Passed to shell unquoted, so can + * contents of main). Passed to shell unquoted, so can * include globs. */ const EXTRAS = [ @@ -28,140 +47,122 @@ const EXTRAS = [ 'build/*.loader.mjs', ]; -let upstream = null; - /** - * Get name of git remote for upstream (typically 'upstream', but this - * is just convention and can be changed.) - */ -function getUpstream() { - if (upstream) return upstream; - for (const line of String(execSync('git remote -v')).split('\n')) { - if (line.includes('google/blockly')) { - upstream = line.split('\t')[0]; - return upstream; - } - } - throw new Error('Unable to determine upstream URL'); -} - -/** - * Stash current state, check out the named branch, and sync with - * google/blockly. + * Stash current state, check out the named branch, and pull + * changes from RaspberryPiFoundation/blockly. */ function syncBranch(branchName) { return function(done) { execSync('git stash save -m "Stash for sync"', { stdio: 'inherit' }); checkoutBranch(branchName); execSync(`git pull ${UPSTREAM_URL} ${branchName}`, { stdio: 'inherit' }); - execSync(`git push origin ${branchName}`, { stdio: 'inherit' }); done(); }; } /** - * Stash current state, check out develop, and sync with - * google/blockly. + * Stash current state, check out main, and sync with + * RaspberryPiFoundation/blockly. */ -export function syncDevelop() { - return syncBranch('develop'); +export function syncMain() { + return syncBranch('main'); }; /** - * Stash current state, check out master, and sync with - * google/blockly. - */ -export function syncMaster() { - return syncBranch('master'); -}; - -/** - * Helper function: get a name for a rebuild branch. Format: - * rebuild_mm_dd_yyyy. - */ -function getRebuildBranchName() { - const date = new Date(); - const mm = date.getMonth() + 1; // Month, 0-11 - const dd = date.getDate(); // Day of the month, 1-31 - const yyyy = date.getFullYear(); - return `rebuild_${mm}_${dd}_${yyyy}`; -}; - -/** - * Helper function: get a name for a rebuild branch. Format: - * rebuild_yyyy_mm. - */ -function getRCBranchName() { - const date = new Date(); - const mm = date.getMonth() + 1; // Month, 0-11 - const yyyy = date.getFullYear(); - return `rc_${yyyy}_${mm}`; -}; - -/** - * If branch does not exist then create the branch. * If branch exists switch to branch. + * If branch does not exist then create the branch. */ function checkoutBranch(branchName) { - execSync(`git switch -c ${branchName}`, + execSync(`git switch ${branchName} || git switch -c ${branchName}`, { stdio: 'inherit' }); } /** - * Create and push an RC branch. - * Note that this pushes to google/blockly. - */ -export const createRC = gulp.series( - syncDevelop(), - function(done) { - const branchName = getRCBranchName(); - execSync(`git switch -C ${branchName}`, { stdio: 'inherit' }); - execSync(`git push ${UPSTREAM_URL} ${branchName}`, { stdio: 'inherit' }); - done(); - } -); - -/** Create the rebuild branch. */ -export function createRebuildBranch(done) { - const branchName = getRebuildBranchName(); - console.log(`make-rebuild-branch: creating branch ${branchName}`); - execSync(`git switch -C ${branchName}`, { stdio: 'inherit' }); - done(); -} - -/** Push the rebuild branch to origin. */ -export function pushRebuildBranch(done) { - console.log('push-rebuild-branch: committing rebuild'); - execSync('git commit -am "Rebuild"', { stdio: 'inherit' }); - const branchName = getRebuildBranchName(); - execSync(`git push origin ${branchName}`, { stdio: 'inherit' }); - console.log(`Branch ${branchName} pushed to GitHub.`); - console.log('Next step: create a pull request against develop.'); - done(); -} - -/** - * Update github pages with what is currently in develop. + * Update github pages with what is currently in main (or current branch if --use-local). * * Prerequisites (invoked): clean, build. + * + * Usage: + * gulp updateGithubPages # sync main, then use origin if exists + * gulp updateGithubPages --upstream # uses hardcoded upstream + * gulp updateGithubPages --remote # uses named remote + * gulp updateGithubPages --use-local # build from current branch, skip syncing main + * */ export const updateGithubPages = gulp.series( - function(done) { - execSync('git stash save -m "Stash for sync"', { stdio: 'inherit' }); - execSync('git switch -C gh-pages', { stdio: 'inherit' }); - execSync(`git fetch ${getUpstream()}`, { stdio: 'inherit' }); - execSync(`git reset --hard ${getUpstream()}/develop`, { stdio: 'inherit' }); - done(); - }, - buildTasks.cleanBuildDir, - packageTasks.cleanReleaseDir, - buildTasks.build, - function(done) { - // Extra paths (e.g. build/, dist/ etc.) are normally gitignored, - // so we have to force add. - execSync(`git add -f ${EXTRAS.join(' ')}`, {stdio: 'inherit'}); - execSync('git commit -am "Rebuild"', {stdio: 'inherit'}); - execSync(`git push ${UPSTREAM_URL} gh-pages --force`, {stdio: 'inherit'}); - done(); + function (done) { + if (!remoteToUse) { + const attemptedRemote = argv.remote || 'origin'; + const remoteLabel = argv.remote + ? `Remote '${attemptedRemote}'` + : "Remote 'origin' (default)"; + const errMsg = `${remoteLabel} not found in git remotes. ` + + 'Please add that remote or use --upstream.\n' + + 'Usage: gulp updateGithubPages [--remote | --upstream]'; + console.error(errMsg); + done(new Error(errMsg)); + return; + } + done(); + }, + function (done) { + if (!argv.useLocal) { + done(); + return; + } + const status = execSync('git status --porcelain', { encoding: 'utf8' }); + if (status.trim()) { + const errMsg = + 'You cannot push the local branch with uncommitted changes. ' + + 'Please commit or stash your changes first.'; + console.error(errMsg); + done(new Error(errMsg)); + return; + } + done(); + }, + function (done) { + if (argv.useLocal) { + done(); + return; + } + syncMain()(done); + }, + function(done) { + const sourceRef = argv.useLocal + ? execSync('git rev-parse HEAD', { encoding: 'utf8' }).trim() + : 'main'; + execSync('git switch -C gh-pages', { stdio: 'inherit' }); + execSync(`git reset --hard ${sourceRef}`, { stdio: 'inherit' }); + done(); + }, + buildTasks.cleanBuildDir, + packageTasks.cleanReleaseDir, + buildTasks.build, + function(done) { + // Extra paths (e.g. build/, dist/ etc.) are normally gitignored, + // so we have to force add. + execSync(`git add -f ${EXTRAS.join(' ')}`, {stdio: 'inherit'}); + execSync('git commit -am "Rebuild"', {stdio: 'inherit'}); + execSync(`git push ${remoteToUse} gh-pages --force`, {stdio: 'inherit'}); + done(); + } + ); + +/** + * Resolves which remote to use for pushing gh-pages. + * @param {string} remoteArg + * @returns {string|undefined} The remote name, or undefined if not found. + */ +function resolveRemote(remoteArg) { + const remoteName = remoteArg || 'origin'; + try { + const remotes = execSync('git remote', {encoding: 'utf8'}).split(/\r?\n/).map(r => r.trim()).filter(Boolean); + if (remotes.includes(remoteName)) { + return remoteName; + } + return undefined; + } catch (e) { + return undefined; } -); +} diff --git a/packages/blockly/scripts/gulpfiles/release_tasks.mjs b/packages/blockly/scripts/gulpfiles/release_tasks.mjs index a678a4f24..ca9c9ffa1 100644 --- a/packages/blockly/scripts/gulpfiles/release_tasks.mjs +++ b/packages/blockly/scripts/gulpfiles/release_tasks.mjs @@ -18,55 +18,6 @@ import * as packageTasks from './package_tasks.mjs'; import {getPackageJson} from './helper_tasks.mjs'; import {RELEASE_DIR} from './config.mjs'; - -// Gets the current major version. -function getMajorVersion() { - const { version } = getPackageJson(); - const re = new RegExp(/^(\d)./); - const match = re.exec(version); - if (!match[0]) { - return null; - } - console.log(match[0]); - return parseInt(match[0]); -} - -// Updates the version depending on user input. -function updateVersion(done, updateType) { - const majorVersion = getMajorVersion(); - if (!majorVersion) { - done(new Error('Something went wrong when getting the major version number.')); - } else if (!updateType) { - // User selected to cancel. - done(new Error('Cancelling process.')); - } - - switch (updateType.toLowerCase()) { - case 'major': - majorVersion++; - execSync(`npm --no-git-tag-version version ${majorVersion}.$(date +'%Y%m%d').0`, {stdio: 'inherit'}); - done(); - break; - case 'minor': - execSync(`npm --no-git-tag-version version ${majorVersion}.$(date +'%Y%m%d').0`, {stdio: 'inherit'}); - done(); - break; - case 'patch': - execSync(`npm --no-git-tag-version version patch`, {stdio: 'inherit'}); - done(); - break; - default: - done(new Error('Unexpected update type was chosen.')) - } -} - -// Prompt the user to figure out what kind of version update we should do. -function updateVersionPrompt(done) { - const releaseTypes = ['Major', 'Minor', 'Patch']; - const index = readlineSync.keyInSelect(releaseTypes, 'Which version type?'); - updateVersion(done, releaseTypes[index]); -} - // Checks with the user that they are on the correct git branch. function checkBranch(done) { const gitBranchName = execSync('git rev-parse --abbrev-ref HEAD').toString(); @@ -162,13 +113,3 @@ export const publishBeta = gulp.series( checkReleaseDir, loginAndPublishBeta ); - -// Switch to a new branch, update the version number, build Blockly -// and check in the resulting built files. -export const recompile = gulp.series( - gitTasks.syncDevelop(), - gitTasks.createRebuildBranch, - updateVersionPrompt, - packageTasks.pack, // Does clean + build. - gitTasks.pushRebuildBranch - );