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
66 changes: 21 additions & 45 deletions .azure/pipelines/build-bravo.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,11 @@ strategy:
bravo-x64:
arch: 'x64'
selfcontained: 'true'
artifact: 'Bravo.$(AppVersionMajor).$(AppVersionMinor).$(AppVersionPatch).x64'
artifactSuffix: 'x64'
bravo-x64-frameworkdependent:
arch: 'x64'
selfcontained: 'false'
artifact: 'Bravo.$(AppVersionMajor).$(AppVersionMinor).$(AppVersionPatch).x64-frameworkdependent'
artifactSuffix: 'x64-frameworkdependent'

pool:
vmImage: 'windows-latest'
Expand All @@ -31,52 +31,28 @@ variables:
installerSourcesDirectory: '$(Build.SourcesDirectory)\installer\wix\src\Bravo'

steps:
- task: PowerShell@2
displayName: 'Set variables'
- checkout: self
fetchDepth: 0 # Required for NBGV
fetchTags: false
clean: true
- task: UseDotNet@2
displayName: Setup DotNet
inputs:
targetType: 'inline'
script: |
Write-Host "Computing variables..."
$url = "$(system.CollectionUri)$(system.TeamProjectId)/_apis/build/builds/$(Build.BuildId)?api-version=5.1"
$build = Invoke-RestMethod -Uri $url -Headers @{ Authorization = "Bearer $env:SYSTEM_ACCESSTOKEN" } -Method Get
$buildTime = [datetime]$build.startTime
$buildNumberRevision = $build.buildNumberRevision
$midnightTime = (Get-Date -Year $buildTime.Year -Month $buildTime.Month -Day $buildTime.Day -Hour 0 -Minute 0 -Second 0 -Millisecond 0)
# Build Number - number of days since 2000-01-01 (same algorithm as msbuild)
$versionBuild = (New-TimeSpan –Start ([datetime]"2000-01-01") –End $buildTime).Days
# Revision - number of seconds since midnight divided by 2 (same algorithm as msbuild)
$versionRevision = [math]::Round((New-TimeSpan –Start $midnightTime –End $buildTime).TotalSeconds / 2)
$buildNumber = '{0:yyyyMMdd}.{1}' -f $buildTime, $buildNumberRevision
$versionNumber = '{0}.{1}.{2}.{3}' -f "$(AppVersionMajor)", "$(AppVersionMinor)", $versionBuild, $versionRevision
Write-Host "Setting output variables..."
Write-Host "##vso[task.setvariable variable=AppBuildNumber;]$buildNumber"
Write-Host "##vso[task.setvariable variable=AppVersionNumber;]$versionNumber"
Write-Host "BuildNumber is $buildNumber"
Write-Host "VersionNumber is $versionNumber"
env:
SYSTEM_ACCESSTOKEN: $(System.AccessToken)
- task: Assembly-Info-NetCore@3
displayName: 'Update AssemblyInfo'
inputs:
Path: '$(Build.SourcesDirectory)'
FileNames: 'src\Bravo.csproj'
InsertAttributes: true
FileEncoding: 'auto'
WriteBOM: false
VersionNumber: '$(AppVersionNumber)'
InformationalVersion: '$(AppVersionInformationalVersion)'
UpdateBuildNumber: '$(AppBuildNumber)-$(AppVersionNumber)'
LogLevel: 'verbose'
FailOnWarning: true
DisableTelemetry: true
- script: dotnet --info
displayName: dotnet info
packageType: sdk
useGlobalJson: true
- script: nbgv cloud --all-vars
displayName: Setup NBGV
- script: dotnet tool install --global AzureSignTool
displayName: Setup AzureSignTool
- bash: |
artifact="Bravo.$(NBGV_SimpleVersion).$(artifactSuffix)"
echo "##vso[task.setvariable variable=artifact]$artifact"
echo "Artifact name: $artifact"
displayName: 'Compute variables'
- script: dotnet restore "$(csproj)" --runtime "win-$(arch)" --verbosity "${{ parameters.verbosity }}"
displayName: dotnet restore
- script: dotnet publish "$(csproj)" --configuration "$(configuration)" --no-restore --runtime "win-$(arch)" --self-contained "$(selfcontained)" --output "$(Build.BinariesDirectory)" --verbosity "${{ parameters.verbosity }}" /p:ContinuousIntegrationBuild="true"
displayName: dotnet publish
- script: dotnet tool install --global AzureSignTool
displayName: dotnet install AzureSignTool
- task: CmdLine@2
displayName: 'Code signing EXE'
inputs:
Expand All @@ -97,13 +73,13 @@ steps:
- task: CmdLine@2
displayName: 'WiX compile app'
inputs:
script: '"%WIX%bin\candle.exe" Bravo.wxs -dPublishFolder="$(Build.BinariesDirectory)" -dVersion="$(AppVersionInformationalVersion)" -arch "$(arch)"'
script: '"%WIX%bin\candle.exe" Bravo.wxs -dPublishFolder="$(Build.BinariesDirectory)" -dVersion="$(NBGV_SimpleVersion)" -arch "$(arch)"'
workingDirectory: '$(installerSourcesDirectory)'
failOnStderr: true
- task: CmdLine@2
displayName: 'WiX compile app (perUser)'
inputs:
script: '"%WIX%bin\candle.exe" Bravo-perUser.wxs -dPublishFolder="$(Build.BinariesDirectory)" -dVersion="$(AppVersionInformationalVersion)" -arch "$(arch)"'
script: '"%WIX%bin\candle.exe" Bravo-perUser.wxs -dPublishFolder="$(Build.BinariesDirectory)" -dVersion="$(NBGV_SimpleVersion)" -arch "$(arch)"'
workingDirectory: '$(installerSourcesDirectory)'
failOnStderr: true
- task: CmdLine@2
Expand Down
2 changes: 2 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ jobs:
steps:
- name: checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: setup dotnet SDK
uses: actions/setup-dotnet@v4
with:
Expand Down
4 changes: 2 additions & 2 deletions Bravo.sln
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.0.32014.148
# Visual Studio Version 18
VisualStudioVersion = 18.7.11903.348 stable
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Bravo", "src\Bravo.csproj", "{3D49664E-E100-4EFF-A709-A59D03F4663E}"
EndProject
Expand Down
2 changes: 1 addition & 1 deletion global.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"sdk": {
"version": "8.0.200",
"version": "10.0.300",
"allowPrerelease": false,
"rollForward": "latestFeature"
}
Expand Down
8 changes: 1 addition & 7 deletions src/Bravo.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@
<IsPublishable>true</IsPublishable>
<SatelliteResourceLanguages>en-US</SatelliteResourceLanguages>
<ApplicationHighDpiMode>PerMonitorV2</ApplicationHighDpiMode>
<IncludeSourceRevisionInInformationalVersion>false</IncludeSourceRevisionInInformationalVersion>
<RestorePackagesWithLockFile>true</RestorePackagesWithLockFile>
</PropertyGroup>

Expand All @@ -34,12 +33,6 @@
<DefineConstants>$(DefineConstants);PUBLISHMODE_SELFCONTAINED</DefineConstants>
</PropertyGroup>

<PropertyGroup>
<!-- Don't change version here -->
<Version>0.0.0.999</Version>
<InformationalVersion>0.0.0.999-DEV</InformationalVersion>
</PropertyGroup>

<ItemGroup>
<AssemblyAttribute Include="System.Runtime.CompilerServices.InternalsVisibleTo">
<_Parameter1>$(AssemblyName).Tests</_Parameter1>
Expand All @@ -59,6 +52,7 @@
<PackageReference Include="Microsoft.ApplicationInsights" Version="2.23.0" />
<PackageReference Include="Microsoft.Web.WebView2" Version="1.0.2739.15" />
<PackageReference Include="Microsoft.Identity.Client.Desktop" Version="4.73.1" />
<PackageReference Include="Nerdbank.GitVersioning" Version="3.10.85" PrivateAssets="all" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="7.0.0" PrivateAssets="all" />
<PackageReference Include="System.CommandLine" Version="2.0.0-beta4.22272.1" />
<PackageReference Include="System.Management" Version="7.0.0" />
Expand Down
20 changes: 3 additions & 17 deletions src/Infrastructure/AppEnvironment.cs
Original file line number Diff line number Diff line change
Expand Up @@ -83,13 +83,8 @@ static AppEnvironment()
ProcessId = Environment.ProcessId;
SessionId = currentProcess.SessionId;
ProcessPath = Environment.ProcessPath!;

VersionInfo = FileVersionInfo.GetVersionInfo(ProcessPath);
BravoUnexpectedException.ThrowIfNull(VersionInfo.FileVersion);
ApplicationFileVersion = VersionInfo.FileVersion;
BravoUnexpectedException.ThrowIfNull(VersionInfo.ProductVersion);
ApplicationProductVersion = VersionInfo.ProductVersion;

VersionInfo = new AppVersionInfo();
ApplicationDataPath = Path.Combine(Environment.GetFolderPath(DeploymentMode == AppDeploymentMode.Packaged ? Environment.SpecialFolder.UserProfile : Environment.SpecialFolder.LocalApplicationData, Environment.SpecialFolderOption.DoNotVerify), ApplicationName);
ApplicationTempPath = Path.Combine(ApplicationDataPath, ".temp");
UserSettingsFilePath = Path.Combine(ApplicationDataPath, "usersettings.json");
Expand All @@ -112,9 +107,6 @@ static AppEnvironment()

public static string ProcessPath { get; }

// TODO: use custom defined constant to identify a stable release. See PublishMode property and "AdditionalConstants" in csproj
public static bool IsStableRelease => Version.TryParse(ApplicationProductVersion, out _);

public static AppPublishMode PublishMode
{
get
Expand Down Expand Up @@ -147,9 +139,7 @@ public static RegistryKey? ApplicationInstallerRegistryHKey
}
}

public static string ApplicationFileVersion { get; }

public static string ApplicationProductVersion { get; }
public static AppVersionInfo VersionInfo { get; }

public static JsonSerializerOptions DefaultJsonOptions { get; }

Expand All @@ -161,8 +151,6 @@ public static RegistryKey? ApplicationInstallerRegistryHKey

public static string MsalTokenCacheFilePath { get; }

public static FileVersionInfo VersionInfo { get; }

public static string? WebView2VersionInfo { get; }

public static bool IsWebView2RuntimeInstalled => WebView2VersionInfo is not null;
Expand Down Expand Up @@ -206,12 +194,10 @@ private static void AddEnvironmentDiagnosticInfo()
//
ApplicationPublishMode = PublishMode.ToString(),
ApplicationDeploymentMode = DeploymentMode.ToString(),
ApplicationFileVersion,
ApplicationProductVersion,
ApplicationVersion = VersionInfo.InformationalVersion,
ApplicationDataPath,
ApplicationTempPath,
ApplicationUserSettingsFilePath = UserSettingsFilePath,
//ApplicationFileVersionInfo = VersionInfo,
};

AddDiagnostics(DiagnosticMessageType.Json, name: $"{nameof(AppEnvironment)}.EnvironmentInfo", content: JsonSerializer.Serialize(info));
Expand Down
36 changes: 36 additions & 0 deletions src/Infrastructure/AppVersionInfo.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
namespace Sqlbi.Bravo.Infrastructure
{
/// <summary>
/// Exposes the application version, stamped at build time by Nerdbank.GitVersioning from version.json.
/// </summary>
internal sealed class AppVersionInfo
{
public AppVersionInfo()
{
var build = ThisAssembly.AssemblyFileVersion;

Build = build;
Version = System.Version.Parse(build).ToString(3);
InformationalVersion = ThisAssembly.AssemblyInformationalVersion;
}

/// <summary>
/// Gets the full four-part assembly file version <c>Major.Minor.Patch.Height</c>, where the fourth field is the
/// git-height build counter. Intended for diagnostics only (e.g. telemetry) - never used for update comparisons
/// or shown to users; use <see cref="Version"/> instead.
/// </summary>
public string Build { get; }

/// <summary>
/// Gets the three-part Semantic Version <c>Major.Minor.Patch</c>. This is the canonical application version:
/// shown to users and used to compare versions when checking for updates.
/// </summary>
public string Version { get; }

/// <summary>
/// Gets the informational version: the version with build metadata (the git commit id) appended,
/// e.g. <c>1.2.3.45+0a1b2c3d4e</c>. Intended for diagnostics.
/// </summary>
public string InformationalVersion { get; }
}
}
7 changes: 2 additions & 5 deletions src/Infrastructure/AppWindow.cs
Original file line number Diff line number Diff line change
Expand Up @@ -134,9 +134,7 @@ private async void InitializeWebViewAsync()
/* ICoreWebView2_3 */ WebView.CoreWebView2.SetVirtualHostNameToFolderMapping("bravo.example", "wwwroot", CoreWebView2HostResourceAccessKind.Allow);
/* ICoreWebView2 */ WebView.CoreWebView2.Navigate("https://bravo.example/index.html");

// Allow users to open the DevTools for troubleshooting; this is only available in non-stable releases
if (!AppEnvironment.IsStableRelease && CommonHelper.IsKeyDown(System.Windows.Forms.Keys.ShiftKey))
WebView.CoreWebView2.OpenDevToolsWindow();
// TODO: Consider allowing users to open DevTools for troubleshooting (e.g. by pressing F12 or via a context menu)
}

protected override void WndProc(ref Message message)
Expand Down Expand Up @@ -307,8 +305,7 @@ private MemoryStream GetConfigJs()
#endif
address = _serverAddressProvider.GetListeningAddress(),
token = AppEnvironment.ApiAuthenticationToken,
version = AppEnvironment.ApplicationProductVersion,
build = AppEnvironment.ApplicationFileVersion,
version = AppEnvironment.VersionInfo.Version,
options = BravoOptions.CreateFromUserPreferences(),
policies = BravoPolicies.Current,
culture = new
Expand Down
12 changes: 1 addition & 11 deletions src/Infrastructure/Extensions/StringExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,17 +17,7 @@ internal static class StringExtensions

public static string AppendApplicationVersion(this string value)
{
var valueAndVersion = $"{value} - v{GetVersionParts(AppEnvironment.ApplicationProductVersion, parts: 4)}";
return valueAndVersion;
}

public static string GetVersionParts(this string? version, int parts)
{
if (version.IsNullOrWhiteSpace())
return string.Empty;

var versionParts = string.Join('-', version.Split('-').Take(parts));
return versionParts;
return $"{value} - v{AppEnvironment.VersionInfo.Version}";
}

/// <summary>
Expand Down
38 changes: 16 additions & 22 deletions src/Infrastructure/Helpers/CommonHelper.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
namespace Sqlbi.Bravo.Infrastructure.Helpers
{
using Sqlbi.Bravo.Infrastructure.Configuration;
using Sqlbi.Bravo.Infrastructure.Configuration.Settings;
using Sqlbi.Bravo.Infrastructure.Extensions;
using Sqlbi.Bravo.Infrastructure.Windows.Interop;
Expand Down Expand Up @@ -104,36 +103,31 @@ public async static Task<BravoUpdate> CheckForUpdateAsync(UpdateChannelType upda
var requestUri = $"https://bravorelease.blob.core.windows.net/{ channelPath }/currentversion.json?nocache={ DateTimeOffset.Now.ToUnixTimeSeconds() }";
var json = await httpClient.GetStringAsync(requestUri, cancellationToken).ConfigureAwait(false);

AppEnvironment.AddDiagnostics(DiagnosticMessageType.Json, name: $"{nameof(CommonHelper)}.{nameof(CheckForUpdateAsync)}", content: json);

using var document = JsonDocument.Parse(json);
var rootElement = document.RootElement;

var version = Version.Parse(rootElement.GetProperty("version").GetString()!)
.ToString(3); // Versioning is SemVer-based: discard a 4th (build) digit if present
var isNewerVersion = Version.Parse(version) > Version.Parse(AppEnvironment.VersionInfo.Version);
var downloadUrl = GetDownloadUrl(rootElement.GetProperty("download").GetString()!);
var changelogUrl = rootElement.GetProperty("changelog").GetString()!;

var bravoUpdate = new BravoUpdate
return new BravoUpdate
{
UpdateChannel = updateChannel,
InstalledVersion = AppEnvironment.ApplicationFileVersion,
CurrentVersion = document.RootElement.GetProperty("version").GetString(),
DownloadUrl = document.RootElement.GetProperty("download").GetString(),
ChangelogUrl = document.RootElement.GetProperty("changelog").GetString(),
IsNewerVersion = isNewerVersion,
Version = version,
DownloadUrl = downloadUrl,
ChangelogUrl = changelogUrl,
};

bravoUpdate.IsNewerVersion = GetIsNewerVersion(bravoUpdate);
bravoUpdate.DownloadUrl = GetDownloadUrl(bravoUpdate);

AppEnvironment.AddDiagnostics(DiagnosticMessageType.Json, name: $"{nameof(CommonHelper)}.{nameof(CheckForUpdateAsync)}", content: JsonSerializer.Serialize(bravoUpdate));
return bravoUpdate;

static bool GetIsNewerVersion(BravoUpdate bravoUpdate)
{
var installedVersion = Version.Parse(bravoUpdate.InstalledVersion!);
var currentVersion = Version.Parse(bravoUpdate.CurrentVersion!);

return currentVersion > installedVersion;
}

static string GetDownloadUrl(BravoUpdate bravoUpdate)
static string GetDownloadUrl(string downloadUrl)
{
BravoUnexpectedException.Assert(AppEnvironment.DeploymentMode != AppDeploymentMode.Packaged);

var downloadUri = new Uri(bravoUpdate.DownloadUrl!, UriKind.Absolute);
var downloadUri = new Uri(downloadUrl, UriKind.Absolute);
var downloadFileNameWithoutExtension = Path.GetFileNameWithoutExtension(downloadUri.LocalPath);
var downloadFileExtension = Path.GetExtension(downloadUri.LocalPath);
var downloadFileName = Path.GetFileName(downloadUri.LocalPath);
Expand Down
6 changes: 3 additions & 3 deletions src/Infrastructure/Helpers/VpaxHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -56,12 +56,12 @@
{
var server = connectionWrapper.Server;
var database = connectionWrapper.Database;
var daxModel = TomExtractor.GetDaxModel(database.Model, extractorApp: AppEnvironment.ApplicationName, extractorVersion: AppEnvironment.ApplicationProductVersion);
var daxModel = TomExtractor.GetDaxModel(database.Model, extractorApp: AppEnvironment.ApplicationName, extractorVersion: AppEnvironment.VersionInfo.Version);

using var connection = connectionWrapper.CreateAdomdConnection(open: false);
{
cancellationToken.ThrowIfCancellationRequested();
DmvExtractor.PopulateFromDmv(daxModel, connection, server.Name, database.Name, extractorApp: AppEnvironment.ApplicationName, extractorVersion: AppEnvironment.ApplicationProductVersion);
DmvExtractor.PopulateFromDmv(daxModel, connection, server.Name, database.Name, extractorApp: AppEnvironment.ApplicationName, extractorVersion: AppEnvironment.VersionInfo.Version);

if (statisticsEnabled)
{
Expand All @@ -71,12 +71,12 @@
var referentialIntegrityViolationSampleRows = 0; // RI violation sampling is not required for model analysis in Bravo nor for VPAX export.

cancellationToken.ThrowIfCancellationRequested();
StatExtractor.UpdateStatisticsModel(daxModel, connection, referentialIntegrityViolationSampleRows, analyzeDirectQuery, analyzeDirectLake); // TOFIX: remove deprecated (requires refactoring VertiPaqAnalyzer APIs)

Check warning on line 74 in src/Infrastructure/Helpers/VpaxHelper.cs

View workflow job for this annotation

GitHub Actions / build-and-test

'StatExtractor.UpdateStatisticsModel(Model, IDbConnection, int, bool, DirectLakeExtractionMode, int)' is obsolete: 'This method may produce incomplete results if used on a model with DirectLake partitions and DirectLakeExtractionMode parameter set to anything other than ResidentOnly. Use TomExtractor.GetDaxModel instead.'

if (analyzeDirectLake > DirectLakeExtractionMode.ResidentOnly && daxModel.HasDirectLakePartitions())
{
cancellationToken.ThrowIfCancellationRequested();
DmvExtractor.PopulateFromDmv(daxModel, connection, server.Name, database.Name, extractorApp: AppEnvironment.ApplicationName, extractorVersion: AppEnvironment.ApplicationProductVersion);
DmvExtractor.PopulateFromDmv(daxModel, connection, server.Name, database.Name, extractorApp: AppEnvironment.ApplicationName, extractorVersion: AppEnvironment.VersionInfo.Version);
}
}
}
Expand Down
Loading
Loading