Skip to content

Releases: wekan/wena

v0.09

Choose a tag to compare

@github-actions github-actions released this 04 Oct 15:20
AROS x86 32-bit (ABIv0) and ARM 64-bit builds: wena-aros-i386 and wena-aros-arm64
  • AROS runs on more CPUs than x86-64, and Wena is now built for every one
    that has a published cross-compiler and SDK:
    • wena-aros-i386: the 32-bit ABIv0 line of deadwood2/AROS that AROS
      One and the other i386 distributions run. It was in the catalog as
      planned.
    • wena-aros-arm64: AROS's AArch64 port (raspi-aarch64, Raspberry Pi
      3/4/5).
  • Both build in BlitterStudio's AROS cross-compiler images
    (midwan/aros-compiler:i386-aros and :aarch64-aros), pinned by digest,
    with the same SDL2 2.32.10 and AROS port as wena-aros-amd64. They are
    two more Amiga jobs in the release workflow, and the release check takes
    each file only as a relocatable ELF of its own CPU.
  • AROS on m68k runs wena-amigaos-m68k. AROS's 32-bit ARM (raspi-armhf)
    and PowerPC (sam440, Efika) ports have no published cross-compiler or SDK,
    so they are noted in config/targets.tsv rather than built.
  • Those images carry a compiler and an SDK and little else, so what needed
    Python or patch in the container now happens on the host first
    (scripts/prepare_amiga_sources.py). It extracts SQLite for every Amiga
    target, and applies AROS's SDL2 port with Wena's edits (no OpenGL, SDL's
    own iconv, wcslen and wcscmp) for every AROS CPU. It stops when the port
    no longer has the lines it drops.
  • Tests: prepare-amiga-sources checks the prepared tree, a missing archive
    and a changed port refused, and that the AROS container path needs no
    Python, patch or sed. amiga-desktop, target-catalog and
    build-entrypoints check the two images, the catalog, and a refused ELF
    of the wrong CPU.

Thanks to xet7.

AmigaOS 3 with RTG draws Wena inside its window, and the mouse points where it is drawn
  • wena7 screenshot (FS-UAE, AmigaOS 3, 68040, RTG): Wena ran and showed
    All Boards, but the frame was drawn at the Workbench screen's top-left
    corner, over everything, and only a stray piece of it was in the "WeKan
    Native" window.
  • The cause is in the pinned AmigaOS 3 SDL fork. The window is a
    GimmeZeroZero one on the Workbench screen, and its RastPort's BitMap is
    the screen's. The fork wrote that bitmap directly, or scaled into it, at
    (0, 0). Every update took the scaling path, because the window's outer
    Width, borders included, is always wider than the frame.
  • scripts/patches/sdl2-amigaos3-window.patch, applied for both
    wena-amigaos-m68k and wena-amigaos-m68k-aga: a window on the
    Workbench screen gets its frame through WritePixelArray into its own
    RastPort, where the layers place and clip it, within the inner
    GZZWidth/GZZHeight. The direct video memory path stays for a window on
    its own screen.
  • The mouse is from the window's GZZMouseX/GZZMouseY. An IntuiMessage's
    MouseX/Y count from the outer corner even in a GimmeZeroZero window, so
    clicks were off by the border sizes.
  • A kept SDL build is reused only when it was made with the current
    patches.
  • Checked for the same fault elsewhere: AROS's SDL port already draws
    through the window's RastPort at its border offset, and AmigaOS 4 uses
    the system's own SDL2, so neither needs it.
  • Tests: amiga-desktop checks that the window patch applies to the
    pinned fork, alone and with the AGA patch. Its windowed path writes only
    through the window's RastPort, clipped to the inner area, and never locks,
    scales or reads the outer size. The mouse is the inner one, and both
    builds apply the patch before CMake.

Thanks to xet7.

WeKan's Admin Panel: People with Edit User, Login, Announcement and Version
  • The member menu's Admin Panel (for an admin) opens WeKan's Admin Panel:
    its header's tabs (Settings, People, Attachments, Problems) and each tab's
    left menu, in WeKan's order. Wena's panes work; the rest are there,
    disabled. The house goes back to the board.
  • People / People: WeKan's table of every user, by username: Edit,
    Username, Email, Admin, Active Person and Created at (WeKan's 'LLL'
    date). A disabled account is struck through, as WeKan's <s>. The Active
    icon (a check or a ban) toggles loginDisabled. Edit User edits
    Username, Full Name, Initials, Admin, Email and Active, with WeKan's taken
    and invalid errors. The last admin who can log in cannot be demoted or
    deactivated (WeKan's "there must be at least one admin"), and an admin
    who removes their own rights is taken back to the board.
  • People / Login: WeKan's "Login: Allow" with Forgot password and
    Self-Registration, ticked when allowed and written at once to
    settings.disableForgotPassword and disableRegistration. Wena never
    makes WeKan's settings document: until WeKan has run on the files, the
    checkboxes cannot be changed and the pane says so.
  • Settings / Announcement: WeKan's Active System-Wide Announcement and
    its message, saved to WeKan's announcement. It is made as WeKan's
    bootstrap makes it when there is none. Its version - WeKan's
    announcementVersion, a djb2 over the id, title and body in UTF-16
    units - and the user's profile.dismissedAnnouncementVersion are read
    and written, matching WeKan's own values.
  • The board shows WeKan's announcement bar under the header (#f8ecbd,
    the message centred, a close cross) while the announcement is on and the
    user has not dismissed this text. Closing it writes
    profile.dismissedAnnouncementVersion, as WeKan's dismissAnnouncement
    does, so a dismissal holds in both, and an edited announcement shows
    again.
  • Settings / Version: what Wena runs on: the database file, SQLite, SDL,
    the platform, and the counts of people and boards.
  • --show admin-version, admin-announcement, admin-people and
    admin-login capture the panes.
  • Tests:
    • admin-panel: the tabs and panes, Wena's four enabled, the house,
      People's Active and Edit, Edit User's Save and close, Announcement's
      Save, Login's checkbox writing the flag the other way and doing nothing
      without WeKan's settings, a disabled pane falling back, and the date.
    • wekan-sync: People by username; the last-admin guard, with a
      disabled admin not counting; Announcement made, then changed;
      announcementVersion matching Node's for three texts, one with Finnish
      letters, an emoji and a dash; the dismissal round trip; Login refused
      without WeKan's settings and keeping its other fields.
    • amiga-aga now checks that every page that presents a frame also
      gives it to the AGA screen.

Thanks to xet7.

WeKan's member menu, with Edit Profile and Change Settings that save to the user's WeKan profile
  • The menu under the user's name is WeKan's memberMenuPopup now, in its
    order and with its icons. It has two columns when one would run past the
    window. All Boards, Admin Panel (for an admin only), Edit Profile, Change
    Settings and Change Language work. The rest are there as WeKan has them,
    disabled until Wena does them.
  • Edit Profile (editProfilePopup) edits Full Name, Username, Initials and
    Email, into profile.fullname, username, profile.initials and the
    first emails[].address, which is made {address, verified: false} when
    the user has none. It shows WeKan's errors when another user has the
    username or the email (in any case), when the username is empty or has a
    space, and when the email has no @. The name in the header changes on save.
  • Change Settings (changeSettingsPopup) has WeKan's toggles: Show desktop
    drag handles, Submit editors with Enter, Open many cards at once and the
    checklist sound. Each is written at once to its profile field, and drag
    handles apply to the board straight away. "Show cards count if list
    contains more than" (profile.showCardsCountAt, -1 and up) and the rescue
    dialogue setting are written on Save.
  • New icons, drawn as WeKan's Font Awesome ones: key, flag, sign-out, font,
    picture and paperclip. A text key that only Wena's named texts had now
    also falls back to its English there.
  • --show member-menu, --show edit-profile and --show change-settings
    capture them.
  • Tests: member-settings checks the menu's order, Admin Panel shown only
    to an admin, the enabled entries, the forms' fields in and out, Save,
    close and the card count's bounds. wekan-sync checks the profile round
    trip, the email array with FerretDB's types, taken and invalid usernames
    and emails changing nothing, and the settings fields, refusing a field
    name that is not plain letters.

Thanks to xet7.

WeKan's mobile/desktop toggle and Show desktop drag handles work on the board
  • The mobile/desktop toggle in the header works now. In mobile mode, as
    WeKan's body.mobile-mode, every list takes the board's whole width and
    the lists stack one under another, each as high as its cards (a collapsed
    one is WeKan's 60 pixel bar), and the page scrolls. The icon is WeKan's
    fa-desktop or fa-mobile, and the choice is the user's
    profile.mobileMode, as Users.setMobileMode writes it.
  • Show desktop drag handles now draws WeKan's arrows icon on every
    minicard (20 pixels at its right, 28 down; a 44 pixel strip in mobile
    mode), every list header and every swimlane bar, and only those icons drag.
    A click elsewhere on a card still opens it, and a click on a list's or
    swimlane's title still renames it. Before, the toggle swapped the card
    drag for an older labelled handle row.
  • --show mobile and --show drag-handles capture either state.
  • Tests: nuklear-board renders with the real Nuklear. In mobile mode the
    lists stack at the same left edge and the heights add up. Without
    handles the whole card, header and bar drag; with them only the 20, 22
    and 26 pixel icons (44 in mobile mode), a card body click opens the card,
    ...
Read more

v0.08

Choose a tag to compare

@github-actions github-actions released this 04 Oct 14:15
The amigaos4-ppc and haiku-amd64 release builds compile and link again
  • v0.07 was published without these two files.
  • amigaos4-ppc: the PowerPC GCC stopped on -Werror=maybe-uninitialized
    in the JPEG decoder: it could not see that the component values are set
    for each of the image's 1 or 3 components before they are read. They
    start at zero now. Every source was rechecked with GCC at -O1, -O2, -O3,
    -Os and -Og.
  • haiku-amd64: the link stopped on std::__throw_length_error. SDL's
    Haiku video is C++ (BWindow, std::vector), and gcc links C only. The
    Haiku release now links -lstdc++ after SDL's static archive.
    libstdc++ ships with Haiku, as its own libbe does.
  • Tests: release-link-flags checks that Haiku links the C++ runtime after
    SDL and that no other system does.

Thanks to xet7.

Each release file is attached as soon as its own build passes, and Release all missing adds what a release lacks
  • release-all.yml attached nothing until every build had finished, so one
    slow or failed job held back all the others' files. Now each build job
    attaches its own file the moment it has been built and checked
    (scripts/attach_release_files.sh, three tries, replacing a file of the
    same name). Windows files are attached after their smoke test on Windows.
    The last job no longer uploads binaries: it downloads what the release has,
    writes SHA256SUMS over all of it, and names anything still missing.
  • A cancelled run used to attach nothing. Now each attach step runs even
    after a cancel, whenever its own build step succeeded, and the
    SHA256SUMS job runs after a cancel too (always()). So every file that
    finished building is on the release, with its checksum.
  • release-all.yml builds only the given targets when asked, and can be
    called by another workflow.
  • The new release-all-missing.yml ("Release all missing") compares the
    newest release's files (or a named release's) with the ready targets
    (package_desktop_release.py missing-from). It runs release-all.yml for
    just the missing ones, from the current branch, so a build fixed after the
    release is built with its fix. It never makes a new version, and starts
    nothing when nothing is missing. Menu option 3's "Build missing files for
    the newest release" now starts it.
  • Tests: release-workflow checks that every step is limited to the asked-for
    targets, that each job's last step attaches its file even after a cancel,
    that no job or step is skipped by a cancel, the Windows order,
    the checksums job and the missing workflow; attach-release-files checks
    the script with a fake gh; build-entrypoints checks the menu's
    workflow. Both workflows pass actionlint.

Thanks to xet7.

v0.07

Choose a tag to compare

@github-actions github-actions released this 04 Oct 12:42
AmigaOS 3 opens WeKan's files: SQLite no longer seeks past the end of a file
  • wena6 log: both AmigaOS 3 builds (RTG and AGA) stopped on WeKan's
    database with no reason given. Running the released
    wena-amigaos-m68k under vamos (amitools' AmigaOS emulator) traced
    it. SQLite's first look at the header of the new, empty
    wekan.sqlite seeked to offset 24. AmigaDOS cannot Seek() past the
    end of a file, and libnix's lseek() makes up for it by writing the
    gap from memory it never cleared. The file became 24 stray bytes
    ("ar(0)) = 0 AND card_id N"), and ATTACH failed with "file is not a
    database", on that start and every start after it.
  • The Amiga builds' SQLite (-DUSE_PREAD, with pread and pwrite
    from server/sqlite_amiga_vfs.c, declared by
    server/sqlite_amiga_io.h) now reads and writes at an offset without
    seeking past the end. A read there is the end of the file; a write
    there pads with zeros first. This covers AmigaOS 3, AmigaOS 4 and
    AROS alike.
  • A wekan.sqlite already spoiled this way (not empty, under 512
    bytes, without SQLite's header) is renamed to
    wekan.sqlite.not-a-database, never removed, and a new database is
    made.
  • So that the next failure says why, a failed open now names its step
    and SQLite's reason:
    • each step of opening WeKan's files is logged on its own;
    • wena_sqlite_open and the attach record why they failed;
    • SQLite's own error log (the OS call, errno and file of a failed
      open, the SQL of a failed statement) goes to the debug log.
  • Tests:
    • amiga-desktop builds SQLite with the Amiga options over an lseek()
      that behaves like libnix's. A fresh attached file is a sound
      database. The same build without the new options fails "file is
      not a database", as on the Amiga.
    • wekan-files: the spoiled file is set aside twice under two names;
      a real header, an empty file, a large file and a missing one stay.

Thanks to xet7.

v0.06

Choose a tag to compare

@github-actions github-actions released this 04 Oct 04:45
Debugging a start that fails, as on AmigaOS 3.2: wena-debug-log.txt beside the program, and the last steps on screen
  • On AmigaOS 3.2 Wena said only "Unable to open the local Wena desktop":
    outside a checkout without WENA_LOG_DIR there was no log, and every
    reason it had was dropped.
  • Each start now writes wena-debug-log.txt beside the executable
    (PROGDIR:wena-debug-log.txt on AmigaOS and AROS, which needs no program
    name - a Workbench start has none), holding the last run. WENA_LOG_DIR
    and a checkout's .tools/log/wena still come first.
  • The log's lines are also kept in memory, and a start that fails prints
    its last 16 where it was started - the Shell or Workbench output window -
    then the log file's name.
  • What is logged: the compiler, the SDL built with and run with; on
    AmigaOS 3 and AROS the Exec version, the stack, free memory (largest
    block, fast and chip) and, on AmigaOS 3, the CPU and FPU, with a warning
    when they are below the 68040 and FPU the build needs; each startup step;
    SDL's video driver, display mode and renderer; and when SDL cannot start
    video, open the window or make the renderer, SDL's reason and its video
    drivers. On AmigaOS 3 it adds that SDL there needs an RTG screen
    (Picasso96 or CyberGraphX), since it is built without AGA.
  • The log's formatter is Wena's own, bounded: C89 has no vsnprintf.
  • Tests: debug-log (the formatter, cut lines, the last 48 lines,
    wena-debug-log.txt beside the program on each system and PROGDIR: on the
    Amiga, the last run only, WENA_LOG_DIR first, no folder and an unwritable
    one), desktop (a start SDL refuses prints its steps, SDL's reason and
    drivers, with and without WENA_LOG_DIR; a start that works prints none).

Thanks to xet7.

A separate AmigaOS 3 AGA executable, wena-amigaos-m68k-aga, built by GitHub Actions
  • wena-amigaos-m68k needs an RTG card; this one is for AGA without one.
    It is built from the same sources with WENA_AMIGA_AGA, in the same
    pinned amigadev/crosstools image, as a new amiga job in the release
    workflow.
  • AGA has no 32-bit screen. SDL's AGA path opens an 8-bit screen of the
    window's size, so the window is 640x512 (PAL hi-res interlaced) and not
    resizable. Wena draws into its own 32-bit frame with SDL's software
    renderer and maps each frame onto 256 colors
    (client/platform/aga_palette.c): WeKan's UI, label and board colors
    first and exact, then a grey ramp for anti-aliased text and a 5x5x5 cube.
    A color is matched the first time it is seen and remembered, since
    matching all 32768 at the start would take seconds on a 68040. With an
    RTG card the frame is copied in full color.
  • It redraws only after input: after two quiet frames it waits for the
    next event, or a second, instead of drawing every 16 ms.
  • It starts with WeKan's « folded, as on a narrow screen, so the header
    fits in 640 pixels.
  • SDL gets scripts/patches/sdl2-amigaos3-aga.patch. The fork's Kalms
    chunky-to-planar writes plane n at Planes[0] + n x 40960, so it is used
    only when the screen's bitmap is laid out exactly that way; any other
    layout goes through graphics.library's WriteChunkyPixels instead of
    writing over memory that is not the screen's. Without vasm in the image
    the build still works, through WriteChunkyPixels alone.
  • --screenshot in this build saves what the AGA screen is given: the
    8-bit, palette-mapped frame.
  • Tests: aga-palette (WeKan's colors exact, every one of the 32768 colors
    near, the conversion with alpha and padded rows, no colors given, too
    many given) and amiga-aga (the patch applies once to the pinned fork
    and guards the c2p, the desktop's AGA branch, an 8-bit 640x512 screenshot
    from a host build, the catalog, the workflow, and a non-HUNK file
    refused).

Thanks to xet7.

v0.05

Choose a tag to compare

@github-actions github-actions released this 04 Oct 01:47
All of WeKan's 35 board views are in the Board View menu, and its 16 report charts are drawn
  • The Board View menu lists every view WeKan has, in WeKan's order with
    its six separators and each view's name and icon, in three columns so
    that it fits. The header names the view that is on. The view is kept as
    WeKan keeps it - its exact key in users.profile.boardView - so WeKan
    and Wena open a board in the same view; a key WeKan does not have opens
    as Swimlanes, as WeKan's own fallback does.
  • WeKan's 16 report charts are drawn from wekan.sqlite: Dashboard,
    Burndown, Burnup, Cumulative Flow, Control Chart, Cycle Time, Lead Time,
    Flow Efficiency, Throughput Histogram with its completion forecast, WIP
    Run, Pulse, Aging WIP, Blocker Analysis, Monte Carlo Forecasts, Process
    Behavior (XmR) and Work Item Size vs. Cycle Time. Each is WeKan's page:
    the title, the method note, the chart (two for Monte Carlo and Process
    Behavior), the data table and the details, in WeKan's colors.
  • The numbers are WeKan's: models/charts.c ports
    chartCalculations.js, flowAnalytics.js, chartExportRows.js and
    flowAnalyticsRows.js - completion at endAt else archivedAt, UTC days,
    Mongo's sort order and JavaScript's stable sort, the Monte Carlo
    bootstrap with WeKan's seed - reading cards, lists, activities and the
    card change history, removed cards' snapshots included, as
    boardChartData.js does (server/wekan_views.c).
  • The views' and charts' texts are WeKan's translations, looked up by key;
    the two forecast texts with __name__ placeholders are filled in.
  • The other views are listed and not yet drawn; they follow.
  • --show view:KEY with --screenshot renders a view.
  • Tests: charts (new) computes all 16 charts on three seeded boards both
    with WeKan's own JavaScript in Node and with Wena, and requires every
    table cell, detail row, note and bar to be the same; wekan-views (new)
    loads cards with every field, a removed card's snapshot, lists, users,
    activities and the history rows the charts replay, and not another
    board's; board-views (new) checks the 35 views, their order,
    separators and charts and draws a chart and an empty one; wekan-sync
    keeps any view key and refuses a malformed one; desktop opens three
    chart views on a WeKan file.

Thanks to xet7.

WeKan's other board views are drawn: Table, Calendars, Time, Timeline, Stats, Gantts, Scrum, Roadmap, Bigboard
  • Table: WeKan's columns - Edit, Card, List, Swimlane, Assignees, Members,
    Labels as chips, Received, Start, Due, End - with its search, sorting by
    any column both ways, 25 cards a page and grouping by swimlane; Edit or
    a title opens the card.
  • Calendar and the Calendar of every board: WeKan's month, week, day and
    list, Monday first, opening on the month at today, with Today, Previous
    and Next; a card spanning its start to its end and an hour at its
    received, due and end dates, the other boards' cards named with their
    board. A card clicked opens, on its own board.
  • Time (time spent, cards with time, overtime, the remaining time until
    due, hours by assignee and by card, the adjustments by author), Stats
    (the board's status) and Group by Assignee.
  • Timeline: the points in time of the board's activities, at most 50, and
    the lists with every card as it was then - title, description, labels,
    members, due date, archived - undoing what happened since.
  • Gantt (a table a week, a day a column, the received, start, due and end
    dates in WeKan's colors), Frappe Gantt and DHTMLX Gantt (bars from start
    to due, red when overdue, filled when done, by day, week or month, and
    DHTMLX's Task / Start / Duration grid) and Roadmap (the cards grouped by
    a text or dropdown custom field, each group's bars).
  • Product Backlog, Sprints (the sprints, a sprint's goal, state, cards and
    events, the releases), Sprint Report and Velocity, from WeKan's sprints,
    releases and events and their stored reports.
  • Bigboard: every board of the user stacked, each with its lists and cards.
  • What they read is WeKan's own: custom fields with dropdown items, card
    numbers, card.scrum, the board's Scrum settings and members, sprints,
    releases and events, and every board's lists (server/wekan_views.c).
  • The Map view is still listed and not drawn: it needs the uploaded image
    decoded, which follows.
  • Tests: view-rows (new) computes the Table's order for every sortable
    column both ways, grouped or not and with searches, the Calendar's
    events, the Time sums, the assignee groups, the Timeline's markers and
    its cards at three points in time, the Gantt tasks and the Scrum order
    and estimates on three seeded boards both with WeKan's own JavaScript in
    Node and with Wena, and requires them to be the same; board-views
    draws every one of these views and opens a card from the Table;
    desktop opens seven more views on a WeKan file.

Thanks to xet7.

WeKan's Map view is drawn, with Wena's own decoder for the map image
  • The Map view shows the board's uploaded map image with a marker for each
    card on it - its first label's color, its card number - and, beside it,
    WeKan's "Not on the map" list: choose a card, then click where it
    belongs. A marker opens its card. Remove the map image takes it off the
    board. Both write WeKan's own fields: the card's mapX and mapY
    (clamped to 0..100 and rounded, as Card.setMapPosition) and the board's
    mapImageAttachmentId.
  • The image is the attachment's recorded file, or the same name in this
    wekan-files/attachments when the bundle has moved.
  • Wena decodes it itself (models/image_decode.c, no new library): PNG in
    every color type and bit depth with transparency and Adam7, baseline and
    extended JPEG, and GIF's first frame with transparency and interlacing.
    WebP and progressive JPEG are refused, and the view then says which file
    could not be read.
  • With this, every one of WeKan's 35 board views is drawn.
  • Tests: image-decode (new) decodes 33 PNG, GIF and JPEG images with
    known pixels - exactly, JPEG within its loss - and refuses WebP, a
    progressive JPEG, a truncated PNG and unknown bytes; wekan-sync writes
    and clears a card's place and removes the image; wekan-views reads the
    image's file and the cards' places and numbers; board-views draws the
    Map without an image, with one - choosing a card to place, Remove - and
    with one that could not be read; desktop opens the Map.

Thanks to xet7.

The release builds compile again with GCC's format and truncation checks
  • wena5 log: every Linux build stopped in generate_wekan_defaults.py,
    which looked two folders up for a WeKan checkout that a CI checkout of
    Wena alone does not have (IndexError). It, and the new logo generator,
    take WEKAN_ROOT or fall back to Wena's own folder, and their --check
    passes when there is nothing to compare with.
  • The BSD, Haiku, Windows cross, AmigaOS and AROS builds stopped on
    -Werror=format-overflow: GCC could not prove the SQL built with
    sprintf fits. The statements are built in 4096-byte buffers (the
    notifications one in 4400, room for its two 2048-byte parts), a chart's
    day key spells out its ranges, and the notification text and the
    control names are copied with their lengths known.
  • AmigaOS m68k stopped on a label chip's y that GCC saw as maybe unset;
    it starts from the row.
  • strncpy into the view rows' fixed fields became a terminating copy,
    which GCC's -O3 truncation check accepts.
  • Checked with MinGW-w64 GCC 16 at -O2, -O3 and -Os over every source with
    the release flags: no warnings.

Thanks to xet7.

WeKan's header extras: its logo, the « that folds the icons, and Show desktop drag handles
  • WeKan's public/logo-header.png is drawn after the board title, from
    client/platform/logo_data.h, generated by
    scripts/generate_wekan_logo.py (whose --check runs with every desktop
    build) and decoded with Wena's own PNG decoder.
  • The « beside the house folds the header's icons as WeKan's does: the
    desktop icon, the drag handles toggle, the star group and the + go, and
    » brings them back.
  • "Show desktop drag handles" is the user's
    profile.showDesktopDragHandles, read when the board opens and written
    as a Boolean when toggled; with it on, a card moves by its handle only,
    and the check or the ban beside it says which.
  • Tests: board-feature (the «, the toggle in both states, the desktop
    icon doing nothing, the folded header), wekan-sync (the field off until
    set, written as FerretDB's bool, nobody and no user), image-decode (the
    embedded logo decodes at 97 x 28 with transparency).

Thanks to xet7.

v0.04

Choose a tag to compare

@github-actions github-actions released this 04 Oct 00:25
WeKan itself opens what Wena wrote: checked with WeKan's bundle on the same wekan-files
  • tools/wekan-ui/dropin.sh checks Wena as a drop-in with WeKan itself: a
    WeKan user is made through FerretDB on an empty wekan-files/db; Wena
    opens those files as that user, makes its board and adds a list, a card,
    a description and a checklist; then WeKan's own bundle serves the same
    files through FerretDB, and its page (Playwright, dropin.e2e.js) shows
    the board on All Boards, the list and card on it, and the card's details
    with the description and the ticked checklist item. It passes.
  • What it found: a board WeKan makes carries its schema's defaults
    (allowsDescriptionText, allowsChecklists and 99 more Booleans), and
    WeKan hides a part of the board whose field is missing. A board Wena makes
    now carries them all, generated from WeKan's models/boards.js into
    server/wekan_defaults_data.h by scripts/generate_wekan_defaults.py,
    whose --check runs with every desktop build (and passes without a WeKan
    checkout, when there is nothing to compare with).

Thanks to xet7.

The language and collapsed lists and swimlanes are the user's, where WeKan keeps them
  • With WeKan's files, the language comes from the user's
    profile.language and the language picker writes it there, through a
    store the picker can now be given instead of its settings file. A
    language WeKan names that Wena does not have resolves to one it has.
  • Collapsed lists and swimlanes and swimlane heights are the user's
    profile.collapsedLists, profile.collapsedSwimlanes and
    profile.swimlaneHeights ({board: {id: value}}): read when a board
    opens and written when they change, the other boards' entries kept.
  • So nothing of Wena's goes into WeKan's db folder: it holds
    wekan.sqlite (and SQLite's -wal and -shm) only, which desktop checks.
  • Tests: language-picker (the store, a refused store changing nothing, an
    unknown language), wekan-sync (profile.language, the per-board maps,
    another board's map kept, only WeKan's fields).

Thanks to xet7.

Wena opens on WeKan's All Boards page, and goes from board to board in one window
  • With WeKan's files, the first page is All Boards as WeKan draws it
    (client/components/boards/all_boards.c, measured from WeKan's own page,
    tests/fixtures/wekan-ui/00-all-boards.json): the header with the house
    and the user, the left menu of sections - Remaining, Starred, Home,
    Templates, Archive - with their counts, and the boards as tiles in their
    board color, "Add Board" first, each with its star.
  • The boards are the user's from WeKan's documents: their own and template
    containers, archived ones in Archive, starred ones from the user's
    profile.starredBoards - which the star writes, one level into the
    user's profile with FerretDB's types. "Add Board" makes a board as WeKan
    does, with its "Default" swimlane and the user its admin.
  • A tile opens its board; the house before the board's title goes back.
    Opening another board releases the board's state and starts its session
    again in the same window, with the same database.
  • --show all-boards and --show open:BOARD (a tile chosen) with
    --screenshot or --smoke.
  • Tests: all-boards (sections, counts, open, star, Add Board, the archived
    and Home negatives, colors), wekan-sync (the board list, stars, a new
    board) and desktop (the files layout, FerretDB's metadata, the first
    run's admin and board, reopening, a board switch, All Boards drawn).

Thanks to xet7.

Wena keeps WeKan's own files: wekan-files/db/wekan.sqlite as FerretDB writes it, a drop-in for WeKan's bundles
  • Opened without a workspace (double-clicked, or 2) Run), Wena uses WeKan's
    files directory: WRITABLE_PATH when set - with files added unless it
    already ends in files or wekan-files, as WeKan's start-wekan.sh and
    .bat do - else wekan-files beside the program, as WeKan's Windows
    executable has it. It makes attachments, avatars and db, and keeps
    the board in db/wekan.sqlite: the file WeKan's FerretDB bundles
    (AppImage, Snap, Docker, Windows) open as database wekan.
  • That file is FerretDB's SQLite format, written directly with SQL
    (server/ferretdb_sqlite.c): the _ferretdb_collections table, one
    <collection>_<FNV-1a> table per collection with its _id_ index, byte
    for byte as FerretDB makes them, and documents with their $s type
    schema. Wena reads it with double-quoted strings off, as release builds
    of SQLite are.
  • WeKan's documents are read into Wena's tables in memory
    (server/wekan_sync.c): users, boards with their members, labels and
    settings, swimlanes and lists with archive state, color and WIP limit,
    cards with description, labels, members, assignees and archive state,
    checklists and their items. After each frame that changed something,
    only the changed fields go back to WeKan's documents, each with its type,
    so the fields of a document Wena does not show stay as they were; new
    documents get the fields WeKan requires, and a title Wena had to shorten
    is not written back unless it was edited.
  • The user is WENA_USER (an _id or username), else the first admin; a
    new file gets a user "admin" and a board "My board" with WeKan's
    "Default" swimlane. WENA_DATABASE and --database still open a Wena
    workspace file.
  • Tests: wekan-files, ferretdb-sqlite (DDL text, $s on insert, update,
    unset, delete), wekan-sync (import, changed fields only, WeKan's fields
    kept, new documents, deletes, rollback, the user) and ferretdb-roundtrip,
    which runs the FerretDB binary WeKan bundles: FerretDB serves through the
    MongoDB driver what Wena wrote, and Wena reads, changes and adds to what
    FerretDB wrote. Not yet run against a WeKan server itself.

Thanks to xet7.

The release builds again: v0.03 stopped on every platform on a stale compiled-in license file
  • wena4 log: every job of the v0.03 release stopped before compiling with
    client/platform/notices_data.h is stale. The licenses compiled into the
    executable include config/release-dependencies.json, which the AROS
    rename (aros-x86 to aros-amd64) changed without regenerating them. The
    current header matches its sources again.
  • New suite generated-sources runs the checks every desktop build runs
    first (scripts/check_desktop_sources.sh: pinned dependencies, SVGs,
    migrations, translations, font and licenses), so a stale generated file
    fails the test run instead of the release. Its negative case changes the
    dependencies on a copy and requires the check to report the stale header.

Thanks to xet7.

Card details, Card Actions, the Add Card composer and the sidebar look and work like WeKan's
  • Card details are WeKan's panel instead of a column of buttons: a header
    with the caret that collapses it, the title (click it to edit, as in
    WeKan), Card Actions, Maximize and Close Card, then the Labels,
    Description and Checklists sections, each with WeKan's caret, icon and
    16px gray heading and each foldable. They show the card's label chips, its
    description and its checklists, whose items can be ticked there.
  • Card Actions (the hamburger on a minicard and in the details) is WeKan's
    popup with the items Wena carries out, in WeKan's order and groups: Move to
    Top, Move to Bottom, Move Card and Move Card to Archive. Move to Top and
    Bottom are new: one version-checked reorder within the card's list. As in
    WeKan, the minicard's hamburger no longer opens the details.
  • Add Card is WeKan's inline composer in the list: a white card with the
    text box, the blue Add and the close cross, above the cards for Add Card
    to Top of List and in place of "+ Add Card" for the bottom. Enter adds and
    the composer stays for the next card; a card added to the top is moved
    there, and a move that fails is reported.
  • The sidebar is WeKan's home view, 420px under the header: the close
    cross, Board Settings, then foldable Members (the board's members and its
    own user), Labels (WeKan's colored chips) and Activities, and the Archive.
  • Label chips on minicards and in the details are WeKan's: bold text on the
    label's color, 4px rounded, side by side. Checklists show their title in
    bold with a finished/total count, and items as WeKan's checkboxes.
  • --show card:ID, card-menu:ID, list-menu:ID, add-card:LIST or
    sidebar with --screenshot renders each state WeKan's capture has, for
    comparison.
  • Fixed on the way: Nuklear's nk_spacing on a one-column row starts a
    new row, which left an empty row after each read-only checklist item;
    raw colors in the look module were drawn black.
  • Tests: card-actions (suite) drives the popup's items against SQLite,
    with disabled items and unknown cards as negatives; move to top and bottom
    are in card-move-reorder-sqlite; the composer, details header and
    sections, sidebar folds and chips are in card-create, board-feature,
    card-description, nuklear-checklist-contents and nuklear-board.

Thanks to xet7.

A board from WeKan's file looks as WeKan draws it: list widths, checklists on minicards and the user's name
  • Lists are as wide as WeKan keeps them: each list's width (WeKan's
    DEFAULT_LIST_WIDTH is 220) is read in, and the minicards in it are 34
    narrower, as in WeKan. A list without a width of its own is 220 wide in
    WeKan mode, 272 otherwise; a width outside WeKan's 100..1000 is not used.
  • Checklists on minicards follow WeKan's board field
    allowsChecklistsOnMinicard (on unless the board turns it off), read in
    and written back under that name; Wena wrote a field WeKan does not have.
    A board made in Wena gets WeKa...
Read more

v0.03

Choose a tag to compare

@github-actions github-actions released this 03 Oct 21:06
The NetBSD, DragonFly BSD, Haiku and OpenBSD builds compile again; FreeBSD riscv64 waits for packages
  • wena3 log: NetBSD amd64 and arm64, DragonFly BSD and Haiku stopped on
    server/executable_path.c: their GCC rejects an if with more statements
    after it on a line of its own (-Werror=misleading-indentation), which
    clang - and so the header check of v0.02 - accepts. Those lines now hold one
    statement each. tests/test_bsd_sources.py also compiles every desktop
    source with GCC 13 on NetBSD's headers (the host's GCC, or the pinned
    gcc:13 image), reproduced the error at the same line before the fix, and
    rejects a probe of the pattern.
  • OpenBSD amd64 and arm64 stopped unpacking SDL2: OpenBSD's tar has no
    --strip-components. scripts/extract_archive.py unpacks the pinned
    archives without their top directory on every system, keeping modes and
    links and refusing entries or links that leave the destination
    (tests/test_extract_archive.py, suite extract-archive).
  • FreeBSD riscv64 is planned again: FreeBSD publishes no riscv64 packages for
    14 or 15, so its virtual machine has no Python, make or X11 to build with.
    Cross-compiling it from Linux is the way there.
  • Verified here: GCC 13 on NetBSD 10.1's headers reproduced the release
    run's error at executable_path.c:31 and passes after the fix; all desktop
    sources compile with clang for FreeBSD, OpenBSD and NetBSD and with GCC for
    NetBSD; the pinned SDL2 and llvm-mingw archives unpack and run. The BSD and
    Haiku builds themselves are verified by the next release run.

Thanks to xet7.

The AROS x86-64 release file is wena-aros-amd64, named for its CPU as every other file is
  • wena-aros-x86 was an x86-64 file (ELF 64-bit LSB relocatable, x86-64),
    while "x86" names 32-bit x86 everywhere else. The target is now
    aros-amd64, its file wena-aros-amd64, as wena-linux-amd64 and
    wena-windows-amd64.exe are.
  • The release check takes the CPU from the name: an aros-amd64 file must
    be a 64-bit x86-64 relocatable ELF and an aros-i386 one a 32-bit i386
    one, and an AROS name with any other CPU is refused. The target catalog
    allows no target ending in the ambiguous -x86.
  • config/targets.tsv lists AROS per CPU: aros-i386 for the 32-bit ABIv0
    line of deadwood2/AROS (planned until its build is in the release
    workflow), AROS on m68k running wena-amigaos-m68k, and AROS on ARM having
    no published toolchain or SDK to build with.

Thanks to xet7.

The desktop opens again after it was closed normally
  • Run, and a double-click on the desktop, said "Unable to open the local Wena
    desktop" for a board that was there. The startup check that an actor or
    board named by mistake writes nothing opened the file read-only, and a
    read-only handle cannot read a WAL database whose -wal file a clean exit
    removed ("unable to open database file"). So every launch after a normal
    quit failed, and only a launch after a crash worked.
  • The check now opens the existing file read-write without creating it, with
    PRAGMA query_only=ON: a missing file still fails, and nothing can be
    written. The debug log names which check failed and SQLite's reason.
  • tests/test_desktop.sh closes a WAL workspace cleanly (no -wal or -shm
    file) and opens it, and checks that an unknown actor there still changes
    nothing. With the read-only handle back, it fails as Run did.

Thanks to xet7.

The desktop board looks and works like WeKan's: its colors, fonts, header, lists, cards and menus
  • Measured from WeKan, not chosen by eye: tools/wekan-ui/capture.e2e.js
    runs in WeKan's Playwright suite against a running WeKan and records each
    state of a seeded board (the board, list and swimlane menus, Add Card, the
    sidebar, card details and its menu) with every visible control's text,
    tooltip, icon, place and colors. tools/wekan-ui/pin.py pins them in
    tests/fixtures/wekan-ui.
  • client/components/common/wekan_look.c holds WeKan's colors (the
    #2980b9 header, #dedede canvas, #e4e4e4 list headers, white
    minicards with #4d4d4d text, white popups with gray title bars, #f7f7f7
    panels, the red #ce1414 of a list over its WIP limit), its fonts (Roboto
    and Roboto Bold, now embedded with its provenance, at WeKan's 12 to 19 px)
    and its Font Awesome icons as vectors. The Nuklear theme uses the same
    palette.
  • The same controls in the same places, named as WeKan names them: the header
    with the board title, Filter, the user and the sidebar toggle; swimlane
    headers with their caret and Swimlane Actions; list headers with Collapse,
    Add Card to Top of List, Add List and List Actions, and a long title that
    wraps; minicards with their caret and Card Actions; "+ Add Card" under each
    list; collapsed lists as a narrow strip with the title stacked; WeKan's
    popup menus for lists, swimlanes and the user, the Filter panel and Change
    Language.
  • Dragging works as in WeKan: the whole minicard, list header or swimlane bar
    is the handle, and a press and release without moving is a click that opens
    the card or edits the title. The swimlane resize handle is WeKan's 10 px
    bar, shown when hovered.
  • Every control is recorded with its WeKan name and place each frame, which
    is what tests click. --screenshot FILE saves the last frame as a BMP, to
    set beside WeKan's captured screenshots.
    An icon's tooltip is drawn at window level: opened from inside a header
    row, it broke the frame, so nothing after the hovered icon was drawn.
  • tests/test_wekan_ui_parity.py (suite wekan-ui-parity) checks every
    Wena color against WeKan's capture, and the WIP color against WeKan's
    stylesheet when the WeKan checkout is next to Wena. The board, list, card,
    filter, theme, SVG, collapse and swimlane-resize suites now click WeKan's
    control names and check WeKan's colors, including the hovered tooltip, the
    sidebar opening below the header, and a missing selection marking nothing.

Thanks to xet7.

v0.02

Choose a tag to compare

@github-actions github-actions released this 03 Oct 18:58
The desktop for AmigaOS 3.x, AmigaOS 4 and AROS: wena-amigaos-m68k, wena-amigaos4-ppc, wena-aros-x86
  • scripts/build_desktop_amiga.sh TARGET OUTPUT compiles the desktop in the
    pinned amigadev/crosstools image of each into one static executable: the
    image's SDL2 2.30 on AmigaOS 4 (PowerPC ELF); SDL2 2.32.10 with AROS's own
    port (SDL2-2.32.10-aros.diff from aros-development-team/contrib, without
    OpenGL) on AROS x86-64 (relocatable ELF); and on AmigaOS 3.x the SDL2 fork
    DevilutionX ships for 68040 with FPU and an RTG card (HUNK). Images and
    sources are pinned by digest and SHA-256.
  • SQLite runs there without WAL, mmap or file locks, through an amiga VFS
    that keeps AmigaDOS names such as PROGDIR:x as they are. Wena's
    journal_mode=WAL then simply stays delete; other platforms keep WAL.
  • The platform code knows Volume: paths, keeps the board in
    PROGDIR:wena.sqlite (ENV: is a RAM disk), publishes a new workspace with
    dos.library Rename() (which never replaces), retries settings writes
    because AmigaDOS Rename() does not replace, keeps the collapse preferences
    file within the original FFS's 30 characters, asks locale.library for the
    language and runs on a 1 MB stack (AmigaOS 4 $STACK cookie, libnix
    __stack, AROS NewStackSwap).
  • Verified here: all three build, link statically and pass the format checks
    (scripts/check_release_executable.py now knows HUNK, static PowerPC ELF
    and AROS's relocatable ELF); the desktop with the exact Amiga SQLite options
    and VFS creates and reopens a board on Linux. Not run on an Amiga or an
    emulator yet. Tests: amiga-desktop, debug-log, build-entrypoints.

Thanks to xet7.

The desktop for Android and iOS: wena-android-arm64.apk and wena-ios-arm64.ipa
  • scripts/build_desktop_android.sh OUTPUT_APK builds libmain.so - the
    desktop with SDL2 2.32.10 and SQLite linked in - with SDL's own Java glue and
    a small fi.wekan.wena.WenaActivity, directly with the NDK, javac, d8,
    aapt2, zipalign and apksigner (no Gradle). Min SDK 21, target SDK 37,
    16 KB-page aligned. It is signed with the release key from the repository
    secrets, or a debug key with a warning.
  • scripts/build_desktop_ios.sh OUTPUT_IPA builds SDL2 for iOS with CMake and
    links Payload/Wena.app (iOS 15 or newer), unsigned: re-sign it with your
    own certificate, AltStore or Sideloadly. Apps built with the iOS 27 SDK must
    use scenes, which SDL 2 does not, so client/platform/ios/scene.m puts
    SDL's windows into the app's scene.
  • On a phone the board lives in the app's own data folder
    (SDL_GetPrefPath), the language comes from the system, the board is laid
    out in density-independent units and drawn at native pixels, touches land
    where they are drawn, the keyboard shows only while a field is edited, and a
    failure is shown in a message box. On Android a new workspace is published
    with rename() after checking nothing is there, because SELinux refuses
    link() in the app's folder.
  • Verified here: the APK passed the smoke test in the Android 17 (API 37)
    emulator, on a second run and after an update over itself, and a card was
    added by touch; the Simulator app passed on iOS 27.0 and 26.5. Real phones,
    Android 5-16 and Xcode 16 builds are verified by use and the release run.
    scripts/check_release_executable.py checks the APK's only library is
    arm64 libmain.so loading Android's own libraries, and the IPA's Wena
    loads only iOS's frameworks. Tests: mobile-desktop, debug-log,
    build-entrypoints.

Thanks to xet7.

Every release file is the desktop GUI, one self-contained wena-TARGET per platform, from one workflow
  • release-all.yml is the only release workflow. release-desktop.yml, the
    .github/release/*.sh scripts and client/main.c are gone: the program they
    released printed one line in a terminal. Every target in config/targets.tsv
    is now the native Nuklear desktop, named after its platform -
    wena-linux-amd64, wena-windows-amd64.exe, wena-freebsd-amd64 - and
    attached beside one SHA256SUMS, without a .sha256 per file or a separate
    notices archive.
  • 28 platforms: Linux amd64, arm64, armhf, armel, i686, riscv64, ppc64le,
    s390x and mips64le; FreeBSD amd64, arm64 and riscv64; NetBSD and OpenBSD
    amd64 and arm64; DragonFly BSD and Haiku amd64, built natively in virtual
    machines (cross-platform-actions v1.6.0, scripts/build_desktop_release_vm.sh);
    macOS arm64 and amd64; Windows amd64, i686 and arm64; and, below, AmigaOS
    3.x, AmigaOS 4, AROS, Android and iOS.
  • SDL2 and SQLite are linked into each one from the pinned sources, as before;
    the licenses of everything in it are now compiled in too
    (scripts/generate_notices.py), and wena --licenses prints them.
  • wena2 log: linux-armel and linux-mips64le stopped at once, because the
    debian:bookworm image no longer lists those CPUs. They build in Debian's
    per-architecture images, arm32v5/debian:bookworm and
    mips64le/debian:bookworm, with the same glibc 2.36. Under QEMU, loading
    Mesa's DRI driver crashes on MIPS64 (SIGBUS) before Wena draws anything,
    whichever Gallium driver is chosen, so that one X11 smoke test keeps Mesa's
    driver unloaded and uses SDL's software renderer. Every X11 smoke test now
    checks the application's own exit status rather than xvfb-run's.
  • Two compile errors that would have stopped the BSD builds, found by
    compiling every desktop source against FreeBSD 15.1, OpenBSD 7.9 and NetBSD
    10.1 headers (tests/test_bsd_sources.py, suite bsd-sources): an unused
    static helper in server/executable_path.c on FreeBSD, NetBSD and DragonFly
    (-Werror), and NetBSD's <sys/sysctl.h> needing _NETBSD_SOURCE.
  • ./build.sh build TARGET builds the same release file into release/ the
    way the workflow does: Linux targets in the workflow's own container image
    (scripts/toolchain.py and the workflow are checked to agree), Windows with
    MinGW-w64 (arm64 with the pinned llvm-mingw, now also on macOS), macOS with
    Xcode. A BSD or Haiku target builds on that system itself.
  • Verified here: macOS arm64 and amd64 built, ran headless twice and printed
    their licenses; Windows amd64, i686 and arm64 built and were checked
    self-contained; linux-arm64 and linux-armel built and passed the headless
    and X11 smoke tests in their containers, and linux-mips64le too, under QEMU. The BSD and Haiku virtual-machine builds, the Windows runs and
    the other Linux CPUs are verified by the next release run. Tests:
    release-workflow, target-catalog, toolchain, build-entrypoints,
    source-structure, bsd-sources, with negatives (the wena2 image, a target
    left out of the workflow, the two BSD errors, a stray release file).

Thanks to xet7.

The desktop compiles its migrations in and reads nothing from its own file
  • It assembled the migration bundle from a footer appended to its executable,
    found through the executable's path, and opened an appended translation
    catalog only to check that it was there. An app bundle, an APK, a signed
    iOS app and Amiga's PROGDIR: either cannot carry appended bytes or cannot
    find the file reliably, and OpenBSD has no /proc to find it with. The
    bundle now comes from the compiled registry, checked against its own
    SHA-256 (wena_sqlite_compiled_bundle); nothing is appended.
  • tests/test_compiled_bundle.sh (suite compiled-bundle) checks the bundle
    against config/migrations-lock.json, NULL arguments, and that neither the
    desktop nor its build reads or appends a footer. The runtime and
    embedded-migration suites test the server's footer reader with a fixture
    instead of the removed terminal program.

Thanks to xet7.

build.sh and build.bat install what a build needs on macOS, Windows, Ubuntu, Debian and Fedora
  • scripts/toolchain.py runs before every build and installs what is
    missing with the computer's own package manager: Homebrew on macOS, apt on
    Debian and Ubuntu, dnf on Fedora, Chocolatey or else winget on Windows.
    build.sh and build.bat install Python 3 first when it is missing.
  • Per target: gcc, Debian's cross-compilers with their C library, MinGW-w64,
    Docker (started when it is not running, with QEMU on arm64 Linux) for
    AmigaOS and AROS, and the Android NDK r29. The NDK is downloaded from Google
    and checked against the size and SHA-1 in Google's own repository manifest
    before it is unpacked into .tools. iOS uses an installed Xcode through
    DEVELOPER_DIR without changing which one is selected.
  • Where this computer has no compiler for a Linux target (Fedora, macOS,
    Windows), it is built in an Ubuntu 24.04 container with Ubuntu's compiler.
    The container's name is a hash of its package list, so a changed list
    builds a new one.
  • On Windows, Git for Windows provides sh and file, a native MinGW-w64 gcc
    builds the Windows target, MSYS2 provides SDL2, SQLite and gcc for the
    desktop, and a python3 shim lets the release scripts call Python.
    android-arm64.sh uses the NDK's prebuilt compiler for this computer
    instead of always Linux's.
  • build all builds every target this computer can build and lists the
    others with the reason, such as iOS without Xcode. install TARGET|all|desktop
    installs without building. WENA_NO_INSTALL=1 only checks.
  • windows-amd64.sh accepts both ways file words a PE executable: file 5.46
    (Fedora 42) puts "Windows" before "x86-64".
  • Verified on this Mac: all ten release targets and the desktop built after
    installing what was missing. On fresh Ubuntu 24.04, Debian 12 and Fedora 42
    containers, starting without Python, these all built: the host target,
    Windows amd64 and the desktop, plus armhf cross-built on Ubuntu and
    Debian. Windows was not run he...
Read more

v0.01

Choose a tag to compare

@github-actions github-actions released this 03 Oct 14:40
Security: no test runs SQL read from outside the program (18 GitHub CodeQL cpp/sql-injection alerts)
  • GitHub CodeQL code scanning reported alerts #2-#19, "Uncontrolled data in
    SQL query": tests read a schema file named on their command line and passed
    its text to sqlite3_exec. The same shape was in 62 tests. Their schema,
    fixture and migration SQL is now compiled in by
    scripts/embed_test_files.py and read through tests/support/test_files.h;
    a path argument only selects one of those files. Reads that only compare or
    hash database and backup files stay, each listed with its reason.
  • The application was already clear: every value is bound with
    sqlite3_bind_*, migrations are embedded and checked against their pinned
    SHA-256, and the five places that format SQL text use fixed table and column
    names or SQLite's %w identifier quoting.
  • tests/test_sql_sources.py (suite sql-sources) fails when a test that runs
    SQL reads a file at run time, when a script passes a .sql file without
    embedding it, or when the application builds SQL text anywhere new; the
    generator and lookup are tested, including an unknown name aborting the
    test. All converted suites pass on Linux; on macOS the same 11 suites fail
    as before, for Apple's SQLite.

Thanks to GitHub CodeQL.

One self-contained desktop executable per platform, numbered from Upcoming and released from the menu
  • Menu option 3) Release (build.sh release next) numbers the Upcoming section
    after the newest release, the way WeKan does (v0.01 ... v9.99, v10.00),
    commits Prepare vX release, pushes, and starts release-desktop.yml.
    build.sh release missing builds and attaches to the newest release. It
    refuses uncommitted changes. Tests, Server and Tools move to 4, 5 and 6.
  • release-desktop.yml publishes the release with that CHANGELOG section as
    its notes, starts release-all.yml, and builds 14 executables: Linux amd64
    and arm64 natively, armhf, armel, i686, riscv64, ppc64le, s390x and
    mips64le under QEMU; macOS arm64 and amd64; Windows amd64, i686 and arm64
    cross-compiled and smoke-tested on Windows runners. Each is attached with its
    .sha256, beside one notices archive of licenses and provenance.
  • SDL2 2.32.10 and SQLite 3.53.4 are built from checksum-pinned sources and
    linked in (scripts/build_desktop_release.sh), SDL with only video,
    rendering and events. A Linux executable needs only glibc and X11 or
    Wayland, macOS only its own frameworks, Windows only its system DLLs;
    scripts/check_release_executable.py reads each executable's own library
    list and refuses anything else.
  • The desktop runs on Windows: drive and UNC paths, wide-character file APIs,
    a workspace published with no-replace MoveFileExW, the board in
    %APPDATA%\Wena, and the debug log.
  • gcc 13 rejected 27 one-line if (...) a; b; statements under
    -Werror=misleading-indentation; each is one statement per line now.
  • Verified here: macOS arm64 and amd64 builds, Linux arm64 and amd64 built on
    Ubuntu 22.04 and smoke-tested under Xvfb (glibc 2.34), Windows amd64, i686
    and arm64 cross-built and checked. Tests: release flow with gh and git
    replaced, numbering and notes, the executable checker against ELF, PE and
    Mach-O with negatives, pinned downloads, packaging, and the workflow's
    platform list.

Thanks to xet7.

Drag the bar below a swimlane to change its height
  • Each expanded swimlane has a bar below it. Dragging it up or down resizes
    the lane live, with the up-down resize cursor; release keeps the height,
    Escape cancels. Heights are clamped to 160-2000 pixels, the default 360
    needs no entry, and the lists inside grow with the lane.
  • Heights are saved per actor and board with collapsed lanes and lists. The
    preferences file is version 2 exactly when it holds heights, so version 1
    files keep loading; heights of lanes the board no longer has are dropped.
  • Tests: a real Nuklear drag test (press, drag, release, Escape, both clamps,
    back to the default, a collapsed lane and a layout without the bar), and
    preference round trips with strict negatives for every malformed height
    line, a full file, and pruning.

Thanks to xet7.

Fix the desktop crash when the mouse reaches a list or swimlane drag handle
  • 42 sources included <nuklear.h> without the NK_INCLUDE_* options that
    sdl_nuklear.h set before compiling Nuklear itself. Those options add fields
    to struct nk_context, so the drag handles read context->current at another
    offset than Nuklear wrote it (0x4920 instead of 0x4a10), got NULL and crashed
    with SIGSEGV, as three macOS crash reports and the debug log showed.
  • The options now live only in client/platform/nuklear_options.h, included
    before <nuklear.h> in every source and test, and the tests that compiled
    Nuklear with two or three of them now use the same set. The narrow clang
    C23-extension silence for Nuklear's alignof moved there too, so 24 Nuklear
    suites build and pass on macOS again.
  • tests/test_nuklear_options.py (suite nuklear-options) fails when any of
    the 100 units includes Nuklear without the options first or sets an option
    elsewhere, with negative cases for both.
  • With no workspace named, also when only --smoke or --language is given,
    the desktop opens the default board; the desktop suite tests its creation,
    reopening and a refused relative WENA_DATABASE.

Thanks to xet7.

Debug log for every desktop run, and the desktop opens its board when double-clicked
  • Each run writes .tools/log/wena/YYYY-MM-DD_HH-MM-SS/desktop.log: the
    arguments, the board opened, the source line of any startup failure with
    SDL's error, the window closing, the exit status, and a fatal signal, written
    with async-signal-safe calls before the default action, so a crash is visible.
    build.sh run adds run.log with everything the app printed and whether it
    exited or was killed by a signal. WENA_LOG_DIR chooses another folder.
  • Started without arguments, as a double-click does, wena-desktop opened
    nothing and printed that it needs a database, actor and board. It now opens
    the same local board as Run, created on the first run.
  • Tests cover the log folder and default board rules with their negative
    cases, a written line and a recorded crash in a child process, and run.log's
    output, exit code and signal.

Thanks to xet7.

Run opens the native Nuklear desktop, and the desktop builds on macOS again
  • Menu option 2) Run and build.sh run open dist/desktop/wena-desktop on a
    local board, created on the first run in the user's data folder or in
    WENA_DATABASE, instead of the bootstrap binary that only prints its name.
    Given arguments go to the desktop unchanged.
  • The desktop did not compile with Apple clang 21: SDL2/SDL.h was not found
    through sdl2-config, mkdtemp was hidden by _POSIX_C_SOURCE, and the pinned
    Nuklear's alignof is reported as a C23 extension. The desktop now includes
    SDL.h like the other sources, defines _DARWIN_C_SOURCE on macOS, and
    silences only that warning around the two Nuklear headers on a clang that
    knows it. The nuklear and sdl-text-input suites pass on macOS again.
  • Tests cover the desktop path per platform, the data folder per system and
    WENA_DATABASE, first-run creation and reopening, both refusals and passed
    arguments; the desktop smoke test passes for a created and a reopened board.

Thanks to xet7.

Add a Run option to the build menu
  • build.sh and build.bat menu option 2) Run starts the binary that 1) Build
    wrote for the current computer, dist/<target>/wena or wena.exe. Tests,
    Server and Tools move to options 3, 4 and 5. The same is run [ARGS...] as a
    named command, which passes its arguments on.
  • A missing or non-executable binary is refused with how to build it. Tests
    cover the file name per platform, both refusals, a real run with its
    arguments and exit code, and the menu order.

Thanks to xet7.

Preserve person assignments when moving cards between boards
  • Reuse shared member filtering and strict SQLite readers in single-card and
    bulk cross-board transfers. Retain members active on the destination board,
    preserve assignees, and keep their original ordering positions.
  • Verify card metadata, both board rosters, and person/actor data throughout the
    transfer transaction. Roll back ignored writes, partial transfers, and changes
    caused by later writes or triggers. Keep foreign-key enforcement enabled.
  • Add regression coverage for inactive and absent destination members, empty and
    full 2048-person sets, roster overflow, deferred parent updates, rollback and
    reopening. Update the roadmap; native person capture adapters, roster
    management and person controls remain unfinished.

Thanks to xet7.