mirror of
https://github.com/kuhyx/wake-alarm.git
synced 2026-11-10 19:07:03 +01:00
Latest stable dependencies, and the gate that keeps them there
**The two shared Python libraries were four minor versions behind and the gate could not see it.** They are PEP 508 direct references (`gatelock @ git+...@gatelock-v0.4.1`), which parsed as unpinned PyPI packages that do not exist on PyPI -- an undeterminable answer, not a stale one. utils@7a682a4 teaches the gate that shape; this repo is the first to benefit: gatelock v0.4.1 -> v0.7.2, crdt-sync v0.5.1 -> v0.9.1. The system install was already on 0.7.1/0.9.0, so only the manifests were adrift. Python side: bandit 1.7 -> 1.9.4, mypy 1 -> 2.3.1, pylint 3 -> 4.0.7, pytest 8 -> 9.1.1, pytest-cov 4 -> 7.1.0, pytest-randomly 3 -> 4.1.0, ruff 0.8 -> 0.16.5, python-kasa 0.7 -> 0.10.2, and the rest exact-pinned. Five majors and not one lint or type finding: `scripts/ci_mirror.sh` builds a clean venv from requirements.txt and runs the whole CI set, 465 tests at 100% branch coverage. phone_app takes crdt_sync_dart v0.11.1 and the flutter_secure_storage 11 chain (compileSdk 37 / AGP 9.3.2 / Gradle 9.7.1). 79 tests green, analyzer clean, release APK builds. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01CRykabMwPgDzFHcARoqpaK
This commit is contained in:
parent
e25bb5a1d7
commit
5117f5a0c9
57
.github/workflows/dependency-freshness.yml
vendored
Normal file
57
.github/workflows/dependency-freshness.yml
vendored
Normal file
@ -0,0 +1,57 @@
|
||||
name: dependency freshness
|
||||
|
||||
# Every dependency on its ecosystem's newest STABLE release, enforced on push
|
||||
# as well as at commit time. The local pre-commit hook only sees the manifests
|
||||
# in a commit and can be skipped entirely by a fresh clone that never ran
|
||||
# `pre-commit install`; this runs `--all` over the whole repo.
|
||||
#
|
||||
# `--strict` is CI-only. Offline the gate degrades to its cached answer and
|
||||
# passes, because `--no-verify` is banned locally and a hook that hard-failed
|
||||
# on a flaky connection would leave no way to commit. A runner is always
|
||||
# online, so here an undeterminable answer is a real failure.
|
||||
#
|
||||
# Expect this to go red for reasons this repo's commit did not cause: an
|
||||
# upstream release overnight is enough. That is the chosen behaviour -- the
|
||||
# alternative is a gate that only notices staleness when someone remembers to
|
||||
# look.
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [main]
|
||||
pull_request:
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
dependency-freshness:
|
||||
name: dependencies on newest stable
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
# The gate lives in the shared utils repo so every repo resolves the
|
||||
# same "latest stable" the same way. Checking it out beats vendoring a
|
||||
# copy, which is exactly how a gate and its survey start disagreeing.
|
||||
- name: Check out the shared gate
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
repository: kuhyx/utils
|
||||
path: .utils
|
||||
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: "3.13"
|
||||
|
||||
- name: Install the gate's two runtime dependencies
|
||||
run: python -m pip install --upgrade pyyaml packaging
|
||||
|
||||
- name: Cache registry lookups
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: ~/.cache/dep-freshness
|
||||
key: dep-freshness-${{ hashFiles('**/pubspec.yaml', '**/pyproject.toml',
|
||||
'**/requirements*.txt', '**/package.json', '**/Cargo.toml', '**/go.mod') }}
|
||||
restore-keys: dep-freshness-
|
||||
|
||||
- name: Every dependency is on newest stable
|
||||
run: bash .utils/scripts/check_dependency_freshness.sh --all --strict
|
||||
@ -171,3 +171,24 @@ repos:
|
||||
entry: scripts/check_md_naming.sh
|
||||
language: system
|
||||
files: \.(md|markdown)$
|
||||
|
||||
# Every dependency on its ecosystem's newest STABLE release, exact-pinned
|
||||
# so the question is mechanically answerable at all.
|
||||
#
|
||||
# `files:` is what keeps this cheap: a commit touching only source makes
|
||||
# ZERO network requests, and manifest commits mostly hit a 6h disk cache.
|
||||
#
|
||||
# Runs WITHOUT --strict on purpose. Offline it degrades to the cached
|
||||
# answer and passes with a loud banner; `--no-verify` is banned here, so
|
||||
# a hook that hard-failed on a flaky connection would leave no way to
|
||||
# commit at all. CI, always online, is the strict authority.
|
||||
- id: dependency-freshness
|
||||
name: dependencies on newest stable
|
||||
entry: scripts/check_dependency_freshness.sh
|
||||
language: system
|
||||
pass_filenames: true
|
||||
files: >-
|
||||
(pubspec\.(yaml|lock)|pyproject\.toml|requirements.*\.txt|uv\.lock
|
||||
|package\.json|package-lock\.json|pnpm-lock\.yaml
|
||||
|Cargo\.(toml|lock)|go\.(mod|sum)
|
||||
|\.fvmrc|\.nvmrc|\.python-version)$
|
||||
|
||||
@ -21,7 +21,12 @@ android {
|
||||
// Pinned explicitly rather than delegated to the Flutter Gradle plugin:
|
||||
// full-screen-intent and foreground-service semantics both changed at
|
||||
// API 34/35, and the alarm path cannot be reasoned about without a floor.
|
||||
compileSdk = 36
|
||||
// Pinned above `flutter.compileSdkVersion` (36 on Flutter 3.47.2):
|
||||
// flutter_secure_storage 11.0.0, which arrives with crdt_sync_flutter
|
||||
// v0.3.1, publishes AAR metadata demanding API 37 or later. That in
|
||||
// turn needs AGP > 9.1.0, which needs Gradle >= 9.5.0 -- see
|
||||
// settings.gradle.kts and gradle-wrapper.properties.
|
||||
compileSdk = 37
|
||||
ndkVersion = flutter.ndkVersion
|
||||
|
||||
compileOptions {
|
||||
|
||||
@ -2,4 +2,4 @@ distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-9.1.0-all.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-9.7.1-all.zip
|
||||
|
||||
@ -19,7 +19,7 @@ pluginManagement {
|
||||
|
||||
plugins {
|
||||
id("dev.flutter.flutter-plugin-loader") version "1.0.0"
|
||||
id("com.android.application") version "9.0.1" apply false
|
||||
id("com.android.application") version "9.3.2" apply false
|
||||
id("org.jetbrains.kotlin.android") version "2.3.20" apply false
|
||||
}
|
||||
|
||||
|
||||
@ -5,10 +5,10 @@ packages:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: android_intent_plus
|
||||
sha256: "2329378af63f49b985cb2e110ac784d08374f1e2b1984be77ba9325b1c8cce11"
|
||||
sha256: "4d4bbd619d698cbee3c400ba89246ecb0f525146b0ae05389f62ede47abd5bec"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "5.3.1"
|
||||
version: "6.1.0"
|
||||
archive:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -93,11 +93,11 @@ packages:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
path: crdt_sync_dart
|
||||
ref: "crdt_sync_dart-v0.10.0"
|
||||
resolved-ref: "5f64a8959b1db342da1f73157b1148aa0dfa38a8"
|
||||
ref: "crdt_sync_dart-v0.11.1"
|
||||
resolved-ref: "978d32af3af66f0d6500c4c6c0c6df5370ebe9a2"
|
||||
url: "https://github.com/kuhyx/utils"
|
||||
source: git
|
||||
version: "0.10.0"
|
||||
version: "0.11.1"
|
||||
crypto:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -130,6 +130,14 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.2.0"
|
||||
ffi_leak_tracker:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: ffi_leak_tracker
|
||||
sha256: "4093d4ef9ca06ffe2786e73bfb25e22aa92112b9bb4ec941f11e3e6b61489a97"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.1.2"
|
||||
file:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -163,50 +171,50 @@ packages:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: flutter_secure_storage
|
||||
sha256: "9cad52d75ebc511adfae3d447d5d13da15a55a92c9410e50f67335b6d21d16ea"
|
||||
sha256: "15e8c8fe269fdf7d469b23008ab3df521c8b826ed345820532364c31bdebace6"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "9.2.4"
|
||||
version: "11.0.0"
|
||||
flutter_secure_storage_darwin:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: flutter_secure_storage_darwin
|
||||
sha256: ac6d76a752de0cd738334eb4b21743fc4943f449f5b6e308f18838b048c02ac0
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.4.0"
|
||||
flutter_secure_storage_linux:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: flutter_secure_storage_linux
|
||||
sha256: be76c1d24a97d0b98f8b54bce6b481a380a6590df992d0098f868ad54dc8f688
|
||||
sha256: "76fa9c841b3b1619fc5b5bc36efc7d158fa2356f223b6caeb1d0c80a54168546"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.2.3"
|
||||
flutter_secure_storage_macos:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: flutter_secure_storage_macos
|
||||
sha256: "6c0a2795a2d1de26ae202a0d78527d163f4acbb11cde4c75c670f3a0fc064247"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.1.3"
|
||||
version: "3.0.2"
|
||||
flutter_secure_storage_platform_interface:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: flutter_secure_storage_platform_interface
|
||||
sha256: cf91ad32ce5adef6fba4d736a542baca9daf3beac4db2d04be350b87f69ac4a8
|
||||
sha256: "788060052712555182aba55ecb5f8b6e5cb9cfe8f776c83249a61fe3ce877db4"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.1.2"
|
||||
version: "2.0.3"
|
||||
flutter_secure_storage_web:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: flutter_secure_storage_web
|
||||
sha256: f4ebff989b4f07b2656fb16b47852c0aab9fed9b4ec1c70103368337bc1886a9
|
||||
sha256: "073a62b3aeb866ab4ce795f960413948e51e5a42a9b0c8333b6daf5bb3208a1c"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.2.1"
|
||||
version: "2.1.1"
|
||||
flutter_secure_storage_windows:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: flutter_secure_storage_windows
|
||||
sha256: b20b07cb5ed4ed74fc567b78a72936203f587eba460af1df11281c9326cd3709
|
||||
sha256: "471951813a97006d899db4948acc654a4f28c440083ea08178935ce20b173ec1"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.1.2"
|
||||
version: "4.2.2"
|
||||
flutter_test:
|
||||
dependency: "direct dev"
|
||||
description: flutter
|
||||
@ -221,11 +229,11 @@ packages:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
path: github_device_auth
|
||||
ref: "github_device_auth-v0.3.0"
|
||||
resolved-ref: "254e3b00c7f41a54c588ec32564017f96f328252"
|
||||
ref: "github_device_auth-v0.3.1"
|
||||
resolved-ref: "11c752fe6508117d4d2db1c0744090221d5f6cb8"
|
||||
url: "https://github.com/kuhyx/utils"
|
||||
source: git
|
||||
version: "0.3.0"
|
||||
version: "0.3.1"
|
||||
google_identity_services_web:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -322,14 +330,6 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.0.1"
|
||||
js:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: js
|
||||
sha256: f2c445dce49627136094980615a031419f7f3eb393237e4ecd97ac15dea343f3
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.6.7"
|
||||
json_annotation:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -611,11 +611,11 @@ packages:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
path: sync_settings_ui
|
||||
ref: "sync_settings_ui-v0.1.0"
|
||||
resolved-ref: "23c693da4e6fd6004df09829a7d75365dc086c2c"
|
||||
ref: "sync_settings_ui-v0.4.1"
|
||||
resolved-ref: "51700aa89eaf1789ae98491aaa854c54d35b4170"
|
||||
url: "https://github.com/kuhyx/utils"
|
||||
source: git
|
||||
version: "0.1.0"
|
||||
version: "0.4.1"
|
||||
term_glyph:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -748,10 +748,10 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: win32
|
||||
sha256: d7cb55e04cd34096cd3a79b3330245f54cb96a370a1c27adb3c84b917de8b08e
|
||||
sha256: a0b93865d5644f11cf6a8c3f6db909f1ec168958b5805f6cc684adea957cd63d
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "5.15.0"
|
||||
version: "6.4.0"
|
||||
xdg_directories:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
||||
@ -8,29 +8,29 @@ environment:
|
||||
sdk: ^3.12.2
|
||||
|
||||
dependencies:
|
||||
android_intent_plus: ^5.0.0
|
||||
android_intent_plus: 6.1.0
|
||||
crdt_sync:
|
||||
git:
|
||||
url: https://github.com/kuhyx/utils
|
||||
ref: crdt_sync_dart-v0.10.0
|
||||
ref: crdt_sync_dart-v0.11.1
|
||||
path: crdt_sync_dart
|
||||
cupertino_icons: ^1.0.8
|
||||
cupertino_icons: 1.0.9
|
||||
flutter:
|
||||
sdk: flutter
|
||||
flutter_secure_storage: ^9.0.0
|
||||
flutter_secure_storage: 11.0.0
|
||||
|
||||
# One-tap sign-in for the sync account. App-side only: crdt_sync stays pure
|
||||
# Dart so it keeps working on Linux desktop and headless.
|
||||
github_device_auth:
|
||||
git:
|
||||
url: https://github.com/kuhyx/utils
|
||||
ref: github_device_auth-v0.3.0
|
||||
ref: github_device_auth-v0.3.1
|
||||
path: github_device_auth
|
||||
google_sign_in: ^7.2.0
|
||||
http: ^1.2.0
|
||||
path: ^1.9.0
|
||||
path_provider: ^2.1.0
|
||||
shared_preferences: ^2.3.0
|
||||
google_sign_in: 7.2.0
|
||||
http: 1.6.0
|
||||
path: 1.9.1
|
||||
path_provider: 2.1.6
|
||||
shared_preferences: 2.5.5
|
||||
|
||||
# Shared "Sync settings" screen (Firebase + optional local backup), reused
|
||||
# across every kuhy app that syncs. GitHub mirror stays app-local (see
|
||||
@ -38,18 +38,18 @@ dependencies:
|
||||
sync_settings_ui:
|
||||
git:
|
||||
url: https://github.com/kuhyx/utils
|
||||
ref: sync_settings_ui-v0.1.0
|
||||
ref: sync_settings_ui-v0.4.1
|
||||
path: sync_settings_ui
|
||||
url_launcher: ^6.3.0
|
||||
uuid: ^4.6.0
|
||||
url_launcher: 6.3.2
|
||||
uuid: 4.6.0
|
||||
|
||||
dev_dependencies:
|
||||
# Generates the Android launcher icons from assets/icon/ (see
|
||||
# python_pkg/app_icons in testsAndMisc for the shared style).
|
||||
flutter_launcher_icons: ^0.14.4
|
||||
flutter_launcher_icons: 0.14.4
|
||||
flutter_test:
|
||||
sdk: flutter
|
||||
very_good_analysis: ^10.2.0
|
||||
very_good_analysis: ^10.3.0
|
||||
|
||||
flutter:
|
||||
uses-material-design: true
|
||||
|
||||
@ -8,12 +8,12 @@ version = "1.0.0"
|
||||
description = "Phone-driven wake alarm with fan ramp and smart-plug control"
|
||||
requires-python = ">=3.10"
|
||||
dependencies = [
|
||||
"gatelock @ git+https://github.com/kuhyx/utils@gatelock-v0.4.1#subdirectory=gatelock",
|
||||
"gatelock @ git+https://github.com/kuhyx/utils@gatelock-v0.7.2#subdirectory=gatelock",
|
||||
# Firebase transport for the alarm read. _sync.py imports it lazily and
|
||||
# falls back to its stdlib GitHub path if the import fails, so a broken
|
||||
# install degrades the read instead of killing the per-minute trigger.
|
||||
"crdt-sync @ git+https://github.com/kuhyx/utils@crdt-sync-v0.5.1#subdirectory=crdt-sync",
|
||||
"python-kasa>=0.7",
|
||||
"crdt-sync @ git+https://github.com/kuhyx/utils@crdt-sync-v0.9.1#subdirectory=crdt-sync",
|
||||
"python-kasa==0.10.2",
|
||||
]
|
||||
|
||||
# Package discovery must be explicit: phone_app/ is a Flutter app, not a Python
|
||||
|
||||
@ -4,18 +4,18 @@
|
||||
# optional at runtime — their modules degrade gracefully if missing (the
|
||||
# alarm read falls back to GitHub, smart-plug control disables itself) — but
|
||||
# both are required here for mypy/pylint/tests.
|
||||
bandit>=1.7.0
|
||||
codespell>=2.2.0
|
||||
coverage>=7.4.0
|
||||
crdt-sync @ git+https://github.com/kuhyx/utils@crdt-sync-v0.5.1#subdirectory=crdt-sync
|
||||
gatelock @ git+https://github.com/kuhyx/utils@gatelock-v0.4.1#subdirectory=gatelock
|
||||
mypy>=1.8.0
|
||||
pre-commit>=3.6.0
|
||||
pylint>=3.0.0
|
||||
pytest>=8.0.0
|
||||
pytest-cov>=4.1.0
|
||||
pytest-randomly>=3.15.0
|
||||
pytest-sugar>=1.0.0
|
||||
pytest-xdist>=3.5.0
|
||||
python-kasa>=0.7
|
||||
ruff>=0.8.0
|
||||
bandit==1.9.4
|
||||
codespell==2.4.3
|
||||
coverage==7.15.4
|
||||
crdt-sync @ git+https://github.com/kuhyx/utils@crdt-sync-v0.9.1#subdirectory=crdt-sync
|
||||
gatelock @ git+https://github.com/kuhyx/utils@gatelock-v0.7.2#subdirectory=gatelock
|
||||
mypy==2.3.1
|
||||
pre-commit==4.6.2
|
||||
pylint==4.0.7
|
||||
pytest==9.1.1
|
||||
pytest-cov==7.1.0
|
||||
pytest-randomly==4.1.0
|
||||
pytest-sugar==1.1.1
|
||||
pytest-xdist==3.8.0
|
||||
python-kasa==0.10.2
|
||||
ruff==0.16.5
|
||||
|
||||
34
scripts/check_dependency_freshness.sh
Executable file
34
scripts/check_dependency_freshness.sh
Executable file
@ -0,0 +1,34 @@
|
||||
#!/bin/bash
|
||||
|
||||
# ============================================================================
|
||||
# Fail if any dependency in the commit is behind its ecosystem's newest stable.
|
||||
#
|
||||
# Thin delegate to the shared gate in ~/utils, which owns the registry
|
||||
# adapters, the pre-release rules and the allowlist semantics. Copying that
|
||||
# logic here is what lets one repo's idea of "current" drift from every other
|
||||
# repo's -- so this script only locates the shared checker and forwards its
|
||||
# arguments.
|
||||
#
|
||||
# Usage:
|
||||
# scripts/check_dependency_freshness.sh <file> [<file> ...] # pre-commit
|
||||
# scripts/check_dependency_freshness.sh --all --strict # CI
|
||||
#
|
||||
# Exit: 0 current | 1 behind | 2 allowlist wrong | 3 undeterminable (offline)
|
||||
# ============================================================================
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
readonly SHARED_GATE="${UTILS_ROOT:-$HOME/utils}/scripts/check_dependency_freshness.sh"
|
||||
|
||||
main() {
|
||||
if [[ ! -x "$SHARED_GATE" ]]; then
|
||||
echo "Error: shared dependency-freshness gate not found at $SHARED_GATE" >&2
|
||||
echo " Clone github.com/kuhyx/utils to ~/utils, or set" >&2
|
||||
echo " UTILS_ROOT to where it lives." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
exec bash "$SHARED_GATE" "$@"
|
||||
}
|
||||
|
||||
main "$@"
|
||||
Loading…
Reference in New Issue
Block a user