Repository navigation
Ship rotula.exe in the installer, the MSI and the portable zip - #14
Open
glenntosco wants to merge 57 commits into
Open
glenntosco wants to merge 57 commits into
glenntosco wants to merge 57 commits into
Conversation
Microsoft.Data.SqlClient 7.1.1 brings Pkcs 9.0.18 and Oracle.ManagedDataAccess.Core brings 8.0.1. Both now have published advisories (GHSA-846f-f764-76mx high, GHSA-2fmv-rv2c-59x7 moderate), which NuGet audit turns into restore errors under TreatWarningsAsErrors. That is what has broken the weekly Database integration workflow since 2026-10-19, and the main Build would fail the same way. Pin the patched MIT package in Rotula.Data (flows to Rotula.Mcp) and in the Oracle pack, and update the third-party notices. Claude-Session: https://claude.ai/code/session_01M3Pqt8Ubw3fJwBV3ztYKQV
fix(deps): pin patched System.Security.Cryptography.Pkcs 10.0.13
…I runner postgres.exe exits at once when the account has administrative rights, which is the case on the GitHub Windows runner, so Start-TestServers failed with "The server stopped right after starting". pg_ctl starts the server with those rights removed. Start/timeout errors now also print the last lines of the server log, since Stop-TestServers deletes it in CI. Claude-Session: https://claude.ai/code/session_01M3Pqt8Ubw3fJwBV3ztYKQV
The gate reads the first coverage.cobertura.xml under coverage/raw, and the folders are random GUIDs. Rotula.Data.Packs.Tests also produced a report, with Rotula.Core almost uncovered, so the gate failed whenever that one sorted first (0.54% on PR #4). Drop its coverlet.collector, the same as Rotula.Data.Integration already does. Claude-Session: https://claude.ai/code/session_01M3Pqt8Ubw3fJwBV3ztYKQV
fix(integration): start PostgreSQL through pg_ctl so it runs on the CI runner
…a job Adds a UI-free decoder for the three ~HS host status strings, a status reader for TCP and (best effort) the Windows spooler, and an opt-in check in PrintService: a blocking fault (head open, paper out, ribbon out, head too hot, diagnostics mode, buffer full, paused) stops the job before any byte is sent, an unknown status never blocks, and a verification after the job reports finished, fault after job or could not verify as a notice.
…ter settings Adds a per-transport switch (on for network printers, off for Windows printers), a Check printer status button that shows the decoded ~HS reply, plain-language messages for a held-back job and for the verification after it, and a single verification after the last job of a batch print. All new texts are in English and Spanish.
Reads the ~HS status of an allowed Windows printer and returns what stops it from printing in plain words. It sends a command to the printer, so it needs the printing permission (allowPrinting and allowedPrinters), but no confirmation token because nothing is printed.
…achable Windows retries a refused TCP connection for about two seconds, so a closed port often ends in the timeout instead of a SocketException. Report that as Unreachable, not NoReply.
Three 5 ms polls took longer than the 300 ms verification limit on a busy CI runner. These tests count polls, so they now use a 30 s limit; the scripted reader still ends them after the expected reply.
…cing Add StationConfigLoader (station.json next to the labels, a folder, a single label or the ProgramData policy file), validated with StationConfig.* message keys; StationPin (PBKDF2-SHA256 hash and constant-time verify); and the UI-free ScanSequencer that turns Enter, Tab and Shift+Tab into field moves, print and label selection.
A locked, print-only station window with label tiles and search, large prompt fields with scanner input, quantity limits, live preview and a big plain-words printer status. Printing goes through IPrintService with the status check on, then the prompts reset keeping the configured values. Exit is PIN-gated with a lockout. Entry points: --station, --station-pin and two File menu items. Strings in en and es.
Add docs/print-station.md (entry points, station.json schema, problem keys, status meanings, PIN), a decisions entry, the README feature rows and sections in English and Spanish, and the changelog entry.
Rotula.Files.Policy reads SOFTWARE\Policies\P4Software\Rotula from HKLM and HKCU (the computer wins, value by value) behind IPolicySource. Policies fix the language and the update check, suggest a default printer, keep user-folder add-ons from loading, and switch MCP printing or database access off. The MCP server applies them on top of its settings file and can only be restricted, never widened. ADMX with en-US and es-ES ADML ship in packaging/policies; tests check the template value names against PolicyNames.
Settings fixed by a policy are disabled with a "Managed by your organization" note. Help > Check for updates once a day is off by default; when the user or a policy switches it on, Rotula sends at most one anonymous GET of the GitHub latest-release API a day and shows a non-modal notice linking to the release page. Nothing is downloaded or installed. Version compare, schedule, parsing and the checker are UI-free with tests; HTTP is behind IReleaseFeed.
A WiX Toolset v5 project (packaging/msi, build tool only, not in Rotula.sln) installs Rotula per machine to Program Files with a Start menu shortcut, the .rotula association, ARP metadata and a fixed UpgradeCode with MajorUpgrade. build-installer.ps1 builds it from the signed stage folder, signs and verifies it like the setup exe, and publishes it. The Inno installer now accepts /ALLUSERS and /CURRENTUSER on the command line.
The installer manifest offers the per-user Inno installer and the machine-scope MSI (ProductCode read from the signed MSI, fixed UpgradeCode). Adds a Spanish locale manifest.
New docs/deployment.md covers silent installs, the MSI, exit codes, Intune, Group Policy, Configuration Manager and the policy settings. CONTRIBUTING and decisions now state the update-check rule precisely: no network traffic unless the user or an administrator enables it, and nothing is sent about the user.
…I runner postgres.exe exits at once when the account has administrative rights, which is the case on the GitHub Windows runner, so Start-TestServers failed with "The server stopped right after starting". pg_ctl starts the server with those rights removed. Start/timeout errors now also print the last lines of the server log, since Stop-TestServers deletes it in CI. Claude-Session: https://claude.ai/code/session_01M3Pqt8Ubw3fJwBV3ztYKQV
The gate reads the first coverage.cobertura.xml under coverage/raw, and the folders are random GUIDs. Rotula.Data.Packs.Tests also produced a report, with Rotula.Core almost uncovered, so the gate failed whenever that one sorted first (0.54% on PR #4). Drop its coverlet.collector, the same as Rotula.Data.Integration already does. Claude-Session: https://claude.ai/code/session_01M3Pqt8Ubw3fJwBV3ztYKQV
Every key of Strings.en.resx, with the same placeholders, access keys and technical tokens (ZPL commands, GS1 AIs, extensions, product name).
Every key of Strings.en.resx, following OQLF usage: courriel, and a non-breaking space before : ; ! ? and inside guillemets. Placeholders, access keys and technical tokens are kept as in English.
Loc.SupportedLanguages now lists en, es, pt-BR and fr-CA by full culture name, and LanguageCode returns that name. On first run any Portuguese desktop gets pt-BR, any French one fr-CA, Spanish es and the rest English; saved en/es settings keep their meaning. View > Language lists each language in its own name. The parity tests now check every Strings.*.resx against English (keys, placeholders, access keys, no empty value, French typography), and the key-coverage tests run over Loc.SupportedLanguages instead of en/es.
README (en/es), CONTRIBUTING, the PR checklist, the changelog and the design decisions now say every new string needs en, es, pt-BR and fr-CA. The installer offers Brazilian Portuguese and French.
pt-BR and fr-CA for the 137 keys the printer status check, the print station and the managed settings / update check added.
The Language policy reads every shipped language case-insensitively and hands on the canonical culture name; the ADMX enum, both ADML files and docs/deployment.md list all four. The managed lock covers the new menu entries, and the tests of the earlier branches that looped over en/es now use Loc.SupportedLanguages.
…utral status test Archivo and Ayuda both took Alt+A, so Alt+A never reached Help. Help is now Ay_uda (Alt+U). The printer-status text test now accepts the French « » quotes.
A UI-free model of label sheets for office printers (paper, margins, label size, grid, pitch), validation with message keys, a small set of generic Letter and A4 templates described by their dimensions, and the imposition that fills sheets in order with a start position.
MergeBatch labels and LabelPrintRun now expose the resolved values of every label (same record iteration and serial numbers as the ZPL), and the renderer can draw a label from those values without resolving counters again. SheetExporter places the labels on sheets at their physical size and writes one PDF page per sheet, with optional crop marks or outlines.
An optional root "sheet" object; older builds ignore it, so it does not raise the format version. A section that makes no sense is dropped.
File > Export > Label sheets (PDF) and a button in the Print dialog open a dialog to pick a generic sheet template or type a custom layout, see the positions, start at a later position on a partly used sheet and save the labels (or the ticked records) as a PDF at the sheet's real size. Serial numbers are reserved and confirmed as for printing; the chosen layout is saved with the label. English and Spanish texts.
The Preview window opens on "As printed" for a label set to ^POI or ^PMY, explains why the picture is turned and offers an "As designed" switch. The renderer flips the whole label inside LabelRenderer.Draw; only LabelDocumentAdapter.AsPrinted sets it, so the canvas and PNG/JPEG/PDF exports stay as designed. The status bar names a label that prints upside down or mirrored. Adds renderer pixel tests, importer round-trip tests, a golden file and view-model tests; marks ^PO and ^PM as previewed in the command catalogue.
pt-BR and fr-CA for the 14 keys of the As printed / As designed preview and the status bar note.
pt-BR and fr-CA for the 66 keys of the Label sheets dialog, its enums and its layout checks.
The main window applies the saved language when it opens, which put the test back in English before the sheet dialog built its template names.
feat(printing): check printer status (~HS) before and after printing
…int-station feat: operator print station (locked print-only mode with scanner input)
…ployment feat: enterprise deployment (machine-wide MSI, policies, opt-in update check, winget)
…calization feat(l10n): add Portuguese (Brazil) and French (Canada)
…int-orientation feat(preview): show print orientation (^PO) and mirror (^PM) as printed
…heet-layouts feat: label sheet layouts for office printers (multi-up PDF export)
…strings The English and Spanish connection-refused, port-validation and start-page subtitle strings named one printer brand. They now say "most label printers" and "ZPL-compatible printer", matching the pt-BR and fr-CA wording.
rotula.exe prints .rotula labels without the designer, for scripts and warehouse systems, through the app's own print path (DPI conversion, darkness/speed, variables, questions, data merge, serial numbers used once). - rotula print / status / printers with JSON output and exit codes - rotula serve: REST API (/api/v1/jobs, printer status and lists, OpenAPI), API keys stored as SHA-256 hashes, label-folder and printer allow-lists, size limits, strict settings and request bodies, Windows service hosting - ~HS status check before every job and verification after the last; one job at a time per printer - PrintEngine policy (ADMX/ADML) to switch it off - 52 new strings in en, es, pt-BR and fr-CA - docs/print-engine.md, README, CHANGELOG, notices, deployment, decisions
The request path, reference and printer name are written to the audit log; control characters (CR, LF and others) now become spaces and long values are cut, so a caller cannot start a fake log entry.
The tests now also reference rotula.exe, which runs on ASP.NET Core, so the build leaves the Microsoft.Extensions.* files that framework provides out of the test folder. Rotula.Mcp.exe runs on plain .NET and could not start from there; the tests now use src/Rotula.Mcp/bin first.
fix(l10n): drop the printer vendor name from UI strings
…-4ng9io-print-engine
…rint-engine Add the headless print engine: rotula CLI and REST API
The release build now publishes the print engine next to the app and the MCP server, signs it and verifies its signature, and the setup program, the MSI and the portable zip install it beside Rotula.App.exe with docs/print-engine.md. The CI release workflow publishes it too and checks that it starts. Docs say where it is installed.
Collaborator
Author
|
Build, test and coverage failed in one test that this PR doesn't touch: Why it failed: the test checks that the saved file does not contain What I did: I re-ran the failed job once. Proposed fix, in a separate PR: assert on Generated by Claude Code |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Requested by Glenn · project thread
What changed and why
This follows #13, which added the print engine (
rotula.exe) but did not ship it.Local release build (
packaging/installer/build-installer.ps1):src/Rotula.Clithe same way as the app and the MCP server (self-contained single file, no symbols).rotula.exeanddocs/print-engine.md.rotula.exeand checks its signature together with the other files.Installers:
Rotula.issandPackage.wxsinstallrotula.exebesideRotula.App.exe, withdocs\print-engine.md.rotula.exebecause it is built from the same stage folder.CI release workflow (
release.yml): publishes the engine, puts it in the unsigned CI zip, and smoke-tests thatrotula.exe versionexits 0.Docs: README,
print-engine.md(where it is installed, and a note on running it as a service),deployment.md,releasing.mdand CHANGELOG.rotula.exeis about 58 MB self-contained, because it includes ASP.NET Core and SkiaSharp.How it was tested
dotnet publish src/Rotula.Cli -r win-x64 --self-contained -p:PublishSingleFile=true ...produces a singlerotula.exe.scripts/check-hygiene.shpasses.rotula.exeis signed;Checklist
Generated by Claude Code