Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
299 commits
Select commit Hold shift + click to select a range
b4da599
feat: add proper kind icons for assets in Dagster UI
iamgp Nov 26, 2025
3b69c56
refactor: remove example-specific code from core phlo framework
iamgp Nov 26, 2025
c97f733
refactor: remove remaining example-specific code from phlo framework
iamgp Nov 26, 2025
06a2c17
fix: remove GitHub models from glucose-platform example
iamgp Nov 26, 2025
d495e8c
feat: auto-publish dbt marts to Postgres for BI
iamgp Nov 26, 2025
4ed09b8
feat: add Nessie branching support and auto dbt compile
iamgp Nov 26, 2025
319c14b
feat: add NessieResource and auto-init branches on startup
iamgp Nov 26, 2025
1b69ce2
fix: improve Nessie sensors and apply ruff formatting
iamgp Nov 26, 2025
ace7660
docs: clean up and reorganize documentation
iamgp Nov 26, 2025
c1b4e2c
docs: update blog posts with correct Nessie branching and WAP pattern
iamgp Nov 26, 2025
9b46f4a
docs: simplify README and move planning docs to specs/
iamgp Nov 26, 2025
033fa0e
chore: remove Licence
iamgp Nov 26, 2025
a0caba9
feat(testing): implement testing infrastructure per spec 001
iamgp Nov 27, 2025
58633d0
feat(cli): implement CLI commands per spec 002
iamgp Nov 27, 2025
94a919d
feat(quality): implement @phlo.quality decorator per spec 003
iamgp Nov 27, 2025
a650563
feat(cli): implement schema catalog and data contracts per specs 004 …
iamgp Nov 27, 2025
de3f44f
feat(observability): implement metrics, alerting, and lineage per spe…
iamgp Nov 27, 2025
1cbd8ac
feat(catalog): implement OpenMetadata integration per spec 009
iamgp Nov 27, 2025
95c1f99
feat(api): implement API layer automation per spec 007
iamgp Nov 27, 2025
a519d4a
feat(plugins): activate plugin system with CLI and example package pe…
iamgp Nov 27, 2025
9838743
chore: update docs
iamgp Nov 27, 2025
25b7552
chore: more docs
iamgp Nov 27, 2025
bca1f9d
docs: update blog posts with current examples (#33)
iamgp Dec 1, 2025
ae5a9b9
fix: glucose demo
iamgp Dec 2, 2025
d95db6a
feat: add github-stats phlo example
iamgp Dec 4, 2025
3e73005
chore: add /smarthandoff
iamgp Dec 4, 2025
7c81740
fix: make sure dbt compile is run
iamgp Dec 4, 2025
85bba8c
feat: add infrastructure configuration to phlo.yaml
iamgp Dec 5, 2025
ecbf06c
feat: add configurable merge strategies
iamgp Dec 6, 2025
812262c
fix: handle ValueError in arrow table casting
iamgp Dec 6, 2025
96d18c4
feat: add Trino driver to Superset image
iamgp Dec 6, 2025
6d439bd
feat (docs): improved docs
iamgp Dec 6, 2025
18e045a
feat: logo
iamgp Dec 6, 2025
e059452
fix: correct merge_config parameter in ingestion workflows
iamgp Dec 6, 2025
7668dae
feat: PatternCheck and Github helpers
iamgp Dec 6, 2025
dbef335
feat: add PhloSchema base class and dbt model Pandera generation
iamgp Dec 7, 2025
9ce8d84
style: format SQL files with sqlfluff
iamgp Dec 7, 2025
198fa1d
fix: repair 12 failing unit tests
iamgp Dec 7, 2025
564f99a
feat(ingestion): auto-inject metadata columns into ingested data
iamgp Dec 7, 2025
0b14e81
feat(validate): warn when partition_date is declared but unused
iamgp Dec 7, 2025
a451ddb
feat(schemas): add Trino-to-Pandas type mapping utilities
iamgp Dec 7, 2025
6b68652
docs(examples): add complete test examples using phlo.testing fixtures
iamgp Dec 7, 2025
7d6ee16
chore: consolidate pytest config into pyproject.toml
iamgp Dec 7, 2025
6d57706
chore: update Makefile and switch to sqlfluff
iamgp Dec 7, 2025
4633d1b
ci: add GitHub Actions for CI, releases, and dependency updates
iamgp Dec 7, 2025
6bfa46b
ci: mark API tests as integration tests
iamgp Dec 7, 2025
ed4dc9e
fix: resolve lint errors for CI
iamgp Dec 7, 2025
836e107
fix: mark more tests as integration and format code
iamgp Dec 7, 2025
b7bb360
fix: add per-file ignores and skip dbt-dependent tests in CI
iamgp Dec 7, 2025
9a832b2
fix: ignore test_quality.py in CI (imports non-existent module)
iamgp Dec 7, 2025
088d6f0
fix: resolve type-check and sql-lint errors
iamgp Dec 7, 2025
ae9040f
style: format Python code
iamgp Dec 7, 2025
a6a0599
chore: add renovate.json (#34)
renovate[bot] Dec 7, 2025
b9ff597
chore: disable Python Docker image updates in Renovate
iamgp Dec 7, 2025
790895a
fix(deps): update dependency bcrypt to >=4.3.0,<4.4.0 (#38)
renovate[bot] Dec 7, 2025
b00faab
chore: remove Dependabot in favor of Renovate
iamgp Dec 7, 2025
48bfd3c
docs: add badges, update install to use uv/PyPI
iamgp Dec 7, 2025
9e02626
docs: remove license badge
iamgp Dec 7, 2025
a2c87e8
chore: configure Release Please for alpha pre-releases
iamgp Dec 7, 2025
170e1a9
chore: unignore release-please config files
iamgp Dec 7, 2025
7b50b75
chore: trigger release please
iamgp Dec 7, 2025
7a007dc
fix: use versioning prerelease for alpha releases
iamgp Dec 7, 2025
1a95200
chore: trigger alpha release
iamgp Dec 7, 2025
055ddd0
chore: trigger release please with prerelease versioning
iamgp Dec 7, 2025
37f3023
chore: bootstrap prerelease version in manifest
iamgp Dec 7, 2025
e604450
chore: force 0.1.0-alpha.1 release
iamgp Dec 7, 2025
a90b8bc
chore(main): release 0.1.0-alpha.1 (#48)
github-actions[bot] Dec 7, 2025
bb2c8da
chore: use PAT for release-please to trigger publish workflow
iamgp Dec 7, 2025
1de0229
chore: add workflow_dispatch to publish.yml
iamgp Dec 7, 2025
1083cac
fix: add contents:read permission for checkout
iamgp Dec 7, 2025
a3a89a5
chore: remove legacy cascade files and rename to phlo (#51)
iamgp Dec 7, 2025
759f8ff
fix(deps): update dependency bcrypt to v5 (#50)
renovate[bot] Dec 7, 2025
2f0a9ad
chore(deps): update postgres docker tag to v18 (#44)
renovate[bot] Dec 7, 2025
b489feb
chore(deps): update github artifact actions (#43)
renovate[bot] Dec 7, 2025
46cf562
chore(deps): update astral-sh/setup-uv action to v7 (#41)
renovate[bot] Dec 7, 2025
0c63561
chore(deps): update actions/checkout action to v6 (#40)
renovate[bot] Dec 7, 2025
ac8ca67
chore: add beads issue tracker
iamgp Dec 7, 2025
710e001
bd sync: 2025-12-10 19:19:04
iamgp Dec 10, 2025
5f54eaf
feat(observatory): Initial Implementation (#52)
iamgp Dec 13, 2025
80e8000
fix(dbt): ensure translator description is always string (#56)
iamgp Dec 13, 2025
c0a5f9a
feat(quality): check naming + metadata contract (#57)
iamgp Dec 13, 2025
e043490
feat: limit datetime coercion (#60)
iamgp Dec 13, 2025
2582b06
chor(beads): close phlo-nwk.2.1 and phlo-nwk.4.2 (#61)
iamgp Dec 13, 2025
f2080c7
feat: warn vs blocking severity policy (#62)
iamgp Dec 13, 2025
78b7eaf
feat: partition-scoped checks + failure sampling (#63)
iamgp Dec 13, 2025
49751f8
feat: correct grouping + move compiled SQL to metadata (#66)
iamgp Dec 13, 2025
9a6f6f5
fix: fix exports and remove print() (#67)
iamgp Dec 13, 2025
006c272
feat: CLI hardening: services refactor + scaffold without TODOs (#70)
iamgp Dec 13, 2025
3481ea2
feat(cli): scaffold publishing.yaml (#72)
iamgp Dec 13, 2025
39185fb
feat(quality): emit pandera and dbt asset checks (#73)
iamgp Dec 14, 2025
0a19668
feat(observatory): implement quality endpoints (#74)
iamgp Dec 14, 2025
bfe1c16
feat(observatory): quality center drilldown (#75)
iamgp Dec 14, 2025
7443662
docs(adr): add retrospective decisions (#76)
iamgp Dec 14, 2025
487d241
feat(observatory): make Data Explorer branch-aware (phlo-nwk.1.2) (#77)
iamgp Dec 14, 2025
27f6b92
feat(cli): generate pandera schemas from dlt inference (phlo-nwk.3.5)…
iamgp Dec 14, 2025
dc6d469
feat: observatory UI redesign (shadcn Lyra preset) (#79)
iamgp Dec 14, 2025
6065af0
feat: TanStack Table migration (#80)
iamgp Dec 15, 2025
0fef4e5
feat(observatory): settings and query guardrails (#81)
iamgp Dec 16, 2025
3b8e2c5
feat(observatory): inline contributing rows with pagination (#82)
iamgp Dec 16, 2025
c12366f
feat(observatory): enhance command palette with table/column search (…
iamgp Dec 17, 2025
0caed77
feat(observatory): add server-side metadata caching (#84)
iamgp Dec 17, 2025
e109015
feat(observatory): virtualized table browser with search and keyboard…
iamgp Dec 17, 2025
ad53974
feat(observatory): add visual diff view between pipeline stages (#86)
iamgp Dec 18, 2025
0188d12
feat(ingestion): add strict_validation config and remove deprecated c…
iamgp Dec 18, 2025
319280d
feat(observatory): add saved queries and bookmarks (#88)
iamgp Dec 19, 2025
372fbe8
feat(quality): add reconciliation checks for cross-table validation (…
iamgp Dec 19, 2025
96fbdd6
bd sync: 2025-12-19 23:21:57
iamgp Dec 19, 2025
ad81680
feat(observatory): add responsive layout for mobile and tablet (#90)
iamgp Dec 19, 2025
8a9bb8f
feat(observatory): add authentication and real-time polling (#91)
iamgp Dec 20, 2025
69e6582
fix(observatory): add QueryClientProvider for SSR (#92)
iamgp Dec 20, 2025
c5a0d50
bd sync: 2025-12-20 10:41:20
iamgp Dec 20, 2025
9998109
bd sync: 2025-12-21 11:26:44
iamgp Dec 21, 2025
04f2eaa
bd sync: 2025-12-21 11:48:51
iamgp Dec 21, 2025
b82534d
feat(observatory): add structured logging with Pino (#93)
iamgp Dec 21, 2025
b38d02a
feat(observatory): add Loki log querying server functions (#94)
iamgp Dec 21, 2025
a9a4e58
chore(example): add Alloy config to github-stats example (#95)
iamgp Dec 21, 2025
dcdea71
feat(cli): add restart command and fix --profile flag behavior (#96)
iamgp Dec 21, 2025
65a87ec
Improve type safety: eliminate all type ignores and reduce Any usage …
iamgp Dec 21, 2025
86b2ec8
feat(phlo-930): Unified Plugin System with Registry (#98)
iamgp Dec 22, 2025
d881b73
feat: Observatory as core with plugin DX improvements (#99)
iamgp Dec 22, 2025
a14d209
refactor: plugin packages and refactoring (#100)
iamgp Dec 26, 2025
22e06fe
chore(deps): update github artifact actions (#53)
renovate[bot] Dec 26, 2025
b4b42c3
chore(deps): update actions/setup-node action to v6 (#71)
renovate[bot] Dec 26, 2025
d3a7e49
chore(main): release 0.1.0-alpha.1 (#49)
iamgp Dec 26, 2025
026372a
chore(release): bump release-please manifest to 0.1.0-alpha.2
iamgp Dec 26, 2025
573986d
chore(release): set release-please to 0.1.0-alpha.2
iamgp Dec 26, 2025
9501f21
chore(main): release 0.1.0-alpha.2 (#104)
iamgp Dec 26, 2025
f96be7f
chore(ci): use Node 22 for observatory checks
iamgp Dec 26, 2025
0a82e2c
chore(renovate): batch weekly updates
iamgp Dec 26, 2025
ad47b1b
docs: update documentation for pip installation and plugin system (#108)
iamgp Dec 26, 2025
f873209
chore(release): fix versioning and simplify configuration (#110)
iamgp Dec 26, 2025
e40d438
feat: add hook bus and update plugins to use them (#111)
iamgp Dec 27, 2025
8893bbd
chore: simplify release-please to use pyproject.toml directly
iamgp Dec 27, 2025
113e7a3
feat(security): add enterprise security configuration options (#117)
iamgp Dec 27, 2025
8eab4e6
feat(iceberg,trino): add table maintenance and caching (#118)
iamgp Dec 28, 2025
d553c9a
feat: auto-configure services for plug-and-play installation (#119)
iamgp Dec 28, 2025
2451b24
feat: migrate from basedpyright to ty typechecker (#120)
iamgp Dec 28, 2025
a80cd05
feat: register phlo-api service plugin (#121)
iamgp Dec 29, 2025
52fd5c7
ci: configure release-please prerelease manifests (#122)
iamgp Dec 29, 2025
17a249a
ci: publish only changed packages (#123)
iamgp Dec 29, 2025
201413b
test: quiet pytest warnings (#125)
iamgp Dec 29, 2025
8fde907
feat(test): integration tests (#126)
iamgp Dec 30, 2025
de4d0e2
feat(iceberg): add maintenance observability (#127)
iamgp Dec 30, 2025
7f998c0
feat: advanced reconciliation checks (#128)
iamgp Dec 30, 2025
0dc2b4b
chore: remove .beads
iamgp Dec 30, 2025
26557b4
chore: remove .claude
iamgp Dec 30, 2025
23cf758
chore: remove .phlo
iamgp Dec 30, 2025
0c42fb1
chore: remove typings
iamgp Dec 30, 2025
2c2a2da
chore: remove .adr-dir
iamgp Dec 30, 2025
5576295
chore: remove gitattributes
iamgp Dec 30, 2025
b47f54e
docs: update all documentation (#129)
iamgp Dec 30, 2025
1161154
feat: standardise env config and add env export (#130)
iamgp Dec 30, 2025
7095974
fix: suppress pyiceberg Pydantic v2.12 deprecation warnings (#131)
iamgp Dec 30, 2025
ab165b4
feat: introduce golden-path e2e workflow test (#132)
iamgp Jan 2, 2026
86ddbf7
feat: make check (#133)
iamgp Jan 2, 2026
411b130
chore(release): use prerelease versioning strategy (#135)
iamgp Jan 2, 2026
6981ed3
Emit pandera contract checks for DLT ingestion (#136)
iamgp Jan 2, 2026
9c0706a
Fix quality checks resource wiring and partition filters (#138)
iamgp Jan 2, 2026
11b35ae
chore: drop prerelease config for releases (#139)
iamgp Jan 2, 2026
c1a3700
chore(release): avoid major bump pre-1.0 (#141)
iamgp Jan 2, 2026
25871c5
chore(main): release 0.3.0 (#142)
iamgp Jan 2, 2026
6fd9975
chore(release): publish only root package (#143)
iamgp Jan 2, 2026
05b8684
docs: refresh AGENTS guidance (#144)
iamgp Jan 2, 2026
abe886d
feat: move dbt project under workflows (#146)
iamgp Jan 2, 2026
e03a802
chore: remove unused templates (#147)
iamgp Jan 3, 2026
1344f8e
chore: deploy docs via GitHub Pages (#148)
iamgp Jan 3, 2026
b35400d
feat(logging): logging improvements (#149)
iamgp Jan 3, 2026
d04c8c7
feat: introduce capability primitives and orchestrator adapters (#150)
iamgp Jan 4, 2026
b0a0b53
chore(deps): update node.js to v24 (#114)
renovate[bot] Jan 4, 2026
f2b0ce4
chore(deps): update github-actions (#113)
renovate[bot] Jan 4, 2026
f0d7bd1
fix(deps): update observatory-js (#115)
renovate[bot] Jan 4, 2026
e582561
chore(deps): update dependency python to 3.14 (#151)
renovate[bot] Jan 4, 2026
7eabe2b
chore(cli): remove root .env.example, add .sqlfluff to project templa…
iamgp Jan 4, 2026
d9bb1cf
fix(deps): update observatory-js (#154)
renovate[bot] Jan 4, 2026
0782207
docs: create comprehensive quality checks catalog (#155)
iamgp Jan 5, 2026
33fcdda
docs: document dbt-to-Pandera schema generation feature (#156)
iamgp Jan 5, 2026
99110ac
docs: fold in work-style, git safety, build/test, and tools guidance
iamgp Jan 5, 2026
638d83f
feat: observatory extensions (#161)
iamgp Jan 10, 2026
cef8bd7
refactor: simplify code with dict dispatch and reduce redundancy (#162)
iamgp Jan 13, 2026
4b4f54f
docs(blog): updates (#163)
iamgp Jan 14, 2026
6313f99
refactor: core package restructure (#164)
iamgp Jan 16, 2026
b40bf2e
refactor: extract core to packages (#165)
iamgp Jan 20, 2026
a63b8bd
fix: stabilize release + runnable lakehouse/docs flow (#171)
iamgp Feb 14, 2026
59498c0
docs(blog): humanise writing style across blog series (#178)
iamgp Feb 14, 2026
52858a1
fix(observatory): harden service discovery and plugins fallback
iamgp Feb 15, 2026
00f862b
fix(observatory): cache plugin registry responses
iamgp Feb 15, 2026
4fbe108
fix: quality/test behavior and observatory settings typing (#179)
iamgp Feb 16, 2026
9677ef6
fix: harden runtime service and CLI reliability (#184)
iamgp Feb 16, 2026
cc4db2f
ci: harden checks, coverage, and integration workflows (#185)
iamgp Feb 16, 2026
a292ad0
refactor: split oversized modules into focused units (#186)
iamgp Feb 16, 2026
9b1814f
docs: clean quickstart and blog structure updates (#187)
iamgp Feb 16, 2026
9296477
ci: add dedicated integration lane with status summary (#194)
iamgp Feb 16, 2026
2c0b549
refactor(phlo-api): extract trino SQL helpers (#193)
iamgp Feb 16, 2026
945bf58
test: harden integration assertions and marker rules (#191)
iamgp Feb 16, 2026
c74d826
fix(iceberg): stabilize integration endpoint resolution (#189)
iamgp Feb 16, 2026
32b5278
fix(metrics): replace placeholder runtime collector logic (#190)
iamgp Feb 16, 2026
7c08af7
test(observatory): add deterministic server and route coverage (#192)
iamgp Feb 16, 2026
92bf099
chore(main): release 0.4.0 (#188)
iamgp Feb 16, 2026
e9e460d
docs: align docs with current CLI and plugin entry points (#195)
iamgp Feb 16, 2026
fb362d3
docs: standardise google-style docstrings across codebase (#197)
iamgp Feb 16, 2026
68b776c
chore: remove folder
iamgp Feb 16, 2026
89f2827
docs: add google-style docstrings for root tests (#198)
iamgp Feb 16, 2026
ae70feb
docs: add docs (#199)
iamgp Feb 17, 2026
aef5572
refactor(logging): strengthen lifecycle instrumentation across core p…
iamgp Feb 18, 2026
4b4cab0
feat: implement plug-and-play capability model across packages (#201)
iamgp Feb 18, 2026
9b9bf06
refactor: remove legacy env aliases and iceberg fallbacks (#202)
iamgp Feb 18, 2026
5205188
refactor: decouple remaining package dependencies via capability boun…
iamgp Feb 20, 2026
05b3cf8
chore(main): release 0.5.0 (#196)
iamgp Feb 20, 2026
f94a710
fix(ci): skip release-please on release commits
iamgp Feb 20, 2026
594b8f7
fix: stabilize dev package loading and logging compatibility
iamgp Feb 21, 2026
fda2d67
fix(services): clear disabled state when re-adding service (#205) (#217)
iamgp Feb 21, 2026
d1ce2a6
fix(cli): improve services list error ux (#216)
iamgp Feb 21, 2026
b57ea51
fix(services): fail fast on invalid --profile in start (#219)
iamgp Feb 21, 2026
f2e426b
fix: honor plugins_auto_discover precedence (#207) (#220)
iamgp Feb 21, 2026
7bc5763
fix(plugins): invoke lifecycle hooks in discovery flow (#206) (#221)
iamgp Feb 21, 2026
717d245
test: add orchestrator selection regression tests (#211) (#222)
iamgp Feb 21, 2026
13032a0
test: add registry client cache fallback coverage for #213 (#223)
iamgp Feb 21, 2026
57f0c6d
test(logging): add core regression tests for #212 (#224)
iamgp Feb 21, 2026
42bcc49
test(infrastructure): add config helper edge-case coverage (#214) (#225)
iamgp Feb 21, 2026
430d73b
test(exceptions): add formatting and helper tests (#215) (#226)
iamgp Feb 21, 2026
3c9a03c
fix: add service discovery cache refresh/invalidation API (#218)
iamgp Feb 21, 2026
a1bff6c
fix(plugins): enforce safe teardown cleanup for #232 (#240)
iamgp Feb 22, 2026
e2a2e4d
docs: sync core behavior docs for services and discovery (#227) (#241)
iamgp Feb 22, 2026
257a8fb
fix(services): normalize enabled/disabled config lists (#231) (#242)
iamgp Feb 22, 2026
3c85f77
test: add CLI golden-output coverage for core error contracts (#246)
iamgp Feb 22, 2026
6747f71
feat(discovery): emit discovery observability lifecycle signals (#234…
iamgp Feb 22, 2026
6258433
test: add core regression suite marker and command (#238) (#248)
iamgp Feb 22, 2026
c843767
perf: add discovery and registry micro-benchmarks (#237) (#249)
iamgp Feb 22, 2026
6e61d16
test: add service state transition e2e coverage (#243)
iamgp Feb 22, 2026
fd7eb14
test: split services cli tests by command (#229) (#244)
iamgp Feb 22, 2026
ab2fd9b
test: add plugin lifecycle failure-policy assertions (#233) (#245)
iamgp Feb 22, 2026
da7219e
refactor: decompose discovery modules into focused units (#250)
iamgp Feb 22, 2026
f7c9fda
docs(blog): add data engineering fundamentals series (#251)
iamgp Feb 22, 2026
0ba415b
chore: blog nit picks
iamgp Feb 25, 2026
23d361d
feat: expand TableStore protocol and add governance primitives (#252)
iamgp Feb 28, 2026
c57bd3c
feat: schema migration core primitives, providers, and CLI (#253)
iamgp Mar 1, 2026
fcaac3c
chore: add prek hooks and repo pre-commit config (#254)
iamgp Mar 1, 2026
772515d
chore: tune pre-commit hooks for repo baseline (#256)
iamgp Mar 1, 2026
8f8311d
chore: Agents.md
iamgp Mar 1, 2026
6f12ac9
refactor(ingestion): move schema conversion into iceberg provider (#257)
iamgp Mar 1, 2026
5c539ad
feat: add Phlo-native contracts for schema migration scaffolding (#258)
iamgp Mar 1, 2026
92eb1bc
feat: add decorator contract metadata for schema contracts (#259)
iamgp Mar 1, 2026
da8e56e
refactor: consolidate shared helpers and service dependency logic (#260)
iamgp Mar 1, 2026
18ea5c5
feat: implement data migration CLI and contract-based scaffolding (#261)
iamgp Mar 1, 2026
85f06a1
feat: add core async operation and hook primitives (#262)
iamgp Mar 1, 2026
53ff747
docs: retire legacy blog and add data migration docs (#263)
iamgp Mar 1, 2026
87cc17c
chore: readme updates
iamgp Mar 1, 2026
117998e
chore(main): release 0.6.0 (#255)
iamgp Mar 1, 2026
277319c
fix: skip release-please if tag already exists
iamgp Mar 1, 2026
ecd5efc
chore(main): release 0.6.1
iamgp Mar 1, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
The diff you're trying to view is too large. We only load the first 3000 changed files.
3 changes: 3 additions & 0 deletions .codespellrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
[codespell]
skip = *.lock,uv.lock,*.svg,*/package-lock.json,package-lock.json,*.min.js
ignore-words-list = iterm,temperatur,coo,vew
42 changes: 0 additions & 42 deletions .env.example

This file was deleted.

10 changes: 10 additions & 0 deletions .github/release-please-config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"packages": {
".": {
"release-type": "python",
"bump-minor-pre-major": true,
"changelog-path": "CHANGELOG.md",
"include-v-in-tag": true
}
}
}
3 changes: 3 additions & 0 deletions .github/release-please-manifest.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
".": "0.6.1"
}
222 changes: 222 additions & 0 deletions .github/scripts/publish_plan.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,222 @@
from __future__ import annotations

import json
import os
import re
import subprocess
import tomllib
from collections import deque
from pathlib import Path


def run(args: list[str]) -> str:
return subprocess.check_output(args, text=True).strip()


def try_run(args: list[str]) -> str:
try:
return run(args)
except subprocess.CalledProcessError:
return ""


def normalize_dep(dep: str) -> str:
dep = dep.split(";", 1)[0].strip()
if not dep:
return ""
dep = dep.split("[", 1)[0]
name = re.split(r"[<>=!~ ]", dep, maxsplit=1)[0]
return name.strip()


def load_packages(root: Path) -> tuple[dict[str, Path], dict[str, dict]]:
package_paths: dict[str, Path] = {}
package_meta: dict[str, dict] = {}

root_pyproject = root / "pyproject.toml"
root_data = tomllib.loads(root_pyproject.read_text(encoding="utf-8"))
root_name = root_data["project"]["name"]
package_paths[root_name] = root
package_meta[root_name] = root_data

packages_dir = root / "packages"
if packages_dir.exists():
for pkg_dir in packages_dir.iterdir():
if not pkg_dir.is_dir():
continue
pyproject = pkg_dir / "pyproject.toml"
if not pyproject.exists():
continue
data = tomllib.loads(pyproject.read_text(encoding="utf-8"))
name = data["project"]["name"]
package_paths[name] = pkg_dir
package_meta[name] = data

return package_paths, package_meta


def collect_internal_deps(
package_meta: dict[str, dict], internal: set[str]
) -> dict[str, list[str]]:
def deps_for(name: str) -> list[str]:
data = package_meta[name]
deps = list(data.get("project", {}).get("dependencies", []) or [])
optional = data.get("project", {}).get("optional-dependencies", {}) or {}
for group in optional.values():
deps.extend(group)
internal_deps = []
for dep in deps:
dep_name = normalize_dep(dep)
if dep_name in internal:
internal_deps.append(dep_name)
return sorted(set(internal_deps))

return {name: deps_for(name) for name in internal}


def find_base_ref(event: str, base_ref_env: str, current_tag: str) -> str:
if base_ref_env:
return base_ref_env
if event == "release" and current_tag:
return try_run(["git", "describe", "--tags", "--abbrev=0", f"{current_tag}^"])
return try_run(["git", "describe", "--tags", "--abbrev=0"])


def collect_changed_files(base_ref: str) -> list[str]:
if base_ref:
diff = try_run(["git", "diff", "--name-only", f"{base_ref}..HEAD"])
return diff.splitlines() if diff else []
return try_run(["git", "ls-files"]).splitlines()


def select_changed_packages(
changed_files: list[str],
package_paths: dict[str, Path],
root_name: str,
root_path: Path,
) -> set[str]:
changed_packages: set[str] = set()
package_prefixes: list[tuple[str, str]] = []
for package_name, package_path in package_paths.items():
if package_name == root_name:
continue
rel = package_path.relative_to(root_path).as_posix()
package_prefixes.append((f"{rel}/", package_name))

for file in changed_files:
matched_package = False
for prefix, package_name in package_prefixes:
if file.startswith(prefix):
changed_packages.add(package_name)
matched_package = True
break
if matched_package:
continue

if (
file == "pyproject.toml"
or file.startswith("src/phlo/")
or file.startswith("registry/")
or file in {"README.md", "CHANGELOG.md"}
):
changed_packages.add(root_name)

return changed_packages


def topo_sort(selected: set[str], dep_map: dict[str, list[str]]) -> list[str]:
in_deg = {name: 0 for name in selected}
dependents: dict[str, list[str]] = {name: [] for name in selected}
for name in selected:
for dep in dep_map.get(name, []):
if dep in selected:
in_deg[name] += 1
dependents.setdefault(dep, []).append(name)

queue = deque(sorted([name for name, deg in in_deg.items() if deg == 0]))
order: list[str] = []
while queue:
node = queue.popleft()
order.append(node)
for dep in sorted(dependents.get(node, [])):
in_deg[dep] -= 1
if in_deg[dep] == 0:
queue.append(dep)

remaining = sorted([name for name in selected if name not in order])
order.extend(remaining)
return order


def parse_target_packages(raw: str, available: set[str]) -> set[str]:
value = raw.strip()
if not value:
return set()

names: set[str]
if value.startswith("["):
try:
parsed = json.loads(value)
except json.JSONDecodeError as exc:
raise ValueError(
f"TARGET_PACKAGES contains invalid JSON: {exc.msg} (pos {exc.pos}) in {value!r}"
) from exc
if not isinstance(parsed, list):
raise ValueError("TARGET_PACKAGES JSON must be a list of package names.")
names = {str(item).strip() for item in parsed if str(item).strip()}
else:
names = {part.strip() for part in value.split(",") if part.strip()}

unknown = sorted(names - available)
if unknown:
raise ValueError(f"Unknown package(s): {', '.join(unknown)}")

return names


def main() -> None:
root = Path(".")
package_paths, package_meta = load_packages(root)
internal = set(package_paths)

dep_map = collect_internal_deps(package_meta, internal)

event = os.environ.get("GITHUB_EVENT_NAME", "")
base_ref_env = os.environ.get("BASE_REF", "").strip()
current_tag = os.environ.get("GITHUB_REF_NAME", "") if event == "release" else ""

base_ref = find_base_ref(event, base_ref_env, current_tag)
changed_files = collect_changed_files(base_ref)

root_name = next(name for name, path in package_paths.items() if path == root)

target_packages_raw = os.environ.get("TARGET_PACKAGES", "")
target_packages = parse_target_packages(target_packages_raw, set(package_paths))
publish_all = os.environ.get("PUBLISH_ALL", "false").strip().lower() == "true"
if target_packages:
selected = target_packages
elif publish_all:
selected = set(package_paths)
else:
selected = select_changed_packages(changed_files, package_paths, root_name, root)
order = topo_sort(selected, dep_map)

dry_run = os.environ.get("DRY_RUN", "false").strip().lower() == "true"
outputs = {
"packages": json.dumps(order),
"has_packages": "true" if order else "false",
"dry_run": "true" if dry_run else "false",
}

output_path = os.environ["GITHUB_OUTPUT"]
with open(output_path, "a", encoding="utf-8") as fh:
for key, value in outputs.items():
fh.write(f"{key}={value}\n")

print(f"Base ref: {base_ref or '(none)'}")
print(f"Changed files: {len(changed_files)}")
print(f"Packages: {order}")


if __name__ == "__main__":
main()
110 changes: 110 additions & 0 deletions .github/workflows/build-core-services.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
name: Build Core Services

on:
push:
branches: [main]
paths:
- "packages/phlo-observatory/**"
- "packages/phlo-api/**"
- ".github/workflows/build-core-services.yml"
pull_request:
branches: [main]
paths:
- "packages/phlo-observatory/**"
- "packages/phlo-api/**"
release:
types: [published]

env:
REGISTRY: ghcr.io

jobs:
build-observatory:
name: Build Observatory
runs-on: ubuntu-latest
permissions:
contents: read
packages: write

steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd
with:
persist-credentials: false

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f

- name: Log in to Container Registry
if: github.event_name != 'pull_request'
uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}

- name: Extract metadata
id: meta
uses: docker/metadata-action@c299e40c65443455700f0fdfc63efafe5b349051
with:
images: ${{ env.REGISTRY }}/${{ github.repository_owner }}/phlo-observatory
tags: |
type=ref,event=branch
type=ref,event=pr
type=semver,pattern={{version}}
type=semver,pattern={{major}}.{{minor}}
type=raw,value=latest,enable={{is_default_branch}}

- name: Build and push
uses: docker/build-push-action@10e90e3645eae34f1e60eeb005ba3a3d33f178e8
with:
context: packages/phlo-observatory/src/phlo_observatory
push: ${{ github.event_name != 'pull_request' }}
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=gha
cache-to: type=gha,mode=max

build-phlo-api:
name: Build phlo-api
runs-on: ubuntu-latest
permissions:
contents: read
packages: write

steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd
with:
persist-credentials: false

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f

- name: Log in to Container Registry
if: github.event_name != 'pull_request'
uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}

- name: Extract metadata
id: meta
uses: docker/metadata-action@c299e40c65443455700f0fdfc63efafe5b349051
with:
images: ${{ env.REGISTRY }}/${{ github.repository_owner }}/phlo-api
tags: |
type=ref,event=branch
type=ref,event=pr
type=semver,pattern={{version}}
type=semver,pattern={{major}}.{{minor}}
type=raw,value=latest,enable={{is_default_branch}}

- name: Build and push
uses: docker/build-push-action@10e90e3645eae34f1e60eeb005ba3a3d33f178e8
with:
context: packages/phlo-api/src/phlo_api
push: ${{ github.event_name != 'pull_request' }}
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=gha
cache-to: type=gha,mode=max
Loading