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
19 changes: 17 additions & 2 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ jobs:
run: dotnet restore .\src\Adomd.Cli\Adomd.Cli.csproj

- name: Publish win-x64 executable
run: dotnet publish .\src\Adomd.Cli\Adomd.Cli.csproj --configuration Release --runtime win-x64 --self-contained true --output .\artifacts\publish\win-x64 -p:PublishSingleFile=true -p:IncludeNativeLibrariesForSelfExtract=true -p:DebugType=None -p:DebugSymbols=false -p:Version=${{ env.PACKAGE_VERSION }} -p:PackageVersion=${{ env.PACKAGE_VERSION }}
run: dotnet publish .\src\Adomd.Cli\Adomd.Cli.csproj --configuration Release --runtime win-x64 --self-contained true --output .\artifacts\publish\win-x64 -p:PublishSingleFile=true -p:PublishReadyToRun=true -p:IncludeNativeLibrariesForSelfExtract=true -p:DebugType=None -p:DebugSymbols=false -p:Version=${{ env.PACKAGE_VERSION }} -p:PackageVersion=${{ env.PACKAGE_VERSION }}

- name: Archive win-x64 executable
shell: pwsh
Expand All @@ -58,6 +58,21 @@ jobs:
$hash = Get-FileHash -Path .\artifacts\adomd-cli-win-x64.zip -Algorithm SHA256
"$($hash.Hash.ToLowerInvariant()) adomd-cli-win-x64.zip" | Out-File -FilePath .\artifacts\adomd-cli-win-x64.zip.sha256 -Encoding ascii -NoNewline

- name: Extract release notes
shell: pwsh
run: |
$version = $env:PACKAGE_VERSION
$changelog = Get-Content .\CHANGELOG.md -Raw
# Grab the body of the section for this version, up to the next "## [" heading.
$pattern = "(?ms)^##\s*\[$([regex]::Escape($version))\].*?$("`n")(.*?)(?=^##\s*\[|\z)"
$match = [regex]::Match($changelog, $pattern)
if ($match.Success) {
$notes = $match.Groups[1].Value.Trim()
} else {
$notes = "Release v$version"
}
Set-Content -Path .\artifacts\release-notes.md -Value $notes -Encoding utf8

- name: Upload executable artifact
uses: actions/upload-artifact@v7
with:
Expand All @@ -72,4 +87,4 @@ jobs:
env:
GH_TOKEN: ${{ github.token }}
run: |
gh release create $env:GITHUB_REF_NAME ./artifacts/adomd-cli-win-x64.zip ./artifacts/adomd-cli-win-x64.zip.sha256 --title $env:GITHUB_REF_NAME --notes "Release $env:GITHUB_REF_NAME" --verify-tag
gh release create $env:GITHUB_REF_NAME ./artifacts/adomd-cli-win-x64.zip ./artifacts/adomd-cli-win-x64.zip.sha256 --title $env:GITHUB_REF_NAME --notes-file ./artifacts/release-notes.md --verify-tag
14 changes: 14 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,20 @@

All notable changes to this project are documented in this file.

## [0.2.1]

### Added
- `--compact` option on all commands to emit single-line (unindented) JSON for piping into line-based tools.
- `schema` now reports a top-level `partial` flag and a `warnings` array when one or more schema rowsets fail, instead of only signalling failure inside individual rows.

### Changed
- UTF-8 is now forced for console output so non-ASCII catalog, dimension, and measure names/values are emitted and parsed correctly regardless of the host code page.
- When a `schema` rowset fails, the error is now reported via top-level `warnings` and per-rowset `error`/`exception` fields rather than as a synthetic data row inside `rows`.
- Release builds now use ReadyToRun for faster startup, and the GitHub Release notes are populated from the matching `CHANGELOG.md` section.

### Fixed
- Corrected a stale hard-coded version fallback used when the assembly informational version attribute is unavailable.

## [0.2.0]

### Added
Expand Down
5 changes: 5 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ dotnet run --project src\Adomd.Cli -- query --connection-string "<connection str
| `--retries <n>` | Number of times to retry opening the connection after a transient failure; default `0` |
| `--retry-delay-ms <ms>` | Delay between connection retry attempts; default `1000` |
| `--rowset <guid>` | `schema` only, repeatable; fetch additional schema rowsets by GUID beyond the built-in six |
| `--compact` | Emit single-line (unindented) JSON, friendlier for piping into line-based tools |

Retries only cover opening the connection (useful for Azure AS auto-resume/auto-scale delays); they do not retry a failed query execution. Retry waits are interruptible with Ctrl+C.

Expand Down Expand Up @@ -120,6 +121,10 @@ Every row-returning field (`catalogs`, `cubes`, `dimensions`, `hierarchies`, `le

`query`/`dmv` can return more than one entry in `resultSets` when a batch produces multiple result sets.

If a `schema` rowset can't be read (for example, a rowset that isn't supported on the target model), `schema` reports `"partial": true` and lists the failures in a top-level `warnings` array, and the affected rowset object carries its own `error`/`exception` fields. The other rowsets are still returned.

By default JSON is pretty-printed; pass `--compact` to emit it on a single line for piping into tools like `jq`.

Errors produce `{ "ok": false, "error": ..., "exception": ..., "inner": ... }` and a non-zero exit code: `2` for a general failure, `130` if the command was cancelled (e.g. Ctrl+C). Credential-bearing fragments (`password=`, `pwd=`, `secret=`, `client secret=`, `access token=`) are redacted from `error`/`inner` and stderr before they're written, in case an ADOMD/OLE DB provider echoes the connection string back in an exception message.

## CI/CD
Expand Down
63 changes: 63 additions & 0 deletions src/Adomd.Cli.Tests/BuildConnectionStringTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
[Collection("EnvironmentSensitive")]
public class BuildConnectionStringTests
{
[Fact]
public void ExplicitConnectionString_TakesPrecedence()
{
var settings = new CommonSettings
{
ConnectionString = "Data Source=explicit;Integrated Security=SSPI",
Server = "ignored"
};

var result = AnalysisServices.BuildConnectionString(settings);

Assert.Equal("Data Source=explicit;Integrated Security=SSPI", result);
}

[Fact]
public void ComposesSspiString_FromServerAndTimeout()
{
var settings = new CommonSettings
{
Server = "FinHubAS",
ConnectTimeoutSeconds = 30
};

var result = AnalysisServices.BuildConnectionString(settings);

Assert.Equal("Data Source=FinHubAS;Integrated Security=SSPI;Connect Timeout=30", result);
}

[Fact]
public void IncludesInitialCatalog_WhenCatalogProvided()
{
var settings = new CommonSettings
{
Server = "FinHubAS",
Catalog = "KPILakeRevenue",
ConnectTimeoutSeconds = 15
};

var result = AnalysisServices.BuildConnectionString(settings);

Assert.Contains("Data Source=FinHubAS", result);
Assert.Contains("Integrated Security=SSPI", result);
Assert.Contains("Connect Timeout=15", result);
Assert.Contains("Initial Catalog=KPILakeRevenue", result);
}

[Fact]
public void OmitsInitialCatalog_WhenCatalogMissing()
{
var settings = new CommonSettings
{
Server = "FinHubAS",
ConnectTimeoutSeconds = 15
};

var result = AnalysisServices.BuildConnectionString(settings);

Assert.DoesNotContain("Initial Catalog", result);
}
}
1 change: 1 addition & 0 deletions src/Adomd.Cli.Tests/CommonSettingsTests.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
[Collection("EnvironmentSensitive")]
public class CommonSettingsTests
{
private const string EnvVarName = "ADOMD_CONNECTION_STRING";
Expand Down
4 changes: 4 additions & 0 deletions src/Adomd.Cli.Tests/EnvironmentSensitiveCollection.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
using Xunit;

[CollectionDefinition("EnvironmentSensitive", DisableParallelization = true)]
public sealed class EnvironmentSensitiveCollection;
27 changes: 23 additions & 4 deletions src/Adomd.Cli.Tests/RowsetResultTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -54,14 +54,33 @@ public void ToJson_ExposesRowCountAndTruncatedFlag()
}

[Fact]
public void Error_WrapsExceptionDetailsAsASingleRow()
public void Error_CarriesExceptionDetailsAndFlagsIsError()
{
var result = RowsetResult.Error(new InvalidOperationException("boom"));

Assert.False(result.Truncated);
Assert.Single(result.Rows);
Assert.Equal("boom", result.Rows[0]["error"]);
Assert.Equal(typeof(InvalidOperationException).FullName, result.Rows[0]["exception"]);
Assert.Empty(result.Rows);
Assert.True(result.IsError);
Assert.Equal("boom", result.ErrorMessage);
Assert.Equal(typeof(InvalidOperationException).FullName, result.ErrorType);
}

[Fact]
public void ToJson_IncludesErrorFields_WhenErrored()
{
dynamic json = RowsetResult.Error(new InvalidOperationException("boom")).ToJson();

Assert.Equal("boom", json.error);
Assert.Equal(typeof(InvalidOperationException).FullName, json.exception);
}

[Fact]
public void IsError_False_ForNormalResult()
{
var result = new RowsetResult { Rows = [], Truncated = false };

Assert.False(result.IsError);
Assert.Null(result.ErrorMessage);
}

private static DataTable CreateTable(int rowCount)
Expand Down
2 changes: 1 addition & 1 deletion src/Adomd.Cli/Adomd.Cli.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
<OutputType>Exe</OutputType>
<TargetFramework>net10.0</TargetFramework>
<AssemblyName>adomd</AssemblyName>
<VersionPrefix>0.2.0</VersionPrefix>
<VersionPrefix>0.2.1</VersionPrefix>
<Authors>sbroenne</Authors>
<Description>JSON-first command-line wrapper for querying Analysis Services through ADOMD.NET.</Description>
<PackageProjectUrl>https://github.com/sbroenne/adomd-cli</PackageProjectUrl>
Expand Down
Loading
Loading