Compare commits
6
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
030f66d806 | ||
|
|
da76b89856 | ||
|
|
20952e8477 | ||
|
|
f4e911c14a | ||
|
|
47a8d565e8 | ||
|
|
581e6b27d8 |
+1
-1
@@ -1,7 +1,7 @@
|
|||||||
# .gitignore
|
# .gitignore
|
||||||
frontend/node_modules/
|
frontend/node_modules/
|
||||||
frontend/dist/
|
frontend/dist/
|
||||||
build/bin/verstak-desktop
|
build/
|
||||||
smoke-platform
|
smoke-platform
|
||||||
plugins/
|
plugins/
|
||||||
vendor/
|
vendor/
|
||||||
|
|||||||
@@ -1,79 +1,206 @@
|
|||||||
# Verstak Desktop
|
# Verstak
|
||||||
|
|
||||||
Verstak is a local-first desktop workspace for files, notes, browser captures,
|
Verstak is a local-first workspace for files, notes, browser captures,
|
||||||
activity and work journal entries. This repository contains the Go/Wails desktop
|
activity and work-journal entries. This repository is the desktop application:
|
||||||
host and UI shell; user-facing functions are delivered by official plugins.
|
the Go/Wails host and UI shell that loads plugins from a `plugins/` directory
|
||||||
|
next to its executable.
|
||||||
|
|
||||||
> **Alpha software.** Use a disposable vault while evaluating it. APIs, storage
|
> **Alpha software.** Use a disposable vault while evaluating it. APIs, storage
|
||||||
> formats and packaging can change before the first stable release.
|
> formats and packaging can change before the first stable release.
|
||||||
|
|
||||||
## What the alpha does
|
|
||||||
|
|
||||||
- keeps each workspace's identity independent of its current directory name;
|
|
||||||
- keeps browser captures in a reviewable Inbox, with archive and restore rather
|
|
||||||
than a destructive “remove from inbox” action;
|
|
||||||
- records local file/note activity and, after review, turns it into journal
|
|
||||||
entries without creating a workspace automatically;
|
|
||||||
- accepts optional browser domain-time batches. The browser extension is
|
|
||||||
opt-in: it sends only normalized domain names and bounded durations, never
|
|
||||||
URLs, page titles, page contents, keystrokes or navigation history;
|
|
||||||
- runs official plugins from a `plugins/` directory next to the executable.
|
|
||||||
|
|
||||||
## Components
|
## Components
|
||||||
|
|
||||||
Clone these repositories as siblings when building a complete local setup:
|
The public alpha is split into small repositories. Keep their `main` branches
|
||||||
|
in the same release line when building from source.
|
||||||
|
|
||||||
| Repository | Purpose |
|
| Component | Repository | What it is for |
|
||||||
| --- | --- |
|
| --- | --- | --- |
|
||||||
| `verstak-desktop` | desktop host and UI shell |
|
| Desktop | [mirivlad/verstak](https://github.com/mirivlad/verstak) | This application: vault UI, local host and plugin runtime. |
|
||||||
| `verstak-official-plugins` | Files, Notes, Browser Inbox, Activity, Journal and other official plugins |
|
| Official plugins | [mirivlad/verstak-official-plugins](https://github.com/mirivlad/verstak-official-plugins) | Files, Notes, Browser Inbox, Activity, Journal, Sync, Todo and other first-party plugins. |
|
||||||
| `verstak-browser-extension` | Chromium/Firefox capture and optional domain-activity extension |
|
| Browser extension | [mirivlad/verstak-browser-extension](https://github.com/mirivlad/verstak-browser-extension) | Manual browser captures and opt-in domain-time activity. |
|
||||||
| `verstak-sdk` | plugin manifest schema and TypeScript API |
|
| Sync server | [mirivlad/verstak-sync-server](https://github.com/mirivlad/verstak-sync-server) | Optional self-hosted synchronization between devices. |
|
||||||
|
| Plugin SDK | [mirivlad/verstak-sdk](https://github.com/mirivlad/verstak-sdk) | TypeScript API, JSON schemas and contract tests for plugin authors. |
|
||||||
|
| Architecture documentation | [mirivlad/verstak-docs](https://github.com/mirivlad/verstak-docs) | Product, platform and plugin-system design documents. |
|
||||||
|
|
||||||
## Build from source (Linux)
|
No server account or browser extension is needed for a local desktop vault.
|
||||||
|
|
||||||
Requirements: Go, Node.js with npm, Python 3, the [Wails v2 build
|
## Build the desktop and official plugins
|
||||||
prerequisites](https://wails.io/docs/gettingstarted/installation/), and the
|
|
||||||
WebKitGTK development package for your distribution.
|
To build from source, install Go 1.24+, Node.js 20+ with npm, Python 3, the [Wails v2 build
|
||||||
|
prerequisites](https://wails.io/docs/gettingstarted/installation/), and your
|
||||||
|
distribution's WebKitGTK development package.
|
||||||
|
|
||||||
|
Clone the repositories as siblings. The directory names below are intentional:
|
||||||
|
the desktop helper finds the official-plugin checkout at
|
||||||
|
`../verstak-official-plugins`.
|
||||||
|
|
||||||
|
```text
|
||||||
|
verstak-workspace/
|
||||||
|
├── verstak/
|
||||||
|
├── verstak-sdk/
|
||||||
|
├── verstak-official-plugins/
|
||||||
|
└── verstak-browser-extension/ # optional for browser integration
|
||||||
|
```
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
git clone https://git.mirv.top/verstak/verstak-sdk.git
|
git clone https://github.com/mirivlad/verstak.git verstak
|
||||||
git clone https://git.mirv.top/verstak/verstak-official-plugins.git
|
git clone https://github.com/mirivlad/verstak-sdk.git verstak-sdk
|
||||||
git clone https://git.mirv.top/verstak/verstak-desktop.git
|
git clone https://github.com/mirivlad/verstak-official-plugins.git verstak-official-plugins
|
||||||
git clone https://git.mirv.top/verstak/verstak-browser-extension.git
|
git clone https://github.com/mirivlad/verstak-browser-extension.git verstak-browser-extension
|
||||||
|
|
||||||
cd verstak-sdk && ./scripts/build.sh
|
cd verstak-sdk && ./scripts/build.sh
|
||||||
cd ../verstak-official-plugins && ./scripts/build.sh
|
cd ../verstak-official-plugins && ./scripts/build.sh
|
||||||
cd ../verstak-desktop
|
cd ../verstak
|
||||||
./scripts/install-dev-plugins.sh
|
./scripts/install-dev-plugins.sh
|
||||||
./scripts/build.sh
|
./scripts/build.sh
|
||||||
```
|
```
|
||||||
|
|
||||||
The Linux executable is placed in `build/bin/`. Start it with `--debug` to
|
`install-dev-plugins.sh` copies the packages from
|
||||||
display internal plugin-provider IDs and write diagnostic logs.
|
`../verstak-official-plugins/dist/` into this repository's `plugins/`
|
||||||
|
directory. `build.sh` then copies them to `build/bin/plugins/`, beside the
|
||||||
## Release artifacts
|
desktop executable:
|
||||||
|
|
||||||
Maintainers can create a Linux desktop tarball after the sibling repositories
|
|
||||||
above have been built:
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
cd verstak-desktop
|
./build/bin/verstak-desktop
|
||||||
./scripts/release.sh v0.1.0-alpha.1
|
|
||||||
```
|
```
|
||||||
|
|
||||||
It writes `release/verstak-desktop-linux-amd64-<version>.tar.gz` and a matching
|
For a manually assembled installation, place each unpacked plugin directory
|
||||||
`SHA256SUMS` file. The archive is self-contained: unpack it and run the
|
directly in `plugins/` beside `verstak-desktop`; for example,
|
||||||
included executable. Browser and SDK packages have their own release scripts
|
`plugins/browser-inbox/plugin.json`. Do not put the release archive itself in
|
||||||
in their repositories.
|
that directory. The desktop release archive already includes its matching
|
||||||
|
`plugins/` directory.
|
||||||
|
|
||||||
## Privacy and activity tracking
|
Start with `--debug` to show internal plugin-provider identifiers and write
|
||||||
|
diagnostic logs:
|
||||||
|
|
||||||
The extension's passive domain tracker is disabled by default. Enabling it
|
```bash
|
||||||
requires an explicit choice in the extension and lets the user maintain a
|
./build/bin/verstak-desktop --debug
|
||||||
domain exclusion list. Manual page, selection and link captures are separate
|
```
|
||||||
actions; they enter Browser Inbox and never create a workspace or journal
|
|
||||||
entry by themselves.
|
## Portable test artifacts
|
||||||
|
|
||||||
|
These commands make local alpha artifacts in `release/`. They do not create a
|
||||||
|
GitHub Release.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Debian 13 / Ubuntu 24.04 or later. APT installs WebKitGTK dependencies.
|
||||||
|
./scripts/package-deb.sh v0.1.0-alpha.1
|
||||||
|
|
||||||
|
# Portable Linux x86_64 AppImage with bundled WebKitGTK runtime and plugins.
|
||||||
|
./scripts/package-appimage.sh v0.1.0-alpha.1
|
||||||
|
```
|
||||||
|
|
||||||
|
Install the Debian package with `sudo apt install ./release/verstak_*.deb`,
|
||||||
|
then launch `verstak`. Run the AppImage directly after making it executable:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
chmod +x release/verstak-linux-x86_64-v0.1.0-alpha.1.AppImage
|
||||||
|
./release/verstak-linux-x86_64-v0.1.0-alpha.1.AppImage
|
||||||
|
```
|
||||||
|
|
||||||
|
On distributions without FUSE support, use
|
||||||
|
`APPIMAGE_EXTRACT_AND_RUN=1 ./release/verstak-linux-x86_64-v0.1.0-alpha.1.AppImage`.
|
||||||
|
|
||||||
|
Build the Windows portable ZIP on Linux with MinGW:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo apt install gcc-mingw-w64-x86-64 zip
|
||||||
|
./scripts/package-windows-portable.sh v0.1.0-alpha.1
|
||||||
|
```
|
||||||
|
|
||||||
|
The ZIP uses the x64 Evergreen Microsoft WebView2 Runtime installed in Windows
|
||||||
|
and writes `release/verstak-windows-amd64-<version>.zip`. Extract it to a local
|
||||||
|
disk (not a network share) and launch `Verstak.cmd`. Windows 11 and most
|
||||||
|
Windows 10 installations already include this runtime. If Verstak does not
|
||||||
|
start, install the official [Microsoft WebView2 Runtime x64 standalone
|
||||||
|
installer](https://go.microsoft.com/fwlink/p/?LinkId=2124701), then launch it
|
||||||
|
again.
|
||||||
|
|
||||||
|
Each format is listed in `release/SHA256SUMS` after packaging.
|
||||||
|
|
||||||
|
## First local vault
|
||||||
|
|
||||||
|
1. Launch the desktop application and choose or create a writable vault folder.
|
||||||
|
Verstak stores its local metadata in that vault; do not point it at a
|
||||||
|
read-only directory.
|
||||||
|
2. Create a Дело (workspace) in the Files plugin before assigning captures or
|
||||||
|
activity to it.
|
||||||
|
3. Open Notes, Files, Activity and Journal as needed. Activity candidates are
|
||||||
|
only suggestions: a Journal entry and a new Дело are always created by the
|
||||||
|
user.
|
||||||
|
|
||||||
|
## Browser extension
|
||||||
|
|
||||||
|
The extension is optional. Build it locally with `npm ci && npm test && npm run
|
||||||
|
build` in `verstak-browser-extension/`, then load `dist/chromium` as an
|
||||||
|
unpacked Chromium extension or `dist/firefox` temporarily in Firefox. A signed
|
||||||
|
Firefox XPI is available from the [extension's GitHub
|
||||||
|
Releases](https://github.com/mirivlad/verstak-browser-extension/releases).
|
||||||
|
|
||||||
|
To connect it to the desktop application:
|
||||||
|
|
||||||
|
1. Ensure the `browser-inbox` plugin is installed and open its settings in
|
||||||
|
Verstak.
|
||||||
|
2. Copy the displayed Receiver URL and Pairing Token.
|
||||||
|
3. Paste both values into the extension's settings and save.
|
||||||
|
4. Use a manual Send Page, selection, link or file action to create a Browser
|
||||||
|
Inbox capture.
|
||||||
|
|
||||||
|
Passive domain activity is disabled by default. When the user explicitly turns
|
||||||
|
it on, the extension sends only bounded time totals by normalized domain. It
|
||||||
|
does not send URLs, page titles, page contents, keystrokes, navigation history
|
||||||
|
or inactive-tab time. The extension settings provide a domain exclusion list.
|
||||||
|
|
||||||
|
## Optional sync server
|
||||||
|
|
||||||
|
The sync server is self-hosted and is not required for local use. Build and
|
||||||
|
start a development instance from a sibling checkout:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git clone https://github.com/mirivlad/verstak-sync-server.git verstak-sync-server
|
||||||
|
cd verstak-sync-server
|
||||||
|
./scripts/build.sh
|
||||||
|
./build/bin/verstak-sync-server --port 47732 --data ./server-data \
|
||||||
|
--admin-user admin --admin-pass 'choose-a-strong-password'
|
||||||
|
```
|
||||||
|
|
||||||
|
For a second device or a production host, follow the deployment, HTTPS and
|
||||||
|
backup guidance in the [sync server
|
||||||
|
README](https://github.com/mirivlad/verstak-sync-server#readme). In the desktop
|
||||||
|
application, open the Sync plugin, enter the server URL and user credentials,
|
||||||
|
test the connection, then select **Connect**. Each vault is paired separately.
|
||||||
|
|
||||||
|
## Separate plugin archives
|
||||||
|
|
||||||
|
The desktop artifacts already include matching official plugins. To distribute
|
||||||
|
plugins separately, build OS-specific archives in the sibling repository:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd ../verstak-official-plugins
|
||||||
|
sudo apt install gcc-mingw-w64-x86-64 zip
|
||||||
|
./scripts/package-portable.sh v0.1.0-alpha.1
|
||||||
|
```
|
||||||
|
|
||||||
|
It writes a Linux `tar.gz` and a Windows ZIP. Both archives expand directly
|
||||||
|
into the `plugins/` directory beside the corresponding desktop executable.
|
||||||
|
Separate archives are required because `platform-test` includes a native
|
||||||
|
sidecar for its target OS.
|
||||||
|
|
||||||
|
## Publish a GitHub Release
|
||||||
|
|
||||||
|
```bash
|
||||||
|
./scripts/publish-github-release.sh v0.1.0-alpha.1
|
||||||
|
```
|
||||||
|
|
||||||
|
The command requires an authenticated [`gh`](https://cli.github.com/) CLI, a
|
||||||
|
clean local `main` equal to `origin/main`, and the sibling official-plugins
|
||||||
|
checkout. It builds the Debian package, Linux AppImage and Windows portable
|
||||||
|
ZIP, then creates or updates the GitHub Release with those three artifacts and
|
||||||
|
`SHA256SUMS`. Alpha, beta and release-candidate tags are marked as GitHub
|
||||||
|
prereleases; stable tags are marked latest. The command creates an annotated
|
||||||
|
tag when needed and pushes it through `origin`, which also mirrors tags in this
|
||||||
|
checkout. Publish the compatible official-plugins release before the desktop
|
||||||
|
release that embeds those plugins.
|
||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
"$id": "https://git.mirv.top/verstak/verstak-sdk/schemas/hostname-normalization-v1.json",
|
"$id": "https://raw.githubusercontent.com/mirivlad/verstak-sdk/main/schemas/hostname-normalization-v1.json",
|
||||||
"title": "Verstak canonical hostname normalization v1 test vectors",
|
"title": "Verstak canonical hostname normalization v1 test vectors",
|
||||||
"description": "Canonical hostnames are lowercase ASCII A-labels without a port or trailing DNS dot. Bare hostnames accept DNS names, IPv4, bracketed IPv6, localhost, and internal single-label names. URL inputs accept only HTTP(S). Invalid or excessively long input normalizes to an empty string.",
|
"description": "Canonical hostnames are lowercase ASCII A-labels without a port or trailing DNS dot. Bare hostnames accept DNS names, IPv4, bracketed IPv6, localhost, and internal single-label names. URL inputs accept only HTTP(S). Invalid or excessively long input normalizes to an empty string.",
|
||||||
"version": 1,
|
"version": 1,
|
||||||
|
|||||||
@@ -243,7 +243,7 @@ func main() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ─── Wails App ───────────────────────────────────────────
|
// ─── Wails App ───────────────────────────────────────────
|
||||||
err = wails.Run(&options.App{
|
appOptions := &options.App{
|
||||||
Title: "Verstak",
|
Title: "Verstak",
|
||||||
Width: 1200,
|
Width: 1200,
|
||||||
Height: 800,
|
Height: 800,
|
||||||
@@ -257,7 +257,8 @@ func main() {
|
|||||||
Bind: []interface{}{
|
Bind: []interface{}{
|
||||||
app,
|
app,
|
||||||
},
|
},
|
||||||
})
|
}
|
||||||
|
err = wails.Run(appOptions)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalf("Error: %v", err)
|
log.Fatalf("Error: %v", err)
|
||||||
|
|||||||
@@ -0,0 +1,11 @@
|
|||||||
|
Package: verstak
|
||||||
|
Version: @VERSION@
|
||||||
|
Section: utils
|
||||||
|
Priority: optional
|
||||||
|
Architecture: amd64
|
||||||
|
Depends: libwebkit2gtk-4.1-0, libgtk-3-0t64 | libgtk-3-0
|
||||||
|
Maintainer: Verstak contributors <dev@verstak.app>
|
||||||
|
Homepage: https://github.com/mirivlad/verstak
|
||||||
|
Description: Local-first workspace
|
||||||
|
Verstak is a local-first workspace for files, notes, browser captures,
|
||||||
|
activity and work-journal entries.
|
||||||
Executable
+2
@@ -0,0 +1,2 @@
|
|||||||
|
#!/usr/bin/env sh
|
||||||
|
exec /opt/verstak/verstak-desktop "$@"
|
||||||
Executable
+13
@@ -0,0 +1,13 @@
|
|||||||
|
#!/usr/bin/env sh
|
||||||
|
set -eu
|
||||||
|
|
||||||
|
HERE="$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)"
|
||||||
|
export APPDIR="$HERE"
|
||||||
|
export LD_LIBRARY_PATH="$HERE/usr/lib${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH}"
|
||||||
|
export GIO_EXTRA_MODULES="$HERE/usr/lib/gio/modules"
|
||||||
|
export GSETTINGS_SCHEMA_DIR="$HERE/usr/share/glib-2.0/schemas"
|
||||||
|
export GST_PLUGIN_SYSTEM_PATH_1_0="$HERE/usr/lib/gstreamer-1.0"
|
||||||
|
export WEBKIT_EXEC_PATH="$HERE/usr/lib/webkit2gtk-4.1"
|
||||||
|
|
||||||
|
cd "$HERE/usr/bin"
|
||||||
|
exec "$HERE/usr/bin/verstak-desktop" "$@"
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
[Desktop Entry]
|
||||||
|
Type=Application
|
||||||
|
Name=Verstak
|
||||||
|
Comment=Local-first workspace
|
||||||
|
Exec=verstak-desktop %U
|
||||||
|
Icon=verstak
|
||||||
|
Terminal=false
|
||||||
|
Categories=Office;Utility;
|
||||||
|
StartupNotify=true
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="128" height="128" viewBox="0 0 128 128">
|
||||||
|
<rect width="128" height="128" rx="26" fill="#1c2f4a"/>
|
||||||
|
<path d="M28 34h72v18H28zm0 31h72v29H28z" fill="#72d2b3"/>
|
||||||
|
<path d="M41 52v13m23-13v13m23-13v13" stroke="#1c2f4a" stroke-width="8"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 290 B |
@@ -0,0 +1,5 @@
|
|||||||
|
@echo off
|
||||||
|
setlocal
|
||||||
|
set "ROOT=%~dp0"
|
||||||
|
|
||||||
|
start "" "%ROOT%verstak-desktop.exe" %*
|
||||||
Executable
+31
@@ -0,0 +1,31 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
ROOT="$(cd "$(dirname "$0")/.." && pwd)"
|
||||||
|
OFFICIAL_PLUGINS="${VERSTAK_OFFICIAL_PLUGINS_DIR:-$ROOT/../verstak-official-plugins}"
|
||||||
|
OUTPUT="${VERSTAK_LINUX_BUNDLE_DIR:-$ROOT/build/linux-amd64}"
|
||||||
|
|
||||||
|
if [[ ! -d "$OFFICIAL_PLUGINS" ]]; then
|
||||||
|
echo "official plugins repository not found: $OFFICIAL_PLUGINS" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "=== verstak desktop Linux amd64 bundle ==="
|
||||||
|
(cd "$OFFICIAL_PLUGINS" && ./scripts/build.sh)
|
||||||
|
"$ROOT/scripts/install-dev-plugins.sh"
|
||||||
|
"$ROOT/scripts/build.sh"
|
||||||
|
|
||||||
|
BINARY="$ROOT/build/bin/verstak-desktop"
|
||||||
|
if [[ ! -x "$BINARY" ]]; then
|
||||||
|
echo "desktop binary was not produced: $BINARY" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
rm -rf "$OUTPUT"
|
||||||
|
mkdir -p "$OUTPUT"
|
||||||
|
install -m 755 "$BINARY" "$OUTPUT/verstak-desktop"
|
||||||
|
install -m 644 "$ROOT/README.md" "$ROOT/LICENSE" "$OUTPUT/"
|
||||||
|
cp -R "$ROOT/plugins" "$OUTPUT/plugins"
|
||||||
|
chmod -R a+rX "$OUTPUT/plugins"
|
||||||
|
|
||||||
|
echo "Linux bundle: $OUTPUT"
|
||||||
Executable
+75
@@ -0,0 +1,75 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
ROOT="$(cd "$(dirname "$0")/.." && pwd)"
|
||||||
|
OFFICIAL_PLUGINS="${VERSTAK_OFFICIAL_PLUGINS_DIR:-$ROOT/../verstak-official-plugins}"
|
||||||
|
WINDOWS_PLUGIN_DIST="${VERSTAK_WINDOWS_PLUGIN_DIST:-$OFFICIAL_PLUGINS/dist-windows}"
|
||||||
|
WINDOWS_OUTPUT="${VERSTAK_WINDOWS_OUTPUT_DIR:-$ROOT/build/windows-amd64}"
|
||||||
|
WINDOWS_CC="${VERSTAK_WINDOWS_CC:-x86_64-w64-mingw32-gcc}"
|
||||||
|
|
||||||
|
if ! command -v "$WINDOWS_CC" >/dev/null; then
|
||||||
|
echo "Windows cross-compiler not found: $WINDOWS_CC" >&2
|
||||||
|
echo "Install x86_64-w64-mingw32-gcc (for example: sudo apt install gcc-mingw-w64-x86-64)." >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
if [[ ! -d "$OFFICIAL_PLUGINS" ]]; then
|
||||||
|
echo "official plugins repository not found: $OFFICIAL_PLUGINS" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
WAILS="${WAILS_BIN:-}"
|
||||||
|
if [[ -z "$WAILS" ]]; then
|
||||||
|
if command -v wails >/dev/null; then
|
||||||
|
WAILS="wails"
|
||||||
|
elif [[ -n "$(go env GOBIN 2>/dev/null)" && -x "$(go env GOBIN)/wails" ]]; then
|
||||||
|
WAILS="$(go env GOBIN)/wails"
|
||||||
|
elif [[ -x "$(go env GOPATH)/bin/wails" ]]; then
|
||||||
|
WAILS="$(go env GOPATH)/bin/wails"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
if [[ -z "$WAILS" ]]; then
|
||||||
|
echo "Wails CLI is required. Install it with: go install github.com/wailsapp/wails/v2/cmd/wails@v2.12.0" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
cd "$ROOT"
|
||||||
|
echo "=== verstak desktop Windows amd64 build ==="
|
||||||
|
|
||||||
|
if [[ ! -d "$ROOT/frontend/node_modules" ]]; then
|
||||||
|
if [[ -f "$ROOT/frontend/package-lock.json" ]]; then
|
||||||
|
(cd "$ROOT/frontend" && npm ci --no-audit --no-fund)
|
||||||
|
else
|
||||||
|
(cd "$ROOT/frontend" && npm install --no-audit --no-fund)
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
(cd "$ROOT/frontend" && npm run build)
|
||||||
|
|
||||||
|
go mod download
|
||||||
|
go test -count=1 ./...
|
||||||
|
|
||||||
|
"$OFFICIAL_PLUGINS/scripts/build-windows.sh"
|
||||||
|
if [[ ! -d "$WINDOWS_PLUGIN_DIST" ]]; then
|
||||||
|
echo "Windows plugin packages were not produced: $WINDOWS_PLUGIN_DIST" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Wails' -compiler option selects a Go binary, not a C compiler. Cross-CGO
|
||||||
|
# therefore has to be supplied through the standard Go environment instead.
|
||||||
|
# The portable archive uses the installed Evergreen WebView2 Runtime, so never
|
||||||
|
# compile an Evergreen downloader into the executable.
|
||||||
|
CC="$WINDOWS_CC" CGO_ENABLED=1 "$WAILS" build -clean -platform windows/amd64 \
|
||||||
|
-webview2 error -o verstak-desktop.exe
|
||||||
|
|
||||||
|
WINDOWS_BINARY="$ROOT/build/bin/verstak-desktop.exe"
|
||||||
|
if [[ ! -f "$WINDOWS_BINARY" ]]; then
|
||||||
|
echo "Windows executable was not produced: $WINDOWS_BINARY" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
rm -rf "$WINDOWS_OUTPUT"
|
||||||
|
mkdir -p "$WINDOWS_OUTPUT/plugins"
|
||||||
|
cp "$WINDOWS_BINARY" "$WINDOWS_OUTPUT/verstak-desktop.exe"
|
||||||
|
cp -R "$WINDOWS_PLUGIN_DIST/." "$WINDOWS_OUTPUT/plugins/"
|
||||||
|
|
||||||
|
echo "Windows test bundle: $WINDOWS_OUTPUT"
|
||||||
|
echo "Copy this directory to Windows and run verstak-desktop.exe."
|
||||||
Executable
+118
@@ -0,0 +1,118 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
ROOT="$(cd "$(dirname "$0")/.." && pwd)"
|
||||||
|
VERSION="${1:-}"
|
||||||
|
APPIMAGETOOL_URL="${APPIMAGETOOL_URL:-https://github.com/AppImage/appimagetool/releases/download/continuous/appimagetool-x86_64.AppImage}"
|
||||||
|
|
||||||
|
if [[ -z "$VERSION" || ! "$VERSION" =~ ^[A-Za-z0-9][A-Za-z0-9._-]*$ ]]; then
|
||||||
|
echo "usage: $0 <version>" >&2
|
||||||
|
echo "example: $0 v0.1.0-alpha.1" >&2
|
||||||
|
exit 2
|
||||||
|
fi
|
||||||
|
if ! command -v ldd >/dev/null || ! command -v file >/dev/null; then
|
||||||
|
echo "ldd and file are required to bundle AppImage runtime libraries" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
"$ROOT/scripts/build-linux-bundle.sh"
|
||||||
|
|
||||||
|
APPIMAGETOOL="${APPIMAGETOOL_BIN:-$ROOT/build/tools/appimagetool-x86_64.AppImage}"
|
||||||
|
if [[ ! -x "$APPIMAGETOOL" ]]; then
|
||||||
|
if ! command -v curl >/dev/null; then
|
||||||
|
echo "appimagetool is missing; install curl or set APPIMAGETOOL_BIN" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
mkdir -p "$(dirname "$APPIMAGETOOL")"
|
||||||
|
curl --fail --location --show-error "$APPIMAGETOOL_URL" -o "$APPIMAGETOOL"
|
||||||
|
chmod +x "$APPIMAGETOOL"
|
||||||
|
fi
|
||||||
|
|
||||||
|
BUNDLE="${VERSTAK_LINUX_BUNDLE_DIR:-$ROOT/build/linux-amd64}"
|
||||||
|
APPDIR="$ROOT/build/appimage/AppDir"
|
||||||
|
RELEASE_ROOT="$ROOT/release"
|
||||||
|
ARCHIVE="$RELEASE_ROOT/verstak-linux-x86_64-$VERSION.AppImage"
|
||||||
|
WEBKIT_RUNTIME_DIR="${VERSTAK_WEBKIT_RUNTIME_DIR:-/usr/lib/x86_64-linux-gnu/webkit2gtk-4.1}"
|
||||||
|
|
||||||
|
if [[ ! -d "$WEBKIT_RUNTIME_DIR" ]] || [[ ! -x "$WEBKIT_RUNTIME_DIR/WebKitWebProcess" ]]; then
|
||||||
|
echo "WebKitWebProcess was not found at $WEBKIT_RUNTIME_DIR" >&2
|
||||||
|
echo "Set VERSTAK_WEBKIT_RUNTIME_DIR to the WebKitGTK 4.1 runtime directory." >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
rm -rf "$APPDIR" "$ARCHIVE"
|
||||||
|
mkdir -p "$APPDIR/usr/bin" "$APPDIR/usr/lib" "$APPDIR/usr/share/applications" \
|
||||||
|
"$APPDIR/usr/share/icons/hicolor/scalable/apps"
|
||||||
|
install -m 755 "$ROOT/packaging/linux/AppRun" "$APPDIR/AppRun"
|
||||||
|
install -m 755 "$BUNDLE/verstak-desktop" "$APPDIR/usr/bin/verstak-desktop"
|
||||||
|
install -m 644 "$ROOT/packaging/linux/verstak.desktop" "$APPDIR/verstak.desktop"
|
||||||
|
install -m 644 "$ROOT/packaging/linux/verstak.desktop" "$APPDIR/usr/share/applications/verstak.desktop"
|
||||||
|
install -m 644 "$ROOT/packaging/linux/verstak.svg" "$APPDIR/verstak.svg"
|
||||||
|
install -m 644 "$ROOT/packaging/linux/verstak.svg" "$APPDIR/usr/share/icons/hicolor/scalable/apps/verstak.svg"
|
||||||
|
cp -R "$BUNDLE/plugins" "$APPDIR/usr/bin/plugins"
|
||||||
|
cp -a "$WEBKIT_RUNTIME_DIR" "$APPDIR/usr/lib/webkit2gtk-4.1"
|
||||||
|
|
||||||
|
copy_runtime_dir() {
|
||||||
|
local source="$1"
|
||||||
|
local target="$2"
|
||||||
|
if [[ -d "$source" ]]; then
|
||||||
|
mkdir -p "$target"
|
||||||
|
cp -a "$source/." "$target/"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
copy_runtime_dir /usr/lib/x86_64-linux-gnu/gio/modules "$APPDIR/usr/lib/gio/modules"
|
||||||
|
copy_runtime_dir /usr/lib/x86_64-linux-gnu/gstreamer-1.0 "$APPDIR/usr/lib/gstreamer-1.0"
|
||||||
|
copy_runtime_dir /usr/lib/x86_64-linux-gnu/gdk-pixbuf-2.0 "$APPDIR/usr/lib/gdk-pixbuf-2.0"
|
||||||
|
copy_runtime_dir /usr/share/glib-2.0/schemas "$APPDIR/usr/share/glib-2.0/schemas"
|
||||||
|
|
||||||
|
declare -A queued=()
|
||||||
|
queue_elf() {
|
||||||
|
local candidate="$1"
|
||||||
|
[[ -f "$candidate" ]] || return
|
||||||
|
if [[ "$(file --brief "$candidate")" != *ELF* ]]; then
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
if [[ -z "${queued[$candidate]:-}" ]]; then
|
||||||
|
queued[$candidate]=1
|
||||||
|
printf '%s\n' "$candidate" >> "$APPDIR/.elf-queue"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
queue_elf "$APPDIR/usr/bin/verstak-desktop"
|
||||||
|
while IFS= read -r candidate; do
|
||||||
|
queue_elf "$candidate"
|
||||||
|
done < <(find "$APPDIR/usr/lib/webkit2gtk-4.1" "$APPDIR/usr/lib/gio/modules" \
|
||||||
|
"$APPDIR/usr/lib/gstreamer-1.0" "$APPDIR/usr/lib/gdk-pixbuf-2.0" -type f)
|
||||||
|
|
||||||
|
while IFS= read -r candidate; do
|
||||||
|
if ldd "$candidate" | grep -q 'not found'; then
|
||||||
|
echo "unresolved shared library in $candidate" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
while IFS= read -r library; do
|
||||||
|
case "$(basename "$library")" in
|
||||||
|
libc.so.6|libm.so.6|libpthread.so.0|librt.so.1|libdl.so.2|ld-linux-x86-64.so.2)
|
||||||
|
continue
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
bundled="$APPDIR/usr/lib/$(basename "$library")"
|
||||||
|
if [[ ! -e "$bundled" ]]; then
|
||||||
|
cp -aL "$library" "$bundled"
|
||||||
|
fi
|
||||||
|
queue_elf "$bundled"
|
||||||
|
done < <(ldd "$candidate" | awk '/=> \/[^ ]+/ { print $3 } /^\// { print $1 }')
|
||||||
|
done < "$APPDIR/.elf-queue"
|
||||||
|
rm -f "$APPDIR/.elf-queue"
|
||||||
|
|
||||||
|
if command -v glib-compile-schemas >/dev/null; then
|
||||||
|
glib-compile-schemas "$APPDIR/usr/share/glib-2.0/schemas"
|
||||||
|
fi
|
||||||
|
|
||||||
|
mkdir -p "$RELEASE_ROOT"
|
||||||
|
ARCH=x86_64 APPIMAGE_EXTRACT_AND_RUN=1 "$APPIMAGETOOL" "$APPDIR" "$ARCHIVE"
|
||||||
|
(cd "$RELEASE_ROOT" && find . -maxdepth 1 -type f \( -name '*.deb' -o -name '*.AppImage' -o -name '*.zip' \) \
|
||||||
|
-printf '%f\n' | LC_ALL=C sort | xargs -r sha256sum > SHA256SUMS)
|
||||||
|
|
||||||
|
echo "AppImage: $ARCHIVE"
|
||||||
|
echo "checksums: $RELEASE_ROOT/SHA256SUMS"
|
||||||
Executable
+44
@@ -0,0 +1,44 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
ROOT="$(cd "$(dirname "$0")/.." && pwd)"
|
||||||
|
VERSION="${1:-}"
|
||||||
|
|
||||||
|
if [[ -z "$VERSION" || ! "$VERSION" =~ ^[A-Za-z0-9][A-Za-z0-9._-]*$ ]]; then
|
||||||
|
echo "usage: $0 <version>" >&2
|
||||||
|
echo "example: $0 v0.1.0-alpha.1" >&2
|
||||||
|
exit 2
|
||||||
|
fi
|
||||||
|
if ! command -v dpkg-deb >/dev/null; then
|
||||||
|
echo "dpkg-deb is required to create a Debian package" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
"$ROOT/scripts/build-linux-bundle.sh"
|
||||||
|
|
||||||
|
PACKAGE_VERSION="${VERSION#v}"
|
||||||
|
BUNDLE="${VERSTAK_LINUX_BUNDLE_DIR:-$ROOT/build/linux-amd64}"
|
||||||
|
STAGING="$ROOT/build/deb/verstak_$PACKAGE_VERSION"
|
||||||
|
RELEASE_ROOT="$ROOT/release"
|
||||||
|
ARCHIVE="$RELEASE_ROOT/verstak_${PACKAGE_VERSION}_amd64.deb"
|
||||||
|
|
||||||
|
rm -rf "$STAGING" "$ARCHIVE"
|
||||||
|
mkdir -p "$STAGING/DEBIAN" "$STAGING/opt/verstak" "$STAGING/usr/bin" \
|
||||||
|
"$STAGING/usr/share/applications" "$STAGING/usr/share/icons/hicolor/scalable/apps" \
|
||||||
|
"$STAGING/usr/share/doc/verstak"
|
||||||
|
|
||||||
|
sed "s/@VERSION@/$PACKAGE_VERSION/g" "$ROOT/packaging/deb/control" > "$STAGING/DEBIAN/control"
|
||||||
|
install -m 755 "$ROOT/packaging/deb/verstak" "$STAGING/usr/bin/verstak"
|
||||||
|
install -m 755 "$BUNDLE/verstak-desktop" "$STAGING/opt/verstak/verstak-desktop"
|
||||||
|
install -m 644 "$BUNDLE/README.md" "$BUNDLE/LICENSE" "$STAGING/usr/share/doc/verstak/"
|
||||||
|
install -m 644 "$ROOT/packaging/linux/verstak.desktop" "$STAGING/usr/share/applications/verstak.desktop"
|
||||||
|
install -m 644 "$ROOT/packaging/linux/verstak.svg" "$STAGING/usr/share/icons/hicolor/scalable/apps/verstak.svg"
|
||||||
|
cp -R "$BUNDLE/plugins" "$STAGING/opt/verstak/plugins"
|
||||||
|
|
||||||
|
mkdir -p "$RELEASE_ROOT"
|
||||||
|
dpkg-deb --root-owner-group --build "$STAGING" "$ARCHIVE"
|
||||||
|
(cd "$RELEASE_ROOT" && find . -maxdepth 1 -type f \( -name '*.deb' -o -name '*.AppImage' -o -name '*.zip' \) \
|
||||||
|
-printf '%f\n' | LC_ALL=C sort | xargs -r sha256sum > SHA256SUMS)
|
||||||
|
|
||||||
|
echo "Debian package: $ARCHIVE"
|
||||||
|
echo "checksums: $RELEASE_ROOT/SHA256SUMS"
|
||||||
Executable
+35
@@ -0,0 +1,35 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
ROOT="$(cd "$(dirname "$0")/.." && pwd)"
|
||||||
|
VERSION="${1:-}"
|
||||||
|
|
||||||
|
if [[ -z "$VERSION" || ! "$VERSION" =~ ^[A-Za-z0-9][A-Za-z0-9._-]*$ ]]; then
|
||||||
|
echo "usage: $0 <version>" >&2
|
||||||
|
echo "example: $0 v0.1.0-alpha.1" >&2
|
||||||
|
exit 2
|
||||||
|
fi
|
||||||
|
for command in zip; do
|
||||||
|
if ! command -v "$command" >/dev/null; then
|
||||||
|
echo "$command is required to create the Windows portable archive" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
"$ROOT/scripts/build-windows.sh"
|
||||||
|
|
||||||
|
RELEASE_ROOT="$ROOT/release"
|
||||||
|
STAGING="$RELEASE_ROOT/verstak-windows-amd64-$VERSION"
|
||||||
|
ARCHIVE="$RELEASE_ROOT/verstak-windows-amd64-$VERSION.zip"
|
||||||
|
rm -rf "$STAGING" "$ARCHIVE"
|
||||||
|
mkdir -p "$STAGING"
|
||||||
|
cp -R "$ROOT/build/windows-amd64/." "$STAGING/"
|
||||||
|
install -m 644 "$ROOT/README.md" "$ROOT/LICENSE" "$STAGING/"
|
||||||
|
install -m 644 "$ROOT/packaging/windows/Verstak.cmd" "$STAGING/Verstak.cmd"
|
||||||
|
|
||||||
|
(cd "$RELEASE_ROOT" && zip -qr "$(basename "$ARCHIVE")" "$(basename "$STAGING")")
|
||||||
|
(cd "$RELEASE_ROOT" && find . -maxdepth 1 -type f \( -name '*.deb' -o -name '*.AppImage' -o -name '*.zip' \) \
|
||||||
|
-printf '%f\n' | LC_ALL=C sort | xargs -r sha256sum > SHA256SUMS)
|
||||||
|
|
||||||
|
echo "Windows portable archive: $ARCHIVE"
|
||||||
|
echo "checksums: $RELEASE_ROOT/SHA256SUMS"
|
||||||
Executable
+81
@@ -0,0 +1,81 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
ROOT="$(cd "$(dirname "$0")/.." && pwd)"
|
||||||
|
VERSION="${1:-}"
|
||||||
|
REPOSITORY="mirivlad/verstak"
|
||||||
|
RELEASE_SCRIPT="${VERSTAK_RELEASE_SCRIPT:-$ROOT/scripts/release.sh}"
|
||||||
|
RELEASE_DIR="${VERSTAK_RELEASE_DIR:-$ROOT/release}"
|
||||||
|
GIT_BIN="${GIT_BIN:-git}"
|
||||||
|
GH_BIN="${GH_BIN:-gh}"
|
||||||
|
|
||||||
|
cd "$ROOT"
|
||||||
|
|
||||||
|
if [[ -z "$VERSION" || ! "$VERSION" =~ ^[A-Za-z0-9][A-Za-z0-9._-]*$ ]]; then
|
||||||
|
echo "usage: $0 <version>" >&2
|
||||||
|
echo "example: $0 v0.1.0-alpha.1" >&2
|
||||||
|
exit 2
|
||||||
|
fi
|
||||||
|
if ! command -v "$GH_BIN" >/dev/null; then
|
||||||
|
echo "gh CLI is required to publish a GitHub Release" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
if [[ "$("$GIT_BIN" branch --show-current)" != "main" ]]; then
|
||||||
|
echo "GitHub releases must be published from main" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
if [[ -n "$("$GIT_BIN" status --porcelain)" ]]; then
|
||||||
|
echo "working tree must be clean before publishing a release" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
"$GH_BIN" auth status
|
||||||
|
"$GIT_BIN" fetch origin main --tags
|
||||||
|
HEAD="$("$GIT_BIN" rev-parse HEAD)"
|
||||||
|
if [[ "$HEAD" != "$("$GIT_BIN" rev-parse origin/main)" ]]; then
|
||||||
|
echo "local main must match origin/main before publishing a release" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
"$RELEASE_SCRIPT" "$VERSION"
|
||||||
|
|
||||||
|
ASSETS=(
|
||||||
|
"$RELEASE_DIR/verstak_${VERSION#v}_amd64.deb"
|
||||||
|
"$RELEASE_DIR/verstak-linux-x86_64-$VERSION.AppImage"
|
||||||
|
"$RELEASE_DIR/verstak-windows-amd64-$VERSION.zip"
|
||||||
|
"$RELEASE_DIR/SHA256SUMS"
|
||||||
|
)
|
||||||
|
for asset in "${ASSETS[@]}"; do
|
||||||
|
if [[ ! -s "$asset" ]]; then
|
||||||
|
echo "required release asset is missing or empty: $asset" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
if "$GIT_BIN" rev-parse -q --verify "refs/tags/$VERSION" >/dev/null; then
|
||||||
|
if [[ "$("$GIT_BIN" rev-parse "${VERSION}^{commit}")" != "$HEAD" ]]; then
|
||||||
|
echo "existing tag $VERSION does not point at HEAD" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
"$GIT_BIN" tag -a "$VERSION" -m "Release $VERSION"
|
||||||
|
"$GIT_BIN" push origin "refs/tags/$VERSION"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if "$GH_BIN" release view "$VERSION" --repo "$REPOSITORY" >/dev/null 2>&1; then
|
||||||
|
"$GH_BIN" release upload "$VERSION" "${ASSETS[@]}" --repo "$REPOSITORY" --clobber
|
||||||
|
else
|
||||||
|
RELEASE_OPTIONS=(--generate-notes --verify-tag)
|
||||||
|
if [[ "$VERSION" == *-* ]]; then
|
||||||
|
RELEASE_OPTIONS+=(--prerelease)
|
||||||
|
else
|
||||||
|
RELEASE_OPTIONS+=(--latest)
|
||||||
|
fi
|
||||||
|
"$GH_BIN" release create "$VERSION" "${ASSETS[@]}" \
|
||||||
|
--repo "$REPOSITORY" \
|
||||||
|
--title "Verstak $VERSION" \
|
||||||
|
"${RELEASE_OPTIONS[@]}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "GitHub release:"
|
||||||
|
"$GH_BIN" release view "$VERSION" --repo "$REPOSITORY" --json url --jq .url
|
||||||
+9
-32
@@ -10,40 +10,17 @@ if [[ -z "$VERSION" || ! "$VERSION" =~ ^[A-Za-z0-9][A-Za-z0-9._-]*$ ]]; then
|
|||||||
exit 2
|
exit 2
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if ! command -v pkg-config >/dev/null || \
|
|
||||||
(! pkg-config --exists webkit2gtk-4.1 && ! pkg-config --exists webkit2gtk-4.0); then
|
|
||||||
echo "Linux desktop releases require libwebkit2gtk-4.1-dev or libwebkit2gtk-4.0-dev." >&2
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
OFFICIAL_PLUGINS="${VERSTAK_OFFICIAL_PLUGINS_DIR:-$ROOT/../verstak-official-plugins}"
|
|
||||||
if [[ ! -d "$OFFICIAL_PLUGINS" ]]; then
|
|
||||||
echo "official plugins repository not found: $OFFICIAL_PLUGINS" >&2
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo "=== verstak desktop release $VERSION ==="
|
echo "=== verstak desktop release $VERSION ==="
|
||||||
(cd "$OFFICIAL_PLUGINS" && ./scripts/build.sh)
|
|
||||||
"$ROOT/scripts/install-dev-plugins.sh"
|
|
||||||
"$ROOT/scripts/build.sh"
|
|
||||||
|
|
||||||
BINARY="$(find "$ROOT/build/bin" -maxdepth 1 -type f -name 'verstak-desktop*' -print -quit)"
|
|
||||||
if [[ -z "$BINARY" ]]; then
|
|
||||||
echo "desktop binary was not produced in build/bin" >&2
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
RELEASE_ROOT="$ROOT/release"
|
RELEASE_ROOT="$ROOT/release"
|
||||||
STAGING="$RELEASE_ROOT/verstak-desktop-$VERSION-linux-amd64"
|
rm -rf "$RELEASE_ROOT"
|
||||||
ARCHIVE="$RELEASE_ROOT/verstak-desktop-linux-amd64-$VERSION.tar.gz"
|
mkdir -p "$RELEASE_ROOT"
|
||||||
rm -rf "$STAGING" "$ARCHIVE"
|
|
||||||
mkdir -p "$STAGING"
|
|
||||||
|
|
||||||
cp "$BINARY" "$STAGING/verstak-desktop"
|
"$ROOT/scripts/package-deb.sh" "$VERSION"
|
||||||
cp "$ROOT/README.md" "$ROOT/LICENSE" "$STAGING/"
|
"$ROOT/scripts/package-appimage.sh" "$VERSION"
|
||||||
cp -R "$ROOT/plugins" "$STAGING/plugins"
|
"$ROOT/scripts/package-windows-portable.sh" "$VERSION"
|
||||||
tar -C "$RELEASE_ROOT" -czf "$ARCHIVE" "$(basename "$STAGING")"
|
|
||||||
(cd "$RELEASE_ROOT" && sha256sum "$(basename "$ARCHIVE")" > SHA256SUMS)
|
|
||||||
|
|
||||||
echo "release archive: $ARCHIVE"
|
(cd "$RELEASE_ROOT" && find . -maxdepth 1 -type f \( -name '*.deb' -o -name '*.AppImage' -o -name '*.zip' \) \
|
||||||
|
-printf '%f\n' | LC_ALL=C sort | xargs -r sha256sum > SHA256SUMS)
|
||||||
|
|
||||||
|
echo "release assets: $RELEASE_ROOT"
|
||||||
echo "checksums: $RELEASE_ROOT/SHA256SUMS"
|
echo "checksums: $RELEASE_ROOT/SHA256SUMS"
|
||||||
|
|||||||
Executable
+21
@@ -0,0 +1,21 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
ROOT="$(cd "$(dirname "$0")/.." && pwd)"
|
||||||
|
BUILDER="$ROOT/scripts/build-windows.sh"
|
||||||
|
|
||||||
|
if [[ ! -x "$BUILDER" ]]; then
|
||||||
|
echo "Windows desktop builder is missing or not executable: $BUILDER" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
bash -n "$BUILDER"
|
||||||
|
grep -Fq -- '-platform windows/amd64' "$BUILDER"
|
||||||
|
grep -Fq 'CC="$WINDOWS_CC"' "$BUILDER"
|
||||||
|
grep -Fq 'CGO_ENABLED=1' "$BUILDER"
|
||||||
|
grep -Fq -- '-webview2 error' "$BUILDER"
|
||||||
|
grep -Fq 'dist-windows' "$BUILDER"
|
||||||
|
grep -Fq 'verstak-desktop.exe' "$BUILDER"
|
||||||
|
grep -Fq 'x86_64-w64-mingw32-gcc' "$BUILDER"
|
||||||
|
|
||||||
|
echo "Windows desktop build script contract passed"
|
||||||
Executable
+41
@@ -0,0 +1,41 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
ROOT="$(cd "$(dirname "$0")/.." && pwd)"
|
||||||
|
|
||||||
|
for script in build-linux-bundle.sh package-deb.sh package-appimage.sh package-windows-portable.sh; do
|
||||||
|
path="$ROOT/scripts/$script"
|
||||||
|
if [[ ! -x "$path" ]]; then
|
||||||
|
echo "packaging script is missing or not executable: $path" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
bash -n "$path"
|
||||||
|
done
|
||||||
|
|
||||||
|
grep -Fq 'dpkg-deb' "$ROOT/scripts/package-deb.sh"
|
||||||
|
grep -Fq -- '--build' "$ROOT/scripts/package-deb.sh"
|
||||||
|
grep -Fq 'packaging/deb/control' "$ROOT/scripts/package-deb.sh"
|
||||||
|
grep -Fq 'libwebkit2gtk-4.1-0' "$ROOT/packaging/deb/control"
|
||||||
|
grep -Fq 'appimagetool' "$ROOT/scripts/package-appimage.sh"
|
||||||
|
grep -Fq 'WebKitWebProcess' "$ROOT/scripts/package-appimage.sh"
|
||||||
|
if grep -Fq 'FixedVersionRuntime' "$ROOT/scripts/package-windows-portable.sh"; then
|
||||||
|
echo "Windows portable archive must not bundle Fixed Version WebView2" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
if grep -Fq 'msedgewebview2.exe' "$ROOT/scripts/package-windows-portable.sh"; then
|
||||||
|
echo "Windows portable archive must not bundle WebView2 binaries" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
if [[ -e "$ROOT/platform_options_windows.go" ]]; then
|
||||||
|
echo "Windows runtime override must not be present" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
grep -Fq 'zip -qr' "$ROOT/scripts/package-windows-portable.sh"
|
||||||
|
grep -Fq 'LinkId=2124701' "$ROOT/README.md"
|
||||||
|
grep -Fq 'WebView2 Runtime' "$ROOT/README.md"
|
||||||
|
grep -Fq 'package-deb.sh' "$ROOT/scripts/release.sh"
|
||||||
|
grep -Fq 'package-appimage.sh' "$ROOT/scripts/release.sh"
|
||||||
|
grep -Fq 'package-windows-portable.sh' "$ROOT/scripts/release.sh"
|
||||||
|
grep -Fq 'chmod -R a+rX' "$ROOT/scripts/build-linux-bundle.sh"
|
||||||
|
|
||||||
|
echo "desktop package script contracts passed"
|
||||||
Executable
+100
@@ -0,0 +1,100 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
ROOT="$(cd "$(dirname "$0")/.." && pwd)"
|
||||||
|
PUBLISHER="$ROOT/scripts/publish-github-release.sh"
|
||||||
|
VERSION="v0.0.0-test"
|
||||||
|
REPOSITORY="mirivlad/verstak"
|
||||||
|
ASSET_NAMES=(
|
||||||
|
"verstak_0.0.0-test_amd64.deb"
|
||||||
|
"verstak-linux-x86_64-v0.0.0-test.AppImage"
|
||||||
|
"verstak-windows-amd64-v0.0.0-test.zip"
|
||||||
|
)
|
||||||
|
WORK="$(mktemp -d)"
|
||||||
|
trap 'rm -rf "$WORK"' EXIT
|
||||||
|
|
||||||
|
if [[ ! -x "$PUBLISHER" ]]; then
|
||||||
|
echo "publisher is missing or not executable: $PUBLISHER" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
mkdir -p "$WORK/bin" "$WORK/release" "$WORK/state"
|
||||||
|
LOG="$WORK/log"
|
||||||
|
export LOG
|
||||||
|
|
||||||
|
cat > "$WORK/release.sh" <<'SCRIPT'
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
printf 'release:%s\n' "$1" >> "$LOG"
|
||||||
|
printf 'deb\n' > "$VERSTAK_RELEASE_DIR/verstak_${1#v}_amd64.deb"
|
||||||
|
printf 'appimage\n' > "$VERSTAK_RELEASE_DIR/verstak-linux-x86_64-$1.AppImage"
|
||||||
|
printf 'zip\n' > "$VERSTAK_RELEASE_DIR/verstak-windows-amd64-$1.zip"
|
||||||
|
printf 'checksum\n' > "$VERSTAK_RELEASE_DIR/SHA256SUMS"
|
||||||
|
SCRIPT
|
||||||
|
chmod +x "$WORK/release.sh"
|
||||||
|
|
||||||
|
cat > "$WORK/bin/git" <<'SCRIPT'
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
if [[ "$PWD" != "${EXPECTED_ROOT:?}" ]]; then
|
||||||
|
echo "publisher did not enter repository root: $PWD" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
case "${1:-}" in
|
||||||
|
status) exit 0 ;;
|
||||||
|
branch) echo main ;;
|
||||||
|
fetch) printf 'fetch\n' >> "$LOG" ;;
|
||||||
|
rev-parse)
|
||||||
|
if [[ "${2:-}" == "-q" ]]; then
|
||||||
|
if [[ -f "$TEST_STATE/tag" ]]; then echo test-commit; exit 0; fi
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
echo test-commit
|
||||||
|
;;
|
||||||
|
tag) touch "$TEST_STATE/tag"; printf 'tag:%s\n' "${3:-}" >> "$LOG" ;;
|
||||||
|
push) printf 'push:%s:%s\n' "${2:-}" "${3:-}" >> "$LOG" ;;
|
||||||
|
*) echo "unexpected git invocation: $*" >&2; exit 1 ;;
|
||||||
|
esac
|
||||||
|
SCRIPT
|
||||||
|
chmod +x "$WORK/bin/git"
|
||||||
|
|
||||||
|
cat > "$WORK/bin/gh" <<'SCRIPT'
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
case "${1:-}:${2:-}" in
|
||||||
|
auth:status) printf 'auth\n' >> "$LOG" ;;
|
||||||
|
release:view)
|
||||||
|
if [[ -f "$TEST_STATE/release" ]]; then echo https://github.example/release; else exit 1; fi
|
||||||
|
;;
|
||||||
|
release:create) touch "$TEST_STATE/release"; printf 'create:%s\n' "$*" >> "$LOG" ;;
|
||||||
|
release:upload) printf 'upload:%s\n' "$*" >> "$LOG" ;;
|
||||||
|
*) echo "unexpected gh invocation: $*" >&2; exit 1 ;;
|
||||||
|
esac
|
||||||
|
SCRIPT
|
||||||
|
chmod +x "$WORK/bin/gh"
|
||||||
|
|
||||||
|
run_publisher() {
|
||||||
|
VERSTAK_RELEASE_SCRIPT="$WORK/release.sh" \
|
||||||
|
VERSTAK_RELEASE_DIR="$WORK/release" \
|
||||||
|
GIT_BIN="$WORK/bin/git" \
|
||||||
|
GH_BIN="$WORK/bin/gh" \
|
||||||
|
EXPECTED_ROOT="$ROOT" \
|
||||||
|
TEST_STATE="$WORK/state" \
|
||||||
|
"$PUBLISHER" "$VERSION"
|
||||||
|
}
|
||||||
|
|
||||||
|
run_publisher
|
||||||
|
grep -Fqx "release:$VERSION" "$LOG"
|
||||||
|
grep -Fqx "tag:$VERSION" "$LOG"
|
||||||
|
grep -Fqx "push:origin:refs/tags/$VERSION" "$LOG"
|
||||||
|
grep -F "release create $VERSION" "$LOG" >/dev/null
|
||||||
|
for asset in "${ASSET_NAMES[@]}"; do
|
||||||
|
grep -F "$asset" "$LOG" >/dev/null
|
||||||
|
done
|
||||||
|
grep -F "SHA256SUMS" "$LOG" >/dev/null
|
||||||
|
grep -F -- "--prerelease" "$LOG" >/dev/null
|
||||||
|
|
||||||
|
run_publisher
|
||||||
|
grep -F "release upload $VERSION" "$LOG" >/dev/null
|
||||||
|
|
||||||
|
echo "GitHub release publisher test passed"
|
||||||
Reference in New Issue
Block a user