Skip to content

Commit cd54108

Browse files
committed
changelogs/1952636.txt
1 parent 679aed1 commit cd54108

196 files changed

Lines changed: 3995 additions & 458 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/copilot-instructions.md

Lines changed: 277 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,277 @@
1+
# Copilot Instructions for QuoteUnquote
2+
3+
This document helps Copilot sessions work effectively in the QuoteUnquote repository.
4+
5+
## Architecture Overview
6+
7+
Quote Unquote is a multi-module Android application with optional cloud backend:
8+
9+
- **`app/`** — Main Android app with UI, local persistence (Room/SQLite), widgets, and cloud sync integration
10+
- **`QuoteUnquote.utilsLib/`** — Shared Android utilities (preferences, notifications, widget helpers)
11+
- **`QuoteUnquote.cloudLib/`** — Android library defining cloud transfer data models and endpoint configuration
12+
- **`QuoteUnquote.cloudLib.functions/`** — Python backend for cloud sync/backup using Flask and Firestore
13+
14+
The app works primarily offline but supports optional cloud sync for favourites and full app state transfer via code-based transfer keys.
15+
16+
## Build & Test Commands
17+
18+
### Prerequisites
19+
20+
After cloning, initialize submodules:
21+
```bash
22+
git submodule update --init --recursive
23+
git submodule foreach git pull origin main
24+
```
25+
26+
Decrypt secrets (requires GPG):
27+
```bash
28+
# Creates local.properties from encrypted .gpg files
29+
# (Done manually in CI via secrets)
30+
```
31+
32+
### Android (Gradle)
33+
34+
All commands use the wrapper: `./gradlew [task]`
35+
36+
**Unit Tests** (runs locally, not on device):
37+
```bash
38+
# Run both build flavors
39+
./gradlew :app:testGooglePlayDebugUnitTestCoverage
40+
./gradlew :app:testFdroidDebugUnitTestCoverage
41+
42+
# Single flavor
43+
./gradlew :app:testDebugUnitTest # Current variant
44+
./gradlew :app:test --stacktrace # With details
45+
```
46+
47+
**Android Instrumentation Tests** (emulator/device):
48+
```bash
49+
# Covered by CI workflow, generally not run locally
50+
./gradlew connectedAndroidTest
51+
```
52+
53+
**Static Analysis** (all run independently):
54+
```bash
55+
./gradlew checkstyle # Code style (sun_checks.xml rules)
56+
./gradlew detekt # Code quality & rules
57+
./gradlew ktlint # Kotlin formatting
58+
./gradlew lintGooglePlayDebug # Android lint (requires google-services.json)
59+
./gradlew lintFdroidDebug # Android lint (F-Droid build)
60+
```
61+
62+
**Build**:
63+
```bash
64+
./gradlew assemble{FdroidDebug,GoogleplayDebug} # APK
65+
./gradlew assemble{FdroidRelease,GoogleplayRelease} # Production (requires signing config)
66+
./gradlew :app:build # Full build with tests
67+
```
68+
69+
**Clean Gradle Cache** (if cache issues):
70+
```bash
71+
./ci_clear_gradle_cache.sh
72+
```
73+
74+
### Python Backend (`QuoteUnquote.cloudLib.functions/`)
75+
76+
**Unit Tests & Coverage**:
77+
```bash
78+
cd QuoteUnquote.cloudLib.functions
79+
python -m pytest --cov=src test/ # Run with coverage
80+
python -m pytest test/[test_name].py # Single test file
81+
python -m pytest test/ -v # Verbose output
82+
```
83+
84+
**Linting & Code Quality**:
85+
```bash
86+
python -m pylint src/ # Pylint
87+
python -m flake8 src/ # Flake8
88+
python -m bandit -r src/blueprint # Security check
89+
python -m ruff check src/ # Ruff linter
90+
```
91+
92+
**Local Development** (Flask):
93+
```bash
94+
cd QuoteUnquote.cloudLib.functions
95+
python -m pip install -r requirements-test.txt
96+
python -m pip install -r src/requirements.txt
97+
python src/index.py # Runs on http://localhost:8080
98+
```
99+
100+
## Key Conventions
101+
102+
### Android App Structure
103+
104+
**Package organization** in `app/src/main/kotlin/com/github/jameshnsears/quoteunquote/`:
105+
- `configure/` — Configuration UI and preference fragments
106+
- `cloud/` — Cloud sync and transfer workflows
107+
- `db/` — Room database models, DAOs, and local persistence
108+
- `scraper/` — Quote parsing and import logic
109+
- `sync/` — Sync state validation
110+
- `utils/` — App-level helpers and preference access
111+
112+
**Build flavors** (in `build.gradle`):
113+
- `fdroid` — F-Droid build (no Firebase/Google Play dependencies)
114+
- `googleplay` — Google Play build (includes Firebase, Google Services)
115+
- `espresso` — Testing flavor with mocked dependencies
116+
- `uiautomator` — UI automation testing flavor
117+
118+
**Database**: Room migrations are tracked in `app/schemas/`; use `@Database(version=X)` and provide migration paths.
119+
120+
**Compose UI**: The app uses Jetpack Compose for UI; Layout composition follows standard Compose patterns (state hoisting, modifier chains).
121+
122+
### Python Backend Structure
123+
124+
**Endpoints** (in `src/endpoint/`):
125+
- `POST /save` → Save favourites by transfer code
126+
- `POST /receive` → Retrieve favourites by transfer code
127+
- `POST /transfer_backup` → Save full transfer payload
128+
- `POST /transfer_restore` → Retrieve full transfer payload
129+
130+
**Cloud integration** (in `src/cloud/gcp/`):
131+
- `gcp_firestore.py` — Firestore read/write operations
132+
- `gcp_logging.py` — Cloud Logging integration
133+
134+
**Validation** (in `src/validation/`): Request validation before Firestore operations
135+
136+
**Storage adapters** (in `src/storage/`): Data serialization and Firestore document mapping
137+
138+
**Testing**: Tests in `test/` mirror endpoint structure (e.g., `test/favourites/`, `test/transfer/`); use `conftest.py` for fixtures.
139+
140+
### Kotlin & Java Style
141+
142+
- **Language**: Kotlin preferred; Java only for legacy/legacy integration
143+
- **Min SDK**: 26 (Android 8)
144+
- **Target SDK**: 36 (Android 15)
145+
- **Java**: 17 (preview features disabled)
146+
- **Formatting**: ktlint (automatic via `./gradlew ktlint -F` to fix)
147+
- **Compose Compiler**: Enabled for Compose support
148+
149+
### Secrets & Configuration
150+
151+
**local.properties** (Git-ignored, decrypted from `.gpg` files in CI):
152+
- Android signing keystore credentials
153+
- Build configuration flags
154+
155+
**google-services.json** (Google Play flavor only):
156+
- Firebase and Google Play configuration
157+
- Decrypted in CI; F-Droid build skips this entirely
158+
159+
**Modules use separate local.properties**:
160+
- Root: `local.properties`
161+
- cloudLib: `QuoteUnquote.cloudLib/cloudLib/local.properties`
162+
- utilsLib: `QuoteUnquote.utilsLib/utilsLib/local.properties`
163+
164+
### Code Quality Gates
165+
166+
**Linting Rules**:
167+
- Checkstyle (`sun_checks.xml`): Standard Java style checks
168+
- Detekt: Kotlin code quality and complexity rules
169+
- ktlint: Kotlin formatting (auto-fixable)
170+
- Android Lint: Platform-specific issues
171+
172+
**Coverage**:
173+
- Instrumented with JaCoCo for both unit and Android tests
174+
- Reports uploaded as workflow artifacts (codecov.io disabled; see README)
175+
176+
**Pre-push Hook**: `bin/pre-push-static-analysis.sh` runs local static checks (optional).
177+
178+
### Test Categories
179+
180+
**Unit Tests** (`src/test/`):
181+
- Run locally without device/emulator
182+
- Include ViewModel tests, utility tests, and business logic
183+
- Faster feedback loop
184+
185+
**Instrumented Tests** (`src/androidTest/`):
186+
- Run on emulator/device
187+
- Include UI tests (Espresso), database tests, integration tests
188+
- Separate flavors for espresso and uiautomator testing
189+
190+
**Python Tests** (`QuoteUnquote.cloudLib.functions/test/`):
191+
- Use pytest + unittest.mock
192+
- Organized by endpoint (favourites, transfer)
193+
- Mock Firestore and cloud logging
194+
195+
## Development Workflow
196+
197+
1. **Create feature branch** from `main`
198+
2. **Run local linting & tests** before committing:
199+
- `./gradlew checkstyle detekt ktlint`
200+
- `./gradlew :app:testDebugUnitTest`
201+
- For Python: `python -m pytest test/` in `QuoteUnquote.cloudLib.functions/`
202+
3. **Stage changes** and check CI workflows:
203+
- `static-analysis.yml` — Runs checkstyle, detekt, ktlint, and Android lint
204+
- `coverage-test.yml` — Runs unit tests for both flavors
205+
- `coverage-androidTest.yml` — Runs instrumented tests (on emulator)
206+
4. **Push to feature branch** for PR
207+
5. **CI validates** all checks before merge to main
208+
209+
## Submodules
210+
211+
The repository uses Git submodules for shared Android libraries:
212+
- `QuoteUnquote.cloudLib` → defines cloud transfer models
213+
- `QuoteUnquote.utilsLib` → defines shared Android utilities
214+
- `QuoteUnquote.cloudLib.functions` → Python backend (separate GitHub Actions)
215+
216+
**Submodule updates**:
217+
```bash
218+
git submodule update --recursive --remote # Update all to latest main
219+
git submodule foreach git pull origin main # Pull specific branch
220+
```
221+
222+
When a submodule changes in the main repo, update the main `.gitmodules` to track the new commit.
223+
224+
## Common Tasks
225+
226+
### Running a Single Test
227+
228+
**Android (Kotlin)**:
229+
```bash
230+
./gradlew -p app test -k "SpecificTestClass" # By class name
231+
./gradlew test --tests "com.github.jameshnsears.quoteunquote.db.*" # By package
232+
```
233+
234+
**Python**:
235+
```bash
236+
cd QuoteUnquote.cloudLib.functions
237+
python -m pytest test/favourites/test_favourites.py::test_save -v
238+
```
239+
240+
### Adding a New Unit Test
241+
242+
1. Create test file in `src/test/kotlin/` or `src/test/java/` (Android)
243+
2. Import test fixtures and use standard JUnit or pytest
244+
3. Run locally: `./gradlew test`
245+
4. Verify coverage in `build/reports/jacoco/`
246+
247+
### Debugging
248+
249+
**Android Studio**:
250+
- Set breakpoints in code
251+
- Use Run > Debug to step through tests or app
252+
253+
**Python**:
254+
```bash
255+
python -m pdb -m pytest test/favourites/test_favourites.py
256+
```
257+
258+
## CI/CD Pipeline
259+
260+
**Workflows** (in `.github/workflows/`):
261+
- `static-analysis.yml` — Runs on all branches (checkstyle, detekt, ktlint, linting)
262+
- `coverage-test.yml` — Unit tests with JaCoCo coverage
263+
- `coverage-androidTest.yml` — Instrumented tests on emulator
264+
- `static-sonarqube.yml` — SonarQube quality gate
265+
- `static-gitleaks.yml` — Secret scanning
266+
- `release-github-fdroid.yml` — F-Droid release automation
267+
268+
**Build Variants**:
269+
- Tests run for both `fdroid` and `googleplay` flavors independently
270+
- Instrumented tests use espresso and uiautomator runners
271+
272+
## Resources
273+
274+
- **Product Context**: See `PRODUCT.md` for user-facing features
275+
- **Architecture Deep-Dive**: See `ARCHITECTURE.md` for module responsibilities
276+
- **Build Config**: Root `build.gradle` defines shared dependencies; modules use individual `build.gradle`
277+
- **Gradle Dependencies**: Managed via version catalog (check `gradle/libs.versions.toml` or similar)

.github/dependabot.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
version: 2
22
updates:
3-
- package-ecosystem: "gradle"
3+
- package-ecosystem: "github-actions"
44
directory: "/"
55
schedule:
66
interval: "daily"
7-
time: "02:00"
7+
# Omit target-branch to stay on the default branch (HEAD)
88
- package-ecosystem: "github-actions"
99
directory: "/"
1010
schedule:

.idea/appInsightsSettings.xml

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

.idea/deploymentTargetSelector.xml

Lines changed: 8 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)