Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 20 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,14 +37,31 @@ Netsuke currently requires:

### Installation

To install from crates.io:
Netsuke v0.1.0 is available from crates.io:

<!-- tested-example: readme-crates-io-install -->

```sh
cargo install netsuke
```
Comment thread
leynos marked this conversation as resolved.

Pre-built installers are available from the
[v0.1.0 GitHub release](https://github.com/leynos/netsuke/releases/tag/v0.1.0):

| Platform | Architectures | Packages |
| -------- | ------------------------------------ | -------------------------------- |
| Linux | x86-64 (`amd64`) and Arm64 (`arm64`) | Debian (`.deb`) and RPM (`.rpm`) |
| macOS | Intel x86-64 and Apple silicon Arm64 | Installer package (`.pkg`) |
| Windows | x64 and Arm64 | Windows Installer (`.msi`) |

The Linux packages install the `netsuke` manual page and declare `ninja-build`
as a dependency. Ninja must be installed separately when using the macOS or
Windows installer. The Windows MSI installs to `C:\Program Files\netsuke` and
does not update `PATH`. SHA-256 checksum files accompany standalone binaries
and staged help and licence files. Installer packages do not have checksum
sidecars in v0.1.0. See the [user's guide](docs/users-guide.md#install-netsuke)
for platform-specific commands and Windows setup.

To install the current source checkout with Cargo:

<!-- tested-example: readme-source-install -->
Expand Down Expand Up @@ -110,9 +127,8 @@ The core build-system compiler is implemented:
- unit, behavioural, integration, property, snapshot, and initial Kani
verification coverage.

Release automation is configured to build packages for Linux, macOS, and
Windows, including platform help artefacts. v0.1.0 will be the first public
release of this work.
The v0.1.0 release provides packages for Linux, macOS, and Windows, including
platform help artefacts. It is the first public release of this work.

______________________________________________________________________

Expand Down
109 changes: 105 additions & 4 deletions docs/users-guide.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,44 @@ change before 1.0. Pin the Netsuke version in automated workflows.
Netsuke requires [Ninja](https://ninja-build.org/) on `PATH`. A source build
also requires Rust 1.89 or later.

To install a published release from crates.io:
Netsuke v0.1.0 is available from crates.io:

<!-- tested-example: guide-crates-io-install -->

```sh
cargo install netsuke
```

Pre-built installers are available from the
[v0.1.0 GitHub release](https://github.com/leynos/netsuke/releases/tag/v0.1.0):

| Platform | Architectures | Packages |
| -------- | ------------------------------------ | -------------------------------- |
| Linux | x86-64 (`amd64`) and Arm64 (`arm64`) | Debian (`.deb`) and RPM (`.rpm`) |
| macOS | Intel x86-64 and Apple silicon Arm64 | Installer package (`.pkg`) |
| Windows | x64 and Arm64 | Windows Installer (`.msi`) |

Download the package for the host architecture, then install it with the
platform tool. Replace `PACKAGE` with the downloaded filename:

- Debian or Ubuntu: `sudo apt install ./PACKAGE.deb`
- Fedora, Rocky Linux, or another RPM-based distribution:
`sudo dnf install ./PACKAGE.rpm`
- macOS: `sudo installer -pkg ./PACKAGE.pkg -target /`
- Windows: `msiexec.exe /i PACKAGE.msi`
Comment thread
coderabbitai[bot] marked this conversation as resolved.

The Linux packages install the binary under `/usr/bin`, add the `netsuke.1`
manual page and declare `ninja-build` as a dependency. The macOS packages
install the binary under `/usr/local/bin`, along with the manual page and
licence. Ninja must be installed separately when using the macOS or Windows
installer. The Windows MSI installs to `C:\Program Files\netsuke` and does not
update `PATH`.

SHA-256 checksum files accompany standalone binaries and staged help and
licence files. Installer packages do not have checksum sidecars in v0.1.0.
Windows PowerShell help files are published beside each MSI as sidecar
artefacts rather than embedded in the installer.

To install the current source checkout with Cargo:

<!-- tested-example: guide-source-install -->
Expand All @@ -31,9 +61,80 @@ cd netsuke
cargo install --path .
```

Release archives contain platform-specific packages and help artefacts. Unix
archives include a `netsuke.1` manual page. Windows archives include PowerShell
external help:
### Complete Windows setup

The MSI does not add its installation directory to `PATH`. Add it to the
current user's persistent `PATH`, update the current PowerShell session, then
verify that the command resolves:

<!-- tested-example: guide-windows-path -->

```powershell
$netsukeDirectory = Join-Path $env:ProgramFiles 'netsuke'
$userPath = [Environment]::GetEnvironmentVariable('Path', 'User')
$userEntries = @($userPath -split ';' | Where-Object { $_ })
if ($userEntries -notcontains $netsukeDirectory) {
$newUserPath = (($userEntries + $netsukeDirectory) -join ';')
[Environment]::SetEnvironmentVariable('Path', $newUserPath, 'User')
}
if (($env:Path -split ';') -notcontains $netsukeDirectory) {
$env:Path = "$env:Path;$netsukeDirectory"
}
netsuke --version
```

The release publishes PowerShell help separately for each Windows architecture.
The following script downloads the matching module script, manifest, Microsoft
Assistance Markup Language (MAML) help, and about-help file. It then restores
the versioned module layout under the current user's standard PowerShell module
directory and imports the module. Set `$architecture` to match the downloaded
MSI:

<!-- tested-example: guide-windows-help-install -->

```powershell
$architecture = 'amd64' # Use 'arm64' for the Arm64 MSI.
$releaseUri = 'https://api.github.com/repos/leynos/netsuke/releases/tags/v0.1.0'
$release = Invoke-RestMethod -Uri $releaseUri

$documents = [Environment]::GetFolderPath('MyDocuments')
$editionDirectory = if ($PSVersionTable.PSEdition -eq 'Desktop') {
'WindowsPowerShell'
} else {
'PowerShell'
}
$moduleRoot = Join-Path $documents "$editionDirectory\Modules"
$moduleDirectory = Join-Path $moduleRoot 'Netsuke\0.1.0'
$helpDirectory = Join-Path $moduleDirectory 'en-US'
New-Item -ItemType Directory -Path $helpDirectory -Force | Out-Null

$patterns = @{
'Netsuke.psm1' = '*Netsuke.psm1'
'Netsuke.psd1' = '*Netsuke.psd1'
'Netsuke-help.xml' = '*en-US-Netsuke-help.xml'
'about_Netsuke.help.txt' = '*en-US-about_Netsuke.help.txt'
}
$localizedFiles = @('Netsuke-help.xml', 'about_Netsuke.help.txt')
foreach ($fileName in $patterns.Keys) {
$pattern = "*windows-$architecture*$($patterns[$fileName])"
$asset = $release.assets | Where-Object { $_.name -like $pattern } | Select-Object -First 1
if ($null -eq $asset) {
throw "Release asset not found: $pattern"
}
$destinationDirectory = if ($localizedFiles -contains $fileName) {
$helpDirectory
} else {
$moduleDirectory
}
$destination = Join-Path $destinationDirectory $fileName
Invoke-WebRequest -Uri $asset.browser_download_url -OutFile $destination -UseBasicParsing
}

Import-Module (Join-Path $moduleDirectory 'Netsuke.psd1') -Force
Comment thread
leynos marked this conversation as resolved.
```

The versioned directory is discoverable in later PowerShell sessions. After the
import, inspect the external help with:

<!-- tested-example: guide-windows-help -->

Expand Down
61 changes: 46 additions & 15 deletions tests/documentation_examples_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ const EXPECTED_EXAMPLE_IDS: &[&str] = &[
"guide-source-install",
"guide-utility-commands",
"guide-windows-help",
"guide-windows-help-install",
"guide-windows-path",
"readme-crates-io-install",
"readme-first-build-commands",
"readme-first-build-manifest",
Expand Down Expand Up @@ -153,15 +155,26 @@ fn installation_examples_match_source_and_release_contracts() -> Result<()> {
let readme_release = documented_example("readme-crates-io-install")?;
let guide_release = documented_example("guide-crates-io-install")?;
let expected_release = "cargo install netsuke\n";
ensure!(
readme_release.body == expected_release,
"README crates.io install drifted"
);
ensure!(
guide_release.body == expected_release,
"user's guide crates.io install drifted"
);

ensure!(readme_release.body == expected_release, "README drifted");
ensure!(guide_release.body == expected_release, "user guide drifted");
let expected_release_details = [
"https://github.com/leynos/netsuke/releases/tag/v0.1.0",
"Debian (`.deb`) and RPM (`.rpm`)",
"Installer package (`.pkg`)",
"Windows Installer (`.msi`)",
"x86-64 (`amd64`) and Arm64 (`arm64`)",
"Installer packages do not have checksum",
"The Windows MSI installs to `C:\\Program Files\\netsuke`",
];
for path in ["README.md", "docs/users-guide.md"] {
let document = test_fs::read_to_string(path).with_context(|| format!("read {path}"))?;
for expected in expected_release_details {
ensure!(
document.contains(expected),
"{path} should document v0.1.0 release detail: {expected}"
);
}
}
let readme = documented_example("readme-source-install")?;
let guide = documented_example("guide-source-install")?;
let expected = concat!(
Expand All @@ -170,15 +183,33 @@ fn installation_examples_match_source_and_release_contracts() -> Result<()> {
"cargo install --path .\n"
);
ensure!(readme.body == expected, "README source install drifted");
ensure!(guide.body == expected, "user guide source install drifted");
let windows = documented_example("guide-windows-help")?;
ensure!(windows.body == "Get-Help Netsuke -Full\n", "help drifted");
let windows_path = documented_example("guide-windows-path")?;
let windows_path_fragments = [
"SetEnvironmentVariable",
"$netsukeDirectory",
"SetEnvironmentVariable('Path', $newUserPath, 'User')",
];
ensure!(
guide.body == expected,
"user's guide source install drifted"
windows_path_fragments
.into_iter()
.all(|fragment| windows_path.body.contains(fragment)),
"Windows PATH setup should persist the MSI installation directory"
);

let windows = documented_example("guide-windows-help")?;
let windows_help_install = documented_example("guide-windows-help-install")?;
let windows_help_fragments = [
"Import-Module",
"$moduleDirectory = Join-Path $moduleRoot 'Netsuke\\0.1.0'",
"Import-Module (Join-Path $moduleDirectory 'Netsuke.psd1')",
"*windows-$architecture*",
];
ensure!(
windows.body == "Get-Help Netsuke -Full\n",
"PowerShell help command drifted"
windows_help_fragments
.into_iter()
.all(|fragment| windows_help_install.body.contains(fragment)),
"Windows help setup should import the downloaded sidecars"
);
Comment on lines +189 to +213

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Assert the Windows setup contract, not only method names.

contains("SetEnvironmentVariable") passes even if the script updates the wrong variable or scope, and contains("Import-Module") passes even if it imports the wrong path. Assert critical fragments such as 'Path', 'User', $netsukeDirectory, the versioned Netsuke.psd1 path, and architecture-aware asset selection.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/documentation_examples_tests.rs` around lines 204 - 213, Strengthen the
assertions in the documentation test around documented_example for
guide-windows-path and guide-windows-help-install: verify the Windows PATH
script targets the Path variable at User scope and uses $netsukeDirectory, and
verify the help script imports the versioned Netsuke.psd1 path while selecting
architecture-aware assets. Keep the existing method-name checks, but add
assertions for these critical fragments.

let staging = test_fs::read_to_string(".github/release-staging.toml")
.context("read release staging configuration")?;
Expand Down
Loading