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
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -66,3 +66,6 @@ app.*.map.json
# Local env (API key IDs, issuer ID, etc.)
.env
.env.local

# Lefthook local overrides (https://lefthook.dev)
lefthook-local.yml
93 changes: 93 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
# Contributing to OpenGlucose

Thanks for helping build OpenGlucose — an open-source, local-first health and
wellness app. This guide covers local setup, the dev toolchain, and the commit
conventions. The Flutter app lives in `openhealth/`; shared Dart/BLE logic lives
in `packages/` (see the [root README](README.md) for the architecture).

## Prerequisites

- **Flutter** (stable, matching `openhealth/pubspec.yaml` → `environment.flutter`).
Verify with `flutter --version`. Run `flutter doctor` to check your toolchain.
- **Node.js** — only used by the commit-message hook (commitlint runs via `npx`).
- **Lefthook** — the git-hook manager. The setup script installs it for you.

## Setup

```bash
git clone https://github.com/shroominic/OpenGlucose
cd OpenGlucose

# Install git hooks (formatting, analysis, tests, commit-msg linting).
make setup # or: ./scripts/install-hooks.sh

# Fetch Dart/Flutter dependencies for the app.
cd openhealth && flutter pub get
```

`make setup` installs Lefthook (via Homebrew or `go install` if it is missing),
then runs `lefthook install` to wire up the hooks in `.git/hooks`.

## Everyday commands

Run these from the repo root via `make`, or directly inside `openhealth/`:

| Task | `make` | Direct (`cd openhealth`) |
| -------------------- | ---------------- | ------------------------------------------------- |
| Format code | `make format` | `dart format .` |
| Check formatting | `make format-check` | `dart format --output=none --set-exit-if-changed .` |
| Static analysis/lint | `make analyze` | `flutter analyze` |
| Run tests | `make test` | `flutter test` |
| Everything (like CI) | `make check` | — |

Run the app with `cd openhealth && flutter run` (on web and in widget tests a
demo driver stands in for real BLE, so the UI is verifiable without hardware).

## Linting & formatting

- **Lints:** we extend [`very_good_analysis`](https://pub.dev/packages/very_good_analysis)
in `openhealth/analysis_options.yaml` — a strong, opinionated set that catches
bugs and enforces consistent style. A handful of rules are temporarily
baselined (with inline comments) because of pre-existing violations; re-enable
and clean them up one at a time (most are auto-fixable). Run `dart fix --apply`
in `openhealth/` to apply automatic fixes.
- **Formatting:** `dart format` is the single source of truth. Keep code
formatted; the pre-commit hook rejects unformatted staged Dart files.

## Git hooks (Lefthook)

Configured in [`lefthook.yml`](lefthook.yml) and installed by `make setup`:

- **pre-commit** — `dart format --set-exit-if-changed` on staged Dart files and
`flutter analyze` over the app. Fast; blocks unformatted or failing code.
- **commit-msg** — `commitlint` enforces Conventional Commits (see below).
- **pre-push** — `flutter test` must pass before you push.

Test a hook without committing: `lefthook run pre-commit`.
Bypass in a genuine emergency only: `git commit --no-verify` (then fix forward).

## Commit messages (Conventional Commits)

Format: `<type>(<scope>): <subject>`, enforced by
[`commitlint.config.mjs`](commitlint.config.mjs).

- **types:** `feat`, `fix`, `docs`, `style`, `refactor`, `perf`, `test`,
`build`, `ci`, `chore`, `revert`.
- **scopes** (optional, a warning if unknown): `app`, `ble`, `aidex`, `core`,
`ui`, `ios`, `android`, `docs`, `deps`, `ci`, `repo`.

Examples:

```
feat(app): add glucose trend arrow to dashboard
fix(aidex): handle truncated history packets during sync
chore(deps): bump flutter_blue_plus to 8.2.1
```

## Pull requests

1. Branch off `main`: `feature/<scope>`, `fix/<scope>`, `chore/<scope>`, or
`docs/<scope>`.
2. Keep changes focused and include tests for new or changed behavior.
3. Ensure `make check` passes (format + analyze + test) before opening the PR.
4. Use a Conventional Commit title and describe what changed and why.
24 changes: 24 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
.PHONY: setup hooks analyze format format-check test check

# One-time setup after cloning: install git hooks.
setup hooks:
./scripts/install-hooks.sh

# Static analysis over the Flutter app.
analyze:
cd openhealth && flutter analyze

# Format all Dart code in place.
format:
cd openhealth && dart format .

# Verify formatting without writing (used in CI / hooks).
format-check:
cd openhealth && dart format --output=none --set-exit-if-changed .

# Run the test suite.
test:
cd openhealth && flutter test

# Run everything the way CI does.
check: format-check analyze test
48 changes: 48 additions & 0 deletions commitlint.config.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
/**
* Conventional Commits enforcement for OpenGlucose.
* Format: <type>(<scope>): <subject>
*
* Scopes map to the app/package areas so history stays navigable. Run by the
* `commit-msg` git hook (see lefthook.yml). Scope is a warning, not an error,
* so it does not block ad-hoc commits while still nudging toward consistency.
*/
export default {
extends: ["@commitlint/config-conventional"],
rules: {
"type-enum": [
2,
"always",
[
"feat",
"fix",
"docs",
"style",
"refactor",
"perf",
"test",
"build",
"ci",
"chore",
"revert",
],
],
"scope-enum": [
1,
"always",
[
"app", // openhealth/ Flutter app
"ble", // cgm_ble / cgm_ble_flutter packages
"aidex", // cgm_aidex package
"core", // cgm_core package
"ui",
"ios",
"android",
"docs",
"deps",
"ci",
"repo",
],
],
"body-max-line-length": [0, "always"],
},
};
38 changes: 38 additions & 0 deletions lefthook.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
# Git hooks for OpenGlucose (https://lefthook.dev)
#
# Install the hooks once after cloning:
#
# ./scripts/install-hooks.sh (or: make setup)
#
# The Flutter app lives in `openhealth/`, so the Dart commands below cd into it.
# Hooks are intentionally fast on commit (format + analyze on staged files only)
# and run the full test suite on push.

pre-commit:
parallel: true
commands:
# Reject staged Dart files that are not formatted. Run `dart format .` to fix.
# `root` scopes the hook to the app and makes {staged_files} relative to it.
format:
root: "openhealth/"
glob: "*.dart"
run: dart format --set-exit-if-changed {staged_files}
# Static analysis (lints + errors) over the app. Runs whenever any Dart file
# under openhealth/ is staged (analyze covers the whole package, not just
# the changed files, so we do not pass {staged_files}).
analyze:
root: "openhealth/"
glob: "*.dart"
run: flutter analyze

commit-msg:
commands:
# Enforce Conventional Commits (see commitlint.config.mjs).
commitlint:
run: npx --yes --package @commitlint/cli --package @commitlint/config-conventional commitlint --edit {1}

pre-push:
commands:
# Full test suite must pass before pushing.
test:
run: cd openhealth && flutter test
55 changes: 32 additions & 23 deletions openhealth/analysis_options.yaml
Original file line number Diff line number Diff line change
@@ -1,28 +1,37 @@
# This file configures the analyzer, which statically analyzes Dart code to
# check for errors, warnings, and lints.
# Static analysis configuration for the OpenGlucose app.
#
# The issues identified by the analyzer are surfaced in the UI of Dart-enabled
# IDEs (https://dart.dev/tools#ides-and-editors). The analyzer can also be
# invoked from the command line by running `flutter analyze`.

# The following line activates a set of recommended lints for Flutter apps,
# packages, and plugins designed to encourage good coding practices.
include: package:flutter_lints/flutter.yaml
# We extend `very_good_analysis` for a strong, opinionated lint set that catches
# bugs and enforces consistent style. CI and the pre-commit hook both run
# `flutter analyze`; run `dart fix --apply` to auto-fix most issues.
# See CONTRIBUTING.md.
include: package:very_good_analysis/analysis_options.yaml

linter:
# The lint rules applied to this project can be customized in the
# section below to disable rules from the `package:flutter_lints/flutter.yaml`
# included above or to enable additional rules. A list of all available lints
# and their documentation is published at https://dart.dev/lints.
#
# Instead of disabling a lint rule for the entire project in the
# section below, it can also be suppressed for a single line of code
# or a specific dart file by using the `// ignore: name_of_lint` and
# `// ignore_for_file: name_of_lint` syntax on the line or in the file
# producing the lint.
rules:
# avoid_print: false # Uncomment to disable the `avoid_print` rule
# prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule
# This is an application, not a published package, so we do not require a
# doc comment on every public member. Documentation is still encouraged for
# non-obvious APIs.
public_member_api_docs: false

# --- Pre-existing-violation baseline (follow-ups) ---
# The rules below are valuable but each has pre-existing violations in the
# current codebase. They are disabled here so the strong lint set can land
# without a large, conflict-prone rewrite of feature code. Re-enable them
# one at a time and clean up (most are auto-fixable via `dart fix --apply`).
# Tracked as a follow-up; see CONTRIBUTING.md.
avoid_catches_without_on_clauses: false # 16 occurrences
always_use_package_imports: false # 12 occurrences (relative imports in lib/)
cascade_invocations: false # 5 occurrences
always_put_required_named_parameters_first: false # 5 occurrences
prefer_const_constructors: false # auto-fixable via `dart fix`
directives_ordering: false # auto-fixable via `dart fix`
avoid_redundant_argument_values: false # auto-fixable via `dart fix`
sort_constructors_first: false
sort_pub_dependencies: false
use_null_aware_elements: false
noop_primitive_operations: false

# Additional information about this file can be found at
# https://dart.dev/guides/language/analysis-options
# `dart format` is the single source of truth for formatting and it leaves
# the few remaining long lines untouched (e.g. long string literals), so we
# disable the line-length lint to keep the analyzer and formatter in sync.
lines_longer_than_80_chars: false
24 changes: 8 additions & 16 deletions openhealth/pubspec.lock
Original file line number Diff line number Diff line change
Expand Up @@ -226,14 +226,6 @@ packages:
url: "https://pub.dev"
source: hosted
version: "0.14.4"
flutter_lints:
dependency: "direct dev"
description:
name: flutter_lints
sha256: "3105dc8492f6183fb076ccf1f351ac3d60564bff92e20bfc4af9cc1651f4e7e1"
url: "https://pub.dev"
source: hosted
version: "6.0.0"
flutter_test:
dependency: "direct dev"
description: flutter
Expand Down Expand Up @@ -292,14 +284,6 @@ packages:
url: "https://pub.dev"
source: hosted
version: "3.0.2"
lints:
dependency: transitive
description:
name: lints
sha256: "12f842a479589fea194fe5c5a3095abc7be0c1f2ddfa9a0e76aed1dbd26a87df"
url: "https://pub.dev"
source: hosted
version: "6.1.0"
matcher:
dependency: transitive
description:
Expand Down Expand Up @@ -529,6 +513,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "2.2.0"
very_good_analysis:
dependency: "direct dev"
description:
name: very_good_analysis
sha256: d1cb1d66a5aae2c702d68caca6c8347306d35e728fd94555fa21fa0448a972e0
url: "https://pub.dev"
source: hosted
version: "10.2.0"
vm_service:
dependency: transitive
description:
Expand Down
2 changes: 1 addition & 1 deletion openhealth/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,10 @@ dependencies:
shared_preferences: ^2.5.3

dev_dependencies:
flutter_lints: ^6.0.0
flutter_launcher_icons: ^0.14.3
flutter_test:
sdk: flutter
very_good_analysis: ^10.2.0

flutter:
uses-material-design: true
Expand Down
37 changes: 37 additions & 0 deletions scripts/install-hooks.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
#!/usr/bin/env bash
#
# Install the project's git hooks (managed by Lefthook).
#
# Usage: ./scripts/install-hooks.sh (or: make setup)
#
# Idempotent: safe to re-run. Requires `lefthook` on PATH; if it is missing this
# script tries to install it via Homebrew, then falls back to printing manual
# install instructions. commitlint runs on demand via `npx`, so it needs Node.
set -euo pipefail

cd "$(dirname "$0")/.."

if ! command -v lefthook >/dev/null 2>&1; then
echo "lefthook not found; attempting to install..."
if command -v brew >/dev/null 2>&1; then
brew install lefthook
elif command -v go >/dev/null 2>&1; then
go install github.com/evilmartians/lefthook@latest
else
cat >&2 <<'EOF'
Could not auto-install lefthook. Install it manually, then re-run this script:
macOS: brew install lefthook
Linux: https://lefthook.dev/installation/
Go: go install github.com/evilmartians/lefthook@latest
EOF
exit 1
fi
fi

if ! command -v node >/dev/null 2>&1; then
echo "warning: Node.js not found. The commit-msg hook (commitlint via npx) will" >&2
echo " fail until Node is installed (https://nodejs.org)." >&2
fi

lefthook install
echo "Git hooks installed. Run 'lefthook run pre-commit' to test."