Skip to content
Open
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
43 changes: 43 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
# EditorConfig helps maintain consistent coding styles
# for multiple developers working on the same project
# across various editors and IDEs.
# https://editorconfig.org

root = true

# All files
[*]
charset = utf-8
end_of_line = lf
insert_final_newline = true
trim_trailing_whitespace = true

# Dart files
[*.dart]
indent_style = space
indent_size = 2
max_line_length = 120

# YAML files
[*.{yaml,yml}]
indent_style = space
indent_size = 2

# JSON files
[*.json]
indent_style = space
indent_size = 2

# Markdown files
[*.md]
trim_trailing_whitespace = false

# Gradle files
[*.gradle]
indent_style = space
indent_size = 4

# Properties files
[*.properties]
indent_style = space
indent_size = 4
172 changes: 172 additions & 0 deletions .github/workflows/pre_commit_check.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,172 @@
name: Pre-Commit Checks

on:
pull_request:
branches: ['**']

permissions:
contents: write
pull-requests: write

jobs:
precommit:
runs-on: ubuntu-latest
outputs:
violations_found: ${{ steps.check.outputs.violations_found }}
steps:
# 1 - Checkout code
- name: Setup workspace
uses: actions/checkout@v4
with:
fetch-depth: 0
token: ${{ secrets.GITHUB_TOKEN }}
ref: ${{ github.head_ref }}

# 2 - Set up Python (pre-commit requires it)
- name: Set up Python
uses: actions/setup-python@v4
with:
python-version: '3.x'

# 3 - Install our pre-commit
- name: Install pre-commit
run: |
python -m pip install --upgrade pip
pip install pre-commit

# 4 - Run pre-commit. If the script exits with a non-zero code, the GitHub Action will fail the PR.
- name: Run pre-commit hooks
run: pre-commit run --all-files

- name: Check code style violations
id: check
run: |
chmod +x ./scripts/auto_check_all.sh
violations_file="/tmp/style_violations.txt"
export VIOLATIONS_OUTPUT="$violations_file"

if ./scripts/auto_check_all.sh; then
echo "violations_found=false" >> $GITHUB_OUTPUT
else
echo "violations_found=true" >> $GITHUB_OUTPUT
echo "violations_file=$violations_file" >> $GITHUB_OUTPUT

if [[ ! -f "$violations_file" || ! -s "$violations_file" ]]; then
echo "VIOLATIONS_DETAILS_START" > "$violations_file"
echo "Code style violations detected but details unavailable" >> "$violations_file"
echo "VIOLATIONS_DETAILS_END" >> "$violations_file"
fi
fi

- name: Comment on PR
if: github.event_name == 'pull_request' && steps.check.outputs.violations_found == 'true'
uses: actions/github-script@v7
with:
script: |
const fs = require('fs');
const { owner, repo } = context.repo;
const issue_number = context.issue.number;

try {
const violationsFound = '${{ steps.check.outputs.violations_found }}' === 'true';
// Create violations comment if violations were found
if (violationsFound) {
let violationsComment = '## Code Style Violations Found\n\n';

// Try to parse violation details from the file
const violationsFile = '${{ steps.check.outputs.violations_file }}';
let detailsSection = '';
let totalCategories = '';
let totalViolations = '';

if (fs.existsSync(violationsFile)) {
try {
const content = fs.readFileSync(violationsFile, 'utf8');
const detailsMatch = content.match(/VIOLATIONS_DETAILS_START\n([\s\S]*?)\nVIOLATIONS_DETAILS_END/);

if (detailsMatch) {
const details = detailsMatch[1];
const lines = details.split('\n').filter(line => line.trim());
const failedChecks = [];

lines.forEach(line => {
if (line.includes('Total Categories Failed:')) {
totalCategories = line.split(': ')[1];
} else if (line.includes('Total Individual Violations:')) {
totalViolations = line.split(': ')[1];
} else if (line.includes('FAILED') && line.includes('violations')) {
// Parse lines like "- Static Constants (UPPER_SNAKE_CASE): FAILED (91 violations)"
const match = line.match(/- ([^:]+): FAILED \((\d+) violations\)/);
if (match) {
failedChecks.push('- **' + match[1] + '**: ' + match[2] + ' violations');
}
}
});

if (totalCategories && totalViolations && failedChecks.length > 0) {
detailsSection = failedChecks.join('\n');
}
}
} catch (error) {
console.log('Could not parse violation details:', error.message);
}
}

// If we couldn't parse details, use a generic message
if (!detailsSection) {
detailsSection = 'Based on the automated check, violations were found in multiple categories.';
}

violationsComment += detailsSection + '\n\n' +
'**Total Violations**: ' + (totalViolations || 'Unknown') + '\n' +
'**Total Categories Failed**: ' + (totalCategories || 'Unknown') + '\n\n' +
'## Here are the formatting rules to follow:\n\n' +
'- **Static Constants** have to use `UPPER_SNAKE_CASE` (e.g., `MAX_RETRY_COUNT`)\n' +
'- **Classes** have to use `UpperCamelCase` (e.g., `UserProfile`)\n' +
'- **Variables/Functions** have to use `lowerCamelCase` (e.g., `userName`)\n' +
'- **Files/Directories** have to use `snake_case` (e.g., `user_profile.dart`)\n' +
'- **Imports** have to use full package paths (e.g., `package:app_name/path/file.dart`)\n' +
'- **If Conditions** have to split long/complex conditions into variables for readability\n\n' +
'### Example of a long if condition violation:\n' +
'```dart\n' +
'if (userDataProvider.isLoggedIn &&\n' +
' (userDataProvider.userProfileModel.classifications?.staff ?? false)) {\n' +
' // action\n' +
'}\n' +
'```\n\n' +
'```dart\n' +
'// GOOD: split condition into variables for readability\n' +
'var isLoggedIn = userDataProvider.isLoggedIn;\n' +
'var isStaff = userDataProvider.userProfileModel.classifications?.staff ?? false;\n' +
'if (isLoggedIn && isStaff) {\n' +
' // action\n' +
'}\n' +
'```\n\n' +
'## To see more details and fix these violations:\n\n' +
'1. Run `./scripts/auto_check_all.sh` locally.\n' +
'2. Apply the suggested corrections.\n' +
'3. Re-run the script to verify fixes.\n' +
'4. Commit your changes.\n\n' +
'---\n' +
'*This comment will continue to appear until all violations are resolved.*';

await github.rest.issues.createComment({
owner, repo, issue_number, body: violationsComment
});
console.log('Violations comment added successfully');
}
} catch (error) {
console.error('Error creating PR comment:', error.message);

try {
await github.rest.issues.createComment({
owner, repo, issue_number,
body: '## Code Style Check Error\n\n' +
'There was an error processing the code style check results.\n\n' +
'**Error**: ' + error.message + '\n\n' +
'Please run the scripts locally to see the specific issues.'
});
} catch (fallbackError) {
console.error('Failed to create fallback comment:', fallbackError.message);
}
}
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
.history
.svn/
*.env
*.bak

# IntelliJ related
*.iml
Expand Down
20 changes: 20 additions & 0 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
repos:
- repo: local
hooks:
- id: run-all-lint-scripts
name: Run all lint scripts
language: system
pass_filenames: false
always_run: true
verbose: true
entry: |
bash -c '
echo "Running all lint scripts.."
bash scripts/auto_fix_all.sh
echo
echo "[pre-commit] All lint scripts completed."
'

# Run the following commands to set up pre-commit locally (one-time only setup):
# $pip install pre-commit (or $brew install pre-commit)
# $pre-commit install (or $python -m pre_commit install)
12 changes: 12 additions & 0 deletions Readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,18 @@ git checkout experimental
git checkout -b experimental
```

#### Using the Pre-Commit Hook
Before you start committing any changes, you can enable the repository's pre-commit hook, which will automatically run our lint/format scripts before each commit.

To enable it:

```shell
# Install pre-commit hook (one-time on your machine)
pip install pre-commit # or brew install pre-commit

# Enable the repo's pre-commit hook
pre-commit install # or python -m pre_commit install
```
You are now ready to begin developing your new feature. Commit your code often, using present-tense and concise verbiage explaining the work completed.

Example: Add, commit, and push your new feature:
Expand Down
2 changes: 1 addition & 1 deletion android/app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ android {

defaultConfig {
applicationId = "edu.ucsd"
minSdk = 23
minSdkVersion = flutter.minSdkVersion
targetSdk = flutter.targetSdkVersion
versionCode = flutter.versionCode
versionName = flutter.versionName
Expand Down
Loading