Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
66 changes: 66 additions & 0 deletions .claude/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
{
"$schema": "https://json.schemastore.org/claude-code-settings.json",
"includeCoAuthoredBy": false,
"enableAllProjectMcpServers": true,
"permissions": {
"allow": [
"Bash(gemini:*)",
"Bash(git:*)"
],
"deny": [
"Bash(sudo:*)",
"Read(.env.*)",
"Read(id_rsa)",
"Read(id_ed25519)",
"Read(**/*token*)",
"Read(**/*key*)",
"Write(.env*)",
"Write(**/secrets/**)",
"Bash(wget:*)",
"Bash(nc:*)",
"Bash(rm:*)",
"Bash(npm uninstall:*)",
"Bash(npm remove:*)",
"Bash(psql:*)",
"Bash(mysql:*)",
"Bash(mongod:*)",
"mcp__supabase__execute_sql"
]
},
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": "if jq -r '.tool_input.command' | grep -q '^git commit' && jq -r '.tool_input.command' | grep -q '🤖 Generated with'; then echo 'Error: コミットメッセージに AI 署名が含まれている' 1>&2; exit 2; fi"
}
]
}
],
"PostToolUse": [],
"Notification": [
{
"matcher": "*",
"hooks": [
{
"type": "command",
"command": "osascript -e 'display notification \"確認待ち\" with title \"Claude Code\"'"
}
]
}
],
"Stop": [
{
"matcher": "*",
"hooks": [
{
"type": "command",
"command": "osascript -e 'display notification \"タスク完了\" with title \"Claude Code\"'"
}
]
}
]
}
}
4 changes: 4 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
[*.{kt,kts}]
ktlint_code_style = ktlint_official
ktlint_standard_no-wildcard-imports = disabled
ktlint_standard_filename = disabled
183 changes: 183 additions & 0 deletions .github/workflows/vrt.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,183 @@
name: Visual Regression Testing

on:
pull_request:
types: [opened, synchronize, reopened]
paths-ignore:
- '**.md'
- 'docs/**'
- '.gitignore'

jobs:
vrt:
name: Visual Regression Tests
runs-on: ubuntu-latest
timeout-minutes: 30

steps:
- name: Checkout code
uses: actions/checkout@v4
with:
fetch-depth: 0

- name: Set up Java
uses: actions/setup-java@v4
with:
distribution: 'temurin'
java-version: '21'
cache: 'gradle'

- name: Set up Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'

- name: Install dependencies
run: |
npm ci
npx playwright install --with-deps chromium

- name: Build application
run: ./gradlew build -x test -x detekt

- name: Start application
run: |
./gradlew bootRun &
sleep 30
curl --retry 10 --retry-delay 5 --retry-connrefused http://localhost:8080

- name: Run Visual Regression Tests
id: vrt
run: npm run test:vrt
env:
BASE_URL: http://localhost:8080

- name: Upload test report
if: always()
uses: actions/upload-artifact@v4
with:
name: playwright-report
path: playwright-report/
retention-days: 7

- name: Upload test results
if: always()
uses: actions/upload-artifact@v4
with:
name: test-results
path: test-results/
retention-days: 7

- name: Upload snapshots on failure
if: failure()
uses: actions/upload-artifact@v4
with:
name: failed-snapshots
path: |
tests/vrt/**/*-actual.png
tests/vrt/**/*-diff.png
retention-days: 30

- name: Comment PR with results
if: always() && github.event_name == 'pull_request'
uses: actions/github-script@v7
with:
script: |
const fs = require('fs');
let message = '## 🎨 Visual Regression Test Results\n\n';

// Check if tests passed
const testOutcome = '${{ steps.vrt.outcome }}';
if (testOutcome === 'success') {
message += '✅ **All visual regression tests passed!**\n\n';
message += 'All page screenshots match the expected baselines.\n';
} else {
message += '❌ **Visual regression tests failed**\n\n';
message += 'Some pages have visual differences. Please review the artifacts:\n\n';
message += '### 📋 Actions to take:\n';
message += '1. [Download test artifacts](https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }})\n';
message += '2. Review the diff images to understand the changes\n';
message += '3. If changes are intentional, add `update-snapshots` label to this PR\n';
}

message += '\n### 📊 Test Coverage\n';
message += '- Desktop (1280x720)\n';
message += '- Tablet (iPad)\n';
message += '- Mobile (iPhone 13)\n';

github.rest.issues.createComment({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
body: message
})

update-snapshots:
name: Update Visual Snapshots
if: github.event_name == 'pull_request' && contains(github.event.pull_request.labels.*.name, 'update-snapshots')
runs-on: ubuntu-latest
timeout-minutes: 30

steps:
- name: Checkout code
uses: actions/checkout@v4
with:
token: ${{ secrets.GITHUB_TOKEN }}
ref: ${{ github.event.pull_request.head.ref }}

- name: Set up Java
uses: actions/setup-java@v4
with:
distribution: 'temurin'
java-version: '21'
cache: 'gradle'

- name: Set up Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'

- name: Install dependencies
run: |
npm ci
npx playwright install --with-deps chromium

- name: Build application
run: ./gradlew build -x test -x detekt

- name: Start application
run: |
./gradlew bootRun &
sleep 30
curl --retry 10 --retry-delay 5 --retry-connrefused http://localhost:8080

- name: Update snapshots
run: npm run test:vrt:update
env:
BASE_URL: http://localhost:8080

- name: Commit updated snapshots
run: |
git config --local user.email "github-actions[bot]@users.noreply.github.com"
git config --local user.name "github-actions[bot]"
git add tests/vrt/**/*.png
if git diff --staged --quiet; then
echo "No snapshot changes detected"
else
git commit -m "chore: update visual regression snapshots"
git push
fi

- name: Remove label
if: always()
uses: actions/github-script@v7
with:
script: |
await github.rest.issues.removeLabel({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.issue.number,
name: 'update-snapshots'
})
20 changes: 20 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -41,3 +41,23 @@ migration-plan.md
local.properties

.playwright-mcp

## Node.js
node_modules/
npm-debug.log*
yarn-debug.log*
yarn-error.log*
yarn.lock

## Playwright
playwright-report/
test-results/
tests/vrt/**/*.png-snapshots/
tests/vrt/**/*-actual.png
tests/vrt/**/*-diff.png
tests/vrt/**/*-expected.png

## Environment variables
.env
.env.local
.env.*.local
48 changes: 48 additions & 0 deletions .mcp.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
{
"mcpServers": {
"serena": {
"type": "stdio",
"command": "uvx",
"args": [
"--from",
"git+https://github.com/oraios/serena",
"serena-mcp-server",
"--context",
"ide-assistant",
"--project",
"."
],
"env": {}
},
"playwright": {
"command": "npx",
"args": [
"@playwright/mcp@latest"
]
},
"sequential-thinking": {
"command": "npx",
"args": [
"-y",
"@modelcontextprotocol/server-sequential-thinking"
]
},
"context7": {
"command": "npx",
"args": [
"-y",
"@upstash/context7-mcp"
]
}
},
"scopes": {
"ide-assistant": {
"mcpServers": [
"serena",
"playwright",
"sequential-thinking",
"context7"
]
}
}
}
3 changes: 3 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"java.configuration.updateBuildConfiguration": "automatic"
}
Loading
Loading