Skip to content
Open
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion .github/actions/install-dependencies/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,6 @@ runs:
key: ${{ runner.os }}-npm-${{ hashFiles('.nvmrc', 'package-lock.json') }}
- if: steps.restore-node-modules-cache.outputs.cache-hit != 'true'
name: Install NPM dependencies
working-directory: .
shell: bash
run: NODE_ENV=development npm ci
- uses: actions/cache/save@0057852bfaa89a56745cba8c7296529d2fc39830 # v4
Expand Down
6 changes: 2 additions & 4 deletions .github/actions/test-package/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,9 @@ runs:
using: composite
steps:
- name: Install Playwright
if: ${{ inputs.package_name == 'scratch-render' }}
shell: bash
run: |
if [[ ${{ inputs.package_name }} == "scratch-render" ]]; then
npx playwright install --with-deps chromium
fi
run: npx playwright install --with-deps chromium
- name: Test
working-directory: ./packages/${{ inputs.package_name }}
shell: bash
Expand Down
49 changes: 37 additions & 12 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,17 @@ on:
pull_request:
push: # WARNING: Renovate sometimes automerges without PR, so we MUST build and test renovate/** branches
workflow_call:
inputs:
force-full-build:
description: 'Build all packages regardless of path filters'
type: boolean
default: false
workflow_dispatch:
inputs:
force-full-build:
description: 'Build all packages regardless of path filters'
type: boolean
default: false

concurrency:
group: "${{ github.workflow }} @ ${{ github.event.compare || github.head_ref || github.ref }}"
Expand All @@ -29,22 +39,40 @@ jobs:
env:
# `env:` values are printed to the log even without using them in `run:`
GH_CONTEXT: ${{ toJson(github) }}
SCRATCH_ENV: ${{ vars.SCRATCH_ENV || '<none>' }}
run: |
cat <<EOF
Working directory: $(pwd)
Node version: $(node --version)
NPM version: $(npm --version)
Scratch environment: ${{ vars.SCRATCH_ENV || '<none>' }}
Scratch environment: $SCRATCH_ENV
EOF
- uses: dorny/paths-filter@de90cc6fb38fc0963ad72b210f1f284cd68cea36 # v3
id: filter
id: paths-filter
if: ${{ !inputs.force-full-build }}
with:
filters: ./.github/path-filters.yml

- name: Resolve changed packages
id: filter
run: |
if [ "${{ inputs.force-full-build }}" = "true" ]; then
echo "any-workspace=true" >> "$GITHUB_OUTPUT"
PACKAGES=$(ls -1d packages/*/ | xargs -n1 basename | jq -Rcn '[inputs]')
echo "changes=$PACKAGES" >> "$GITHUB_OUTPUT"
else
echo "any-workspace=${{ steps.paths-filter.outputs.any-workspace }}" >> "$GITHUB_OUTPUT"
PACKAGES=$(echo '${{ steps.paths-filter.outputs.changes }}' | jq -c '[.[] | select(. != "global" and . != "any-workspace")]')
echo "changes=$PACKAGES" >> "$GITHUB_OUTPUT"
fi
- if: ${{ steps.filter.outputs.any-workspace == 'true' }}
uses: ./.github/actions/install-dependencies

# IMPORTANT: always build all packages or none - never a subset.
# The publish workflow reuses these artifacts, so partial artifacts would cause publish
# failures for omitted packages.
- name: Build packages
if: ${{ steps.filter.outputs.any-workspace == 'true' }}
run: npm run build
Expand All @@ -54,6 +82,7 @@ jobs:
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5
with:
name: build
retention-days: 90
path: |
packages/**/build
packages/**/dist
Expand All @@ -62,7 +91,7 @@ jobs:
test:
runs-on: ubuntu-latest
needs: build
if: ${{ needs.build.outputs.any-workspace == 'true' }}
if: ${{ needs.build.outputs.any-workspace == 'true' && needs.build.outputs.packages != '[]' }}
permissions:
checks: write
pull-requests: write
Expand All @@ -72,9 +101,6 @@ jobs:
fail-fast: false
matrix:
package: ${{ fromJSON(needs.build.outputs.packages) }}
exclude:
- package: global
- package: any-workspace
name: Test ${{ matrix.package }}
steps:
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5
Expand Down Expand Up @@ -157,21 +183,20 @@ jobs:
name: Test Results
runs-on: ubuntu-latest
needs: test
if: ${{ !cancelled() }}
if: ${{ !cancelled() && needs.test.result != 'skipped' }}
steps:
- run: |
case "${{ needs.test.result }}" in
success)
echo "Tests passed successfully."
exit 0
;;
skipped)
echo "Tests were unnecessary for these changes, so they were skipped."
echo "If this is unexpected, check the path filters."
exit 0
cancelled)
echo "Tests were cancelled."
exit 1
;;
*)
echo "Tests failed."
echo "Tests failed. Result: ${{ needs.test.result }}"
exit 1
;;
esac
1 change: 1 addition & 0 deletions .github/workflows/commitlint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ on: [pull_request]

concurrency:
group: "${{ github.workflow }} @ ${{ github.event.pull_request.head.label || github.head_ref || github.sha }}"
cancel-in-progress: true

jobs:
commitlint:
Expand Down
4 changes: 4 additions & 0 deletions .github/workflows/ghpages-cleanup.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@ on:
- cron: 0 0 * * 6 # midnight on Saturdays
workflow_dispatch:

concurrency:
group: ghpages-cleanup
cancel-in-progress: false # queue rather than cancel: avoid half-cleaned states

jobs:
cleanup:
permissions:
Expand Down
162 changes: 113 additions & 49 deletions .github/workflows/publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,42 +5,105 @@ on:
types: [published]

jobs:
ci:
find-artifacts:
name: Find CI artifacts
runs-on: ubuntu-latest
outputs:
ci-run-id: ${{ steps.find.outputs.run-id }}
needs-build: ${{ steps.find.outputs.needs-build }}
steps:
- name: Find successful CI run for release target
id: find
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
TARGET: ${{ github.event.release.target_commitish }}
shell: bash
run: |
# Resolve branch name or tag to a commit SHA
SHA=$(gh api "repos/$GITHUB_REPOSITORY/commits/$TARGET" --jq '.sha' 2>/dev/null || echo "$TARGET")
echo "Resolved target '$TARGET' to SHA: $SHA"

# Find the most recent successful CI run for this SHA
RUN_ID=$(gh api "repos/$GITHUB_REPOSITORY/actions/workflows/ci.yml/runs" \
-F "head_sha=$SHA" \
-F "status=success" \
-F "per_page=1" \
--jq '.workflow_runs[0].id // empty') || {
echo "::error::Failed to query CI workflow runs. If ci.yml was renamed, update the reference in the find-artifacts job in publish.yml."
exit 1
}

if [ -z "$RUN_ID" ]; then
echo "No successful CI run found for SHA $SHA. A fresh build will be triggered."
echo "run-id=" >> "$GITHUB_OUTPUT"
echo "needs-build=true" >> "$GITHUB_OUTPUT"
else
echo "Found successful CI run: $RUN_ID"
echo "run-id=$RUN_ID" >> "$GITHUB_OUTPUT"
echo "needs-build=false" >> "$GITHUB_OUTPUT"
fi

build:
name: Build (no prior CI run found)
needs: find-artifacts
if: ${{ needs.find-artifacts.outputs.needs-build == 'true' }}
uses: ./.github/workflows/ci.yml
with:
force-full-build: true

cd:
name: Publish to npm
needs:
- ci
- find-artifacts
- build
# Run if find-artifacts succeeded AND (build succeeded OR build was skipped because artifacts already exist)
if: ${{ !cancelled() && needs.find-artifacts.result == 'success' && (needs.build.result == 'success' || needs.build.result == 'skipped') }}
runs-on: ubuntu-latest
permissions:
actions: read # to download artifacts from the CI run
contents: write # to push the version commit and tag
issues: write # to comment on issues when a fix is released
pull-requests: write # to comment on PRs when a fix is released
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
steps:
- name: Debug info
# https://docs.github.com/en/actions/reference/security/secure-use#use-an-intermediate-environment-variable
env:
# `env:` values are printed to the log even without using them in `run:`
RELEASE_TAG_NAME: ${{ github.event.release.tag_name }}
RELEASE_TARGET_COMMITISH: ${{ github.event.release.target_commitish }}
run: |
cat <<EOF
Release tag name: ${{ github.event.release.tag_name }}
Release target commit-ish: ${{ github.event.release.target_commitish }}
Release tag name: $RELEASE_TAG_NAME
Release target commit-ish: $RELEASE_TARGET_COMMITISH
EOF

- name: Determine NPM tag
id: npm_tag
shell: bash
env:
TARGET_COMMITISH: ${{ github.event.release.target_commitish }}
IS_PRERELEASE: ${{ github.event.release.prerelease }}
run: |
case ${{ github.event.release.target_commitish }} in
case "$TARGET_COMMITISH" in
develop | main | master)
if [[ ${{ github.event.release.prerelease }} == true ]]; then
if [[ "$IS_PRERELEASE" == true ]]; then
npm_tag=beta
else
npm_tag=latest
fi
;;
*)
# use the branch name
npm_tag="${{ github.event.release.target_commitish }}"
# use the branch name as the npm tag
npm_tag="$TARGET_COMMITISH"
;;
esac
echo "Determined NPM tag: [$npm_tag]"
echo "npm_tag=${npm_tag}" >> "$GITHUB_OUTPUT"
echo "NPM_TAG=${npm_tag}" >> "$GITHUB_ENV"

- name: Check NPM tag
run: |
if [ -z "${{ steps.npm_tag.outputs.npm_tag }}" ]; then
if [ -z "$NPM_TAG" ]; then
echo "Refusing to publish with empty NPM tag."
exit 1
fi
Expand All @@ -63,76 +126,67 @@ jobs:

- uses: ./.github/actions/install-dependencies

- name: Download build artifacts (from previous CI run)
if: ${{ needs.build.result == 'skipped' }}
uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # v6
with:
name: build
path: packages
run-id: ${{ needs.find-artifacts.outputs.ci-run-id }}
github-token: ${{ secrets.GITHUB_TOKEN }}

- name: Download build artifacts (from fallback build in this run)
if: ${{ needs.build.result == 'success' }}
uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # v6
with:
name: build
path: packages

- name: Update the version in the package files
shell: bash
env:
GIT_TAG: ${{ github.event.release.tag_name }}
run: |
GIT_TAG="${{github.event.release.tag_name}}"
NEW_VERSION="${GIT_TAG/v/}"

npm version "$NEW_VERSION" --no-git-tag-version
git add package* && git commit -m "chore(release): $NEW_VERSION [skip ci]"

# Install dependencies after the version update so that
# the build outputs refer to the newest version of inner packages
- uses: ./.github/actions/install-dependencies

- name: Publish scratch-svg-renderer
run: |
npm run build --workspace @scratch/scratch-svg-renderer
npm publish --access=public --tag="${{steps.npm_tag.outputs.npm_tag}}" --workspace=@scratch/scratch-svg-renderer
env:
NODE_AUTH_TOKEN: ${{secrets.NPM_TOKEN}}
run: npm publish --access=public --tag="$NPM_TAG" --workspace=@scratch/scratch-svg-renderer

- name: Publish scratch-render
run: |
npm run build --workspace @scratch/scratch-render
npm publish --access=public --tag="${{steps.npm_tag.outputs.npm_tag}}" --workspace=@scratch/scratch-render
env:
NODE_AUTH_TOKEN: ${{secrets.NPM_TOKEN}}
run: npm publish --access=public --tag="$NPM_TAG" --workspace=@scratch/scratch-render

- name: Publish scratch-vm
run: |
npm run build --workspace @scratch/scratch-vm
npm publish --access=public --tag="${{steps.npm_tag.outputs.npm_tag}}" --workspace=@scratch/scratch-vm
env:
NODE_AUTH_TOKEN: ${{secrets.NPM_TOKEN}}
run: npm publish --access=public --tag="$NPM_TAG" --workspace=@scratch/scratch-vm

- name: Publish scratch-gui
run: |
cp ./packages/scratch-gui/package.json ./packages/scratch-gui/package-copy.json

jq 'del(.exports["./standalone"])' ./packages/scratch-gui/package.json | npx sponge ./packages/scratch-gui/package.json

npm run build:dist --workspace @scratch/scratch-gui
npm publish --access=public --tag="${{steps.npm_tag.outputs.npm_tag}}" --workspace=@scratch/scratch-gui
npm publish --access=public --tag="$NPM_TAG" --workspace=@scratch/scratch-gui

mv ./packages/scratch-gui/package-copy.json ./packages/scratch-gui/package.json
env:
NODE_AUTH_TOKEN: ${{secrets.NPM_TOKEN}}

- name: Publish scratch-gui-standalone
run: |
bash ./scripts/prepare-standalone-gui.sh

npm --workspace=@scratch/scratch-gui-standalone run clean && npm --workspace=@scratch/scratch-gui-standalone run build:dist-standalone
npm publish --access=public --tag="${{steps.npm_tag.outputs.npm_tag}}" --workspace=@scratch/scratch-gui-standalone
env:
NODE_AUTH_TOKEN: ${{secrets.NPM_TOKEN}}
npm publish --access=public --tag="$NPM_TAG" --workspace=@scratch/scratch-gui-standalone

- name: Publish task-herder
run: |
npm run build --workspace @scratch/task-herder
npm publish --access=public --tag="${{steps.npm_tag.outputs.npm_tag}}" --workspace=@scratch/task-herder
env:
NODE_AUTH_TOKEN: ${{secrets.NPM_TOKEN}}
run: npm publish --access=public --tag="$NPM_TAG" --workspace=@scratch/task-herder

- name: Push to develop
shell: bash
env:
TAG_NAME: ${{ github.event.release.tag_name }}
run: |
git fetch origin develop

TAG_NAME="${{github.event.release.tag_name}}"
LAST_COMMIT_ID="$(git rev-parse $TAG_NAME)"
LAST_COMMIT_ID="$(git rev-parse "$TAG_NAME")"
DEVELOP_COMMIT_ID="$(git rev-parse origin/develop)"

if [ "$LAST_COMMIT_ID" = "$DEVELOP_COMMIT_ID" ]; then
Expand All @@ -141,9 +195,19 @@ jobs:
echo "Not pushing to develop because the tag we're operating on is behind"
fi

- name: Comment on resolved issues and merged PRs
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cool!

if: ${{ !github.event.release.prerelease }}
uses: apexskier/github-release-commenter@e7813a9625eabd79a875b4bc4046cfcae377ab34 # v1
with:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
comment-template: |
:tada: This is included in release {release_link}.

# See https://stackoverflow.com/a/24849501
- name: Change connected commit on release
shell: bash
env:
TAG_NAME: ${{ github.event.release.tag_name }}
run: |
git tag -f "${{github.event.release.tag_name}}" HEAD
git push -f origin "refs/tags/${{github.event.release.tag_name}}"
git tag -f "$TAG_NAME" HEAD
git push -f origin "refs/tags/$TAG_NAME"
Loading