feat(classroom): 授業支援 — 課題配信・組管理・AI 評価支援・課題テンプレート (EPIC #974) #2076
Workflow file for this run
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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 |