diff --git a/.github/workflows/devin-pr-review.yml b/.github/workflows/devin-pr-review.yml new file mode 100644 index 0000000000..d7b5cd6a82 --- /dev/null +++ b/.github/workflows/devin-pr-review.yml @@ -0,0 +1,212 @@ +name: "[PR] Devin Review" + +on: + pull_request: + types: [labeled] + +jobs: + request_devin_review: + if: ${{ github.event.label.name == 'devin-review' }} + runs-on: ubuntu-latest + timeout-minutes: 10 + permissions: + contents: read + pull-requests: write + steps: + - name: Checkout repository + uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 # v4.3.0 + with: + persist-credentials: false + + - name: Load review guidelines + id: guidelines + run: | + GUIDELINES_FILE="docs/review-guidelines.md" + if [ ! -f "$GUIDELINES_FILE" ]; then + echo "Error: $GUIDELINES_FILE not found" + exit 1 + fi + GUIDELINES=$(cat "$GUIDELINES_FILE") + if [ -z "$GUIDELINES" ]; then + echo "Error: $GUIDELINES_FILE is empty" + exit 1 + fi + echo "REVIEW_GUIDELINES<> $GITHUB_ENV + echo "$GUIDELINES" >> $GITHUB_ENV + echo "EOF" >> $GITHUB_ENV + + - name: Select API Key + id: select-api-key + env: + SENDER_LOGIN: ${{ github.event.sender.login }} + DEVIN_API_KEY_MH4GF: ${{ secrets.DEVIN_API_KEY_MH4GF }} + DEVIN_API_KEY_HOSHINOTSUYOSHI: ${{ secrets.DEVIN_API_KEY_HOSHINOTSUYOSHI }} + DEVIN_API_KEY_FUNAMA_YUKINA: ${{ secrets.DEVIN_API_KEY_FUNAMA_YUKINA }} + DEVIN_API_KEY_JUNKISAI: ${{ secrets.DEVIN_API_KEY_JUNKISAI }} + DEVIN_API_KEY_NORITAKE_IKEDA: ${{ secrets.DEVIN_API_KEY_NORITAKE_IKEDA }} + DEVIN_API_KEY_KUMANOAYUMI: ${{ secrets.DEVIN_API_KEY_KUMANOAYUMI }} + GH_TOKEN: ${{ github.token }} + run: | + set -euo pipefail + + # Function to post comment to PR + post_pr_comment() { + local comment_body="$1" + gh api \ + --method POST \ + -H "Accept: application/vnd.github+json" \ + -H "X-GitHub-Api-Version: 2022-11-28" \ + "/repos/${{ github.repository }}/issues/${{ github.event.pull_request.number }}/comments" \ + -f body="$comment_body" || true + } + + if [ -z "$SENDER_LOGIN" ] || [ "$SENDER_LOGIN" = "null" ]; then + echo "Error: github.event.sender.login is undefined or null" + exit 1 + fi + + echo "Label added by user: $SENDER_LOGIN" + + case "$SENDER_LOGIN" in + "MH4GF") + SELECTED_KEY="$DEVIN_API_KEY_MH4GF" + ;; + "hoshinotsuyoshi") + SELECTED_KEY="$DEVIN_API_KEY_HOSHINOTSUYOSHI" + ;; + "FunamaYukina") + SELECTED_KEY="$DEVIN_API_KEY_FUNAMA_YUKINA" + ;; + "junkisai") + SELECTED_KEY="$DEVIN_API_KEY_JUNKISAI" + ;; + "NoritakaIkeda") + SELECTED_KEY="$DEVIN_API_KEY_NORITAKE_IKEDA" + ;; + "kumanoayumi") + SELECTED_KEY="$DEVIN_API_KEY_KUMANOAYUMI" + ;; + *) + echo "Error: No API Key configured for user: $SENDER_LOGIN" + post_pr_comment "❌ Error: No Devin API Key configured for user \`$SENDER_LOGIN\`. Please contact repository administrators." + exit 1 + ;; + esac + + if [ -z "$SELECTED_KEY" ] || [ "$SELECTED_KEY" = "null" ]; then + echo "Error: API Key for user $SENDER_LOGIN is empty or not set" + post_pr_comment "❌ Error: Devin API Key for user \`$SENDER_LOGIN\` is empty or not set. Please contact repository administrators." + exit 1 + fi + + echo "DEVIN_API_KEY=$SELECTED_KEY" >> "$GITHUB_ENV" + echo "API Key configured for: $SENDER_LOGIN" + + - name: Request Devin Review + env: + PR_URL: ${{ github.event.pull_request.html_url }} + GH_TOKEN: ${{ github.token }} + CURL_MAX_TIME: 30 + CURL_CONNECT_TIMEOUT: 10 + run: | + set -euo pipefail + + # Function to post comment to PR + post_pr_comment() { + local comment_body="$1" + gh api \ + --method POST \ + -H "Accept: application/vnd.github+json" \ + -H "X-GitHub-Api-Version: 2022-11-28" \ + "/repos/${{ github.repository }}/issues/${{ github.event.pull_request.number }}/comments" \ + -f body="$comment_body" || true + } + + # Create JSON payload using jq with direct variable expansion + JSON_PAYLOAD=$(jq -n \ + --arg pr_url "$PR_URL" \ + --arg guidelines "$REVIEW_GUIDELINES" \ + '{prompt: ("@Devin " + $pr_url + " のブランチを引き継いで内容を深くレビューし、出てきた問題を全て修正してください。\n\nレビュー観点は docs/review-guidelines.md を参照してください。以下にその内容を記載します:\n\n" + $guidelines)}') + + echo "Sending request to Devin API..." + HTTP_CODE=$(curl -w "%{http_code}" -o response.json \ + --max-time "${CURL_MAX_TIME}" \ + --connect-timeout "${CURL_CONNECT_TIMEOUT}" \ + -X POST "https://api.devin.ai/v1/sessions" \ + -H "Authorization: Bearer $DEVIN_API_KEY" \ + -H "Content-Type: application/json" \ + -d "$JSON_PAYLOAD" \ + -s) || { + echo "Error: API request failed or timed out" + if [ -f response.json ]; then cat response.json; fi + post_pr_comment "❌ Error: Request to Devin API failed or timed out. Please try again later." + exit 1 + } + + if [ "$HTTP_CODE" -lt 200 ] || [ "$HTTP_CODE" -ge 300 ]; then + echo "Error: API request failed with HTTP status $HTTP_CODE" + cat response.json + post_pr_comment "❌ Error: Devin API request failed (HTTP $HTTP_CODE). Check GitHub Actions logs for details." + exit 1 + fi + + RESPONSE=$(cat response.json) + echo "Devin API request successful (HTTP $HTTP_CODE)" + + # Validate response is valid JSON + if ! echo "$RESPONSE" | jq empty 2>/dev/null; then + echo "Error: Received invalid JSON response from Devin API" + echo "Response (first 500 characters): ${RESPONSE:0:500}" + post_pr_comment "❌ Error: Received invalid response from Devin API. Check GitHub Actions logs for details." + exit 1 + fi + + # Extract session URL and check for errors in response + SESSION_URL=$(echo "$RESPONSE" | jq -r '.url // empty') + SESSION_ID=$(echo "$RESPONSE" | jq -r '.session_id // empty') + ERROR_MESSAGE=$(echo "$RESPONSE" | jq -r '.error.message // empty') + + if [ -n "$ERROR_MESSAGE" ]; then + echo "Error: API request failed with message: $ERROR_MESSAGE" + echo "Full response: $RESPONSE" + post_pr_comment "❌ Error: Devin API error: \`$ERROR_MESSAGE\`" + exit 1 + fi + + if [ -z "$SESSION_ID" ]; then + echo "Error: No session ID in response" + echo "Response: $RESPONSE" + post_pr_comment "❌ Error: Failed to create Devin session (no session ID). Check GitHub Actions logs for details." + exit 1 + fi + + if [ -z "$SESSION_URL" ]; then + echo "Warning: Session created but no URL in response" + echo "Session ID: $SESSION_ID" + echo "Response: $RESPONSE" + else + echo "Session URL: $SESSION_URL" + fi + + echo "SESSION_URL=$SESSION_URL" >> "$GITHUB_ENV" + + - name: Add comment to PR + env: + GH_TOKEN: ${{ github.token }} + run: | + SESSION_URL="${SESSION_URL:-}" + if [ -n "$SESSION_URL" ]; then + COMMENT_BODY="🤖 Devin review started. Track progress at <${SESSION_URL}>" + else + COMMENT_BODY="🤖 Devin review started. Fixes will be committed when review is complete." + fi + + if ! gh api \ + --method POST \ + -H "Accept: application/vnd.github+json" \ + -H "X-GitHub-Api-Version: 2022-11-28" \ + "/repos/${{ github.repository }}/issues/${{ github.event.pull_request.number }}/comments" \ + -f body="$COMMENT_BODY"; then + echo "::warning::Failed to post comment to PR #${{ github.event.pull_request.number }}, but Devin session was created successfully" + echo "Comment body was: $COMMENT_BODY" + fi diff --git a/docs/review-guidelines.md b/docs/review-guidelines.md new file mode 100644 index 0000000000..8b107049b7 --- /dev/null +++ b/docs/review-guidelines.md @@ -0,0 +1,211 @@ +# Review Guidelines + +This document defines code review guidelines for the liam-hq/liam repository. + +## General Principles + +### Code Quality + +- **Readability**: Code should be clear and easy to understand +- **Maintainability**: Future changes and extensions should be straightforward +- **Consistency**: Follow existing codebase style and conventions +- **Simplicity**: Avoid unnecessary complexity + +### Security + +- **Sensitive Information**: No API keys, passwords, or secrets in code +- **Authentication & Authorization**: Proper authentication mechanisms implemented +- **Input Validation**: User input properly validated +- **Dependencies**: No dependencies with known security vulnerabilities + +### Performance + +- **Efficiency**: Appropriate algorithm and data structure choices +- **Resource Usage**: Optimized memory and CPU usage +- **Scalability**: Design that can handle future scale + +## Coding Standards + +### Biome Configuration Compliance + +This project uses Biome for code quality. Follow these settings: + +- **Formatting**: + - Indent: 2 spaces + - Line width: 80 characters + - Quotes: Single quotes (`'`) + - Semicolons: As needed (asNeeded) + +- **Linter Rules**: + - `noUnusedVariables`: No unused variables + - `noUndeclaredVariables`: No undeclared variables + - `noUnusedImports`: No unused imports + - `noConsole`: Only `console.warn`, `console.error`, `console.info`, `console.debug` allowed (no `console.log`) + - `noUndeclaredDependencies`: All dependencies must be declared + - `useExhaustiveDependencies`: React hooks must have exhaustive dependencies + - `noExcessiveCognitiveComplexity`: Keep functions simple + - `noParameterAssign`: Don't reassign parameters + - `useSelfClosingElements`: Use self-closing tags when appropriate + +### TypeScript / JavaScript + +- **Type Safety**: Use proper type definitions, avoid `any` +- **Naming Conventions**: + - Variables/functions: camelCase + - Components/classes: PascalCase + - Constants: UPPER_SNAKE_CASE +- **Imports**: + - Remove unused imports + - Imports are organized (Biome's organizeImports is enabled) + +### React Components + +- **File Structure**: Follow the monorepo structure under `frontend/` +- **CSS Modules**: Use CSS Modules for styling +- **Props Type Definition**: Props must have clear type definitions +- **Hooks**: Follow React hooks best practices with exhaustive dependencies + +### Monorepo Structure + +- **Packages**: Code organized under `frontend/packages/`, `frontend/apps/`, and `frontend/internal-packages/` +- **Build Dependencies**: Respect Turbo build dependencies (see `turbo.json`) +- **Package Dependencies**: Declare all dependencies properly for each package + +### Git Commits + +- **Commit Messages**: Clear description of changes +- **Commit Size**: Appropriate granularity (not too large, not too small) +- **Commit History**: No unnecessary merge commits or reverts + +## Pull Request Guidelines + +### PR Description + +- **Purpose**: Clear statement of PR purpose +- **Changes**: What was changed +- **Key Points**: What reviewers should focus on +- **Related Issues**: Link to related GitHub Issues +- **Language**: Write in English + +### Changesets + +- Follow the [Changeset Creation Guide](./changeset-guide.md) +- Add appropriate changesets for versioned packages + +### Testing + +- **Test Addition**: Appropriate tests added for new features or fixes +- **Existing Tests**: All existing tests pass +- **Edge Cases**: Edge case testing considered + +### Documentation + +- **README Updates**: README updated when necessary +- **Comments**: Complex logic has appropriate comments (but avoid excessive comments) +- **Type Definitions**: Public API type definitions properly documented + +## Project-Specific Guidelines + +### Directory Structure + +- **frontend/packages/**: Public packages (`@liam-hq/cli`, `@liam-hq/erd-core`, `@liam-hq/schema`, `@liam-hq/ui`) +- **frontend/apps/**: Applications (`@liam-hq/app`, `@liam-hq/docs`, `@liam-hq/storybook`) +- **frontend/internal-packages/**: Internal packages (configs, e2e, etc.) +- **docs/**: Documentation files +- **scripts/**: Setup and utility scripts + +### Build System (Turbo) + +- **Build Order**: Respect build dependencies defined in `turbo.json` +- **Generation**: Run `gen` tasks before building when needed +- **Lint Dependencies**: Lint tasks depend on `gen` and `^build` +- **Test Dependencies**: Test tasks depend on `^build` and `gen` + +### Linting and Formatting + +- **Before Commit**: Run `pnpm run fmt` to format code +- **Lint Check**: Run `pnpm run lint` to check for issues +- **Stylelint**: CSS files must pass stylelint checks +- **Knip**: Unused dependencies and exports must be removed +- **Syncpack**: Package versions must be synchronized across workspace + +### Dependencies + +- **No Unnecessary Dependencies**: Don't add unnecessary dependencies +- **Version Management**: Dependencies managed with syncpack +- **License Compliance**: Check licenses of added dependencies + +### Environment Setup + +- **Environment Variables**: Use `.env.template` as reference +- **Supabase**: Local development uses Supabase +- **Test Credentials**: Use provided test credentials for local development + +## Review Process + +### Reviewer Responsibilities + +- **Constructive Feedback**: Provide specific and constructive feedback +- **Timely Review**: Review as quickly as possible +- **Clarify Questions**: Ask questions to clarify unclear points + +### PR Author Responsibilities + +- **Respond to Reviews**: Respond appropriately to review comments +- **Add Explanations**: Provide additional explanations when needed +- **Fix Issues**: Fix identified problems + +### Merge Criteria + +- **Approval**: Obtained approval from reviewers +- **CI/CD**: All CI/CD checks pass +- **Conflicts**: Merge conflicts resolved +- **Review Comments**: All review comments addressed + +## Checklist + +Use this checklist when reviewing: + +- [ ] Code follows Biome configuration +- [ ] Type safety maintained +- [ ] No security issues +- [ ] No performance issues +- [ ] Tests appropriately added +- [ ] Documentation updated +- [ ] PR description sufficient +- [ ] Changesets added (if needed) +- [ ] Commit messages clear +- [ ] Consistency with existing codebase maintained +- [ ] Build dependencies respected +- [ ] No unused dependencies or exports +- [ ] Package versions synchronized + +## Common Issues to Watch For + +### Build Issues + +- **Missing Build Artifacts**: Ensure `@liam-hq/db-structure` is built before linting +- **Generation Tasks**: Run `gen` tasks when schema definitions change +- **Turbo Cache**: Clear Turbo cache if builds behave unexpectedly + +### Lint Issues + +- **Console Logs**: Remove `console.log` statements (use `console.info`, `console.warn`, `console.error`, or `console.debug` instead) +- **Unused Imports**: Remove unused imports +- **Exhaustive Dependencies**: Ensure React hooks have all dependencies listed +- **Undeclared Dependencies**: Declare all used dependencies in package.json + +### Test Issues + +- **Test Principles**: Follow [test principles](./test-principles.md) +- **E2E Tests**: E2E tests depend on builds being complete +- **Coverage**: Maintain or improve test coverage + +## References + +- [CONTRIBUTING.md](../CONTRIBUTING.md) +- [README.md](../README.md) +- [Changeset Creation Guide](./changeset-guide.md) +- [Test Principles](./test-principles.md) +- [Biome Official Documentation](https://biomejs.dev/) +- [Turbo Documentation](https://turbo.build/repo/docs)