Commit Graph

26 Commits

Author SHA1 Message Date
Henrik Jess Nielsen
e5ba01a52b feat: add AzDO pipeline schema completions (task@version, inputs, steps)
All checks were successful
Build and Deploy iLSP / test (push) Successful in 20s
Build and Deploy iLSP / build-and-deploy (push) Successful in 1m27s
- Inject AzDO schema into yaml-language-server via initializationOptions
  at startup (primary mechanism, works without workspace.configuration)
- Respond to workspace/configuration pull requests from yaml-language-server
  so schema is applied even when editors declare configuration capability
- Keep post-init workspace/didChangeConfiguration as belt-and-suspenders
- Bake azdo-pipeline-schema.json (~1.6MB, 119 defs) into Docker image
- Add smoke test [8]: AzDO task@version completions (254 items)
- Update smoke test YAML initialize to declare workspace.configuration
2026-05-10 16:55:54 +02:00
Henrik Jess Nielsen
acccd9ba20 docs: add README and EDITOR_SETUP with YAML pipeline template section
All checks were successful
Build and Deploy iLSP / test (push) Successful in 21s
Build and Deploy iLSP / build-and-deploy (push) Successful in 46s
- README.md: project overview, quick start, deploy instructions
- EDITOR_SETUP.md: editor config (neovim, VS Code), full feature matrix
  - Bicep: internal module registry, versions, params, allowed values
  - YAML AzDO: pipeline template completions with parameter injection
  - YAML GHA: reusable workflow completions with input injection
  - Health check fields explained, smoke test usage
2026-05-10 16:40:58 +02:00
Henrik Jess Nielsen
ae751f944c fix: yaml stdio per-connection, iac catalog path, makefile port
All checks were successful
Build and Deploy iLSP / test (push) Successful in 25s
Build and Deploy iLSP / build-and-deploy (push) Successful in 1m37s
- yaml-language-server: rewrite to stdio per WebSocket (fixes crash loop)
  vscode-jsonrpc v9 createServerSocketTransport is a TCP client, not server
  now spawns yaml-language-server --stdio per connection via asyncio subprocess

- bicep/modules.py: add /iac_source_catalog.json as first path in _IAC_SOURCE_PATHS
  Dockerfile copies to /iac_source_catalog.json but path wasn't listed

- server.py: remove YAML_LSP_PORT daemon (no longer needed with stdio mode)

- Makefile: add -e HTTP_PORT=$(HEALTH_PORT) to all docker run commands
  server defaulted to :8000 but Makefile exposed :2089 with no override
2026-05-10 16:37:42 +02:00
Henrik Jess Nielsen
2a1717ff81 feat: bake iac_source_catalog into Docker image; fix YAML smoke test; add .gitignore
All checks were successful
Build and Deploy iLSP / test (push) Successful in 23s
Build and Deploy iLSP / build-and-deploy (push) Successful in 1m35s
- Dockerfile: COPY iac_source_catalog.json in builder + final stage
- push_catalogs.sh: cp iac_source_catalog.json to iLSP repo root before SCP
- smoke_test_completions.py: detect WS CLOSE in _recv_until_id; 20s YAML init timeout; clearer error message
- .gitignore: standard Python exclusions

Fixes: iac_source_modules=0 (was never baked into image)
2026-05-10 16:23:02 +02:00
Henrik Jess Nielsen
ef3535048b fix: Bicep module ref path — strip bicep/ prefix, lookup by ref_path
All checks were successful
Build and Deploy iLSP / build-and-deploy (push) Successful in 1m29s
Build and Deploy iLSP / test (push) Successful in 24s
Two bugs fixed in BicepModuleCatalog:

1. as_completion_items() generated 'br/modules:bicep/modules/appservice:...'
   but bicepconfig modulePath='bicep' means Bicep prepends 'bicep/' automatically.
   Fix: store ref_path = path.removeprefix('bicep/') and use it in insertText.
   Correct output: 'br/modules:modules/appservice:2.3.x'

2. version/param lookups used get_module_by_name() which only matches the last
   path segment ('appservice'). New-style refs capture 'modules/appservice' from
   the regex, so lookup returned empty. Fix: add get_module_by_ref() that matches
   both ref_path and bare name.

Also fixes _iac_param_map to strip path prefix so IAC source descriptions
still enrich completions for 'modules/appservice' refs.

All 63 tests pass.
2026-05-10 16:10:36 +02:00
Henrik Jess Nielsen
333d986e76 feat: YAML pipeline template autocomplete (AzDO + GHA)
All checks were successful
Build and Deploy iLSP / test (push) Successful in 25s
Build and Deploy iLSP / build-and-deploy (push) Successful in 1m34s
- Add scripts/sync_pipeline_templates.py — scans LRU AzDO and GHA template
  repos; outputs unified pipeline_templates_catalog.json (48 templates: 45
  AzDO + 3 GHA)
- Add scripts/template_sources.yml — source config (AzDO alias, GHA org)
- Add pipeline_templates_catalog.json — baked catalog (49 KB)
- Add ilsp/yaml_lsp/catalog.py — PipelineTemplateCatalog with completion item
  generators for template paths, param names, allowed values, GHA inputs
- Add ilsp/yaml_lsp/proxy.py — async WS↔TCP bridge with LSP frame buffering,
  per-connection document tracking, AzDO/GHA context detection, and completion
  injection (LRU items sortText 0_, standard items downgraded to 9_)
- Wire yaml_ws_handler into server.py (replaces raw _ws_proxy call)
- Load PipelineTemplateCatalog at startup; reload + health report template count
- Update push_catalogs.sh to push pipeline_templates_catalog.json
- Update Dockerfile to bake pipeline_templates_catalog.json as image fallback
- Add tests/test_yaml_catalog.py (14 tests) + tests/test_yaml_proxy.py (18 tests)
  All 67 tests green
2026-05-10 15:59:37 +02:00
Henrik Jess Nielsen
5501254b55 feat: YAML LSP (/yaml endpoint) + IAC source catalog enrichment
All checks were successful
Build and Deploy iLSP / test (push) Successful in 21s
Build and Deploy iLSP / build-and-deploy (push) Successful in 2m49s
- Add yaml-language-server (Node.js) to Dockerfile stage 3
- Add YAML_LSP_PORT=2090 env var (Dockerfile + ilsp.nomad)
- Start yaml-language-server in background thread (_serve_yaml_lsp)
- Expose /yaml WebSocket endpoint (same WS→TCP proxy as /python and /bicep)
- Load iac_source_catalog.json alongside bicep_modules_catalog.json
- Enrich param_completion_items() with descriptions + required flag from IAC source
  - Required params sorted first (sortText 0_lru_param_0_...) and marked with *
  - detail field shows * prefix for required params
- Update /health to report iac_source_modules + yaml_lsp fields
- Rewrite EDITOR_SETUP.md: WebSocket URLs, YAML schemas config for all editors
  (Helix, Neovim, PyCharm, VS Code) with azure-pipelines + gitea actions schemas
- All 35 tests pass
2026-05-10 15:40:13 +02:00
Henrik Jess Nielsen
b93aa84737 feat: param_value context — enum/allowed completions for principalType, environmentType etc.
All checks were successful
Build and Deploy iLSP / test (push) Successful in 20s
Build and Deploy iLSP / build-and-deploy (push) Successful in 1m20s
- Add _KNOWN_ENUMS dict (principalType, principalObjectType, environmentType fallbacks)
- Add param_value_completion_items() to BicepModuleCatalog
- Detect 'param_value' context in _detect_context() (cursor after 'param: ' inside params block)
- Wire param_value into _inject_completions()
- 9 new unit tests (context detection, catalog allowed, known enum fallback, injection)
- Fix modules.py edit regression (param_completion_items was orphaned)
- All 35 tests pass
2026-05-10 15:30:31 +02:00
Henrik Jess Nielsen
bf24b5677f fix: backend unavailable test — use free port + ws.close(timeout=2s)
All checks were successful
Build and Deploy iLSP / test (push) Successful in 20s
Build and Deploy iLSP / build-and-deploy (push) Successful in 1m32s
- Use _free_port() instead of hardcoded 19999 (avoids CI port conflicts)
- Add timeout=2.0 to ws.close() so close handshake never blocks >2s
2026-05-10 15:16:55 +02:00
Henrik Jess Nielsen
404bd1418d fix: add 3s timeout to LSP backend connection (handles CI firewall drops)
Some checks failed
Build and Deploy iLSP / test (push) Failing after 27s
Build and Deploy iLSP / build-and-deploy (push) Has been skipped
asyncio.open_connection hangs indefinitely when backend port is silently
dropped. Add wait_for(timeout=3.0) so the WS close frame is always sent
within the test's 5s window.
2026-05-10 15:13:03 +02:00
Henrik Jess Nielsen
a708cb779e fix: push_catalogs.sh uses ilsp.i80.dk (not lsp.i80.dk)
Some checks failed
Build and Deploy iLSP / test (push) Failing after 26s
Build and Deploy iLSP / build-and-deploy (push) Has been skipped
2026-05-10 15:07:22 +02:00
Henrik Jess Nielsen
27947e4f7f feat: context-aware Bicep completions (version + param injection)
Some checks failed
Build and Deploy iLSP / test (push) Failing after 27s
Build and Deploy iLSP / build-and-deploy (push) Has been skipped
- ProxySession tracks open documents per TCP connection
- _detect_context() identifies version, param, and module_path contexts
- version context: autocomplete versions for 'br/modules:NAME:' cursor positions
- param context: autocomplete params for specific module+version (with version fallback)
- modules.py: added get_module_by_name(), version_completion_items(), param_completion_items()
- 28/28 tests passing
2026-05-10 15:04:11 +02:00
Henrik Jess Nielsen
eafddb6f4a test: fake LSP client integration tests against real pylsp
Some checks failed
Build and Deploy iLSP / test (push) Failing after 27s
Build and Deploy iLSP / build-and-deploy (push) Has been skipped
- Start real pylsp process in fixture (retry-loop until port accepts)
- Fake client sends LSP initialize via WebSocket proxy
- Verify real pylsp capabilities + completionProvider in response
- Fix LSP frame parser to handle multi-header responses (Content-Length + Content-Type)
- Test graceful close when backend unreachable
2026-05-10 14:52:43 +02:00
Henrik Jess Nielsen
941d7b003f refactor: single HTTP port, WebSocket proxy for LSP endpoints
All checks were successful
Build and Deploy iLSP / test (push) Successful in 19s
Build and Deploy iLSP / build-and-deploy (push) Successful in 1m27s
- Remove static ports 2087/2088/2089 from Nomad; use one dynamic port
- pylsp and Bicep LS stay on localhost inside container (not exposed)
- aiohttp adds /python and /bicep WebSocket routes bridging to localhost LSPs
- Nomad env: HTTP_PORT=$NOMAD_PORT_http, internal ports fixed at 2087/2088
- Editors connect via ws://ilsp.i80.dk/python and ws://ilsp.i80.dk/bicep
- Traefik routes ilsp.i80.dk → single dynamic HTTP port
2026-05-10 14:44:33 +02:00
Henrik Jess Nielsen
83817229e0 fix: remove host volume requirement until autobox is configured
All checks were successful
Build and Deploy iLSP / test (push) Successful in 18s
Build and Deploy iLSP / build-and-deploy (push) Successful in 49s
Volume can be added back once ilsp-data is registered in nomad.hcl.
Baked-in catalog (27 modules) is sufficient for initial deploy.
2026-05-10 14:20:31 +02:00
Henrik Jess Nielsen
0527df717c feat: volume-based catalog refresh with hot-reload
Some checks failed
Build and Deploy iLSP / test (push) Successful in 18s
Build and Deploy iLSP / build-and-deploy (push) Failing after 12m14s
- modules.py: check /data/ volume first, then baked-in /bicep_modules_catalog.json
- server.py: add POST /reload endpoint — reloads catalogs without restart
- ilsp.nomad: add 'ilsp-data' host volume mounted at /data
- Makefile: add push-catalogs, health-prod, run-with-data targets; DEVOPS_MCP_REPO var
- scripts/push_catalogs.sh: SCP both catalogs to autobox + call /reload

Workflow: sync scripts on Mac → make push-catalogs → completions live in <5s
2026-05-10 13:51:01 +02:00
Henrik Jess Nielsen
6b38cbd70c feat: bake bicep catalog into image; fix dict-based modules parsing
Some checks failed
Build and Deploy iLSP / build-and-deploy (push) Has been cancelled
Build and Deploy iLSP / test (push) Successful in 18s
- Remove all DevOpsMCP/aiohttp runtime deps from BicepModuleCatalog
- BicepModuleCatalog.load() reads bicep_modules_catalog.json from disk at startup (sync)
- Fix _load_catalog: catalog uses dict {path: {versions, schema}} not a list
- server.py: call BicepModuleCatalog.load() synchronously, not via asyncio.gather
- Dockerfile: COPY bicep_modules_catalog.json into both builder + runtime stages
- Health endpoint now reports bicep_modules: 27

Verified locally: make run-quick → health returns pypi_packages:40 bicep_modules:27
2026-05-10 13:40:48 +02:00
Henrik Jess Nielsen
44da791f5a fix: update tests to match thread-based proxy API (_frame, _inject_completions)
All checks were successful
Build and Deploy iLSP / build-and-deploy (push) Successful in 2m6s
Build and Deploy iLSP / test (push) Successful in 19s
BicepProxy class and _ContentLengthFramer no longer exist after rewrite.
Tests now call module-level functions directly.
2026-05-10 13:35:40 +02:00
Henrik Jess Nielsen
c48ea919f6 ci: add --ignore-installed to avoid typing_extensions uninstall error
Some checks failed
Build and Deploy iLSP / test (push) Failing after 19s
Build and Deploy iLSP / build-and-deploy (push) Has been skipped
2026-05-10 13:33:03 +02:00
Henrik Jess Nielsen
6385e159ff fix: replace asyncio subprocess proxy with thread-based Popen proxy
Some checks failed
Build and Deploy iLSP / test (push) Failing after 12s
Build and Deploy iLSP / build-and-deploy (push) Has been skipped
asyncio subprocess PIPE unreliable for long-lived stdio bridging. Use Popen + threads instead. Also fix smoke_test.sh stdin handling.
2026-05-10 13:02:52 +02:00
Henrik Jess Nielsen
c550a4963e Fix PyPI regex and switch Bicep modules to /api/bicep-modules endpoint
Some checks failed
Build and Deploy iLSP / test (push) Successful in 7s
Build and Deploy iLSP / build-and-deploy (push) Failing after 25s
catalog.py: Fix HTML parsing regex — pypi-server.i80.dk uses relative hrefs
  like href="pkg-name/" not /simple/pkg-name/. Use simpler <a> text extractor.
modules.py: Replace /call-tool POST (wrong) with GET /api/bicep-modules (new REST
  endpoint added to DevOpsMCP). Simpler, no MCP protocol overhead.
2026-05-10 12:48:13 +02:00
Henrik Jess Nielsen
1a594c78c3 Fix Dockerfile: use mcr.microsoft.com/dotnet/runtime:8.0 as base, add Makefile
Some checks failed
Build and Deploy iLSP / test (push) Successful in 6s
Build and Deploy iLSP / build-and-deploy (push) Failing after 20s
Dockerfile:
- Final stage now FROM mcr.microsoft.com/dotnet/runtime:8.0 instead of python:3.12-slim
  + MS apt repo. Reason: packages.microsoft.com GPG key uses SHA1 which Debian trixie
  rejects since 2026-02-01. The official MS container image has no signing issue.
- Add python3 + pip3 + wget on top of dotnet base (bookworm)
- pip3 install --break-system-packages for debian bookworm compatibility

Makefile targets:
  make build        - build image locally
  make rebuild      - force no-cache build
  make run          - build + start container with port mappings
  make run-quick    - start without rebuilding
  make stop/restart - container lifecycle
  make logs         - follow logs
  make shell        - bash into running container
  make health       - curl health endpoint
  make smoke        - end-to-end TCP + health test (scripts/smoke_test.sh)
  make test         - unit tests (pytest, no Docker)
  make ps/ports     - status helpers
  make clean        - stop + remove image
2026-05-10 12:43:09 +02:00
Henrik Jess Nielsen
cd17e9bfaa Add unit tests, smoke test script, fix CI to debian-host + test job
Some checks failed
Build and Deploy iLSP / test (push) Successful in 19s
Build and Deploy iLSP / build-and-deploy (push) Failing after 29s
- tests/test_catalog.py: 5 unit tests for PypiCatalog (fetch, cache, sort prefix, completions)
- tests/test_proxy.py: 5 unit tests for BicepProxy (framing, injection, list result, passthrough)
- tests/conftest.py: pytest asyncio_mode=auto config
- scripts/smoke_test.sh: end-to-end TCP + health smoke test script
- .gitea/workflows/ci.yml: split into test + build-and-deploy jobs (test blocks deploy)
  - runs-on: debian-host (was ubuntu-latest = broken)
  - test job installs deps + runs pytest before building image
- pyproject.toml: [project.optional-dependencies] dev = pytest + pytest-asyncio
2026-05-10 12:38:41 +02:00
Henrik Jess Nielsen
d8536468ab feat: initial iLSP project scaffolding
Some checks failed
CI / deploy (push) Has been cancelled
CI / build-and-push (push) Has been cancelled
- Python LSP (pylsp + pylsp_i80 plugin): i80 pypi package completions
- Bicep LSP (asyncio TCP proxy → Bicep.LangServer.dll): LRU module injection
- Health HTTP endpoint (:2089) for Consul/Nomad checks
- Startup catalog fetch from pypi-server.i80.dk + DevOpsMCP (no volume needed)
- Multi-stage Dockerfile: downloads Bicep LS at build time, dotnet-runtime-8.0 + python3.12
- Nomad job: static TCP ports 2087/2088, health check on 2089
- Gitea Actions CI: build + push + deploy pipeline
- Editor configs: Helix / nvim / LSP4IJ / VS Code
2026-05-10 12:23:05 +02:00
Henrik Jess Nielsen
e8708191f6 First run 2026-05-10 12:16:38 +02:00
Henrik Jess Nielsen
3db41fb251 first commit 2026-05-10 12:13:32 +02:00