Skip to content

Merge pull request #1031 from smalruby/topic/autopilot-1030 #2086

Merge pull request #1031 from smalruby/topic/autopilot-1030

Merge pull request #1031 from smalruby/topic/autopilot-1030 #2086

Workflow file for this run

name: CI/CD
on:
pull_request:
paths-ignore:
- '.claude/**'
- '.gemini/**'
- '.serena/**'
- 'Dockerfile'
- 'docker-compose.yml'
- 'CLAUDE.md'
- 'GEMINI.md'
- '.editorconfig'
- '.env.example'
- '.gitignore'
- '.mcp.json'
- 'entrypoint.sh'
- 'README.md'
- 'Release.md'
- 'TRADEMARK'
- 'infra/**'
- 'ruby/**'
- 'tools/**'
- 'docs/**'
- 'bin/**'
push:
branches: [main, master, develop, hotfix/*]
paths-ignore:
- '.claude/**'
- '.gemini/**'
- '.serena/**'
- 'Dockerfile'
- 'docker-compose.yml'
- 'CLAUDE.md'
- 'GEMINI.md'
- '.editorconfig'
- '.env.example'
- '.gitignore'
- '.mcp.json'
- 'entrypoint.sh'
- 'README.md'
- 'Release.md'
- 'TRADEMARK'
- 'infra/**'
- 'ruby/**'
- 'tools/**'
- 'docs/**'
- 'bin/**'
workflow_dispatch:
concurrency:
group: "${{ github.workflow }} @ ${{ github.head_ref || github.ref }}"
cancel-in-progress: true
permissions:
contents: write # publish a GitHub release
pages: write # deploy to GitHub Pages
issues: write # comment on released issues
pull-requests: write # comment on released pull requests
jobs:
lint:
runs-on: ubuntu-latest
if: |
(!(
github.ref == 'refs/heads/develop' ||
github.ref == 'refs/heads/master' ||
github.ref == 'refs/heads/main'
))
steps:
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5
- uses: actions/setup-node@2028fbc5c25fe9cf00d9f06a71cc4710d4507903 # v6
with:
cache: 'npm'
node-version-file: '.nvmrc'
- name: Install Dependencies
uses: ./.github/actions/install-dependencies
- name: Build dependency packages
run: npm run build:dev --workspace=packages/scratch-svg-renderer --workspace=packages/scratch-render --workspace=packages/scratch-vm
- name: Lint
run: npm run lint
unit-test-vm:
runs-on: ubuntu-latest
if: |
(!(
github.ref == 'refs/heads/develop' ||
github.ref == 'refs/heads/master' ||
github.ref == 'refs/heads/main'
))
env:
NODE_OPTIONS: --max-old-space-size=4000
steps:
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5
- uses: actions/setup-node@2028fbc5c25fe9cf00d9f06a71cc4710d4507903 # v6
with:
cache: 'npm'
node-version-file: '.nvmrc'
- name: Install Dependencies
uses: ./.github/actions/install-dependencies
- name: Build dependency packages
run: npm run build:dev --workspace=packages/scratch-svg-renderer --workspace=packages/scratch-render --workspace=packages/scratch-vm
- name: Run scratch-vm Unit Tests
run: npm run test:unit --workspace=packages/scratch-vm
unit-test-gui:
runs-on: ubuntu-latest
if: |
(!(
github.ref == 'refs/heads/develop' ||
github.ref == 'refs/heads/master' ||
github.ref == 'refs/heads/main'
))
env:
NODE_OPTIONS: --max-old-space-size=4000
steps:
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5
- uses: actions/setup-node@2028fbc5c25fe9cf00d9f06a71cc4710d4507903 # v6
with:
cache: 'npm'
node-version-file: '.nvmrc'
- name: Install Dependencies
uses: ./.github/actions/install-dependencies
- name: Build dependency packages
run: npm run build:dev --workspace=packages/scratch-svg-renderer --workspace=packages/scratch-render --workspace=packages/scratch-vm
- name: Run scratch-gui Unit Tests
run: npm run test:unit --workspace=packages/scratch-gui
integration-test-vm:
runs-on: ubuntu-latest
if: |
(!(
github.ref == 'refs/heads/develop' ||
github.ref == 'refs/heads/master' ||
github.ref == 'refs/heads/main'
))
strategy:
matrix:
shard: [1, 2]
env:
NODE_OPTIONS: --max-old-space-size=4000
steps:
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5
- uses: actions/setup-node@2028fbc5c25fe9cf00d9f06a71cc4710d4507903 # v6
with:
cache: 'npm'
node-version-file: '.nvmrc'
- name: Info
run: |
cat <<EOF
Node version: $(node --version)
NPM version: $(npm --version)
GitHub ref: ${{ github.ref }}
GitHub head ref: ${{ github.head_ref }}
EOF
- name: Install Dependencies
uses: ./.github/actions/install-dependencies
- name: Build packages
run: npm run build:dev
- name: Create test-results directories
run: mkdir -p packages/scratch-vm/test-results
- name: Run scratch-vm Integration Tests
env:
MESH_DATA_UPDATE_INTERVAL_MS: 100
MESH_EVENT_BATCH_INTERVAL_MS: 100
MESH_PERIODIC_DATA_SYNC_INTERVAL_MS: 1000
working-directory: packages/scratch-vm
run: |
# Collect all integration test files and sort for deterministic sharding
files=$(find test/integration -name '*.js' -o -name '*.test.js' | sort)
total=$(echo "$files" | wc -l)
half=$(( (total + 1) / 2 ))
if [ "${{ matrix.shard }}" = "1" ]; then
selected=$(echo "$files" | head -n "$half")
else
selected=$(echo "$files" | tail -n +"$((half + 1))")
fi
echo "Shard ${{ matrix.shard }}/$total files: running $(echo "$selected" | wc -l) files"
echo "$selected"
echo "$selected" | xargs npx tap
- name: Store Test Results
if: always() # Even if tests fail
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5
with:
name: test-output-integration-vm-shard-${{ matrix.shard }}
path: packages/scratch-vm/test-results/*
integration-test-gui:
runs-on: ubuntu-latest
if: |
(!(
github.ref == 'refs/heads/develop' ||
github.ref == 'refs/heads/master' ||
github.ref == 'refs/heads/main'
))
strategy:
matrix:
shard: [1, 2]
env:
NODE_OPTIONS: --max-old-space-size=4000
steps:
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5
- uses: actions/setup-node@2028fbc5c25fe9cf00d9f06a71cc4710d4507903 # v6
with:
cache: 'npm'
node-version-file: '.nvmrc'
- uses: browser-actions/setup-chrome@c785b87e244131f27c9f19c1a33e2ead956ab7ce # v1
id: setup-chrome
with:
chrome-version: stable
- name: Info
run: |
cat <<EOF
Node version: $(node --version)
NPM version: $(npm --version)
Chrome: ${{ steps.setup-chrome.outputs.chrome-path }} ($(${{ steps.setup-chrome.outputs.chrome-path }} --version))
GitHub ref: ${{ github.ref }}
GitHub head ref: ${{ github.head_ref }}
EOF
- name: Install Dependencies
uses: ./.github/actions/install-dependencies
- name: Build packages
run: npm run build:dev
- name: Create test-results directories
run: mkdir -p packages/scratch-gui/test-results
- name: Run scratch-gui Integration Tests
env:
JEST_JUNIT_OUTPUT_DIR: packages/scratch-gui/test-results
run: npm run test:integration --workspace=packages/scratch-gui -- --shard=${{ matrix.shard }}/2
- name: Store Test Results
if: always() # Even if tests fail
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5
with:
name: test-output-integration-gui-shard-${{ matrix.shard }}
path: packages/scratch-gui/test-results/*
build-and-deploy:
runs-on: ubuntu-latest
env:
NODE_OPTIONS: --max-old-space-size=4000
steps:
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5
- uses: actions/setup-node@2028fbc5c25fe9cf00d9f06a71cc4710d4507903 # v6
with:
cache: 'npm'
node-version-file: '.nvmrc'
- name: Info
run: |
cat <<EOF
Node version: $(node --version)
NPM version: $(npm --version)
GitHub ref: ${{ github.ref }}
GitHub head ref: ${{ github.head_ref }}
EOF
- name: Install Dependencies
uses: ./.github/actions/install-dependencies
- name: Run Build
env:
NODE_ENV: production
GOOGLE_CLIENT_ID: ${{ secrets.GOOGLE_CLIENT_ID }}
GOOGLE_API_KEY: ${{ secrets.GOOGLE_API_KEY }}
MESH_GRAPHQL_ENDPOINT: ${{ secrets.MESH_GRAPHQL_ENDPOINT }}
MESH_API_KEY: ${{ secrets.MESH_API_KEY }}
MESH_AWS_REGION: ${{ secrets.MESH_AWS_REGION }}
MESH_DATA_UPDATE_INTERVAL_MS: ${{ vars.MESH_DATA_UPDATE_INTERVAL_MS }}
MESH_EVENT_BATCH_INTERVAL_MS: ${{ vars.MESH_EVENT_BATCH_INTERVAL_MS }}
MESH_PERIODIC_DATA_SYNC_INTERVAL_MS: ${{ vars.MESH_PERIODIC_DATA_SYNC_INTERVAL_MS }}
RUBYTEE_RELAY_ENDPOINT: ${{ secrets.RUBYTEE_RELAY_ENDPOINT }}
CLASSROOM_API_ENDPOINT: ${{ secrets.CLASSROOM_API_ENDPOINT }}
BUG_REPORT_API_ENDPOINT: ${{ secrets.BUG_REPORT_API_ENDPOINT }}
SCRATCH_API_PROXY_ENDPOINT: ${{ vars.SCRATCH_API_PROXY_ENDPOINT }}
MICROSOFT_CLIENT_ID: ${{ secrets.MICROSOFT_CLIENT_ID }}
MAX_USER_MESSAGE_LENGTH: ${{ vars.MAX_USER_MESSAGE_LENGTH }}
MIN_USER_MESSAGE_LENGTH: ${{ vars.MIN_USER_MESSAGE_LENGTH }}
GTM_ID: ${{ github.ref == 'refs/heads/develop' && secrets.GTM_ID || '' }}
GTM_ENV_AUTH: ${{ github.ref == 'refs/heads/develop' && secrets.GTM_ENV_AUTH || '' }}
COMMIT_SHA: ${{ github.sha }}
run: npm run build
- name: Generate version.json
run: |
echo '{"commitId":"${{ github.sha }}"}' > packages/scratch-gui/build/version.json
echo '{"commitId":"${{ github.sha }}"}' > packages/scratch-gui/dist/version.json
- name: Store Build Output
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5
with:
name: build-output
path: packages/scratch-gui/build
- name: Store Dist Output
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5
with:
name: dist-output
path: packages/scratch-gui/dist
- name: Prepare deployment files for smalruby.app
if: github.ref == 'refs/heads/develop'
run: touch packages/scratch-gui/dist/.nojekyll
- name: Deploy to smalruby.app GitHub Pages
uses: peaceiris/actions-gh-pages@4f9cc6602d3f66b9c108549d475ec49e8ef4d45e # v4
if: github.ref == 'refs/heads/develop'
with:
deploy_key: ${{ secrets.SMALRUBY_APP_DEPLOY_KEY }}
publish_dir: ./packages/scratch-gui/dist
full_commit_message: "Build for ${{ github.sha }} ${{ github.event.head_commit.message }}"
cname: smalruby.app
external_repository: smalruby/smalruby.app
- name: Rebuild for smalruby3-editor GitHub Pages
if: github.ref == 'refs/heads/develop' || github.ref == 'refs/heads/master' || github.ref == 'refs/heads/main'
env:
PUBLIC_PATH: /smalruby3-editor/
GOOGLE_CLIENT_ID: ${{ secrets.GOOGLE_CLIENT_ID }}
GOOGLE_API_KEY: ${{ secrets.GOOGLE_API_KEY }}
MESH_GRAPHQL_ENDPOINT: ${{ secrets.MESH_GRAPHQL_ENDPOINT }}
MESH_API_KEY: ${{ secrets.MESH_API_KEY }}
MESH_AWS_REGION: ${{ secrets.MESH_AWS_REGION }}
MESH_DATA_UPDATE_INTERVAL_MS: ${{ vars.MESH_DATA_UPDATE_INTERVAL_MS }}
MESH_EVENT_BATCH_INTERVAL_MS: ${{ vars.MESH_EVENT_BATCH_INTERVAL_MS }}
MESH_PERIODIC_DATA_SYNC_INTERVAL_MS: ${{ vars.MESH_PERIODIC_DATA_SYNC_INTERVAL_MS }}
RUBYTEE_RELAY_ENDPOINT: ${{ secrets.RUBYTEE_RELAY_ENDPOINT }}
CLASSROOM_API_ENDPOINT: ${{ secrets.CLASSROOM_API_ENDPOINT }}
BUG_REPORT_API_ENDPOINT: ${{ secrets.BUG_REPORT_API_ENDPOINT }}
SCRATCH_API_PROXY_ENDPOINT: ${{ vars.SCRATCH_API_PROXY_ENDPOINT }}
MICROSOFT_CLIENT_ID: ${{ secrets.MICROSOFT_CLIENT_ID }}
MAX_USER_MESSAGE_LENGTH: ${{ vars.MAX_USER_MESSAGE_LENGTH }}
MIN_USER_MESSAGE_LENGTH: ${{ vars.MIN_USER_MESSAGE_LENGTH }}
GTM_ID: ''
GTM_ENV_AUTH: ''
run: cd packages/scratch-gui && npm exec node ./scripts/postbuild.mjs
- name: Prepare deployment files
if: github.ref == 'refs/heads/develop' || github.ref == 'refs/heads/master' || github.ref == 'refs/heads/main'
run: touch packages/scratch-gui/build/.nojekyll
- name: Deploy to smalruby3-editor GitHub Pages
uses: peaceiris/actions-gh-pages@4f9cc6602d3f66b9c108549d475ec49e8ef4d45e # v4
if: github.ref == 'refs/heads/develop' || github.ref == 'refs/heads/master' || github.ref == 'refs/heads/main'
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
publish_dir: ./packages/scratch-gui/build
full_commit_message: "Build for ${{ github.sha }} ${{ github.event.head_commit.message }}"
- name: Set branch name
id: branch
run: echo "BRANCH_NAME=${{ github.head_ref || github.ref_name }}" >> $GITHUB_OUTPUT
- name: Rebuild for branch GitHub Pages
if: |
(!(
github.ref == 'refs/heads/develop' ||
github.ref == 'refs/heads/master' ||
github.ref == 'refs/heads/main' ||
startsWith(github.ref, 'refs/heads/hotfix/') ||
startsWith(github.ref, 'refs/heads/dependabot/') ||
startsWith(github.ref, 'refs/heads/renovate/')
))
env:
PUBLIC_PATH: /smalruby3-editor/${{ steps.branch.outputs.BRANCH_NAME }}/
GOOGLE_CLIENT_ID: ${{ secrets.GOOGLE_CLIENT_ID }}
GOOGLE_API_KEY: ${{ secrets.GOOGLE_API_KEY }}
MESH_GRAPHQL_ENDPOINT: ${{ secrets.MESH_GRAPHQL_ENDPOINT }}
MESH_API_KEY: ${{ secrets.MESH_API_KEY }}
MESH_AWS_REGION: ${{ secrets.MESH_AWS_REGION }}
MESH_DATA_UPDATE_INTERVAL_MS: ${{ vars.MESH_DATA_UPDATE_INTERVAL_MS }}
MESH_EVENT_BATCH_INTERVAL_MS: ${{ vars.MESH_EVENT_BATCH_INTERVAL_MS }}
MESH_PERIODIC_DATA_SYNC_INTERVAL_MS: ${{ vars.MESH_PERIODIC_DATA_SYNC_INTERVAL_MS }}
RUBYTEE_RELAY_ENDPOINT: ${{ secrets.RUBYTEE_RELAY_ENDPOINT }}
CLASSROOM_API_ENDPOINT: ${{ secrets.CLASSROOM_API_ENDPOINT }}
BUG_REPORT_API_ENDPOINT: ${{ secrets.BUG_REPORT_API_ENDPOINT }}
SCRATCH_API_PROXY_ENDPOINT: ${{ vars.SCRATCH_API_PROXY_ENDPOINT }}
MICROSOFT_CLIENT_ID: ${{ secrets.MICROSOFT_CLIENT_ID }}
MAX_USER_MESSAGE_LENGTH: ${{ vars.MAX_USER_MESSAGE_LENGTH }}
MIN_USER_MESSAGE_LENGTH: ${{ vars.MIN_USER_MESSAGE_LENGTH }}
GTM_ID: ''
GTM_ENV_AUTH: ''
run: cd packages/scratch-gui && npm exec node ./scripts/postbuild.mjs
- name: Prepare deployment files for branch GitHub Pages
if: |
(!(
github.ref == 'refs/heads/develop' ||
github.ref == 'refs/heads/master' ||
github.ref == 'refs/heads/main' ||
startsWith(github.ref, 'refs/heads/hotfix/') ||
startsWith(github.ref, 'refs/heads/dependabot/') ||
startsWith(github.ref, 'refs/heads/renovate/')
))
run: touch packages/scratch-gui/build/.nojekyll
- name: Deploy playground to GitHub Pages for branch
if: |
(!(
github.ref == 'refs/heads/develop' ||
github.ref == 'refs/heads/master' ||
github.ref == 'refs/heads/main' ||
startsWith(github.ref, 'refs/heads/hotfix/') ||
startsWith(github.ref, 'refs/heads/dependabot/') ||
startsWith(github.ref, 'refs/heads/renovate/')
))
uses: peaceiris/actions-gh-pages@4f9cc6602d3f66b9c108549d475ec49e8ef4d45e # v4
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
publish_dir: ./packages/scratch-gui/build
full_commit_message: "Build for ${{ steps.branch.outputs.BRANCH_NAME }} (${{ github.sha }}) ${{ github.event.head_commit.message }}"
destination_dir: ${{ steps.branch.outputs.BRANCH_NAME }}
keep_files: true
- name: Comment preview URL on PR (once only)
if: |
github.event_name == 'pull_request' &&
(!(
github.ref == 'refs/heads/develop' ||
github.ref == 'refs/heads/master' ||
github.ref == 'refs/heads/main' ||
startsWith(github.ref, 'refs/heads/hotfix/') ||
startsWith(github.ref, 'refs/heads/dependabot/') ||
startsWith(github.ref, 'refs/heads/renovate/')
))
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
PREVIEW_URL: https://smalruby.jp/smalruby3-editor/${{ steps.branch.outputs.BRANCH_NAME }}/
run: |
PR_NUMBER=${{ github.event.pull_request.number }}
ALREADY_COMMENTED=$(gh pr view "$PR_NUMBER" --repo ${{ github.repository }} --json comments \
--jq "[.comments[].body | contains(\"$PREVIEW_URL\")] | any")
if [ "$ALREADY_COMMENTED" != "true" ]; then
gh pr comment "$PR_NUMBER" --repo ${{ github.repository }} \
--body "🚀 Preview deployed: $PREVIEW_URL"
fi