Commit Graph

8 Commits

Author SHA1 Message Date
gffranco f2fd7d6376 ci(release): pin upload/download-artifact to v3 for Gitea Actions
CI / cargo fmt --check (push) Successful in 22s
CI / cargo clippy (push) Successful in 19s
CI / cargo test (push) Successful in 31s
Release / build x86_64-unknown-linux-gnu (push) Successful in 1m34s
Release / build aarch64-unknown-linux-musl (push) Successful in 55s
Release / build aarch64-unknown-linux-gnu (push) Failing after 57s
Release / build x86_64-unknown-linux-musl (push) Successful in 1m16s
Release / gitea release (push) Has been skipped
CI / editor keymaps (push) Successful in 1m24s
actions/upload-artifact@v4 and download-artifact@v4 require the
GitHub-hosted artifact backend, which Gitea Actions does not
implement (GHESNotSupportedError on v2.0.0+). Downgrade to v3.

v3's download-artifact has no merge-multiple flag and nests each
artifact under artifacts/<artifact-name>/, so the upload loop now
recurses to find the archives.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-14 22:55:31 +00:00
gffranco 82ff454e0f ci(release): drop cross, use rustup targets + native linkers
CI / cargo fmt --check (push) Successful in 22s
CI / cargo clippy (push) Successful in 23s
CI / cargo test (push) Failing after 16m25s
Release / build x86_64-unknown-linux-gnu (push) Failing after 56s
Release / build aarch64-unknown-linux-musl (push) Failing after 56s
Release / build aarch64-unknown-linux-gnu (push) Failing after 1m43s
Release / build x86_64-unknown-linux-musl (push) Failing after 1m31s
Release / gitea release (push) Has been skipped
CI / editor keymaps (push) Has been cancelled
cross spawns Docker containers per target, but the Gitea Actions
runner doesn't expose /var/run/docker.sock, so every cross-compile
step died with "Cannot connect to the Docker daemon".

Replace with rustup-installed targets plus per-target linker setup:
  - x86_64-gnu: native (no extra deps)
  - aarch64-gnu: gcc-aarch64-linux-gnu from apt
  - x86_64-musl: musl-tools from apt
  - aarch64-musl: rust-lld + link-self-contained (rust-std bundles
    musl libc.a + crt, no apt deps needed)

Verified aarch64-musl path locally: produces a statically linked
ARM aarch64 ELF.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-14 22:29:36 +00:00
gffranco a229977b77 ci(keymaps): pin Neovim 0.11 from upstream release tarball
CI / cargo fmt --check (push) Successful in 20s
CI / cargo clippy (push) Successful in 1m18s
CI / cargo test (push) Successful in 1m13s
CI / editor keymaps (push) Successful in 1m44s
CI log for the keymaps job showed Lua crashing with
`attempt to call field 'get_clients' (a nil value)` plus a flood of
`W18: Invalid character in group name` on the `@vimwiki*` highlight
links. Both signal that apt's `neovim` package is too old (Ubuntu
LTS ships 0.6/0.7) — `vim.lsp.get_clients` only landed in 0.10, and
Tree-sitter-style `@group.modifier` highlight names only became
valid sometime in the 0.8-ish era.

Switched the installer to pull the official static tarball
(`neovim/neovim/releases/v0.11.3/nvim-linux-x86_64.tar.gz`) and
symlink it into `/usr/local/bin/nvim`. Vim from apt is kept — it
only runs the pure-VimL harness so its age doesn't matter.

Also added a defensive fallback in the harness:
`get_lsp_clients = vim.lsp.get_clients or vim.lsp.get_active_clients`,
plus a `server_capabilities` nil guard. Won't matter on the pinned
0.11 runner, but means a future regression that drops the deps will
fail with a clear `lsp.attached` FAIL message instead of a Lua
stack trace.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-12 13:29:37 +00:00
gffranco a489bea480 test(keymaps): hard timeouts + serialise the CI job behind test
CI / cargo fmt --check (push) Successful in 29s
CI / cargo clippy (push) Successful in 1m16s
CI / cargo test (push) Successful in 1m18s
CI / editor keymaps (push) Failing after 2m25s
User reported the editor-keymaps CI job hung for 30 minutes before
"Has been cancelled" — twice in a row. Two changes to keep that from
happening again:

1. Wrap both harness invocations with `timeout` (60s Neovim, 30s
   Vim). A misbehaving LSP attach, a stuck `vim.defer_fn`, or
   ex-mode hung on stdin can no longer hold the runner indefinitely;
   `timeout` kills the process and the wrapper exits non-zero so CI
   shows the real failure shape.

2. `</dev/null` on `vim -e -s` so ex-mode doesn't sit waiting for
   input on CI's non-TTY stdin (the local zsh run inherits the
   user's tty, masking this).

3. CI: the keymaps job now has `needs: test` and
   `timeout-minutes: 10`. `needs: test` serialises behind the cargo
   jobs so we don't fight for the single Gitea runner, and the
   workflow-level timeout is a belt to the script-level `timeout`'s
   braces — if for some reason both fail the same way, the runner
   reclaims itself in 10 minutes instead of 30.

Local timing: `test-keymaps.sh` 10.4s, `test-keymaps-vim.sh` 0.1s.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-12 13:17:10 +00:00
gffranco 5fdd7a842e test(keymaps): Vim path harness + fix 25 broken one-liner functions
CI / cargo fmt --check (push) Successful in 19s
CI / cargo clippy (push) Successful in 1m10s
CI / cargo test (push) Successful in 1m20s
CI / editor keymaps (push) Has been cancelled
User asked about the Vim path of the keymap suite. Building it
surfaced a real bug: 25 of our autoload functions were written as
`function! foo() abort | call bar() | endfunction` one-liners, which
isn't valid Vim syntax — `function!` requires a multi-line body, and
Vim parses the `|` after `abort` as an unexpected trailing character
(E488). Most invocations of the buggy autoload functions errored
out the moment Vim tried to parse them, which is why the user saw
broken keymaps and confusing diagnostics.

Rewrote all 25 one-liners (`autoload/nuwiki/commands.vim`) into the
standard three-line form. Affected groups: `diary_*`, `toggle_list_item`,
`cycle_list_item`, `reject_list_item`, `heading_add`, `heading_remove`,
`toc_generate`, `links_generate`, `export_current` / `_all` /
`_all_force` / `_rss`, and the §13.1 deferred stubs (`list_change_lvl`,
`list_remove_done`, `table_*`, `colorize`, `paste_link`, `paste_url`).

Added `scripts/test-keymaps-vim.{sh,vim}` — a Vim-side counterpart of
the Neovim harness covering the pure-VimL bindings (header nav,
link nav, `o`/`O` bullet continuation, `<CR>` wrap step). The
LSP-roundtrip bindings (`<C-Space>`, `=`, `-`, …) stay on the Neovim
side because vim-lsp's async layer uses timers that don't fire
inside `vim -e -s` headless mode — their server-side codepath is
already exercised by the Neovim harness and the cargo test suite.

Vim harness covers 12 cases: filetype + 2 command-presence smoke
tests, 4 header-nav (`]]`/`[[`/`]=`/`]u`), `<Tab>` link-nav, `<CR>`
wrap-on-first-press, and 3 bullet-continuation flows.

CI: extended the existing `keymaps` job to install both nvim + vim
and run both harnesses. Verified locally:

  Neovim harness:  19 passed, 0 failed
  Vim harness:     12 passed, 0 failed

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-12 12:41:46 +00:00
gffranco 3b6693129c test(keymaps): headless Neovim harness for buffer-local bindings + CI
CI / cargo fmt --check (push) Successful in 19s
CI / cargo clippy (push) Successful in 1m20s
CI / cargo test (push) Successful in 1m14s
CI / editor keymaps (push) Has been cancelled
`scripts/test-keymaps.sh` boots `nvim --headless` against a scratch
wiki, sources `scripts/test-keymaps.lua`, and asserts the post-state
of each buffer-local mapping registered by `ftplugin/vimwiki.vim` +
`lua/nuwiki/keymaps.lua`.

The harness covers the bindings that actually have observable effects
on the buffer or cursor:

- **Lists** (LSP round-trip): `<C-Space>` / `<C-@>` / `<Nul>` toggle,
  `gln` cycle, `glx` reject, plus a `[X]→[ ]` round-trip.
- **Tasks**: `gnt` jumps to the next unfinished `[ ]`.
- **Headings** (LSP round-trip): `=` adds a level, `-` removes one,
  `=` on h6 clamps without growing.
- **Header nav** (pure Lua): `]]` next, `[[` prev, `]u` parent.
- **Link nav** (pure Lua): `<Tab>` to the next `[[…]]`.
- **`<CR>` two-step**: first press wraps a bare word as `[[word]]`
  and stops (matches vimwiki's review-then-follow).
- **Bullet continuation**: `o` / `O` keep the marker, and `o` on a
  `[ ]` line carries the checkbox forward.

Each case sets buffer lines, places the cursor (1-based), fires
`nvim_feedkeys` with `replace_termcodes`, waits long enough for the
LSP `executeCommand` round-trip (800 ms by default; 100 ms for the
pure-client maps), and asserts either the resulting lines, a specific
line, the cursor's new line, or the buffer's new name.

Output goes via `$NUWIKI_KEYMAP_RESULTS` (env-var IPC keeps it
robust to `--clean -u` argument parsing). Exit code mirrors the
harness: 0 on green, 1 on any FAIL. Local run yields:

  SUMMARY: 19 passed, 0 failed

CI: new `keymaps` job in `.gitea/workflows/ci.yaml` installs Neovim
and runs the script, so a regression in `lua/nuwiki/keymaps.lua`,
`autoload/nuwiki/commands.vim`, or the LSP command surface is caught
on every push.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-12 12:17:11 +00:00
gffranco 02291c2744 phase 10: release pipeline (Gitea release on v* tag)
CI / cargo fmt --check (push) Successful in 33s
CI / cargo clippy (push) Successful in 1m5s
CI / cargo test (push) Successful in 1m13s
P9 resolved (SPEC §11): stay manual. CI builds the four Linux targets
via cross; macOS + Windows binaries are produced ad hoc by maintainers
and uploaded to the same Gitea release.

§8.2/§8.4 updated: crates.io publish is deferred for now (workflow
ships the Gitea release only; can be re-enabled with a one-line
`cargo publish -p nuwiki-core` job once we're ready to publish). The
CARGO_REGISTRY_TOKEN row in §8.4 is struck through accordingly.

release.yaml:

- Trigger: `push` on tags matching `v*`.
- build matrix (4 jobs): x86_64/aarch64 × gnu/musl. Each pins
  Rust 1.83, caches `~/.cargo/{bin,registry,git}` + `target` keyed
  on target + Cargo.lock hash, installs `cross 0.2.5` if not in
  cache, runs `cross build --release -p nuwiki-ls`, packages as
  `nuwiki-ls-{version}-{target}.tar.gz`, uploads as an artifact.
- release job: `needs: build`. Downloads all build artifacts via
  download-artifact@v4 with `merge-multiple: true`; installs jq +
  curl if missing; POSTs a release-create payload to
  `/api/v1/repos/$REPO/releases` using `RELEASE_TOKEN`, then streams
  each `.tar.gz` to `/releases/{id}/assets?name=…`. Up-front check
  fails fast if the secret is unset.

README + SPEC top-line status: "All phases (0–10) complete." 172
tests still green locally.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-11 00:47:40 +00:00
gffranco cf336ee839 phase 0: scaffold workspace, plugin layout, and CI
CI / cargo fmt --check (push) Successful in 46s
CI / cargo clippy (push) Successful in 1m33s
CI / cargo test (push) Successful in 53s
Lay down the empty repo skeleton defined in SPEC.md §5 so subsequent
phases have somewhere to land:

- Cargo workspace (resolver v2, edition 2021, MSRV 1.83) with
  nuwiki-core, nuwiki-lsp, nuwiki-ls — dep direction matches §6.2.
- Vim/Neovim plugin directory layout (plugin, lua, autoload, ftdetect,
  ftplugin, syntax, doc, scripts) with header-only stubs.
- .gitea/workflows/ci.yaml running fmt, clippy -D warnings, and tests
  pinned to Rust 1.83.
- README, dual MIT/Apache-2.0 license texts, .gitignore.

Verified: cargo check / fmt --check / clippy / test all clean.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-10 16:01:58 +00:00