瀏覽代碼

Merge pull request #468 from PixiEditor/auto-send-crash-report

Send crash reports automatically
Krzysztof Krysiński 2 年之前
父節點
當前提交
ef36a13717

+ 2 - 0
src/PixiEditor.Builder/build.ps1

@@ -0,0 +1,2 @@
+dotnet run --project build/PixiEditor.Builder.csproj -- $args
+exit $LASTEXITCODE;

+ 1 - 0
src/PixiEditor.Builder/build.sh

@@ -0,0 +1 @@
+dotnet run --project ./build/PixiEditor.Builder.csproj -- "$@"

+ 12 - 0
src/PixiEditor.Builder/build/PixiEditor.Builder.csproj

@@ -0,0 +1,12 @@
+<Project Sdk="Microsoft.NET.Sdk">
+    <PropertyGroup>
+        <OutputType>Exe</OutputType>
+        <TargetFramework>net7.0</TargetFramework>
+        <RunWorkingDirectory>$(MSBuildProjectDirectory)</RunWorkingDirectory>
+        <AssemblyName>PixiEditor.Builder</AssemblyName>
+        <RootNamespace>PixiEditor.Builder</RootNamespace>
+    </PropertyGroup>
+    <ItemGroup>
+        <PackageReference Include="Cake.Frosting" Version="3.0.0" />
+    </ItemGroup>
+</Project>

+ 129 - 0
src/PixiEditor.Builder/build/Program.cs

@@ -0,0 +1,129 @@
+using System.IO;
+using Cake.Common.Build;
+using Cake.Common.Tools.DotNet;
+using Cake.Common.Tools.DotNet.Publish;
+using Cake.Core;
+using Cake.Core.Diagnostics;
+using Cake.Frosting;
+using Path = System.IO.Path;
+
+namespace PixiEditor.Cake.Builder;
+
+public static class Program
+{
+    public static int Main(string[] args)
+    {
+        return new CakeHost()
+            .UseContext<BuildContext>()
+            .Run(args);
+    }
+}
+
+public class BuildContext : FrostingContext
+{
+    public string PathToProject { get; set; } = "../PixiEditor/PixiEditor.csproj";
+
+    public string CrashReportWebhookUrl { get; set; }
+
+    public string BackedUpConstants { get; set; }
+
+    public string BuildConfiguration { get; set; } = "Release";
+
+    public string OutputDirectory { get; set; } = "Builds";
+
+    public string Runtime { get; set; }
+
+    public BuildContext(ICakeContext context)
+        : base(context)
+    {
+        bool hasWebhook = context.Arguments.HasArgument("crash-report-webhook-url");
+        CrashReportWebhookUrl = hasWebhook
+            ? context.Arguments.GetArgument("crash-report-webhook-url")
+            : string.Empty;
+
+        bool hasCustomProjectPath = context.Arguments.HasArgument("project-path");
+        if (hasCustomProjectPath)
+        {
+            PathToProject = context.Arguments.GetArgument("project-path");
+        }
+
+        bool hasCustomConfiguration = context.Arguments.HasArgument("build-configuration");
+        if (hasCustomConfiguration)
+        {
+            BuildConfiguration = context.Arguments.GetArgument("build-configuration");
+        }
+
+        bool hasCustomOutputDirectory = context.Arguments.HasArgument("o");
+        if (hasCustomOutputDirectory)
+        {
+            OutputDirectory = context.Arguments.GetArgument("o");
+        }
+
+        Runtime = context.Arguments.GetArgument("runtime");
+    }
+}
+
+[TaskName("Default")]
+[IsDependentOn(typeof(BuildProjectTask))]
+public sealed class DefaultTask : FrostingTask<BuildContext>
+{
+    public override void Run(BuildContext context)
+    {
+        context.Log.Information("Built project successfully!");
+    }
+}
+
+[TaskName("ReplaceSpecialStrings")]
+public sealed class ReplaceSpecialStringsTask : FrostingTask<BuildContext>
+{
+    public override void Run(BuildContext context)
+    {
+        context.Log.Information("Replacing special strings...");
+        string projectPath = context.PathToProject;
+        string filePath = Path.Combine(projectPath, "BuildConstants.cs");
+
+        string result;
+        var fileContent = File.ReadAllText(filePath);
+        context.BackedUpConstants = fileContent;
+        result = ReplaceSpecialStrings(context, fileContent);
+
+        File.WriteAllText(filePath, result);
+    }
+
+    private string ReplaceSpecialStrings(BuildContext context, string fileContent)
+    {
+        string result = fileContent
+            .Replace("${crash-report-webhook-url}", context.CrashReportWebhookUrl);
+
+        return result;
+    }
+}
+
+[TaskName("BuildProject")]
+[IsDependentOn(typeof(ReplaceSpecialStringsTask))]
+public sealed class BuildProjectTask : FrostingTask<BuildContext>
+{
+    public override void Run(BuildContext context)
+    {
+        context.Log.Information("Building project...");
+        string projectPath = context.PathToProject;
+
+        var settings = new DotNetPublishSettings()
+        {
+            Configuration = context.BuildConfiguration,
+            SelfContained = false,
+            Runtime = context.Runtime,
+            OutputDirectory = context.OutputDirectory,
+        };
+
+        context.DotNetPublish(projectPath, settings);
+    }
+
+    public override void Finally(BuildContext context)
+    {
+        context.Log.Information("Cleaning up...");
+        string constantsPath = Path.Combine(context.PathToProject, "BuildConstants.cs");
+
+        File.WriteAllText(constantsPath, context.BackedUpConstants);
+    }
+}

+ 20 - 0
src/PixiEditor.Builder/stylecop.json

@@ -0,0 +1,20 @@
+{
+  "$schema": "https://raw.githubusercontent.com/DotNetAnalyzers/StyleCopAnalyzers/master/StyleCop.Analyzers/StyleCop.Analyzers/Settings/stylecop.schema.json",
+  "settings": {
+    "indentation": {
+      "indentationSize": 4
+    },
+    "maintainabilityRules": {
+      "topLevelTypes": [ "class", "interface", "enum", "struct" ]
+    },
+    "readabilityRules": {
+      "allowBuiltInTypeAliases": false
+    },
+    "documentationRules": {
+      "xmlHeader": false,
+      "documentInterfaces": false,
+      "documentExposedElements": false,
+      "documentInternalElements": false
+    }
+  }
+}

+ 38 - 0
src/PixiEditor.sln

@@ -38,6 +38,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PixiEditor.DrawingApi.Skia"
 EndProject
 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PixiEditorGen", "PixiEditorGen\PixiEditorGen.csproj", "{1DC5B4C4-6902-4659-AE7E-17FDA0403DEB}"
 EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PixiEditor.Builder", "PixiEditor.Builder\build\PixiEditor.Builder.csproj", "{7AEE19FA-A4F8-4ACA-9E39-401AA1F603C2}"
+EndProject
 Global
 	GlobalSection(SolutionConfigurationPlatforms) = preSolution
 		Debug|Any CPU = Debug|Any CPU
@@ -575,6 +577,42 @@ Global
 		{1DC5B4C4-6902-4659-AE7E-17FDA0403DEB}.Steam|x64.Build.0 = Steam|x64
 		{1DC5B4C4-6902-4659-AE7E-17FDA0403DEB}.Steam|x86.ActiveCfg = Steam|x86
 		{1DC5B4C4-6902-4659-AE7E-17FDA0403DEB}.Steam|x86.Build.0 = Steam|x86
+		{7AEE19FA-A4F8-4ACA-9E39-401AA1F603C2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{7AEE19FA-A4F8-4ACA-9E39-401AA1F603C2}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{7AEE19FA-A4F8-4ACA-9E39-401AA1F603C2}.Debug|x64.ActiveCfg = Debug|Any CPU
+		{7AEE19FA-A4F8-4ACA-9E39-401AA1F603C2}.Debug|x64.Build.0 = Debug|Any CPU
+		{7AEE19FA-A4F8-4ACA-9E39-401AA1F603C2}.Debug|x86.ActiveCfg = Debug|Any CPU
+		{7AEE19FA-A4F8-4ACA-9E39-401AA1F603C2}.Debug|x86.Build.0 = Debug|Any CPU
+		{7AEE19FA-A4F8-4ACA-9E39-401AA1F603C2}.Dev Release|Any CPU.ActiveCfg = Debug|Any CPU
+		{7AEE19FA-A4F8-4ACA-9E39-401AA1F603C2}.Dev Release|Any CPU.Build.0 = Debug|Any CPU
+		{7AEE19FA-A4F8-4ACA-9E39-401AA1F603C2}.Dev Release|x64.ActiveCfg = Debug|Any CPU
+		{7AEE19FA-A4F8-4ACA-9E39-401AA1F603C2}.Dev Release|x64.Build.0 = Debug|Any CPU
+		{7AEE19FA-A4F8-4ACA-9E39-401AA1F603C2}.Dev Release|x86.ActiveCfg = Debug|Any CPU
+		{7AEE19FA-A4F8-4ACA-9E39-401AA1F603C2}.Dev Release|x86.Build.0 = Debug|Any CPU
+		{7AEE19FA-A4F8-4ACA-9E39-401AA1F603C2}.MSIX Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{7AEE19FA-A4F8-4ACA-9E39-401AA1F603C2}.MSIX Debug|Any CPU.Build.0 = Debug|Any CPU
+		{7AEE19FA-A4F8-4ACA-9E39-401AA1F603C2}.MSIX Debug|x64.ActiveCfg = Debug|Any CPU
+		{7AEE19FA-A4F8-4ACA-9E39-401AA1F603C2}.MSIX Debug|x64.Build.0 = Debug|Any CPU
+		{7AEE19FA-A4F8-4ACA-9E39-401AA1F603C2}.MSIX Debug|x86.ActiveCfg = Debug|Any CPU
+		{7AEE19FA-A4F8-4ACA-9E39-401AA1F603C2}.MSIX Debug|x86.Build.0 = Debug|Any CPU
+		{7AEE19FA-A4F8-4ACA-9E39-401AA1F603C2}.MSIX|Any CPU.ActiveCfg = Debug|Any CPU
+		{7AEE19FA-A4F8-4ACA-9E39-401AA1F603C2}.MSIX|Any CPU.Build.0 = Debug|Any CPU
+		{7AEE19FA-A4F8-4ACA-9E39-401AA1F603C2}.MSIX|x64.ActiveCfg = Debug|Any CPU
+		{7AEE19FA-A4F8-4ACA-9E39-401AA1F603C2}.MSIX|x64.Build.0 = Debug|Any CPU
+		{7AEE19FA-A4F8-4ACA-9E39-401AA1F603C2}.MSIX|x86.ActiveCfg = Debug|Any CPU
+		{7AEE19FA-A4F8-4ACA-9E39-401AA1F603C2}.MSIX|x86.Build.0 = Debug|Any CPU
+		{7AEE19FA-A4F8-4ACA-9E39-401AA1F603C2}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{7AEE19FA-A4F8-4ACA-9E39-401AA1F603C2}.Release|Any CPU.Build.0 = Release|Any CPU
+		{7AEE19FA-A4F8-4ACA-9E39-401AA1F603C2}.Release|x64.ActiveCfg = Release|Any CPU
+		{7AEE19FA-A4F8-4ACA-9E39-401AA1F603C2}.Release|x64.Build.0 = Release|Any CPU
+		{7AEE19FA-A4F8-4ACA-9E39-401AA1F603C2}.Release|x86.ActiveCfg = Release|Any CPU
+		{7AEE19FA-A4F8-4ACA-9E39-401AA1F603C2}.Release|x86.Build.0 = Release|Any CPU
+		{7AEE19FA-A4F8-4ACA-9E39-401AA1F603C2}.Steam|Any CPU.ActiveCfg = Debug|Any CPU
+		{7AEE19FA-A4F8-4ACA-9E39-401AA1F603C2}.Steam|Any CPU.Build.0 = Debug|Any CPU
+		{7AEE19FA-A4F8-4ACA-9E39-401AA1F603C2}.Steam|x64.ActiveCfg = Debug|Any CPU
+		{7AEE19FA-A4F8-4ACA-9E39-401AA1F603C2}.Steam|x64.Build.0 = Debug|Any CPU
+		{7AEE19FA-A4F8-4ACA-9E39-401AA1F603C2}.Steam|x86.ActiveCfg = Debug|Any CPU
+		{7AEE19FA-A4F8-4ACA-9E39-401AA1F603C2}.Steam|x86.Build.0 = Debug|Any CPU
 	EndGlobalSection
 	GlobalSection(SolutionProperties) = preSolution
 		HideSolutionNode = FALSE

+ 6 - 0
src/PixiEditor/BuildConstants.cs

@@ -0,0 +1,6 @@
+namespace PixiEditor;
+
+public static class BuildConstants
+{
+    public const string CrashReportWebhookUrl = "${crash-report-webhook-url}";
+}

+ 24 - 0
src/PixiEditor/ViewModels/CrashReportViewModel.cs

@@ -1,4 +1,7 @@
 using System.Diagnostics;
+using System.IO;
+using System.Net.Http;
+using System.Text;
 using System.Windows;
 using PixiEditor.Helpers;
 using PixiEditor.Models.DataHolders;
@@ -35,6 +38,27 @@ internal class CrashReportViewModel : ViewModelBase
         OpenSendCrashReportCommand = new((_) => new SendCrashReportWindow(CrashReport).Show());
         RecoverDocumentsCommand = new(RecoverDocuments, (_) => hasRecoveredDocuments);
         AttachDebuggerCommand = new(AttachDebugger);
+
+        if (!IsDebugBuild)
+            SendReportTextToWebhook(report);
+    }
+
+    private async void SendReportTextToWebhook(CrashReport report)
+    {
+        byte[] bytes = Encoding.UTF8.GetBytes(report.ReportText);
+        string filename = Path.GetFileNameWithoutExtension(report.FilePath) + ".txt";
+
+        MultipartFormDataContent formData = new MultipartFormDataContent
+        {
+            { new ByteArrayContent(bytes, 0, bytes.Length), "crash-report", filename }
+        };
+        try
+        {
+            using HttpClient httpClient = new HttpClient();
+            string url = BuildConstants.CrashReportWebhookUrl;
+            await httpClient.PostAsync(url, formData);
+        }
+        catch { }
     }
 
     public void RecoverDocuments(object args)

+ 1 - 0
src/PixiEditor/ViewModels/ViewModelMain.cs

@@ -1,4 +1,5 @@
 using System.ComponentModel;
+using System.Windows;
 using Microsoft.Extensions.DependencyInjection;
 using PixiEditor.DrawingApi.Core.ColorsImpl;
 using PixiEditor.Helpers;

+ 13 - 12
windows-x64-release-dev.yml

@@ -12,9 +12,13 @@ pool:
   vmImage: 'windows-latest'
 
 variables:
-  solution: '**/*.sln'
-  buildPlatform: 'x64'
-  buildConfiguration: 'Release'
+- group: Release Secrets
+- name: solution 
+  value: '**/*.sln'
+- name: buildPlatform 
+  value: 'x64'
+- name: buildConfiguration
+  value: 'Release'
 
 steps:
 - task: UseDotNet@2
@@ -47,16 +51,13 @@ steps:
   inputs:
     filePath: 'assemblyVerReader.ps1'
 
-- task: DotNetCoreCLI@2
-  displayName: "Build release PixiEditor x64 light"
+- task: PowerShell@2
+  displayName: Publish PixiEditor
   inputs:
-    command: 'publish'
-    publishWebProjects: false
-    projects: '**/PixiEditor.csproj'
-    arguments: >
-      -o "Builds\PixiEditor-x64-light" --self-contained=false -r "win-x64" -c "Dev Release"
-    zipAfterPublish: false
-    
+    filePath: 'src/PixiEditor.Builder/build.ps1'
+    arguments: '--project-path "$(System.DefaultWorkingDirectory)\src\PixiEditor" --build-configuration "Dev_Release" --runtime "win-x64" -o "$(System.DefaultWorkingDirectory)\Builds\PixiEditor-x64-light\PixiEditor" --crash-report-webhook-url "$(crash-webhook-url)"'
+    workingDirectory: 'src/PixiEditor.Builder'
+
 - task: ArchiveFiles@2
   inputs:
     rootFolderOrFile: 'Builds\PixiEditor-x64-light'

+ 13 - 11
windows-x64-release.yml

@@ -12,9 +12,13 @@ pool:
   vmImage: 'windows-latest'
 
 variables:
-  solution: '**/*.sln'
-  buildPlatform: 'x64'
-  buildConfiguration: 'Release'
+- group: Release Secrets
+- name: solution 
+  value: '**/*.sln'
+- name: buildPlatform 
+  value: 'x64'
+- name: buildConfiguration
+  value: 'Release'
 
 steps:
 - task: UseDotNet@2
@@ -47,15 +51,13 @@ steps:
   inputs:
     filePath: 'assemblyVerReader.ps1'
 
-- task: DotNetCoreCLI@2
-  displayName: "Build release PixiEditor x64 light"
+- task: PowerShell@2
+  displayName: Publish PixiEditor
   inputs:
-    command: 'publish'
-    publishWebProjects: false
-    projects: '**/PixiEditor.csproj'
-    arguments: '-o "Builds\PixiEditor-x64-light" --self-contained=false -r "win-x64" -c Release'
-    zipAfterPublish: false
-    
+    filePath: 'src/PixiEditor.Builder/build.ps1'
+    arguments: '--project-path "$(System.DefaultWorkingDirectory)\src\PixiEditor" --build-configuration "Release" --runtime "win-x64" -o "$(System.DefaultWorkingDirectory)\Builds\PixiEditor-x64-light\PixiEditor" --crash-report-webhook-url "$(crash-webhook-url)"'
+    workingDirectory: 'src/PixiEditor.Builder'
+
 - task: ArchiveFiles@2
   inputs:
     rootFolderOrFile: 'Builds\PixiEditor-x64-light'

+ 12 - 11
windows-x86-release-dev.yml

@@ -11,9 +11,13 @@ pool:
   vmImage: 'windows-latest'
 
 variables:
-  solution: '**/*.sln'
-  buildPlatform: 'x86'
-  buildConfiguration: 'Release'
+- group: Release Secrets
+- name: solution 
+  value: '**/*.sln'
+- name: buildPlatform 
+  value: 'x86'
+- name: buildConfiguration
+  value: 'Release'
 
 steps:
 
@@ -49,15 +53,12 @@ steps:
   inputs:
     filePath: 'assemblyVerReader.ps1'
 
-- task: DotNetCoreCLI@2
-  displayName: "Build release PixiEditor x86 light"
+- task: PowerShell@2
+  displayName: Publish PixiEditor
   inputs:
-    command: 'publish'
-    publishWebProjects: false
-    projects: '**/PixiEditor.csproj'
-    arguments: >
-      -o "Builds\PixiEditor-x86-light" --self-contained=false -r "win-x86" -c "Dev Release"
-    zipAfterPublish: false
+    filePath: 'src/PixiEditor.Builder/build.ps1'
+    arguments: '--project-path "$(System.DefaultWorkingDirectory)\src\PixiEditor" --build-configuration "Dev_Release" --runtime "win-x86" -o "$(System.DefaultWorkingDirectory)\Builds\PixiEditor-x86-light\PixiEditor" --crash-report-webhook-url "$(crash-webhook-url)"'
+    workingDirectory: 'src/PixiEditor.Builder'
 
 - task: ArchiveFiles@2
   inputs:

+ 12 - 10
windows-x86-release.yml

@@ -11,9 +11,13 @@ pool:
   vmImage: 'windows-latest'
 
 variables:
-  solution: '**/*.sln'
-  buildPlatform: 'x86'
-  buildConfiguration: 'Release'
+- group: Release Secrets
+- name: solution 
+  value: '**/*.sln'
+- name: buildPlatform 
+  value: 'x86'
+- name: buildConfiguration
+  value: 'Release'
 
 steps:
 
@@ -49,14 +53,12 @@ steps:
   inputs:
     filePath: 'assemblyVerReader.ps1'
 
-- task: DotNetCoreCLI@2
-  displayName: "Build release PixiEditor x86 light"
+- task: PowerShell@2
+  displayName: Publish PixiEditor
   inputs:
-    command: 'publish'
-    publishWebProjects: false
-    projects: '**/PixiEditor.csproj'
-    arguments: '-o "Builds\PixiEditor-x86-light" --self-contained=false -r "win-x86" -c Release'
-    zipAfterPublish: false
+    filePath: 'src/PixiEditor.Builder/build.ps1'
+    arguments: '--project-path "$(System.DefaultWorkingDirectory)\src\PixiEditor" --build-configuration "Release" --runtime "win-x86" -o "$(System.DefaultWorkingDirectory)\Builds\PixiEditor-x86-light\PixiEditor" --crash-report-webhook-url "$(crash-webhook-url)"'
+    workingDirectory: 'src/PixiEditor.Builder'
 
 - task: ArchiveFiles@2
   inputs: