diff --git a/.editorconfig b/.editorconfig
index ecb4b867..984a626c 100644
--- a/.editorconfig
+++ b/.editorconfig
@@ -4,6 +4,8 @@
[*.cs]
+file_header_template = Copyright (c) Microsoft Corporation.\r\nLicensed under the MIT License.
+
#Core editorconfig formatting - indentation
#use soft tabs (spaces) for indentation
diff --git a/.gitattributes b/.gitattributes
new file mode 100644
index 00000000..d788d54a
--- /dev/null
+++ b/.gitattributes
@@ -0,0 +1 @@
+* text=crlf
diff --git a/.github/policies/moderatorTriggers.yml b/.github/policies/moderatorTriggers.yml
index e9b92fd3..9b5608c0 100644
--- a/.github/policies/moderatorTriggers.yml
+++ b/.github/policies/moderatorTriggers.yml
@@ -78,7 +78,7 @@ configuration:
if:
- payloadType: Issue_Comment
- commentContains:
- pattern: '\/logs)'
+ pattern: '\/logs'
isRegex: True
- or:
- activitySenderHasAssociation:
@@ -98,9 +98,6 @@ configuration:
repo names). Alternatively, you can open a Feedback Hub issue and attach them there.
If you use Feedback Hub, please paste the URL at the bottom of the report here so we
can easily find it.
- - closeIssue
- - removeLabel:
- label: Needs-Triage
- removeLabel:
label: Needs-Team-Response
#
@@ -119,8 +116,6 @@ configuration:
- activitySenderHasAssociation:
association: Member
then:
- - removeLabel:
- label: Needs-Triage
- removeLabel:
label: Needs-Team-Response
- addLabel:
diff --git a/Directory.Build.props b/Directory.Build.props
index 58f53349..b4a1e118 100644
--- a/Directory.Build.props
+++ b/Directory.Build.props
@@ -39,7 +39,7 @@
-
+
all
runtime; build; native; contentfiles; analyzers; buildtransitive
diff --git a/GitHubExtension.sln b/GitHubExtension.sln
index 4082b7ed..8e7e8aa3 100644
--- a/GitHubExtension.sln
+++ b/GitHubExtension.sln
@@ -48,6 +48,12 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "scripts", "scripts", "{E4D6
test\scripts\CleanWidgets.ps1 = test\scripts\CleanWidgets.ps1
EndProjectSection
EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{864DD9CD-9F45-47E8-847F-B72ED182626B}"
+ ProjectSection(SolutionItems) = preProject
+ .editorconfig = .editorconfig
+ exclusion.dic = exclusion.dic
+ EndProjectSection
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
diff --git a/TestingScenarios.md b/TestingScenarios.md
index aeab785a..6ed4e2f3 100644
--- a/TestingScenarios.md
+++ b/TestingScenarios.md
@@ -1,10 +1,11 @@
## Testing Scenarios
-These are the testing scenarios that need to be validated before shipping a new release. When an automated test is added, please remove it from the below lists.
+These are the testing scenarios that need to be validated before shipping a new release. When an automated test is added, please remove it from the below lists.
### Widgets
-1. For each widget: user can configure the widget before pinning
-1. For each widget: user can see widget in dashboard after pinning
+
+1. For each widget: user can configure the widget immediately after first pin
+1. For each widget: user can customize (reconfigure) the widget after it was initially configured
1. For each widget that supports customization: can be customized and persist after restart
1. Widgets have correct data
1. Widgets are adequately performant
@@ -12,4 +13,5 @@ These are the testing scenarios that need to be validated before shipping a new
1. Notifications are displayed
### Clone repositories
-1. User can log in and get the list of repositories
\ No newline at end of file
+
+1. User can log in and get the list of repositories
diff --git a/build/azure-pipelines.yml b/build/azure-pipelines.yml
index e74bbf09..e5c97b05 100644
--- a/build/azure-pipelines.yml
+++ b/build/azure-pipelines.yml
@@ -20,7 +20,7 @@ parameters:
- release
variables:
- MSIXVersion: '0.1000'
+ MSIXVersion: '0.1100'
solution: '**/GitHubExtension.sln'
appxPackageDir: 'AppxPackages'
testOutputArtifactDir: 'TestResults'
diff --git a/build/scripts/Build.ps1 b/build/scripts/Build.ps1
index 4ae8b97d..dab04cdb 100644
--- a/build/scripts/Build.ps1
+++ b/build/scripts/Build.ps1
@@ -14,7 +14,7 @@ $StartTime = Get-Date
if ($Help) {
Write-Host @"
-Copyright (c) Microsoft Corporation and Contributors.
+Copyright (c) Microsoft Corporation.
Licensed under the MIT License.
Syntax:
diff --git a/build/scripts/CreateBuildInfo.ps1 b/build/scripts/CreateBuildInfo.ps1
index 65dfcc7a..17a84fc2 100644
--- a/build/scripts/CreateBuildInfo.ps1
+++ b/build/scripts/CreateBuildInfo.ps1
@@ -5,7 +5,7 @@ Param(
)
$Major = "0"
-$Minor = "10"
+$Minor = "11"
$Patch = "99" # default to 99 for local builds
$versionSplit = $Version.Split(".");
diff --git a/build/scripts/Test.ps1 b/build/scripts/Test.ps1
index d637b443..b52c976f 100644
--- a/build/scripts/Test.ps1
+++ b/build/scripts/Test.ps1
@@ -9,7 +9,7 @@ $StartTime = Get-Date
if ($Help) {
Write-Host @"
-Copyright (c) Microsoft Corporation and Contributors.
+Copyright (c) Microsoft Corporation.
Licensed under the MIT License.
Syntax:
diff --git a/build/scripts/Unstub.ps1 b/build/scripts/Unstub.ps1
index 792d749f..e6eac77d 100644
--- a/build/scripts/Unstub.ps1
+++ b/build/scripts/Unstub.ps1
@@ -10,12 +10,12 @@ if ($projFileContent.Contains('Microsoft.Telemetry.Inbox.Managed')) {
return;
}
-$xml = [xml]$projFileContent
+$xml = [System.Xml.XmlDocument]$projFileContent
$xml.PreserveWhitespace = $true
-$packageRef = $xml.SelectSingleNode("//ItemGroup/PackageReference")
-$newNode = $packageRef.Clone()
-$newNode.Include="Microsoft.Telemetry.Inbox.Managed"
-$newNode.Version="10.0.25148.1001-220626-1600.rs-fun-deploy-dev5"
-$parentNode = $packageRef.ParentNode
-$parentNode.AppendChild($newNode)
+$itemGroup = $xml.CreateElement("ItemGroup")
+$packageRef = $xml.CreateElement("PackageReference")
+$packageRef.SetAttribute("Include", "Microsoft.Telemetry.Inbox.Managed")
+$packageRef.SetAttribute("Version", "10.0.25148.1001-220626-1600.rs-fun-deploy-dev5")
+$itemGroup.AppendChild($packageRef)
+$xml.Project.AppendChild($itemGroup)
$xml.Save($projFile)
\ No newline at end of file
diff --git a/codeAnalysis/GlobalSuppressions.cs b/codeAnalysis/GlobalSuppressions.cs
index 303231c7..6adc7ff0 100644
--- a/codeAnalysis/GlobalSuppressions.cs
+++ b/codeAnalysis/GlobalSuppressions.cs
@@ -1,5 +1,5 @@
-// Copyright (c) Microsoft Corporation and Contributors
-// Licensed under the MIT license.
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
// This file is used by Code Analysis to maintain SuppressMessage
// attributes that are applied to this project.
@@ -13,10 +13,10 @@
[assembly: SuppressMessage("StyleCop.CSharp.ReadabilityRules", "SA1101:PrefixLocalCallsWithThis", Justification = "We follow the C# Core Coding Style which avoids using `this` unless absolutely necessary.")]
[assembly: SuppressMessage("StyleCop.CSharp.OrderingRules", "SA1200:UsingDirectivesMustBePlacedWithinNamespace", Justification = "We follow the C# Core Coding Style which puts using statements outside the namespace.")]
-[assembly: SuppressMessage("StyleCop.CSharp.OrderingRules", "SA1201:ElementsMustAppearInTheCorrectOrder", Justification = "It is not a priority and have hight impact in code changes.")]
-[assembly: SuppressMessage("StyleCop.CSharp.OrderingRules", "SA1202:ElementsMustBeOrderedByAccess", Justification = "It is not a priority and have hight impact in code changes.")]
-[assembly: SuppressMessage("StyleCop.CSharp.OrderingRules", "SA1203:ConstantsMustAppearBeforeFields", Justification = "It is not a priority and have hight impact in code changes.")]
-[assembly: SuppressMessage("StyleCop.CSharp.OrderingRules", "SA1204:StaticElementsMustAppearBeforeInstanceElements", Justification = "It is not a priority and have hight impact in code changes.")]
+[assembly: SuppressMessage("StyleCop.CSharp.OrderingRules", "SA1201:ElementsMustAppearInTheCorrectOrder", Justification = "It is not a priority and has high impact in code changes.")]
+[assembly: SuppressMessage("StyleCop.CSharp.OrderingRules", "SA1202:ElementsMustBeOrderedByAccess", Justification = "It is not a priority and has high impact in code changes.")]
+[assembly: SuppressMessage("StyleCop.CSharp.OrderingRules", "SA1203:ConstantsMustAppearBeforeFields", Justification = "It is not a priority and has high impact in code changes.")]
+[assembly: SuppressMessage("StyleCop.CSharp.OrderingRules", "SA1204:StaticElementsMustAppearBeforeInstanceElements", Justification = "It is not a priority and has high impact in code changes.")]
[assembly: SuppressMessage("StyleCop.CSharp.NamingRules", "SA1309:FieldNamesMustNotBeginWithUnderscore", Justification = "We follow the C# Core Coding Style which uses underscores as prefixes rather than using `this.`.")]
diff --git a/codeAnalysis/StyleCop.json b/codeAnalysis/StyleCop.json
index bb7d02ca..f13fa14b 100644
--- a/codeAnalysis/StyleCop.json
+++ b/codeAnalysis/StyleCop.json
@@ -3,7 +3,7 @@
"settings": {
"documentationRules": {
"companyName": "Microsoft Corporation",
- "copyrightText": "Copyright (c) Microsoft Corporation and Contributors\r\nLicensed under the MIT license.",
+ "copyrightText": "Copyright (c) Microsoft Corporation.\r\nLicensed under the MIT License.",
"xmlHeader": false,
"headerDecoration": "",
"fileNamingConvention": "metadata",
diff --git a/docs/specs/spec-template.md b/docs/specs/spec-template.md
index 136cfb14..a7e6f54a 100644
--- a/docs/specs/spec-template.md
+++ b/docs/specs/spec-template.md
@@ -1,58 +1,58 @@
----
-author: /
-created on:
-last updated:
-issue id:
----
-
-# Spec Title
-
-## Abstract
-
-[comment]: # Outline what this spec describes
-
-## Inspiration
-
-[comment]: # What were the drivers/inspiration behind the creation of this spec.
-
-## Solution Design
-
-[comment]: # Outline the design of the solution. Feel free to include ASCII-art diagrams, etc.
-
-## UI/UX Design
-
-[comment]: # What will this fix/feature look like? How will it affect the end user?
-
-## Capabilities
-
-[comment]: # Discuss how the proposed fixes/features impact the following key considerations:
-
-### Accessibility
-
-[comment]: # How will the proposed change impact accessibility for users of screen readers, assistive input devices, etc.
-
-### Security
-
-[comment]: # How will the proposed change impact security?
-
-### Reliability
-
-[comment]: # Will the proposed change improve reliability? If not, why make the change?
-
-### Compatibility
-
-[comment]: # Will the proposed change break existing code/behaviors? If so, how, and is the breaking change "worth it"?
-
-### Performance, Power, and Efficiency
-
-## Potential Issues
-
-[comment]: # What are some of the things that might cause problems with the fixes/features proposed? Consider how the user might be negatively impacted.
-
-## Future considerations
-
-[comment]: # What are some of the things that the fixes/features might unlock in the future? Does the implementation of this spec enable scenarios?
-
-## Resources
-
+---
+author: /
+created on:
+last updated:
+issue id:
+---
+
+# Spec Title
+
+## Abstract
+
+[comment]: # Outline what this spec describes
+
+## Inspiration
+
+[comment]: # What were the drivers/inspiration behind the creation of this spec.
+
+## Solution Design
+
+[comment]: # Outline the design of the solution. Feel free to include ASCII-art diagrams, etc.
+
+## UI/UX Design
+
+[comment]: # What will this fix/feature look like? How will it affect the end user?
+
+## Capabilities
+
+[comment]: # Discuss how the proposed fixes/features impact the following key considerations:
+
+### Accessibility
+
+[comment]: # How will the proposed change impact accessibility for users of screen readers, assistive input devices, etc.
+
+### Security
+
+[comment]: # How will the proposed change impact security?
+
+### Reliability
+
+[comment]: # Will the proposed change improve reliability? If not, why make the change?
+
+### Compatibility
+
+[comment]: # Will the proposed change break existing code/behaviors? If so, how, and is the breaking change "worth it"?
+
+### Performance, Power, and Efficiency
+
+## Potential Issues
+
+[comment]: # What are some of the things that might cause problems with the fixes/features proposed? Consider how the user might be negatively impacted.
+
+## Future considerations
+
+[comment]: # What are some of the things that the fixes/features might unlock in the future? Does the implementation of this spec enable scenarios?
+
+## Resources
+
[comment]: # Be sure to add links to references, resources, footnotes, etc.
\ No newline at end of file
diff --git a/exclusion.dic b/exclusion.dic
index d0e22042..548f38ae 100644
--- a/exclusion.dic
+++ b/exclusion.dic
@@ -1 +1,14 @@
devhome
+enums
+Octokit
+advapi
+Urls
+Dependabot
+github.com
+inlines
+abcd
+Doggos
+Stringify
+riid
+Impl
+microsoft
diff --git a/src/GitHubExtension/Client/Exceptions.cs b/src/GitHubExtension/Client/Exceptions.cs
index bf265121..ef04f597 100644
--- a/src/GitHubExtension/Client/Exceptions.cs
+++ b/src/GitHubExtension/Client/Exceptions.cs
@@ -1,39 +1,40 @@
-// Copyright (c) Microsoft Corporation and Contributors
-// Licensed under the MIT license.
-
-namespace GitHubExtension.Client;
-public class InvalidUrlException : Exception
-{
- public InvalidUrlException()
- {
- }
-
- public InvalidUrlException(string message)
- : base(message)
- {
- }
-}
-
-public class InvalidGitHubUrlException : Exception
-{
- public InvalidGitHubUrlException()
- {
- }
-
- public InvalidGitHubUrlException(string message)
- : base(message)
- {
- }
-}
-
-public class InvalidApiException : Exception
-{
- public InvalidApiException()
- {
- }
-
- public InvalidApiException(string message)
- : base(message)
- {
- }
-}
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+namespace GitHubExtension.Client;
+
+public class InvalidUrlException : Exception
+{
+ public InvalidUrlException()
+ {
+ }
+
+ public InvalidUrlException(string message)
+ : base(message)
+ {
+ }
+}
+
+public class InvalidGitHubUrlException : Exception
+{
+ public InvalidGitHubUrlException()
+ {
+ }
+
+ public InvalidGitHubUrlException(string message)
+ : base(message)
+ {
+ }
+}
+
+public class InvalidApiException : Exception
+{
+ public InvalidApiException()
+ {
+ }
+
+ public InvalidApiException(string message)
+ : base(message)
+ {
+ }
+}
diff --git a/src/GitHubExtension/Client/GithubClientProvider.cs b/src/GitHubExtension/Client/GithubClientProvider.cs
index 02cd9109..830bc53c 100644
--- a/src/GitHubExtension/Client/GithubClientProvider.cs
+++ b/src/GitHubExtension/Client/GithubClientProvider.cs
@@ -1,99 +1,99 @@
-// Copyright (c) Microsoft Corporation and Contributors
-// Licensed under the MIT license.
-
-using DevHome.Logging.Helpers;
-using GitHubExtension.DeveloperId;
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+using DevHome.Logging.Helpers;
+using GitHubExtension.DeveloperId;
using Microsoft.Windows.DevHome.SDK;
-using Octokit;
-
-namespace GitHubExtension.Client;
-
-public class GitHubClientProvider
-{
- private readonly GitHubClient publicRepoClient;
-
- private static readonly object InstanceLock = new ();
-
- private static GitHubClientProvider? _instance;
-
- public static GitHubClientProvider Instance
- {
- get
- {
- if (_instance == null)
- {
- lock (InstanceLock)
- {
- _instance = new GitHubClientProvider();
- }
- }
-
- return _instance;
- }
- }
-
- public GitHubClientProvider()
- {
- publicRepoClient = new GitHubClient(new ProductHeaderValue(Constants.DEV_HOME_APPLICATION_NAME));
- }
-
- public GitHubClient? GetClient(IDeveloperId devId)
- {
- var devIdInternal = DeveloperIdProvider.GetInstance().GetDeveloperIdInternal(devId) ?? throw new ArgumentException(devId.LoginId);
- return devIdInternal.GitHubClient;
- }
-
- public GitHubClient GetClient(string url)
- {
- var devIdInternal = DeveloperIdProvider.GetInstance().GetLoggedInDeveloperIdsInternal().Where(i => i.Url.Equals(url, StringComparison.OrdinalIgnoreCase)).FirstOrDefault();
- if (devIdInternal == null)
- {
- return publicRepoClient;
- }
-
- return devIdInternal.GitHubClient;
- }
-
- public GitHubClient GetClient()
- {
- return publicRepoClient;
- }
-
- public async Task GetClientForLoggedInDeveloper(bool logRateLimit = false)
- {
- var authProvider = DeveloperIdProvider.GetInstance();
- var devIds = authProvider.GetLoggedInDeveloperIdsInternal();
- GitHubClient client;
- if (devIds == null || !devIds.Any())
- {
- Log.Logger()?.ReportInfo($"No logged in developer, using public GitHub client.");
- client = Instance.GetClient();
- }
- else
- {
- Log.Logger()?.ReportInfo($"Using authenticated user: {devIds.First().LoginId}");
- client = devIds.First().GitHubClient;
- }
-
- if (client == null)
- {
- Log.Logger()?.ReportError($"Failed creating GitHubClient.");
- return client!;
- }
-
- if (logRateLimit)
+using Octokit;
+
+namespace GitHubExtension.Client;
+
+public class GitHubClientProvider
+{
+ private readonly GitHubClient publicRepoClient;
+
+ private static readonly object InstanceLock = new ();
+
+ private static GitHubClientProvider? _instance;
+
+ public static GitHubClientProvider Instance
+ {
+ get
+ {
+ if (_instance == null)
+ {
+ lock (InstanceLock)
+ {
+ _instance = new GitHubClientProvider();
+ }
+ }
+
+ return _instance;
+ }
+ }
+
+ public GitHubClientProvider()
+ {
+ publicRepoClient = new GitHubClient(new ProductHeaderValue(Constants.DEV_HOME_APPLICATION_NAME));
+ }
+
+ public GitHubClient? GetClient(IDeveloperId devId)
+ {
+ var devIdInternal = DeveloperIdProvider.GetInstance().GetDeveloperIdInternal(devId) ?? throw new ArgumentException(devId.LoginId);
+ return devIdInternal.GitHubClient;
+ }
+
+ public GitHubClient GetClient(string url)
+ {
+ var devIdInternal = DeveloperIdProvider.GetInstance().GetLoggedInDeveloperIdsInternal().Where(i => i.Url.Equals(url, StringComparison.OrdinalIgnoreCase)).FirstOrDefault();
+ if (devIdInternal == null)
+ {
+ return publicRepoClient;
+ }
+
+ return devIdInternal.GitHubClient;
+ }
+
+ public GitHubClient GetClient()
+ {
+ return publicRepoClient;
+ }
+
+ public async Task GetClientForLoggedInDeveloper(bool logRateLimit = false)
+ {
+ var authProvider = DeveloperIdProvider.GetInstance();
+ var devIds = authProvider.GetLoggedInDeveloperIdsInternal();
+ GitHubClient client;
+ if (devIds == null || !devIds.Any())
+ {
+ Log.Logger()?.ReportInfo($"No logged in developer, using public GitHub client.");
+ client = Instance.GetClient();
+ }
+ else
+ {
+ Log.Logger()?.ReportInfo($"Using authenticated user: {devIds.First().LoginId}");
+ client = devIds.First().GitHubClient;
+ }
+
+ if (client == null)
+ {
+ Log.Logger()?.ReportError($"Failed creating GitHubClient.");
+ return client!;
+ }
+
+ if (logRateLimit)
{
try
{
var miscRateLimit = await client.RateLimit.GetRateLimits();
Log.Logger()?.ReportInfo($"Rate Limit: Remaining: {miscRateLimit.Resources.Core.Remaining} Total: {miscRateLimit.Resources.Core.Limit} Resets: {miscRateLimit.Resources.Core.Reset.ToStringInvariant()}");
- }
+ }
catch (Exception ex)
{
Log.Logger()?.ReportError($"Rate limiting not enabled for server.", ex);
- }
- }
-
- return client;
- }
-}
+ }
+ }
+
+ return client;
+ }
+}
diff --git a/src/GitHubExtension/Client/Validation.cs b/src/GitHubExtension/Client/Validation.cs
index d38bde43..24f14d5f 100644
--- a/src/GitHubExtension/Client/Validation.cs
+++ b/src/GitHubExtension/Client/Validation.cs
@@ -1,5 +1,6 @@
-// Copyright (c) Microsoft Corporation and Contributors
-// Licensed under the MIT license.
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
using GitHubExtension.DataModel;
using Octokit;
diff --git a/src/GitHubExtension/Configuration/DeveloperOAuthConfiguration.cs b/src/GitHubExtension/Configuration/DeveloperOAuthConfiguration.cs
index 040da66f..1eb28a66 100644
--- a/src/GitHubExtension/Configuration/DeveloperOAuthConfiguration.cs
+++ b/src/GitHubExtension/Configuration/DeveloperOAuthConfiguration.cs
@@ -1,7 +1,8 @@
-// Copyright (c) Microsoft Corporation and Contributors
-// Licensed under the MIT license.
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
namespace GitHubExtension;
+
internal static class DeveloperOAuthConfiguration
{
//// Follow this link https://docs.github.com/en/developers/apps/building-oauth-apps/creating-an-oauth-app
diff --git a/src/GitHubExtension/Configuration/OAuthConfiguration.cs b/src/GitHubExtension/Configuration/OAuthConfiguration.cs
index 14f1d7b1..45841ba2 100644
--- a/src/GitHubExtension/Configuration/OAuthConfiguration.cs
+++ b/src/GitHubExtension/Configuration/OAuthConfiguration.cs
@@ -1,7 +1,8 @@
-// Copyright (c) Microsoft Corporation and Contributors
-// Licensed under the MIT license.
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
namespace GitHubExtension;
+
internal static class OauthConfiguration
{
// This redirect url has to be configured into the OAuth app. This package has "devhome://"
diff --git a/src/GitHubExtension/Constants.cs b/src/GitHubExtension/Constants.cs
index bdac2e0f..3728442f 100644
--- a/src/GitHubExtension/Constants.cs
+++ b/src/GitHubExtension/Constants.cs
@@ -1,7 +1,8 @@
-// Copyright (c) Microsoft Corporation and Contributors
-// Licensed under the MIT license.
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
namespace GitHubExtension;
+
internal class Constants
{
#pragma warning disable SA1310 // Field names should not contain underscore
diff --git a/src/GitHubExtension/DataManager/DataManagerUpdateEventArgs.cs b/src/GitHubExtension/DataManager/DataManagerUpdateEventArgs.cs
index b42abed9..25d468cd 100644
--- a/src/GitHubExtension/DataManager/DataManagerUpdateEventArgs.cs
+++ b/src/GitHubExtension/DataManager/DataManagerUpdateEventArgs.cs
@@ -1,5 +1,5 @@
-// Copyright (c) Microsoft Corporation and Contributors
-// Licensed under the MIT license.
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
namespace GitHubExtension.DataManager;
diff --git a/src/GitHubExtension/DataManager/DataStoreOperationParameters.cs b/src/GitHubExtension/DataManager/DataStoreOperationParameters.cs
index 07f6b5a1..bb1a8c4a 100644
--- a/src/GitHubExtension/DataManager/DataStoreOperationParameters.cs
+++ b/src/GitHubExtension/DataManager/DataStoreOperationParameters.cs
@@ -1,5 +1,5 @@
-// Copyright (c) Microsoft Corporation and Contributors
-// Licensed under the MIT license.
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
using Microsoft.Windows.DevHome.SDK;
diff --git a/src/GitHubExtension/DataManager/DataUpdater.cs b/src/GitHubExtension/DataManager/DataUpdater.cs
index ff906d98..a2b9f5d8 100644
--- a/src/GitHubExtension/DataManager/DataUpdater.cs
+++ b/src/GitHubExtension/DataManager/DataUpdater.cs
@@ -1,7 +1,8 @@
-// Copyright (c) Microsoft Corporation and Contributors
-// Licensed under the MIT license.
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
namespace GitHubExtension.DataManager;
+
public class DataUpdater : IDisposable
{
// This is the default interval the timer will run. It is not the interval that we necessarily do work.
diff --git a/src/GitHubExtension/DataManager/Enums/SearchCategory.cs b/src/GitHubExtension/DataManager/Enums/SearchCategory.cs
index 227faeaf..2cb0cc9c 100644
--- a/src/GitHubExtension/DataManager/Enums/SearchCategory.cs
+++ b/src/GitHubExtension/DataManager/Enums/SearchCategory.cs
@@ -1,12 +1,12 @@
-// Copyright (c) Microsoft Corporation and Contributors
-// Licensed under the MIT license.
-
-namespace GitHubExtension.DataManager;
-
-public enum SearchCategory
-{
- Issues,
- PullRequests,
- IssuesAndPullRequests,
- Unknown,
-}
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+namespace GitHubExtension.DataManager;
+
+public enum SearchCategory
+{
+ Issues,
+ PullRequests,
+ IssuesAndPullRequests,
+ Unknown,
+}
diff --git a/src/GitHubExtension/DataManager/Exceptions.cs b/src/GitHubExtension/DataManager/Exceptions.cs
index 87f6f330..3fd90786 100644
--- a/src/GitHubExtension/DataManager/Exceptions.cs
+++ b/src/GitHubExtension/DataManager/Exceptions.cs
@@ -1,7 +1,8 @@
-// Copyright (c) Microsoft Corporation and Contributors
-// Licensed under the MIT license.
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
namespace GitHubExtension;
+
public class RepositoryNotFoundException : ApplicationException
{
public RepositoryNotFoundException()
diff --git a/src/GitHubExtension/DataManager/GitHubDataManager.cs b/src/GitHubExtension/DataManager/GitHubDataManager.cs
index 5d4cfee8..c5b3ec30 100644
--- a/src/GitHubExtension/DataManager/GitHubDataManager.cs
+++ b/src/GitHubExtension/DataManager/GitHubDataManager.cs
@@ -1,5 +1,5 @@
-// Copyright (c) Microsoft Corporation and Contributors
-// Licensed under the MIT license.
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
using GitHubExtension.Client;
using GitHubExtension.DataManager;
@@ -8,6 +8,7 @@
using Windows.Storage;
namespace GitHubExtension;
+
public partial class GitHubDataManager : IGitHubDataManager, IDisposable
{
public static event DataManagerUpdateEventHandler? OnUpdate;
@@ -16,6 +17,7 @@ public partial class GitHubDataManager : IGitHubDataManager, IDisposable
private static readonly TimeSpan NotificationRetentionTime = TimeSpan.FromDays(7);
private static readonly TimeSpan SearchRetentionTime = TimeSpan.FromDays(7);
private static readonly TimeSpan PullRequestStaleTime = TimeSpan.FromDays(1);
+ private static readonly TimeSpan ReviewStaleTime = TimeSpan.FromDays(7);
// It is possible different widgets have queries which touch the same pull requests.
// We want to keep this window large enough that we don't delete data being used by
@@ -438,6 +440,27 @@ private async Task UpdatePullRequestsForLoggedInDeveloperIdsAsync(DataStoreOpera
CommitCombinedStatus.GetOrCreate(DataStore, commitCombinedStatus);
CreatePullRequestStatus(dsPullRequest);
+
+ // Review information for this pull request.
+ // We will only get review data for the logged-in Developer's pull requests.
+ try
+ {
+ var octoReviews = await devId.GitHubClient.PullRequest.Review.GetAll(repoName[0], repoName[1], octoPull.Number);
+ foreach (var octoReview in octoReviews)
+ {
+ ProcessReview(dsPullRequest, octoReview);
+ }
+ }
+ catch (Exception e)
+ {
+ // Octokit can sometimes fail unexpectedly or have bugs. Should that occur here, we
+ // will not stop processing all pull requests and instead skip over getting the PR
+ // review information for this particular pull request.
+ Log.Logger()?.ReportError($"Error updating Reviews for Pull Request #{octoPull.Number}: {e.Message}");
+
+ // Put the full stack trace in debug if this occurs to reduce log spam.
+ Log.Logger()?.ReportDebug($"Error updating Reviews for Pull Request #{octoPull.Number}.", e);
+ }
}
Log.Logger()?.ReportDebug(Name, $"Updated developer pull requests for {repoFullName}.");
@@ -514,6 +537,36 @@ private async Task UpdatePullRequestsAsync(Repository repository, Octokit.GitHub
PullRequest.DeleteLastObservedBefore(DataStore, repository.Id, DateTime.UtcNow - LastObservedDeleteSpan);
}
+ private void ProcessReview(PullRequest pullRequest, Octokit.PullRequestReview octoReview)
+ {
+ // Skip reviews that are stale.
+ if ((DateTime.Now - octoReview.SubmittedAt) > ReviewStaleTime)
+ {
+ return;
+ }
+
+ // For creating review notifications, must first determine if the review has changed.
+ var existingReview = Review.GetByInternalId(DataStore, octoReview.Id);
+
+ // Add/update the review record.
+ var newReview = Review.GetOrCreateByOctokitReview(DataStore, octoReview, pullRequest.Id);
+
+ // Ignore comments or pending state.
+ if (string.IsNullOrEmpty(newReview.State) || newReview.State == "Commented")
+ {
+ Log.Logger()?.ReportDebug(Name, "Notifications", $"Ignoring review for {pullRequest}. State: {newReview.State}");
+ return;
+ }
+
+ // Create a new notification if the state is different or the review did not exist.
+ if (existingReview == null || (existingReview.State != newReview.State))
+ {
+ // We assume that the logged in developer created this pull request.
+ Log.Logger()?.ReportInfo(Name, "Notifications", $"Creating NewReview Notification for {pullRequest}. State: {newReview.State}");
+ Notification.Create(DataStore, newReview, NotificationType.NewReview);
+ }
+ }
+
private void CreatePullRequestStatus(PullRequest pullRequest)
{
// Get the previous status for comparison.
@@ -525,15 +578,13 @@ private void CreatePullRequestStatus(PullRequest pullRequest)
if (ShouldCreateCheckFailureNotification(curStatus, prevStatus))
{
Log.Logger()?.ReportInfo(Name, "Notifications", $"Creating CheckRunFailure Notification for {curStatus}");
- var notification = Notification.Create(curStatus, NotificationType.CheckRunFailed);
- Notification.Add(DataStore, notification);
+ Notification.Create(DataStore, curStatus, NotificationType.CheckRunFailed);
}
if (ShouldCreateCheckSucceededNotification(curStatus, prevStatus))
{
Log.Logger()?.ReportDebug(Name, "Notifications", $"Creating CheckRunSuccess Notification for {curStatus}");
- var notification = Notification.Create(curStatus, NotificationType.CheckRunSucceeded);
- Notification.Add(DataStore, notification);
+ Notification.Create(DataStore, curStatus, NotificationType.CheckRunSucceeded);
}
}
@@ -662,6 +713,7 @@ private void PruneObsoleteData()
Notification.DeleteBefore(DataStore, DateTime.Now - NotificationRetentionTime);
Search.DeleteBefore(DataStore, DateTime.Now - SearchRetentionTime);
SearchIssue.DeleteUnreferenced(DataStore);
+ Review.DeleteUnreferenced(DataStore);
}
// Sets a last-updated in the MetaData.
diff --git a/src/GitHubExtension/DataManager/GitHubDataManagerUpdate.cs b/src/GitHubExtension/DataManager/GitHubDataManagerUpdate.cs
index 4c1a91f8..1082f6ff 100644
--- a/src/GitHubExtension/DataManager/GitHubDataManagerUpdate.cs
+++ b/src/GitHubExtension/DataManager/GitHubDataManagerUpdate.cs
@@ -1,10 +1,11 @@
-// Copyright (c) Microsoft Corporation and Contributors
-// Licensed under the MIT license.
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
using GitHubExtension.DataManager;
using GitHubExtension.DataModel;
namespace GitHubExtension;
+
public partial class GitHubDataManager
{
// This is how frequently the DataStore update occurs.
@@ -47,6 +48,12 @@ private static async Task UpdateDeveloperPullRequests()
{
notification.ShowToast();
}
+
+ // Show notifications for new reviews.
+ if (notification.Type == NotificationType.NewReview)
+ {
+ notification.ShowToast();
+ }
}
}
diff --git a/src/GitHubExtension/DataManager/GitHubSearchManger.cs b/src/GitHubExtension/DataManager/GitHubSearchManger.cs
index aff6bdae..7e00e996 100644
--- a/src/GitHubExtension/DataManager/GitHubSearchManger.cs
+++ b/src/GitHubExtension/DataManager/GitHubSearchManger.cs
@@ -1,98 +1,98 @@
-// Copyright (c) Microsoft Corporation and Contributors
-// Licensed under the MIT license.
-
-using GitHubExtension.Client;
-using GitHubExtension.DataManager;
-using GitHubExtension.DataModel;
-using Microsoft.Windows.DevHome.SDK;
-using Octokit;
-
-namespace GitHubExtension;
-
-public delegate void SearchManagerResultsAvailableEventHandler(IEnumerable results, string resultType);
-
-public partial class GitHubSearchManager : IGitHubSearchManager, IDisposable
-{
- private static readonly string Name = nameof(GitHubSearchManager);
-
- public static event SearchManagerResultsAvailableEventHandler? OnResultsAvailable;
-
- public GitHubSearchManager()
- {
- }
-
- public static IGitHubSearchManager? CreateInstance()
- {
- try
- {
- return new GitHubSearchManager();
- }
- catch (Exception e)
- {
- Log.Logger()?.ReportError(Name, "Failed creating GitHubSearchManager", e);
- Environment.FailFast(e.Message, e);
- return null;
- }
- }
-
- public async Task SearchForGitHubIssuesOrPRs(Octokit.SearchIssuesRequest request, string initiator, SearchCategory category, IDeveloperId developerId, RequestOptions? options = null)
- {
- var client = GitHubClientProvider.Instance.GetClient(developerId.Url) ?? throw new InvalidOperationException($"Client does not exist for {developerId.Url}");
-
- await SearchForGitHubIssuesOrPRs(request, initiator, category, client, options);
- }
-
- public async Task SearchForGitHubIssuesOrPRs(Octokit.SearchIssuesRequest request, string initiator, SearchCategory category, RequestOptions? options = null)
- {
- var client = await GitHubClientProvider.Instance.GetClientForLoggedInDeveloper(true);
-
- await SearchForGitHubIssuesOrPRs(request, initiator, category, client, options);
- }
-
- private async Task SearchForGitHubIssuesOrPRs(Octokit.SearchIssuesRequest request, string initiator, SearchCategory category, GitHubClient client, RequestOptions? options = null)
- {
- Log.Logger()?.ReportInfo(Name, $"Searching for issues or pull requests for widget {initiator}");
- request.State = Octokit.ItemState.Open;
- request.Archived = false;
- request.PerPage = 10;
- request.SortField = Octokit.IssueSearchSort.Updated;
- request.Order = Octokit.SortDirection.Descending;
-
- // Set is: parameter according to the search category.
- // For the case we are searching for both we don't have to set the parameter
- if (category.Equals(SearchCategory.Issues))
- {
- request.Is = new List() { Octokit.IssueIsQualifier.Issue };
- }
- else if (category.Equals(SearchCategory.PullRequests))
- {
- request.Is = new List() { Octokit.IssueIsQualifier.PullRequest };
- }
-
- var octokitResult = await client.Search.SearchIssues(request);
- if (octokitResult == null)
- {
- Log.Logger()?.ReportDebug($"No issues or PRs found.");
- SendResultsAvailable(new List(), initiator);
- }
- else
- {
- Log.Logger()?.ReportDebug(Name, $"Results contain {octokitResult.Items.Count} items.");
- SendResultsAvailable(octokitResult.Items, initiator);
- }
- }
-
- private void SendResultsAvailable(IEnumerable results, string initiator)
- {
- if (OnResultsAvailable != null)
- {
- Log.Logger()?.ReportInfo(Name, $"Sending search results available Event, of type: {initiator}");
- OnResultsAvailable.Invoke(results, initiator);
- }
- }
-
- public void Dispose()
- {
- GC.SuppressFinalize(this);
- }
-}
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+using GitHubExtension.Client;
+using GitHubExtension.DataManager;
+using GitHubExtension.DataModel;
+using Microsoft.Windows.DevHome.SDK;
+using Octokit;
+
+namespace GitHubExtension;
+
+public delegate void SearchManagerResultsAvailableEventHandler(IEnumerable results, string resultType);
+
+public partial class GitHubSearchManager : IGitHubSearchManager, IDisposable
+{
+ private static readonly string Name = nameof(GitHubSearchManager);
+
+ public static event SearchManagerResultsAvailableEventHandler? OnResultsAvailable;
+
+ public GitHubSearchManager()
+ {
+ }
+
+ public static IGitHubSearchManager? CreateInstance()
+ {
+ try
+ {
+ return new GitHubSearchManager();
+ }
+ catch (Exception e)
+ {
+ Log.Logger()?.ReportError(Name, "Failed creating GitHubSearchManager", e);
+ Environment.FailFast(e.Message, e);
+ return null;
+ }
+ }
+
+ public async Task SearchForGitHubIssuesOrPRs(Octokit.SearchIssuesRequest request, string initiator, SearchCategory category, IDeveloperId developerId, RequestOptions? options = null)
+ {
+ var client = GitHubClientProvider.Instance.GetClient(developerId.Url) ?? throw new InvalidOperationException($"Client does not exist for {developerId.Url}");
+
+ await SearchForGitHubIssuesOrPRs(request, initiator, category, client, options);
+ }
+
+ public async Task SearchForGitHubIssuesOrPRs(Octokit.SearchIssuesRequest request, string initiator, SearchCategory category, RequestOptions? options = null)
+ {
+ var client = await GitHubClientProvider.Instance.GetClientForLoggedInDeveloper(true);
+
+ await SearchForGitHubIssuesOrPRs(request, initiator, category, client, options);
+ }
+
+ private async Task SearchForGitHubIssuesOrPRs(Octokit.SearchIssuesRequest request, string initiator, SearchCategory category, GitHubClient client, RequestOptions? options = null)
+ {
+ Log.Logger()?.ReportInfo(Name, $"Searching for issues or pull requests for widget {initiator}");
+ request.State = Octokit.ItemState.Open;
+ request.Archived = false;
+ request.PerPage = 10;
+ request.SortField = Octokit.IssueSearchSort.Updated;
+ request.Order = Octokit.SortDirection.Descending;
+
+ // Set is: parameter according to the search category.
+ // For the case we are searching for both we don't have to set the parameter
+ if (category.Equals(SearchCategory.Issues))
+ {
+ request.Is = new List() { Octokit.IssueIsQualifier.Issue };
+ }
+ else if (category.Equals(SearchCategory.PullRequests))
+ {
+ request.Is = new List() { Octokit.IssueIsQualifier.PullRequest };
+ }
+
+ var octokitResult = await client.Search.SearchIssues(request);
+ if (octokitResult == null)
+ {
+ Log.Logger()?.ReportDebug($"No issues or PRs found.");
+ SendResultsAvailable(new List(), initiator);
+ }
+ else
+ {
+ Log.Logger()?.ReportDebug(Name, $"Results contain {octokitResult.Items.Count} items.");
+ SendResultsAvailable(octokitResult.Items, initiator);
+ }
+ }
+
+ private void SendResultsAvailable(IEnumerable results, string initiator)
+ {
+ if (OnResultsAvailable != null)
+ {
+ Log.Logger()?.ReportInfo(Name, $"Sending search results available Event, of type: {initiator}");
+ OnResultsAvailable.Invoke(results, initiator);
+ }
+ }
+
+ public void Dispose()
+ {
+ GC.SuppressFinalize(this);
+ }
+}
diff --git a/src/GitHubExtension/DataManager/IGitHubDataManager.cs b/src/GitHubExtension/DataManager/IGitHubDataManager.cs
index 9ec32318..a7f6e21e 100644
--- a/src/GitHubExtension/DataManager/IGitHubDataManager.cs
+++ b/src/GitHubExtension/DataManager/IGitHubDataManager.cs
@@ -1,5 +1,5 @@
-// Copyright (c) Microsoft Corporation and Contributors
-// Licensed under the MIT license.
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
using GitHubExtension.DataModel;
diff --git a/src/GitHubExtension/DataManager/IGitHubSearchManager.cs b/src/GitHubExtension/DataManager/IGitHubSearchManager.cs
index 68514e8d..dbe24872 100644
--- a/src/GitHubExtension/DataManager/IGitHubSearchManager.cs
+++ b/src/GitHubExtension/DataManager/IGitHubSearchManager.cs
@@ -1,14 +1,14 @@
-// Copyright (c) Microsoft Corporation and Contributors
-// Licensed under the MIT license.
-
-using GitHubExtension.DataManager;
-using Microsoft.Windows.DevHome.SDK;
-
-namespace GitHubExtension;
-
-public interface IGitHubSearchManager : IDisposable
-{
- Task SearchForGitHubIssuesOrPRs(Octokit.SearchIssuesRequest request, string initiator, SearchCategory category, RequestOptions? options = null);
-
- Task SearchForGitHubIssuesOrPRs(Octokit.SearchIssuesRequest request, string initiator, SearchCategory category, IDeveloperId developerId, RequestOptions? options = null);
-}
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+using GitHubExtension.DataManager;
+using Microsoft.Windows.DevHome.SDK;
+
+namespace GitHubExtension;
+
+public interface IGitHubSearchManager : IDisposable
+{
+ Task SearchForGitHubIssuesOrPRs(Octokit.SearchIssuesRequest request, string initiator, SearchCategory category, RequestOptions? options = null);
+
+ Task SearchForGitHubIssuesOrPRs(Octokit.SearchIssuesRequest request, string initiator, SearchCategory category, IDeveloperId developerId, RequestOptions? options = null);
+}
diff --git a/src/GitHubExtension/DataManager/RequestOptions.cs b/src/GitHubExtension/DataManager/RequestOptions.cs
index aa69f232..3f5380e6 100644
--- a/src/GitHubExtension/DataManager/RequestOptions.cs
+++ b/src/GitHubExtension/DataManager/RequestOptions.cs
@@ -1,9 +1,10 @@
-// Copyright (c) Microsoft Corporation and Contributors
-// Licensed under the MIT license.
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
using Octokit;
namespace GitHubExtension;
+
public class RequestOptions
{
// Request options for making queries to GitHub.
diff --git a/src/GitHubExtension/DataModel/DataObjects/CheckRun.cs b/src/GitHubExtension/DataModel/DataObjects/CheckRun.cs
index 482e6da8..0e2911d6 100644
--- a/src/GitHubExtension/DataModel/DataObjects/CheckRun.cs
+++ b/src/GitHubExtension/DataModel/DataObjects/CheckRun.cs
@@ -1,5 +1,5 @@
-// Copyright (c) Microsoft Corporation and Contributors
-// Licensed under the MIT license.
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
using Dapper;
using Dapper.Contrib.Extensions;
diff --git a/src/GitHubExtension/DataModel/DataObjects/CheckSuite.cs b/src/GitHubExtension/DataModel/DataObjects/CheckSuite.cs
index e846ac22..ef09e60d 100644
--- a/src/GitHubExtension/DataModel/DataObjects/CheckSuite.cs
+++ b/src/GitHubExtension/DataModel/DataObjects/CheckSuite.cs
@@ -1,5 +1,5 @@
-// Copyright (c) Microsoft Corporation and Contributors
-// Licensed under the MIT license.
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
using Dapper;
using Dapper.Contrib.Extensions;
diff --git a/src/GitHubExtension/DataModel/DataObjects/CommitCombinedStatus.cs b/src/GitHubExtension/DataModel/DataObjects/CommitCombinedStatus.cs
index fe19fe44..267d905e 100644
--- a/src/GitHubExtension/DataModel/DataObjects/CommitCombinedStatus.cs
+++ b/src/GitHubExtension/DataModel/DataObjects/CommitCombinedStatus.cs
@@ -1,5 +1,5 @@
-// Copyright (c) Microsoft Corporation and Contributors
-// Licensed under the MIT license.
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
using Dapper;
using Dapper.Contrib.Extensions;
diff --git a/src/GitHubExtension/DataModel/DataObjects/Issue.cs b/src/GitHubExtension/DataModel/DataObjects/Issue.cs
index e735794a..8eadcc57 100644
--- a/src/GitHubExtension/DataModel/DataObjects/Issue.cs
+++ b/src/GitHubExtension/DataModel/DataObjects/Issue.cs
@@ -1,5 +1,5 @@
-// Copyright (c) Microsoft Corporation and Contributors
-// Licensed under the MIT license.
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
using Dapper;
using Dapper.Contrib.Extensions;
diff --git a/src/GitHubExtension/DataModel/DataObjects/IssueAssign.cs b/src/GitHubExtension/DataModel/DataObjects/IssueAssign.cs
index c4284b80..578ab91f 100644
--- a/src/GitHubExtension/DataModel/DataObjects/IssueAssign.cs
+++ b/src/GitHubExtension/DataModel/DataObjects/IssueAssign.cs
@@ -1,5 +1,5 @@
-// Copyright (c) Microsoft Corporation and Contributors
-// Licensed under the MIT license.
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
using Dapper;
using Dapper.Contrib.Extensions;
diff --git a/src/GitHubExtension/DataModel/DataObjects/IssueLabel.cs b/src/GitHubExtension/DataModel/DataObjects/IssueLabel.cs
index 01ef27bd..5ab44d4e 100644
--- a/src/GitHubExtension/DataModel/DataObjects/IssueLabel.cs
+++ b/src/GitHubExtension/DataModel/DataObjects/IssueLabel.cs
@@ -1,5 +1,5 @@
-// Copyright (c) Microsoft Corporation and Contributors
-// Licensed under the MIT license.
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
using Dapper;
using Dapper.Contrib.Extensions;
diff --git a/src/GitHubExtension/DataModel/DataObjects/Label.cs b/src/GitHubExtension/DataModel/DataObjects/Label.cs
index 7f738a4c..016f8363 100644
--- a/src/GitHubExtension/DataModel/DataObjects/Label.cs
+++ b/src/GitHubExtension/DataModel/DataObjects/Label.cs
@@ -1,5 +1,5 @@
-// Copyright (c) Microsoft Corporation and Contributors
-// Licensed under the MIT license.
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
using Dapper;
using Dapper.Contrib.Extensions;
diff --git a/src/GitHubExtension/DataModel/DataObjects/MetaData.cs b/src/GitHubExtension/DataModel/DataObjects/MetaData.cs
index b855ff9e..2a2e8781 100644
--- a/src/GitHubExtension/DataModel/DataObjects/MetaData.cs
+++ b/src/GitHubExtension/DataModel/DataObjects/MetaData.cs
@@ -1,5 +1,5 @@
-// Copyright (c) Microsoft Corporation and Contributors
-// Licensed under the MIT license.
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
using Dapper;
using Dapper.Contrib.Extensions;
diff --git a/src/GitHubExtension/DataModel/DataObjects/Notification.cs b/src/GitHubExtension/DataModel/DataObjects/Notification.cs
index 950c0f27..3f7e715c 100644
--- a/src/GitHubExtension/DataModel/DataObjects/Notification.cs
+++ b/src/GitHubExtension/DataModel/DataObjects/Notification.cs
@@ -1,5 +1,5 @@
-// Copyright (c) Microsoft Corporation and Contributors
-// Licensed under the MIT license.
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
using Dapper;
using Dapper.Contrib.Extensions;
@@ -161,6 +161,7 @@ public bool ShowToast()
{
NotificationType.CheckRunFailed => ShowFailedCheckRunToast(),
NotificationType.CheckRunSucceeded => ShowSucceededCheckRunToast(),
+ NotificationType.NewReview => ShowNewReviewToast(),
_ => false,
};
}
@@ -225,9 +226,52 @@ private bool ShowSucceededCheckRunToast()
return true;
}
- public static Notification Create(PullRequestStatus status, NotificationType type)
+ private bool ShowNewReviewToast()
{
- return new Notification
+ try
+ {
+ Notifications.Log.Logger()?.ReportInfo($"Showing Notification for {this}");
+ var resLoader = new ResourceLoader(ResourceLoader.GetDefaultResourceFilePath(), "GitHubExtension/Resources");
+ var nb = new AppNotificationBuilder();
+ nb.SetDuration(AppNotificationDuration.Long);
+ nb.AddArgument("htmlurl", HtmlUrl);
+
+ switch (Result)
+ {
+ case "Approved":
+ nb.AddText($"✅ {resLoader.GetString("Notifications_Toast_NewReview/Approved")}");
+ break;
+
+ case "ChangesRequested":
+ nb.AddText($"⚠️ {resLoader.GetString("Notifications_Toast_NewReview/ChangesRequested")}");
+ break;
+
+ default:
+ throw new ArgumentException($"Unknown Review Result: {Result}");
+ }
+
+ nb.AddText($"#{Identifier} - {Repository.FullName}", new AppNotificationTextProperties().SetMaxLines(1));
+
+ // We want to show Author login but the AppNotification has a max 3 AddText calls, see:
+ // https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.windows.appnotifications.builder.appnotificationbuilder.addtext?view=windows-app-sdk-1.2
+ // The newline is a workaround to the 3 line restriction to show the Author line.
+ nb.AddText(Title + Environment.NewLine + "@" + User.Login);
+ nb.AddButton(new AppNotificationButton(resLoader.GetString("Notifications_Toast_Button/Dismiss")).AddArgument("action", "dismiss"));
+ AppNotificationManager.Default.Show(nb.BuildNotification());
+ Toasted = true;
+ }
+ catch (Exception ex)
+ {
+ Notifications.Log.Logger()?.ReportError($"Failed creating the Notification for {this}", ex);
+ return false;
+ }
+
+ return true;
+ }
+
+ public static Notification Create(DataStore dataStore, PullRequestStatus status, NotificationType type)
+ {
+ var pullRequestNotification = new Notification
{
TypeId = (long)type,
UserId = status.PullRequest.AuthorId,
@@ -242,6 +286,33 @@ public static Notification Create(PullRequestStatus status, NotificationType typ
TimeOccurred = status.TimeOccurred,
TimeCreated = DateTime.Now.ToDataStoreInteger(),
};
+
+ Add(dataStore, pullRequestNotification);
+ SetOlderNotificationsToasted(dataStore, pullRequestNotification);
+ return pullRequestNotification;
+ }
+
+ public static Notification Create(DataStore dataStore, Review review, NotificationType type)
+ {
+ var reviewNotification = new Notification
+ {
+ TypeId = (long)type,
+ UserId = review.AuthorId,
+ RepositoryId = review.PullRequest.RepositoryId,
+ Title = review.PullRequest.Title,
+ Description = review.Body,
+ Identifier = review.PullRequest.Number.ToStringInvariant(),
+ Result = review.State,
+ HtmlUrl = review.HtmlUrl,
+ DetailsUrl = review.HtmlUrl,
+ ToastState = 0,
+ TimeOccurred = review.TimeSubmitted,
+ TimeCreated = DateTime.Now.ToDataStoreInteger(),
+ };
+
+ Add(dataStore, reviewNotification);
+ SetOlderNotificationsToasted(dataStore, reviewNotification);
+ return reviewNotification;
}
public static Notification Add(DataStore dataStore, Notification notification)
@@ -272,6 +343,30 @@ public static IEnumerable Get(DataStore dataStore, DateTime? since
return notifications;
}
+ public static void SetOlderNotificationsToasted(DataStore dataStore, Notification notification)
+ {
+ // Get all untoasted notifications for the same type, identifier, and author that are older
+ // than the specified notification.
+ var sql = @"SELECT * FROM Notification WHERE TypeId = @TypeId AND RepositoryId = @RepositoryId AND Identifier = @Identifier AND UserId = @UserId AND TimeOccurred < @TimeOccurred AND ToastState = 0";
+ var param = new
+ {
+ notification.TypeId,
+ notification.RepositoryId,
+ notification.Identifier,
+ notification.UserId,
+ notification.TimeOccurred,
+ };
+
+ Log.Logger()?.ReportDebug(DataStore.GetSqlLogMessage(sql, param));
+ var outDatedNotifications = dataStore.Connection!.Query(sql, param, null) ?? Enumerable.Empty();
+ foreach (var olderNotification in outDatedNotifications)
+ {
+ olderNotification.DataStore = dataStore;
+ olderNotification.Toasted = true;
+ Notifications.Log.Logger()?.ReportInfo($"Found older notification for {olderNotification.Identifier} with result {olderNotification.Result}, marking toasted.");
+ }
+ }
+
public static void DeleteBefore(DataStore dataStore, DateTime date)
{
// Delete notifications older than the date listed.
diff --git a/src/GitHubExtension/DataModel/DataObjects/PullRequest.cs b/src/GitHubExtension/DataModel/DataObjects/PullRequest.cs
index 4ac02178..c07052c2 100644
--- a/src/GitHubExtension/DataModel/DataObjects/PullRequest.cs
+++ b/src/GitHubExtension/DataModel/DataObjects/PullRequest.cs
@@ -1,5 +1,5 @@
-// Copyright (c) Microsoft Corporation and Contributors
-// Licensed under the MIT license.
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
using Dapper;
using Dapper.Contrib.Extensions;
@@ -317,6 +317,26 @@ public PullRequestStatus? PullRequestStatus
}
}
+ ///
+ /// Gets all reviews associated with this pull request.
+ ///
+ [Write(false)]
+ [Computed]
+ public IEnumerable Reviews
+ {
+ get
+ {
+ if (DataStore == null)
+ {
+ return Enumerable.Empty();
+ }
+ else
+ {
+ return Review.GetAllForPullRequest(DataStore, this) ?? Enumerable.Empty();
+ }
+ }
+ }
+
public override string ToString() => $"{Number}: {Title}";
// Create pull request from OctoKit pull request data
@@ -365,7 +385,7 @@ private static PullRequest CreateFromOctokitPullRequest(DataStore dataStore, Oct
pull.AssigneeIds = string.Join(",", assignees);
- // Owner is a rowid in the User table
+ // Owner is a rowId in the User table
var author = User.GetOrCreateByOctokitUser(dataStore, okitPull.User);
pull.AuthorId = author.Id;
diff --git a/src/GitHubExtension/DataModel/DataObjects/PullRequestAssign.cs b/src/GitHubExtension/DataModel/DataObjects/PullRequestAssign.cs
index 1723fac4..3034cfe1 100644
--- a/src/GitHubExtension/DataModel/DataObjects/PullRequestAssign.cs
+++ b/src/GitHubExtension/DataModel/DataObjects/PullRequestAssign.cs
@@ -1,5 +1,5 @@
-// Copyright (c) Microsoft Corporation and Contributors
-// Licensed under the MIT license.
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
using Dapper;
using Dapper.Contrib.Extensions;
diff --git a/src/GitHubExtension/DataModel/DataObjects/PullRequestLabel.cs b/src/GitHubExtension/DataModel/DataObjects/PullRequestLabel.cs
index 28cc446a..ffd08077 100644
--- a/src/GitHubExtension/DataModel/DataObjects/PullRequestLabel.cs
+++ b/src/GitHubExtension/DataModel/DataObjects/PullRequestLabel.cs
@@ -1,5 +1,5 @@
-// Copyright (c) Microsoft Corporation and Contributors
-// Licensed under the MIT license.
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
using Dapper;
using Dapper.Contrib.Extensions;
diff --git a/src/GitHubExtension/DataModel/DataObjects/PullRequestStatus.cs b/src/GitHubExtension/DataModel/DataObjects/PullRequestStatus.cs
index 8fcbfe12..4de8ea59 100644
--- a/src/GitHubExtension/DataModel/DataObjects/PullRequestStatus.cs
+++ b/src/GitHubExtension/DataModel/DataObjects/PullRequestStatus.cs
@@ -1,5 +1,5 @@
-// Copyright (c) Microsoft Corporation and Contributors
-// Licensed under the MIT license.
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
using Dapper;
using Dapper.Contrib.Extensions;
diff --git a/src/GitHubExtension/DataModel/DataObjects/Repository.cs b/src/GitHubExtension/DataModel/DataObjects/Repository.cs
index 61a79132..f0fc3d8f 100644
--- a/src/GitHubExtension/DataModel/DataObjects/Repository.cs
+++ b/src/GitHubExtension/DataModel/DataObjects/Repository.cs
@@ -1,5 +1,5 @@
-// Copyright (c) Microsoft Corporation and Contributors
-// Licensed under the MIT license.
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
using Dapper;
using Dapper.Contrib.Extensions;
@@ -149,7 +149,7 @@ private static Repository CreateFromOctokitRepository(DataStore dataStore, Octok
TimePushed = octokitRepository.UpdatedAt.DateTime.ToDataStoreInteger(),
};
- // Owner is a rowid in the User table
+ // Owner is a rowId in the User table
var owner = User.GetOrCreateByOctokitUser(dataStore, octokitRepository.Owner);
repo.OwnerId = owner.Id;
@@ -250,12 +250,12 @@ public static IEnumerable GetAll(DataStore dataStore)
return repo;
}
- public static Repository? Get(DataStore dataStore, string fullname)
+ public static Repository? Get(DataStore dataStore, string fullName)
{
- var nameSplit = fullname.Split(new[] { '/' }, 2);
+ var nameSplit = fullName.Split(new[] { '/' }, 2);
if (nameSplit.Length != 2)
{
- Log.Logger()?.ReportWarn($"Invalid fullname input into Repository.Get: {fullname}");
+ Log.Logger()?.ReportWarn($"Invalid fullName input into Repository.Get: {fullName}");
return null;
}
diff --git a/src/GitHubExtension/DataModel/DataObjects/Review.cs b/src/GitHubExtension/DataModel/DataObjects/Review.cs
new file mode 100644
index 00000000..b3db32fb
--- /dev/null
+++ b/src/GitHubExtension/DataModel/DataObjects/Review.cs
@@ -0,0 +1,213 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+using Dapper;
+using Dapper.Contrib.Extensions;
+using GitHubExtension.Helpers;
+
+namespace GitHubExtension.DataModel;
+
+[Table("Review")]
+public class Review
+{
+ [Key]
+ public long Id { get; set; } = DataStore.NoForeignKey;
+
+ public long InternalId { get; set; } = DataStore.NoForeignKey;
+
+ // Pull request table
+ public long PullRequestId { get; set; } = DataStore.NoForeignKey;
+
+ // User table
+ public long AuthorId { get; set; } = DataStore.NoForeignKey;
+
+ public string Body { get; set; } = string.Empty;
+
+ public string State { get; set; } = string.Empty;
+
+ public string HtmlUrl { get; set; } = string.Empty;
+
+ public long TimeSubmitted { get; set; } = DataStore.NoForeignKey;
+
+ public long TimeLastObserved { get; set; } = DataStore.NoForeignKey;
+
+ [Write(false)]
+ private DataStore? DataStore
+ {
+ get; set;
+ }
+
+ [Write(false)]
+ [Computed]
+ public DateTime SubmittedAt => TimeSubmitted.ToDateTime();
+
+ [Write(false)]
+ [Computed]
+ public DateTime LastObservedAt => TimeLastObserved.ToDateTime();
+
+ [Write(false)]
+ [Computed]
+ public PullRequest PullRequest
+ {
+ get
+ {
+ if (DataStore == null)
+ {
+ return new PullRequest();
+ }
+ else
+ {
+ return PullRequest.GetById(DataStore, PullRequestId) ?? new PullRequest();
+ }
+ }
+ }
+
+ [Write(false)]
+ [Computed]
+ public User Author
+ {
+ get
+ {
+ if (DataStore == null)
+ {
+ return new User();
+ }
+ else
+ {
+ return User.GetById(DataStore, AuthorId) ?? new User();
+ }
+ }
+ }
+
+ public override string ToString() => $"{PullRequestId}: {AuthorId} - {State}";
+
+ // Create review from OctoKit review data
+ private static Review CreateFromOctokitReview(DataStore dataStore, Octokit.PullRequestReview okitReview, long pullRequestId)
+ {
+ var review = new Review
+ {
+ DataStore = dataStore,
+ InternalId = okitReview.Id,
+ Body = okitReview.Body ?? string.Empty,
+ State = okitReview.State.Value.ToString(),
+ HtmlUrl = okitReview.HtmlUrl ?? string.Empty,
+ TimeSubmitted = okitReview.SubmittedAt.DateTime.ToDataStoreInteger(),
+ TimeLastObserved = DateTime.UtcNow.ToDataStoreInteger(),
+ };
+
+ // Author is a rowid in the User table
+ var author = User.GetOrCreateByOctokitUser(dataStore, okitReview.User);
+ review.AuthorId = author.Id;
+
+ // Repo is a row id in the Repository table.
+ // It is likely the case that we already know the repository id (such as when querying pulls for a repository).
+ if (pullRequestId != DataStore.NoForeignKey)
+ {
+ review.PullRequestId = pullRequestId;
+ }
+
+ return review;
+ }
+
+ private static Review AddOrUpdateReview(DataStore dataStore, Review review)
+ {
+ // Check for existing pull request data.
+ var existingReview = GetByInternalId(dataStore, review.InternalId);
+ if (existingReview is not null)
+ {
+ // Existing pull requests must always be updated to update the LastObserved time.
+ review.Id = existingReview.Id;
+ dataStore.Connection!.Update(review);
+ review.DataStore = dataStore;
+ return review;
+ }
+
+ // No existing pull request, add it.
+ review.Id = dataStore.Connection!.Insert(review);
+ review.DataStore = dataStore;
+ return review;
+ }
+
+ public static Review? GetById(DataStore dataStore, long id)
+ {
+ var review = dataStore.Connection!.Get(id);
+ if (review is not null)
+ {
+ // Add Datastore so this object can make internal queries.
+ review.DataStore = dataStore;
+ }
+
+ return review;
+ }
+
+ public static Review? GetByInternalId(DataStore dataStore, long internalId)
+ {
+ var sql = @"SELECT * FROM Review WHERE InternalId = @InternalId;";
+ var param = new
+ {
+ InternalId = internalId,
+ };
+
+ var review = dataStore.Connection!.QueryFirstOrDefault(sql, param, null);
+ if (review is not null)
+ {
+ // Add Datastore so this object can make internal queries.
+ review.DataStore = dataStore;
+ }
+
+ return review;
+ }
+
+ public static Review GetOrCreateByOctokitReview(DataStore dataStore, Octokit.PullRequestReview octokitReview, long repositoryId = DataStore.NoForeignKey)
+ {
+ var newReview = CreateFromOctokitReview(dataStore, octokitReview, repositoryId);
+ return AddOrUpdateReview(dataStore, newReview);
+ }
+
+ public static IEnumerable GetAllForPullRequest(DataStore dataStore, PullRequest pullRequest)
+ {
+ var sql = @"SELECT * FROM Review WHERE PullRequestId = @PullRequestId ORDER BY TimeSubmitted DESC;";
+ var param = new
+ {
+ PullRequestId = pullRequest.Id,
+ };
+
+ Log.Logger()?.ReportDebug(DataStore.GetSqlLogMessage(sql, param));
+ var reviews = dataStore.Connection!.Query(sql, param, null) ?? Enumerable.Empty();
+ foreach (var review in reviews)
+ {
+ review.DataStore = dataStore;
+ }
+
+ return reviews;
+ }
+
+ public static IEnumerable GetAllForUser(DataStore dataStore, User user)
+ {
+ var sql = @"SELECT * FROM Review WHERE AuthorId = @AuthorId;";
+ var param = new
+ {
+ AuthorId = user.Id,
+ };
+
+ Log.Logger()?.ReportDebug(DataStore.GetSqlLogMessage(sql, param));
+ var reviews = dataStore.Connection!.Query(sql, param, null) ?? Enumerable.Empty();
+ foreach (var review in reviews)
+ {
+ review.DataStore = dataStore;
+ }
+
+ return reviews;
+ }
+
+ public static void DeleteUnreferenced(DataStore dataStore)
+ {
+ // Delete any reviews that have no matching PullRequestId in the PullRequest table.
+ var sql = @"DELETE FROM Review WHERE PullRequestId NOT IN (SELECT Id FROM PullRequest)";
+ var command = dataStore.Connection!.CreateCommand();
+ command.CommandText = sql;
+ Log.Logger()?.ReportDebug(DataStore.GetCommandLogMessage(sql, command));
+ var rowsDeleted = command.ExecuteNonQuery();
+ Log.Logger()?.ReportDebug(DataStore.GetDeletedLogMessage(rowsDeleted));
+ }
+}
diff --git a/src/GitHubExtension/DataModel/DataObjects/Search.cs b/src/GitHubExtension/DataModel/DataObjects/Search.cs
index f64a1037..e445c6d6 100644
--- a/src/GitHubExtension/DataModel/DataObjects/Search.cs
+++ b/src/GitHubExtension/DataModel/DataObjects/Search.cs
@@ -1,5 +1,5 @@
-// Copyright (c) Microsoft Corporation and Contributors
-// Licensed under the MIT license.
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
using Dapper;
using Dapper.Contrib.Extensions;
diff --git a/src/GitHubExtension/DataModel/DataObjects/SearchIssue.cs b/src/GitHubExtension/DataModel/DataObjects/SearchIssue.cs
index 4d903252..7c226499 100644
--- a/src/GitHubExtension/DataModel/DataObjects/SearchIssue.cs
+++ b/src/GitHubExtension/DataModel/DataObjects/SearchIssue.cs
@@ -1,5 +1,5 @@
-// Copyright (c) Microsoft Corporation and Contributors
-// Licensed under the MIT license.
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
using Dapper;
using Dapper.Contrib.Extensions;
diff --git a/src/GitHubExtension/DataModel/DataObjects/User.cs b/src/GitHubExtension/DataModel/DataObjects/User.cs
index d00f0240..50407a71 100644
--- a/src/GitHubExtension/DataModel/DataObjects/User.cs
+++ b/src/GitHubExtension/DataModel/DataObjects/User.cs
@@ -1,5 +1,5 @@
-// Copyright (c) Microsoft Corporation and Contributors
-// Licensed under the MIT license.
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
using Dapper;
using Dapper.Contrib.Extensions;
diff --git a/src/GitHubExtension/DataModel/DataStore.cs b/src/GitHubExtension/DataModel/DataStore.cs
index 95169d86..dc6379a1 100644
--- a/src/GitHubExtension/DataModel/DataStore.cs
+++ b/src/GitHubExtension/DataModel/DataStore.cs
@@ -1,5 +1,5 @@
-// Copyright (c) Microsoft Corporation and Contributors
-// Licensed under the MIT license.
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
using System.Globalization;
using System.Reflection;
diff --git a/src/GitHubExtension/DataModel/DataStoreOptions.cs b/src/GitHubExtension/DataModel/DataStoreOptions.cs
index 818c6b79..9929f445 100644
--- a/src/GitHubExtension/DataModel/DataStoreOptions.cs
+++ b/src/GitHubExtension/DataModel/DataStoreOptions.cs
@@ -1,27 +1,28 @@
-// Copyright (c) Microsoft Corporation and Contributors
-// Licensed under the MIT license.
-
-namespace GitHubExtension.DataModel;
-public partial class DataStoreOptions
-{
- private const string DataStoreFileNameDefault = "GitHubData.db";
-
- public string DataStoreFileName { get; set; } = DataStoreFileNameDefault;
-
- // The Temp Path is used for storage by default so tests can run this code without being packaged.
- // If we directly put in the ApplicationData folder, it would fail anytime the program was not packaged.
- // For use with packaged application, set in Options to:
- // ApplicationData.Current.LocalFolder.Path
- private readonly string dataStoreFolderPathDefault = Path.Combine(Path.GetTempPath(), "GitHubExtension");
-
- // ApplicationData is not static, using a static folder for initialization.
- private string? dataStoreFolderPath;
-
- public string DataStoreFolderPath
- {
- get => dataStoreFolderPath is null ? dataStoreFolderPathDefault : dataStoreFolderPath;
- set => dataStoreFolderPath = string.IsNullOrEmpty(value) ? dataStoreFolderPathDefault : value;
- }
-
- public IDataStoreSchema? DataStoreSchema { get; set; }
-}
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+namespace GitHubExtension.DataModel;
+
+public partial class DataStoreOptions
+{
+ private const string DataStoreFileNameDefault = "GitHubData.db";
+
+ public string DataStoreFileName { get; set; } = DataStoreFileNameDefault;
+
+ // The Temp Path is used for storage by default so tests can run this code without being packaged.
+ // If we directly put in the ApplicationData folder, it would fail anytime the program was not packaged.
+ // For use with packaged application, set in Options to:
+ // ApplicationData.Current.LocalFolder.Path
+ private readonly string dataStoreFolderPathDefault = Path.Combine(Path.GetTempPath(), "GitHubExtension");
+
+ // ApplicationData is not static, using a static folder for initialization.
+ private string? dataStoreFolderPath;
+
+ public string DataStoreFolderPath
+ {
+ get => dataStoreFolderPath is null ? dataStoreFolderPathDefault : dataStoreFolderPath;
+ set => dataStoreFolderPath = string.IsNullOrEmpty(value) ? dataStoreFolderPathDefault : value;
+ }
+
+ public IDataStoreSchema? DataStoreSchema { get; set; }
+}
diff --git a/src/GitHubExtension/DataModel/DataStoreTransaction.cs b/src/GitHubExtension/DataModel/DataStoreTransaction.cs
index bcc3c14d..12d49658 100644
--- a/src/GitHubExtension/DataModel/DataStoreTransaction.cs
+++ b/src/GitHubExtension/DataModel/DataStoreTransaction.cs
@@ -1,62 +1,63 @@
-// Copyright (c) Microsoft Corporation and Contributors
-// Licensed under the MIT license.
-
-using Microsoft.Data.Sqlite;
-
-namespace GitHubExtension.DataModel;
-public class DataStoreTransaction : IDataStoreTransaction
-{
- private SqliteTransaction? transaction;
-
- public static IDataStoreTransaction BeginTransaction(DataStore dataStore)
- {
- if (dataStore != null)
- {
- if (dataStore.Connection != null)
- {
- return new DataStoreTransaction(dataStore.Connection.BeginTransaction());
- }
- }
-
- return new DataStoreTransaction(null);
- }
-
- private DataStoreTransaction(SqliteTransaction? tx)
- {
- transaction = tx;
- }
-
- public void Commit()
- {
- transaction?.Commit();
- }
-
- public void Rollback()
- {
- transaction?.Rollback();
- }
-
- private bool disposed; // To detect redundant calls.
-
- protected virtual void Dispose(bool disposing)
- {
- if (!disposed)
- {
- if (disposing)
- {
- transaction?.Dispose();
- transaction = null;
- }
-
- disposed = true;
- }
- }
-
- // This code added to correctly implement the disposable pattern.
- public void Dispose()
- {
- // Do not change this code. Put cleanup code in Dispose(bool disposing) above.
- Dispose(true);
- GC.SuppressFinalize(this);
- }
-}
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+using Microsoft.Data.Sqlite;
+
+namespace GitHubExtension.DataModel;
+
+public class DataStoreTransaction : IDataStoreTransaction
+{
+ private SqliteTransaction? transaction;
+
+ public static IDataStoreTransaction BeginTransaction(DataStore dataStore)
+ {
+ if (dataStore != null)
+ {
+ if (dataStore.Connection != null)
+ {
+ return new DataStoreTransaction(dataStore.Connection.BeginTransaction());
+ }
+ }
+
+ return new DataStoreTransaction(null);
+ }
+
+ private DataStoreTransaction(SqliteTransaction? tx)
+ {
+ transaction = tx;
+ }
+
+ public void Commit()
+ {
+ transaction?.Commit();
+ }
+
+ public void Rollback()
+ {
+ transaction?.Rollback();
+ }
+
+ private bool disposed; // To detect redundant calls.
+
+ protected virtual void Dispose(bool disposing)
+ {
+ if (!disposed)
+ {
+ if (disposing)
+ {
+ transaction?.Dispose();
+ transaction = null;
+ }
+
+ disposed = true;
+ }
+ }
+
+ // This code added to correctly implement the disposable pattern.
+ public void Dispose()
+ {
+ // Do not change this code. Put cleanup code in Dispose(bool disposing) above.
+ Dispose(true);
+ GC.SuppressFinalize(this);
+ }
+}
diff --git a/src/GitHubExtension/DataModel/Enums/CheckConclusion.cs b/src/GitHubExtension/DataModel/Enums/CheckConclusion.cs
index 6c48c6ab..e1048d56 100644
--- a/src/GitHubExtension/DataModel/Enums/CheckConclusion.cs
+++ b/src/GitHubExtension/DataModel/Enums/CheckConclusion.cs
@@ -1,5 +1,5 @@
-// Copyright (c) Microsoft Corporation and Contributors
-// Licensed under the MIT license.
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
namespace GitHubExtension.DataModel;
diff --git a/src/GitHubExtension/DataModel/Enums/CheckStatus.cs b/src/GitHubExtension/DataModel/Enums/CheckStatus.cs
index dca3e598..a20774bf 100644
--- a/src/GitHubExtension/DataModel/Enums/CheckStatus.cs
+++ b/src/GitHubExtension/DataModel/Enums/CheckStatus.cs
@@ -1,5 +1,5 @@
-// Copyright (c) Microsoft Corporation and Contributors
-// Licensed under the MIT license.
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
namespace GitHubExtension.DataModel;
diff --git a/src/GitHubExtension/DataModel/Enums/CommitState.cs b/src/GitHubExtension/DataModel/Enums/CommitState.cs
index fcbe67d7..0525dafa 100644
--- a/src/GitHubExtension/DataModel/Enums/CommitState.cs
+++ b/src/GitHubExtension/DataModel/Enums/CommitState.cs
@@ -1,5 +1,5 @@
-// Copyright (c) Microsoft Corporation and Contributors
-// Licensed under the MIT license.
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
namespace GitHubExtension.DataModel;
diff --git a/src/GitHubExtension/DataModel/Enums/NotificationType.cs b/src/GitHubExtension/DataModel/Enums/NotificationType.cs
index 9a4f54e0..bf35e15f 100644
--- a/src/GitHubExtension/DataModel/Enums/NotificationType.cs
+++ b/src/GitHubExtension/DataModel/Enums/NotificationType.cs
@@ -1,5 +1,5 @@
-// Copyright (c) Microsoft Corporation and Contributors
-// Licensed under the MIT license.
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
namespace GitHubExtension.DataModel;
@@ -8,4 +8,5 @@ public enum NotificationType
Unknown = 0,
CheckRunFailed = 1,
CheckRunSucceeded = 2,
+ NewReview = 3,
}
diff --git a/src/GitHubExtension/DataModel/Enums/PullRequestCombinedStatus.cs b/src/GitHubExtension/DataModel/Enums/PullRequestCombinedStatus.cs
index 91f653fa..11ef8773 100644
--- a/src/GitHubExtension/DataModel/Enums/PullRequestCombinedStatus.cs
+++ b/src/GitHubExtension/DataModel/Enums/PullRequestCombinedStatus.cs
@@ -1,5 +1,5 @@
-// Copyright (c) Microsoft Corporation and Contributors
-// Licensed under the MIT license.
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
namespace GitHubExtension.DataModel;
diff --git a/src/GitHubExtension/DataModel/GitHubDataStoreSchema.cs b/src/GitHubExtension/DataModel/GitHubDataStoreSchema.cs
index 9d586bde..13fe1dda 100644
--- a/src/GitHubExtension/DataModel/GitHubDataStoreSchema.cs
+++ b/src/GitHubExtension/DataModel/GitHubDataStoreSchema.cs
@@ -1,7 +1,8 @@
-// Copyright (c) Microsoft Corporation and Contributors
-// Licensed under the MIT license.
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
namespace GitHubExtension.DataModel;
+
public class GitHubDataStoreSchema : IDataStoreSchema
{
public long SchemaVersion => SchemaVersionValue;
@@ -13,7 +14,7 @@ public GitHubDataStoreSchema()
}
// Update this anytime incompatible changes happen with a released version.
- private const long SchemaVersionValue = 0x0005;
+ private const long SchemaVersionValue = 0x0006;
private static readonly string Metadata =
@"CREATE TABLE Metadata (" +
@@ -233,6 +234,20 @@ public GitHubDataStoreSchema()
");" +
"CREATE UNIQUE INDEX IDX_SearchIssue_SearchIssue ON SearchIssue (Search, Issue);";
+ private static readonly string Review =
+ @"CREATE TABLE Review (" +
+ "Id INTEGER PRIMARY KEY NOT NULL," +
+ "InternalId INTEGER NOT NULL," +
+ "PullRequestId INTEGER NOT NULL," +
+ "AuthorId INTEGER NOT NULL," +
+ "Body TEXT NOT NULL COLLATE NOCASE," +
+ "State TEXT NOT NULL COLLATE NOCASE," +
+ "HtmlUrl TEXT NULL COLLATE NOCASE," +
+ "TimeSubmitted INTEGER NOT NULL," +
+ "TimeLastObserved INTEGER NOT NULL" +
+ ");" +
+ "CREATE UNIQUE INDEX IDX_Review_InternalId ON Review (InternalId);";
+
// All Sqls together.
private static readonly List SchemaSqlsValue = new ()
{
@@ -253,5 +268,6 @@ public GitHubDataStoreSchema()
Notification,
Search,
SearchIssue,
+ Review,
};
}
diff --git a/src/GitHubExtension/DataModel/IDataStoreSchema.cs b/src/GitHubExtension/DataModel/IDataStoreSchema.cs
index db28e45d..b77a8691 100644
--- a/src/GitHubExtension/DataModel/IDataStoreSchema.cs
+++ b/src/GitHubExtension/DataModel/IDataStoreSchema.cs
@@ -1,5 +1,5 @@
-// Copyright (c) Microsoft Corporation and Contributors
-// Licensed under the MIT license.
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
namespace GitHubExtension.DataModel;
diff --git a/src/GitHubExtension/DataModel/IDataStoreTransaction.cs b/src/GitHubExtension/DataModel/IDataStoreTransaction.cs
index a6d42360..c302f9b2 100644
--- a/src/GitHubExtension/DataModel/IDataStoreTransaction.cs
+++ b/src/GitHubExtension/DataModel/IDataStoreTransaction.cs
@@ -1,11 +1,11 @@
-// Copyright (c) Microsoft Corporation and Contributors
-// Licensed under the MIT license.
-
-namespace GitHubExtension.DataModel;
-
-public interface IDataStoreTransaction : IDisposable
-{
- void Commit();
-
- void Rollback();
-}
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+namespace GitHubExtension.DataModel;
+
+public interface IDataStoreTransaction : IDisposable
+{
+ void Commit();
+
+ void Rollback();
+}
diff --git a/src/GitHubExtension/DataModel/Logging.cs b/src/GitHubExtension/DataModel/Logging.cs
index 2a14568f..4898760a 100644
--- a/src/GitHubExtension/DataModel/Logging.cs
+++ b/src/GitHubExtension/DataModel/Logging.cs
@@ -1,10 +1,11 @@
-// Copyright (c) Microsoft Corporation and Contributors
-// Licensed under the MIT license.
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
using DevHome.Logging;
using Windows.Storage;
namespace GitHubExtension.DataModel;
+
public class Log
{
private static Logger? _logger;
diff --git a/src/GitHubExtension/DeveloperId/CredentialManager.cs b/src/GitHubExtension/DeveloperId/CredentialManager.cs
index 96835e0f..68f9a270 100644
--- a/src/GitHubExtension/DeveloperId/CredentialManager.cs
+++ b/src/GitHubExtension/DeveloperId/CredentialManager.cs
@@ -1,64 +1,65 @@
-// Copyright (c) Microsoft Corporation and Contributors
-// Licensed under the MIT license.
-
-using System.Runtime.InteropServices;
-
-namespace GitHubExtension.DeveloperId;
-public static class CredentialManager
-{
- public enum CRED_TYPE : int
- {
- GENERIC = 1,
- DOMAIN_PASSWORD = 2,
- DOMAIN_CERTIFICATE = 3,
- DOMAIN_VISIBLE_PASSWORD = 4,
- MAXIMUM = 5,
- }
-
- public enum CRED_PERSIST : uint
- {
- Session = 1,
- LocalMachine = 2,
- Enterprise = 3,
- }
-
- [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
- public struct CREDENTIAL
- {
- public int Flags;
- public CRED_TYPE Type;
- [MarshalAs(UnmanagedType.LPWStr)]
- public string TargetName;
- [MarshalAs(UnmanagedType.LPWStr)]
- public string Comment;
- public System.Runtime.InteropServices.ComTypes.FILETIME LastWritten;
- public int CredentialBlobSize;
- public IntPtr CredentialBlob;
- public int Persist;
- public int AttributeCount;
- public IntPtr CredAttribute;
- [MarshalAs(UnmanagedType.LPWStr)]
- public string TargetAlias;
- [MarshalAs(UnmanagedType.LPWStr)]
- public string UserName;
- }
-
- [DllImport("advapi32.dll", EntryPoint = "CredWriteW", CharSet = CharSet.Unicode, SetLastError = true)]
- [return: MarshalAs(UnmanagedType.Bool)]
- internal static extern bool CredWrite(CREDENTIAL credential, int flags);
-
- [DllImport("advapi32.dll", EntryPoint = "CredDeleteW", CharSet = CharSet.Unicode)]
- [return: MarshalAs(UnmanagedType.Bool)]
- internal static extern bool CredDelete(string target, CRED_TYPE type, int flags);
-
- [DllImport("advapi32.dll", EntryPoint = "CredReadW", CharSet = CharSet.Unicode, SetLastError = true)]
- [return: MarshalAs(UnmanagedType.Bool)]
- internal static extern bool CredRead(string target, CRED_TYPE type, int flags, out IntPtr credential);
-
- [DllImport("advapi32.dll", EntryPoint = "CredEnumerateW", CharSet = CharSet.Unicode, SetLastError = true)]
- [return: MarshalAs(UnmanagedType.Bool)]
- internal static extern bool CredEnumerate(string filter, uint flags, out uint count, out IntPtr credentials);
-
- [DllImport("advapi32.dll", EntryPoint = "CredFree", CharSet = CharSet.Unicode)]
- internal static extern void CredFree(IntPtr buffer);
-}
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+using System.Runtime.InteropServices;
+
+namespace GitHubExtension.DeveloperId;
+
+public static class CredentialManager
+{
+ public enum CRED_TYPE : int
+ {
+ GENERIC = 1,
+ DOMAIN_PASSWORD = 2,
+ DOMAIN_CERTIFICATE = 3,
+ DOMAIN_VISIBLE_PASSWORD = 4,
+ MAXIMUM = 5,
+ }
+
+ public enum CRED_PERSIST : uint
+ {
+ Session = 1,
+ LocalMachine = 2,
+ Enterprise = 3,
+ }
+
+ [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
+ public struct CREDENTIAL
+ {
+ public int Flags;
+ public CRED_TYPE Type;
+ [MarshalAs(UnmanagedType.LPWStr)]
+ public string TargetName;
+ [MarshalAs(UnmanagedType.LPWStr)]
+ public string Comment;
+ public System.Runtime.InteropServices.ComTypes.FILETIME LastWritten;
+ public int CredentialBlobSize;
+ public IntPtr CredentialBlob;
+ public int Persist;
+ public int AttributeCount;
+ public IntPtr CredAttribute;
+ [MarshalAs(UnmanagedType.LPWStr)]
+ public string TargetAlias;
+ [MarshalAs(UnmanagedType.LPWStr)]
+ public string UserName;
+ }
+
+ [DllImport("advapi32.dll", EntryPoint = "CredWriteW", CharSet = CharSet.Unicode, SetLastError = true)]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ internal static extern bool CredWrite(CREDENTIAL credential, int flags);
+
+ [DllImport("advapi32.dll", EntryPoint = "CredDeleteW", CharSet = CharSet.Unicode)]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ internal static extern bool CredDelete(string target, CRED_TYPE type, int flags);
+
+ [DllImport("advapi32.dll", EntryPoint = "CredReadW", CharSet = CharSet.Unicode, SetLastError = true)]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ internal static extern bool CredRead(string target, CRED_TYPE type, int flags, out IntPtr credential);
+
+ [DllImport("advapi32.dll", EntryPoint = "CredEnumerateW", CharSet = CharSet.Unicode, SetLastError = true)]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ internal static extern bool CredEnumerate(string filter, uint flags, out uint count, out IntPtr credentials);
+
+ [DllImport("advapi32.dll", EntryPoint = "CredFree", CharSet = CharSet.Unicode)]
+ internal static extern void CredFree(IntPtr buffer);
+}
diff --git a/src/GitHubExtension/DeveloperId/CredentialVault.cs b/src/GitHubExtension/DeveloperId/CredentialVault.cs
index 3c3abcf1..99a678c6 100644
--- a/src/GitHubExtension/DeveloperId/CredentialVault.cs
+++ b/src/GitHubExtension/DeveloperId/CredentialVault.cs
@@ -1,5 +1,5 @@
-// Copyright (c) Microsoft Corporation and Contributors
-// Licensed under the MIT license.
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
using System.ComponentModel;
using System.Runtime.InteropServices;
@@ -8,6 +8,7 @@
using static GitHubExtension.DeveloperId.CredentialManager;
namespace GitHubExtension.DeveloperId;
+
public class CredentialVault : ICredentialVault
{
private readonly string _credentialResourceName;
diff --git a/src/GitHubExtension/DeveloperId/DeveloperId.cs b/src/GitHubExtension/DeveloperId/DeveloperId.cs
index f2a821d3..48fd4e82 100644
--- a/src/GitHubExtension/DeveloperId/DeveloperId.cs
+++ b/src/GitHubExtension/DeveloperId/DeveloperId.cs
@@ -1,5 +1,5 @@
-// Copyright (c) Microsoft Corporation and Contributors
-// Licensed under the MIT license.
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
using Microsoft.Windows.DevHome.SDK;
using Octokit;
diff --git a/src/GitHubExtension/DeveloperId/DeveloperIdProvider.cs b/src/GitHubExtension/DeveloperId/DeveloperIdProvider.cs
index 895ff03b..566949fa 100644
--- a/src/GitHubExtension/DeveloperId/DeveloperIdProvider.cs
+++ b/src/GitHubExtension/DeveloperId/DeveloperIdProvider.cs
@@ -1,5 +1,5 @@
-// Copyright (c) Microsoft Corporation and Contributors
-// Licensed under the MIT license.
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
using System.Net;
using System.Security;
diff --git a/src/GitHubExtension/DeveloperId/Enums/LoginUIState.cs b/src/GitHubExtension/DeveloperId/Enums/LoginUIState.cs
index 2a340c82..eacdd596 100644
--- a/src/GitHubExtension/DeveloperId/Enums/LoginUIState.cs
+++ b/src/GitHubExtension/DeveloperId/Enums/LoginUIState.cs
@@ -1,5 +1,5 @@
-// Copyright (c) Microsoft Corporation and Contributors
-// Licensed under the MIT license.
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
namespace GitHubExtension.DeveloperId;
diff --git a/src/GitHubExtension/DeveloperId/ICredentialVault.cs b/src/GitHubExtension/DeveloperId/ICredentialVault.cs
index dd6a187b..b7ef13de 100644
--- a/src/GitHubExtension/DeveloperId/ICredentialVault.cs
+++ b/src/GitHubExtension/DeveloperId/ICredentialVault.cs
@@ -1,5 +1,5 @@
-// Copyright (c) Microsoft Corporation and Contributors
-// Licensed under the MIT license.
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
using System.Security;
using Windows.Security.Credentials;
diff --git a/src/GitHubExtension/DeveloperId/IDeveloperIdProviderInternal.cs b/src/GitHubExtension/DeveloperId/IDeveloperIdProviderInternal.cs
index 1ac28961..26511720 100644
--- a/src/GitHubExtension/DeveloperId/IDeveloperIdProviderInternal.cs
+++ b/src/GitHubExtension/DeveloperId/IDeveloperIdProviderInternal.cs
@@ -1,5 +1,5 @@
-// Copyright (c) Microsoft Corporation and Contributors
-// Licensed under the MIT license.
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
using System.Security;
using Microsoft.Windows.DevHome.SDK;
diff --git a/src/GitHubExtension/DeveloperId/Logging.cs b/src/GitHubExtension/DeveloperId/Logging.cs
index dae84d62..1d8e628f 100644
--- a/src/GitHubExtension/DeveloperId/Logging.cs
+++ b/src/GitHubExtension/DeveloperId/Logging.cs
@@ -1,10 +1,11 @@
-// Copyright (c) Microsoft Corporation and Contributors
-// Licensed under the MIT license.
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
using DevHome.Logging;
using Windows.Storage;
namespace GitHubExtension.DeveloperId;
+
public class Log
{
private static Logger? _logger;
diff --git a/src/GitHubExtension/DeveloperId/LoginUI/EndPage.cs b/src/GitHubExtension/DeveloperId/LoginUI/EndPage.cs
index c66895e7..51234cc6 100644
--- a/src/GitHubExtension/DeveloperId/LoginUI/EndPage.cs
+++ b/src/GitHubExtension/DeveloperId/LoginUI/EndPage.cs
@@ -1,5 +1,5 @@
-// Copyright (c) Microsoft Corporation and Contributors
-// Licensed under the MIT license.
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
namespace GitHubExtension.DeveloperId.LoginUI;
diff --git a/src/GitHubExtension/DeveloperId/LoginUI/EnterpriseServerPATPage.cs b/src/GitHubExtension/DeveloperId/LoginUI/EnterpriseServerPATPage.cs
index de7bc318..b94740b5 100644
--- a/src/GitHubExtension/DeveloperId/LoginUI/EnterpriseServerPATPage.cs
+++ b/src/GitHubExtension/DeveloperId/LoginUI/EnterpriseServerPATPage.cs
@@ -1,5 +1,5 @@
-// Copyright (c) Microsoft Corporation and Contributors
-// Licensed under the MIT license.
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
using System.Security;
using GitHubExtension.Helpers;
diff --git a/src/GitHubExtension/DeveloperId/LoginUI/EnterpriseServerPage.cs b/src/GitHubExtension/DeveloperId/LoginUI/EnterpriseServerPage.cs
index de2fb908..bc6842b2 100644
--- a/src/GitHubExtension/DeveloperId/LoginUI/EnterpriseServerPage.cs
+++ b/src/GitHubExtension/DeveloperId/LoginUI/EnterpriseServerPage.cs
@@ -1,5 +1,5 @@
-// Copyright (c) Microsoft Corporation and Contributors
-// Licensed under the MIT license.
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
using GitHubExtension.Helpers;
diff --git a/src/GitHubExtension/DeveloperId/LoginUI/LoginFailedPage.cs b/src/GitHubExtension/DeveloperId/LoginUI/LoginFailedPage.cs
index 3d546869..a8144102 100644
--- a/src/GitHubExtension/DeveloperId/LoginUI/LoginFailedPage.cs
+++ b/src/GitHubExtension/DeveloperId/LoginUI/LoginFailedPage.cs
@@ -1,5 +1,5 @@
-// Copyright (c) Microsoft Corporation and Contributors
-// Licensed under the MIT license.
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
using GitHubExtension.Helpers;
diff --git a/src/GitHubExtension/DeveloperId/LoginUI/LoginPage.cs b/src/GitHubExtension/DeveloperId/LoginUI/LoginPage.cs
index cc7bd0bf..688ec225 100644
--- a/src/GitHubExtension/DeveloperId/LoginUI/LoginPage.cs
+++ b/src/GitHubExtension/DeveloperId/LoginUI/LoginPage.cs
@@ -1,5 +1,5 @@
-// Copyright (c) Microsoft Corporation and Contributors
-// Licensed under the MIT license.
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
using GitHubExtension.Helpers;
diff --git a/src/GitHubExtension/DeveloperId/LoginUI/LoginSucceededPage.cs b/src/GitHubExtension/DeveloperId/LoginUI/LoginSucceededPage.cs
index 942fbb0b..5ef03649 100644
--- a/src/GitHubExtension/DeveloperId/LoginUI/LoginSucceededPage.cs
+++ b/src/GitHubExtension/DeveloperId/LoginUI/LoginSucceededPage.cs
@@ -1,5 +1,5 @@
-// Copyright (c) Microsoft Corporation and Contributors
-// Licensed under the MIT license.
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
using GitHubExtension.Helpers;
using Microsoft.Windows.DevHome.SDK;
diff --git a/src/GitHubExtension/DeveloperId/LoginUI/LoginUIPage.cs b/src/GitHubExtension/DeveloperId/LoginUI/LoginUIPage.cs
index 34c5a3ab..d6fe7453 100644
--- a/src/GitHubExtension/DeveloperId/LoginUI/LoginUIPage.cs
+++ b/src/GitHubExtension/DeveloperId/LoginUI/LoginUIPage.cs
@@ -1,5 +1,5 @@
-// Copyright (c) Microsoft Corporation and Contributors
-// Licensed under the MIT license.
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
using GitHubExtension.Helpers;
using Microsoft.Windows.DevHome.SDK;
diff --git a/src/GitHubExtension/DeveloperId/LoginUI/WaitingPage.cs b/src/GitHubExtension/DeveloperId/LoginUI/WaitingPage.cs
index 7401ea06..19739c8b 100644
--- a/src/GitHubExtension/DeveloperId/LoginUI/WaitingPage.cs
+++ b/src/GitHubExtension/DeveloperId/LoginUI/WaitingPage.cs
@@ -1,5 +1,5 @@
-// Copyright (c) Microsoft Corporation and Contributors
-// Licensed under the MIT license.
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
using GitHubExtension.Helpers;
diff --git a/src/GitHubExtension/DeveloperId/LoginUIController.cs b/src/GitHubExtension/DeveloperId/LoginUIController.cs
index 419ef0aa..e29bb009 100644
--- a/src/GitHubExtension/DeveloperId/LoginUIController.cs
+++ b/src/GitHubExtension/DeveloperId/LoginUIController.cs
@@ -1,5 +1,5 @@
-// Copyright (c) Microsoft Corporation and Contributors
-// Licensed under the MIT license.
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
using System.Net;
using GitHubExtension.Client;
@@ -9,6 +9,7 @@
using Windows.Foundation;
namespace GitHubExtension.DeveloperId;
+
public class LoginUIController : IExtensionAdaptiveCardSession
{
private readonly IDeveloperIdProviderInternal _developerIdProvider;
@@ -60,15 +61,6 @@ public IAsyncOperation OnAction(string action, string i
{
try
{
- // If there is already a developer id, we should block another login.
- if (_developerIdProvider.GetLoggedInDeveloperIdsInternal().Any())
- {
- Log.Logger()?.ReportInfo($"DeveloperId {_developerIdProvider.GetLoggedInDeveloperIdsInternal().First().LoginId} already exists. Blocking login.");
- new LoginFailedPage().UpdateExtensionAdaptiveCard(_loginUI);
- operationResult = new ProviderOperationResult(ProviderOperationStatus.Failure, null, "Only one DeveloperId can be logged in at a time", "One DeveloperId already exists");
- break;
- }
-
var loginPageActionPayload = Json.ToObject(action) ?? throw new InvalidOperationException("Invalid action");
if (!loginPageActionPayload.IsSubmitAction())
diff --git a/src/GitHubExtension/DeveloperId/OAuthRequest.cs b/src/GitHubExtension/DeveloperId/OAuthRequest.cs
index b6d08435..826fd6e9 100644
--- a/src/GitHubExtension/DeveloperId/OAuthRequest.cs
+++ b/src/GitHubExtension/DeveloperId/OAuthRequest.cs
@@ -1,5 +1,5 @@
-// Copyright (c) Microsoft Corporation and Contributors
-// Licensed under the MIT license.
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
using System.Net;
using System.Security;
@@ -9,6 +9,7 @@
using Octokit;
namespace GitHubExtension.DeveloperId;
+
internal class OAuthRequest : IDisposable
{
internal string State { get; private set; }
diff --git a/src/GitHubExtension/GitHubExtension.cs b/src/GitHubExtension/GitHubExtension.cs
index 609ed651..9dd8204b 100644
--- a/src/GitHubExtension/GitHubExtension.cs
+++ b/src/GitHubExtension/GitHubExtension.cs
@@ -1,5 +1,5 @@
-// Copyright (c) Microsoft Corporation and Contributors
-// Licensed under the MIT license.
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
using System.Runtime.InteropServices;
using GitHubExtension.DeveloperId;
diff --git a/src/GitHubExtension/GitHubExtension.csproj b/src/GitHubExtension/GitHubExtension.csproj
index b3839c54..15c68e57 100644
--- a/src/GitHubExtension/GitHubExtension.csproj
+++ b/src/GitHubExtension/GitHubExtension.csproj
@@ -1,11 +1,12 @@
-
+
Library
enable
enable
Dev
+ portable
@@ -70,27 +71,27 @@
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
-
-
+
+
-
+
@@ -147,39 +148,8 @@
-
-
- all
- runtime; build; native; contentfiles; analyzers; buildtransitive
-
-
-
$(DefineConstants);CANARY_BUILD
$(DefineConstants);STABLE_BUILD
-
-
- portable
-
-
-
- portable
-
-
-
- portable
-
-
-
- portable
-
-
-
- portable
-
-
-
- portable
-
diff --git a/src/GitHubExtension/Helpers/DateTimeExtensions.cs b/src/GitHubExtension/Helpers/DateTimeExtensions.cs
index 0462311b..f1236cbe 100644
--- a/src/GitHubExtension/Helpers/DateTimeExtensions.cs
+++ b/src/GitHubExtension/Helpers/DateTimeExtensions.cs
@@ -1,9 +1,10 @@
-// Copyright (c) Microsoft Corporation and Contributors
-// Licensed under the MIT license.
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
using System.Globalization;
namespace GitHubExtension.Helpers;
+
public static class DateTimeExtensions
{
// Data store stores time as integers, which is just the Ticks so we don't lose precision.
diff --git a/src/GitHubExtension/Helpers/EnumHelper.cs b/src/GitHubExtension/Helpers/EnumHelper.cs
index ab8d3c9f..e0db3c49 100644
--- a/src/GitHubExtension/Helpers/EnumHelper.cs
+++ b/src/GitHubExtension/Helpers/EnumHelper.cs
@@ -1,29 +1,30 @@
-// Copyright (c) Microsoft Corporation and Contributors
-// Licensed under the MIT license.
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
-using GitHubExtension.DataManager;
-
-namespace GitHubExtension.Helpers;
-public class EnumHelper
-{
- public static string SearchCategoryToString(SearchCategory searchCategory) => searchCategory switch
- {
- SearchCategory.Issues => "Issues",
- SearchCategory.PullRequests => "PullRequests",
- SearchCategory.IssuesAndPullRequests => "IssuesAndPullRequests",
- _ => "unknown"
- };
-
- public static SearchCategory StringToSearchCategory(string value)
- {
- try
- {
- return Enum.Parse(value);
- }
- catch (Exception)
- {
- // Invalid value.
- return SearchCategory.Unknown;
- }
- }
-}
+using GitHubExtension.DataManager;
+
+namespace GitHubExtension.Helpers;
+
+public class EnumHelper
+{
+ public static string SearchCategoryToString(SearchCategory searchCategory) => searchCategory switch
+ {
+ SearchCategory.Issues => "Issues",
+ SearchCategory.PullRequests => "PullRequests",
+ SearchCategory.IssuesAndPullRequests => "IssuesAndPullRequests",
+ _ => "unknown"
+ };
+
+ public static SearchCategory StringToSearchCategory(string value)
+ {
+ try
+ {
+ return Enum.Parse(value);
+ }
+ catch (Exception)
+ {
+ // Invalid value.
+ return SearchCategory.Unknown;
+ }
+ }
+}
diff --git a/src/GitHubExtension/Helpers/FileHelper.cs b/src/GitHubExtension/Helpers/FileHelper.cs
index a2f16333..8580af20 100644
--- a/src/GitHubExtension/Helpers/FileHelper.cs
+++ b/src/GitHubExtension/Helpers/FileHelper.cs
@@ -1,5 +1,5 @@
-// Copyright (c) Microsoft Corporation and Contributors
-// Licensed under the MIT license.
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
using System.Text;
using Newtonsoft.Json;
diff --git a/src/GitHubExtension/Helpers/IconLoader.cs b/src/GitHubExtension/Helpers/IconLoader.cs
index ba2c870c..c6a17645 100644
--- a/src/GitHubExtension/Helpers/IconLoader.cs
+++ b/src/GitHubExtension/Helpers/IconLoader.cs
@@ -1,9 +1,10 @@
-// Copyright (c) Microsoft Corporation and Contributors
-// Licensed under the MIT license.
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
using GitHubExtension.DataModel;
namespace GitHubExtension.Helpers;
+
public class IconLoader
{
private static readonly Dictionary Base64ImageRegistry = new ();
diff --git a/src/GitHubExtension/Helpers/Json.cs b/src/GitHubExtension/Helpers/Json.cs
index ff3c48bd..314d3a9a 100644
--- a/src/GitHubExtension/Helpers/Json.cs
+++ b/src/GitHubExtension/Helpers/Json.cs
@@ -1,5 +1,5 @@
-// Copyright (c) Microsoft Corporation and Contributors
-// Licensed under the MIT license.
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
using System.Text.Json;
using System.Text.Json.Serialization;
diff --git a/src/GitHubExtension/Helpers/LocalSettings.cs b/src/GitHubExtension/Helpers/LocalSettings.cs
index 9aabb7bf..76563412 100644
--- a/src/GitHubExtension/Helpers/LocalSettings.cs
+++ b/src/GitHubExtension/Helpers/LocalSettings.cs
@@ -1,10 +1,11 @@
-// Copyright (c) Microsoft Corporation and Contributors
-// Licensed under the MIT license.
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
using DevHome.Common.Services;
using Windows.Storage;
namespace GitHubExtension.Helpers;
+
public static class LocalSettings
{
private static readonly string _applicationDataFolder = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "DevHome/ApplicationData");
diff --git a/src/GitHubExtension/Helpers/Resources.cs b/src/GitHubExtension/Helpers/Resources.cs
index 29b4df72..e3051708 100644
--- a/src/GitHubExtension/Helpers/Resources.cs
+++ b/src/GitHubExtension/Helpers/Resources.cs
@@ -1,10 +1,11 @@
-// Copyright (c) Microsoft Corporation and Contributors
-// Licensed under the MIT license.
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
using DevHome.Logging;
using Microsoft.Windows.ApplicationModel.Resources;
namespace GitHubExtension.Helpers;
+
public static class Resources
{
private static ResourceLoader? _resourceLoader;
@@ -100,6 +101,7 @@ public static string[] GetWidgetResourceIdentifiers()
"Widget_Template_Button/Cancel",
"Widget_Template_Tooltip/Save",
"Widget_Template_Tooltip/Cancel",
+ "Widget_Template/ChooseAccountPlaceholder",
};
}
}
diff --git a/src/GitHubExtension/Helpers/RuntimeHelper.cs b/src/GitHubExtension/Helpers/RuntimeHelper.cs
index 7cd3f578..59c9f95d 100644
--- a/src/GitHubExtension/Helpers/RuntimeHelper.cs
+++ b/src/GitHubExtension/Helpers/RuntimeHelper.cs
@@ -1,5 +1,5 @@
-// Copyright (c) Microsoft Corporation and Contributors
-// Licensed under the MIT license.
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
using Windows.Win32;
using Windows.Win32.Foundation;
diff --git a/src/GitHubExtension/Helpers/StringExtensions.cs b/src/GitHubExtension/Helpers/StringExtensions.cs
index 59da8dba..9b8440ba 100644
--- a/src/GitHubExtension/Helpers/StringExtensions.cs
+++ b/src/GitHubExtension/Helpers/StringExtensions.cs
@@ -1,15 +1,16 @@
-// Copyright (c) Microsoft Corporation and Contributors
-// Licensed under the MIT license.
-
-using System.Globalization;
-
-namespace GitHubExtension.Helpers;
-public static class StringExtensions
-{
- public static string ToStringInvariant(this T value) => Convert.ToString(value, CultureInfo.InvariantCulture)!;
-
- public static string FormatInvariant(this string value, params object[] arguments)
- {
- return string.Format(CultureInfo.InvariantCulture, value, arguments);
- }
-}
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+using System.Globalization;
+
+namespace GitHubExtension.Helpers;
+
+public static class StringExtensions
+{
+ public static string ToStringInvariant(this T value) => Convert.ToString(value, CultureInfo.InvariantCulture)!;
+
+ public static string FormatInvariant(this string value, params object[] arguments)
+ {
+ return string.Format(CultureInfo.InvariantCulture, value, arguments);
+ }
+}
diff --git a/src/GitHubExtension/Helpers/TimeSpanHelper.cs b/src/GitHubExtension/Helpers/TimeSpanHelper.cs
index fe6f8db6..9afbc566 100644
--- a/src/GitHubExtension/Helpers/TimeSpanHelper.cs
+++ b/src/GitHubExtension/Helpers/TimeSpanHelper.cs
@@ -1,10 +1,11 @@
-// Copyright (c) Microsoft Corporation and Contributors
-// Licensed under the MIT license.
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
using DevHome.Logging;
using Jeffijoe.MessageFormat;
namespace GitHubExtension.Helpers;
+
internal class TimeSpanHelper
{
public static string TimeSpanToDisplayString(TimeSpan timeSpan, Logger? log = null)
diff --git a/src/GitHubExtension/NativeMethods.txt b/src/GitHubExtension/NativeMethods.txt
index 820e3114..498e284c 100644
--- a/src/GitHubExtension/NativeMethods.txt
+++ b/src/GitHubExtension/NativeMethods.txt
@@ -1 +1 @@
-GetCurrentPackageFullName
+GetCurrentPackageFullName
diff --git a/src/GitHubExtension/Notifications/Logging.cs b/src/GitHubExtension/Notifications/Logging.cs
index fe1d6a0a..390d7ff9 100644
--- a/src/GitHubExtension/Notifications/Logging.cs
+++ b/src/GitHubExtension/Notifications/Logging.cs
@@ -1,10 +1,11 @@
-// Copyright (c) Microsoft Corporation and Contributors
-// Licensed under the MIT license.
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
using DevHome.Logging;
using Windows.Storage;
namespace GitHubExtension.Notifications;
+
public class Log
{
private static Logger? _logger;
diff --git a/src/GitHubExtension/Notifications/NotificationHandler.cs b/src/GitHubExtension/Notifications/NotificationHandler.cs
index fef70865..c6626b7b 100644
--- a/src/GitHubExtension/Notifications/NotificationHandler.cs
+++ b/src/GitHubExtension/Notifications/NotificationHandler.cs
@@ -1,5 +1,5 @@
-// Copyright (c) Microsoft Corporation and Contributors
-// Licensed under the MIT license.
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
using System.Diagnostics;
using System.Globalization;
@@ -8,6 +8,7 @@
using Microsoft.Windows.AppNotifications;
namespace GitHubExtension.Notifications;
+
public class NotificationHandler
{
#pragma warning disable IDE0060 // Remove unused parameter
diff --git a/src/GitHubExtension/Notifications/NotificationManager.cs b/src/GitHubExtension/Notifications/NotificationManager.cs
index 1155f6f2..3d9e3756 100644
--- a/src/GitHubExtension/Notifications/NotificationManager.cs
+++ b/src/GitHubExtension/Notifications/NotificationManager.cs
@@ -1,5 +1,5 @@
-// Copyright (c) Microsoft Corporation and Contributors
-// Licensed under the MIT license.
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
using Microsoft.Windows.AppNotifications;
diff --git a/src/GitHubExtension/Providers/DevHomeRepository.cs b/src/GitHubExtension/Providers/DevHomeRepository.cs
index bc13040c..fe86428c 100644
--- a/src/GitHubExtension/Providers/DevHomeRepository.cs
+++ b/src/GitHubExtension/Providers/DevHomeRepository.cs
@@ -1,5 +1,5 @@
-// Copyright (c) Microsoft Corporation and Contributors
-// Licensed under the MIT license.
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
using GitHubExtension.Client;
@@ -29,13 +29,13 @@ public class DevHomeRepository : Microsoft.Windows.DevHome.SDK.IRepository
///
/// Initializes a new instance of the class.
///
- /// The repository received from ocktokit
- public DevHomeRepository(Octokit.Repository ocktokitRepository)
+ /// The repository received from octokit
+ public DevHomeRepository(Octokit.Repository octokitRepository)
{
- this.name = ocktokitRepository.Name;
- this.cloneUrl = new Uri(ocktokitRepository.CloneUrl);
+ this.name = octokitRepository.Name;
+ this.cloneUrl = new Uri(octokitRepository.CloneUrl);
- _lastUpdated = ocktokitRepository.UpdatedAt;
- _isPrivate = ocktokitRepository.Private;
+ _lastUpdated = octokitRepository.UpdatedAt;
+ _isPrivate = octokitRepository.Private;
}
}
diff --git a/src/GitHubExtension/Providers/Logging.cs b/src/GitHubExtension/Providers/Logging.cs
index 938284e3..af5e21a7 100644
--- a/src/GitHubExtension/Providers/Logging.cs
+++ b/src/GitHubExtension/Providers/Logging.cs
@@ -1,10 +1,11 @@
-// Copyright (c) Microsoft Corporation and Contributors
-// Licensed under the MIT license.
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
using DevHome.Logging;
using Windows.Storage;
namespace GitHubExtension.Providers;
+
public class Log
{
private static Logger? _logger;
diff --git a/src/GitHubExtension/Providers/RepositoryProvider.cs b/src/GitHubExtension/Providers/RepositoryProvider.cs
index 463272d0..47b1fc2e 100644
--- a/src/GitHubExtension/Providers/RepositoryProvider.cs
+++ b/src/GitHubExtension/Providers/RepositoryProvider.cs
@@ -1,5 +1,5 @@
-// Copyright (c) Microsoft Corporation and Contributors
-// Licensed under the MIT license.
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
using GitHubExtension.Client;
using GitHubExtension.DeveloperId;
@@ -129,7 +129,7 @@ public IAsyncOperation GetRepositoryFromUriAsync(Uri uri, IDev
return new RepositoryResult(exception, $"{exception.Message} HResult: {exception.HResult}");
}
- Octokit.Repository? ocktokitRepo = null;
+ Octokit.Repository? octokitRepo = null;
var owner = Validation.ParseOwnerFromGitHubURL(uri);
var repoName = Validation.ParseRepositoryFromGitHubURL(uri);
@@ -147,7 +147,7 @@ public IAsyncOperation GetRepositoryFromUriAsync(Uri uri, IDev
gitHubClient = GitHubClientProvider.Instance.GetClient();
}
- ocktokitRepo = gitHubClient.Repository.Get(owner, repoName).Result;
+ octokitRepo = gitHubClient.Repository.Get(owner, repoName).Result;
}
catch (AggregateException e)
{
@@ -176,13 +176,13 @@ public IAsyncOperation GetRepositoryFromUriAsync(Uri uri, IDev
return new RepositoryResult(e, $"Unspecified error when cloning a repo. HResult: {e.HResult}");
}
- if (ocktokitRepo == null)
+ if (octokitRepo == null)
{
return new RepositoryResult(new ArgumentException("Repo is still null"), "Repo is still null");
}
else
{
- return new RepositoryResult(new DevHomeRepository(ocktokitRepo));
+ return new RepositoryResult(new DevHomeRepository(octokitRepo));
}
}).AsAsyncOperation();
}
diff --git a/src/GitHubExtension/Providers/SettingsProvider.cs b/src/GitHubExtension/Providers/SettingsProvider.cs
index 09ee8efc..420f6c51 100644
--- a/src/GitHubExtension/Providers/SettingsProvider.cs
+++ b/src/GitHubExtension/Providers/SettingsProvider.cs
@@ -1,5 +1,5 @@
-// Copyright (c) Microsoft Corporation and Contributors
-// Licensed under the MIT license.
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
using GitHubExtension.Helpers;
using Microsoft.Windows.DevHome.SDK;
diff --git a/src/GitHubExtension/Providers/SettingsUIController.cs b/src/GitHubExtension/Providers/SettingsUIController.cs
index 98904cec..6c8cfa39 100644
--- a/src/GitHubExtension/Providers/SettingsUIController.cs
+++ b/src/GitHubExtension/Providers/SettingsUIController.cs
@@ -1,5 +1,5 @@
-// Copyright (c) Microsoft Corporation and Contributors
-// Licensed under the MIT license.
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
using GitHubExtension.Helpers;
using Microsoft.Windows.ApplicationModel.Resources;
@@ -7,6 +7,7 @@
using Windows.Foundation;
namespace GitHubExtension.Providers;
+
internal class SettingsUIController : IExtensionAdaptiveCardSession
{
private static readonly string _notificationsEnabledString = "NotificationsEnabled";
diff --git a/src/GitHubExtension/Strings/en-US/Resources.resw b/src/GitHubExtension/Strings/en-US/Resources.resw
index 9f74e894..f3efd99a 100644
--- a/src/GitHubExtension/Strings/en-US/Resources.resw
+++ b/src/GitHubExtension/Strings/en-US/Resources.resw
@@ -501,4 +501,16 @@
Please enter the PAT
LoginUI Error text if input is null
+
+ Approved
+ Shown in toast notification.
+
+
+ Changes requested
+ Shown in toast notification.
+
+
+ Please choose an account
+ Placeholder text for a combobox where the user can select between accounts
+
\ No newline at end of file
diff --git a/src/GitHubExtension/Widgets/Enums/WidgetAction.cs b/src/GitHubExtension/Widgets/Enums/WidgetAction.cs
index 671fc664..a732257d 100644
--- a/src/GitHubExtension/Widgets/Enums/WidgetAction.cs
+++ b/src/GitHubExtension/Widgets/Enums/WidgetAction.cs
@@ -1,7 +1,8 @@
-// Copyright (c) Microsoft Corporation and Contributors
-// Licensed under the MIT license.
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
namespace GitHubExtension.Widgets.Enums;
+
public enum WidgetAction
{
///
diff --git a/src/GitHubExtension/Widgets/Enums/WidgetActivityState.cs b/src/GitHubExtension/Widgets/Enums/WidgetActivityState.cs
index 20ecab98..aa678140 100644
--- a/src/GitHubExtension/Widgets/Enums/WidgetActivityState.cs
+++ b/src/GitHubExtension/Widgets/Enums/WidgetActivityState.cs
@@ -1,7 +1,8 @@
-// Copyright (c) Microsoft Corporation and Contributors
-// Licensed under the MIT license.
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
namespace GitHubExtension.Widgets.Enums;
+
public enum WidgetActivityState
{
///
diff --git a/src/GitHubExtension/Widgets/Enums/WidgetDataState.cs b/src/GitHubExtension/Widgets/Enums/WidgetDataState.cs
index 545f7be0..23ea2cca 100644
--- a/src/GitHubExtension/Widgets/Enums/WidgetDataState.cs
+++ b/src/GitHubExtension/Widgets/Enums/WidgetDataState.cs
@@ -1,7 +1,8 @@
-// Copyright (c) Microsoft Corporation and Contributors
-// Licensed under the MIT license.
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
namespace GitHubExtension.Widgets;
+
public enum WidgetDataState
{
Unknown,
diff --git a/src/GitHubExtension/Widgets/Enums/WidgetPageState.cs b/src/GitHubExtension/Widgets/Enums/WidgetPageState.cs
index 47b0a380..70e1bf7a 100644
--- a/src/GitHubExtension/Widgets/Enums/WidgetPageState.cs
+++ b/src/GitHubExtension/Widgets/Enums/WidgetPageState.cs
@@ -1,7 +1,8 @@
-// Copyright (c) Microsoft Corporation and Contributors
-// Licensed under the MIT license.
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
namespace GitHubExtension.Widgets;
+
public enum WidgetPageState
{
Unknown,
diff --git a/src/GitHubExtension/Widgets/GitHubAssignedWidget.cs b/src/GitHubExtension/Widgets/GitHubAssignedWidget.cs
index bdfd067f..45ea2655 100644
--- a/src/GitHubExtension/Widgets/GitHubAssignedWidget.cs
+++ b/src/GitHubExtension/Widgets/GitHubAssignedWidget.cs
@@ -1,85 +1,86 @@
-// Copyright (c) Microsoft Corporation and Contributors
-// Licensed under the MIT license.
-
-using Octokit;
-
-namespace GitHubExtension.Widgets;
-internal class GitHubAssignedWidget : GitHubUserWidget
-{
- private static readonly string TitleIconData =
- "iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAYAAACqaXHeAAAABGdBTUEAALGPC/xhBQAAAAlwS" +
- "FlzAAAOwgAADsIBFShKgAAACXVJREFUeF7tmvuSFEUWh3kFDXAMQvJk9QChj7EhyMSsCLIwMR" +
- "r7n4KgIHKTiyIIgqiIwIg6iOve3H2XZWZfafb3nc6srp5Ld1VP9whsn4gT1V15O3nuJys3jWE" +
- "MYxjDGDYY7Eh43k6E3XYyvBY/Ep4Ke+xD/f8g7LJ3w3Op29MPbLS4GvYW98Kh1k8225pP+NAW" +
- "Wj/b0gp86LjgfdS/eGAzxVf2ZjwbtqYpnw6IF8M2CG/NpY3+Tfj39Pyr8Nc+SL+MfxH+aAvFH" +
- "ftTvGp7pSUvpGWePPCNz4UZEb7Y+ocIZ7NsAOQ3TOD9P4W/Cf9lS5MV9He0ZWbBDMbyzGN/ts" +
- "V4PUymJZ8MkA2/6Bv/VRuH2F+EmXBQWlD8ICnet0NIsrhtB4qv7c0SpS3+/Ebvv1X7d3awmLM" +
- "ZJO8alOfKzGSdhzKRa9ZKJPx+IMJ3th6JoLxpnu3fi8K3Wz/YTLxmb9h7tjkNqQ3xpE0UN2w/" +
- "c2hO5uswF5Q2uGmcsIk0ZOPAjobNLC7VXnR1zYSh6j9J2p8PVzqKFhNohq/HGlVG3LfH8bS9m" +
- "LqOHuLx8AKLOiEQkImZ18Zv2v74vm1JXYcO8aJtK+5pbdarmFshpsdPLKRuowPsvfUgLJSLZ/" +
- "x+gwgQYE6ufW0za68PPWjeJduWug0fImoP96uSfyS8KxWUvaZuGwbFLdvhESfTwhNBjMoc3AZ" +
- "ZJHtkFmXzR5s7uGGBMwFNqGik6Hxs79hwM0rZ9nZ3QHkhwtOd33fzGUrBZKEooyyu277UvH6I" +
- "5+0lT1GZvCr54zZQVmZyonYmTMXzYRqHml4PDITB0iknGgtM4aMhmGU8rHxeki4lDwMG8Ljxt" +
- "JKlW7bfk6EHclY/+jxLivELxV0lPl/YvnjYnk/dN9n7YUtxI+z35Ih64NPe6xVXrBBtnXwELV" +
- "D+kZoHB4jokvy8JlZykpr7AgVRvKk5FCI9nQVhJtIif8gprv5ju3Jge+yw/aG4Gf7DmpP/Vpv" +
- "SY5iUplwTyCKdzkSrxjyOHwympSUoHZ11Itk8kyoKWE27p4pDW3x8ZmDePP+p/sRQf887RRTN" +
- "vySJL0nrKILa/Uilv+zPdEzK+7MGT4R1xfam5uZQXAmF236eEAKV6KTmnuCbJ5ev2KU/SZspd" +
- "cn5Vd0Vn9nr1AFaZ1Z92ipMaM2Y163BALTNNS3TC+Nkdqm5OUgah5ygRBQqZTUdn2sOhOTxyu" +
- "Wx/175gkxrO/2c+MywxIAoH5G69YTiS5lbLqASzQOZgR0LWyg2SmIahBbfSDVBQRKScmruCVp" +
- "jsmQCGgAT2UjNteMFmQHONTFfVehS/NimUnN9UG0/7eqb1anmRPFyMI1pq3JCokiTalBEz5TM" +
- "Y30YWNOWOWZj01U/E2Vmqbk+FF+Efb545iTZ1ZFOmFoLiltSwarTVJgT4xodacXrWhsHmZkgZ" +
- "6hcZDo19wSvUhVmSwagPTXNpwQj9n8XHvviTIIEajg/aoXWPY3Ljo/FFcNTc21A+1TddZj/QA" +
- "xQeEzNfcEPUyqRp0nYduCU1gnIDNDveLm/GsWrYe8KyX1if0zNtUERZMpDIIyEiXOa56S9lpr" +
- "7As62iwFNNUA193S5eaFL4Gx/+/eF8+EIC5MzDOCBlTXu6WIAnrzBGcO6GUB89uwsb+R7MeBD" +
- "252a1wSlt7POABbGbGrE7tUgfiwNQANhAPPctgOpqRasYEBjE1DI8dPZzID7tmTHbFdqXhXcb" +
- "5D1VRnw+WC5eDwXptwEYQDht6EfcR+Q6YD+xibAQWTWAE1Cekp+nppXBRUvu0qppdAVB0xD4y" +
- "WFYFLkzIAGmmTvhOeoBEsGYEJNBRHl8Vcw4EhvBvCJqyQ6M2CQ+CtQIdTO5piHON6k+DoaXm3" +
- "JZ5UMEE2NHbEzIMfymhpA5BgaA6jqWJt52EADCXpBlDUR9Z8b4FyAvLvLCdbwASs0AMnVCJ3L" +
- "IUqFtYEFl16WoJxyau4L8Vp4w0NxEkJTB+qwIgooDlufKDAsE8AB+niQ9RsyQAncQew+C2GgQ" +
- "xEk5xtBAjBAYdBO9c7E/FsBksvjYMAAUcBT6Sz9hhoQT4QJ0ds+twRJxM4NUgip6HEuIgGIoB" +
- "BScpSa14SuPADv27AW59hMRLfPHvPaMKAmIwtqCDae1/9Widi7A5wOUwrL7ttfX0BUqYYn9io" +
- "uO080Rw7IGnwvIN6Xa2YGsHadOuR8eMmZxxgxQcJY4DA3NTcHP1jIxAj9MKTPURgHmN4/SxAn" +
- "VFMLJL1JTIhSFqfLWJ8LSbK21Dt1XQEqgSdgdpfZruckCCiuqLBJm3fEni70NgO3wUxIhwmLH" +
- "IYojK5ZSovZO7wfIUsxO55RJphL2szINQ5U1HcrJ8ul6tOf2uHYOr9P8jVWk7UdChOjijVOZf" +
- "wcocoAxiJFFUbxU20u3QUib4hicnFXXpuTp2XnBpL6QTcnfFF7/QVCGqWy3y0iXebEmqyPduh" +
- "kPb4HnBrSpzFJge/y7YkhhEMR+YfUvCp4Kqp+pToyjvH8p74gvOIo2Ry/wUeS/nXruvWh0rrg" +
- "vW+sOkcel+eiPSF+a2ibB5B4aYttKdTSAr8cRUGSv9nl8VXM75HsLduRhnZB8VXYqX6dsLZ8j" +
- "oyYj7LHQb9UrQn2XtjsnhWJJU1wO62ZWkqNX9HYP0tynU2ASJJD03mbLfp88WndsZe9LzQsnw" +
- "PmKPIUo/wsTwjKm3duY8/y9qm5FhDfsXdSbK7LxEs23eS2F2aFzZNZkhOQqJHgcP6XuowOXJ3" +
- "lVZ3jmQlSW23mybqpNUrgWoo2330RAdu9YdtTl2cfCrzy8mtwMOHm/xMTbttObbwTmtoasUgK" +
- "i52mbs82OBOqmpAQPxGVkqZuzzYoCrSZkH1CRhIXxX95+ZHc1LJzYSvZXzzT7EvTSKDgG2D+F" +
- "J0ZkOMz9wXT5+/1ZGZknRxxkXz5MRnnDZwzND3mHhVQ/JCfu1/IaWn2DUpcJtulMUXODNVlvB" +
- "xe56uP1wPHwi4OMB35fVz1wWnVBxfCtNcI34QDrfnQvlyRL1BnZo/yKtwgoMTEVOwcIiqUWsA" +
- "zmwjP/J6Mrh9Wx2fM4/lN4bRBlzIbAbc0lTrPitCV/qG6kdWw2pb7gp2xi9Kut7gh+kT4gF7g" +
- "qSu2i3mQQP0mcwBzBQei0stR7+mT+v5X9v6Wl8Aqo7k1lqZ/uoAbm/GE7ZbUpqgByOe57MDXG" +
- "k5sHfmNwyTXv6g+Z9V32JXdGMYwhjGMYQzLYNOm/wESzvR5z0LQ4QAAAABJRU5ErkJggg==";
-
- protected static readonly new string Name = nameof(GitHubAssignedWidget);
-
- protected override string GetTitleIconData()
- {
- return TitleIconData;
- }
-
- public override void RequestContentData()
- {
- var request = new SearchIssuesRequest()
- {
- Assignee = UserName,
- };
-
- RequestContentData(request);
- }
-
- public override string GetTemplatePath(WidgetPageState page)
- {
- return page switch
- {
- WidgetPageState.SignIn => @"Widgets\Templates\GitHubSignInTemplate.json",
- WidgetPageState.Configure => @"Widgets\Templates\GitHubAssignedConfigurationTemplate.json",
- WidgetPageState.Content => @"Widgets\Templates\GitHubAssignedTemplate.json",
- WidgetPageState.Loading => @"Widgets\Templates\GitHubLoadingTemplate.json",
- _ => throw new NotImplementedException(),
- };
- }
-}
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+using Octokit;
+
+namespace GitHubExtension.Widgets;
+
+internal class GitHubAssignedWidget : GitHubUserWidget
+{
+ private static readonly string TitleIconData =
+ "iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAYAAACqaXHeAAAABGdBTUEAALGPC/xhBQAAAAlwS" +
+ "FlzAAAOwgAADsIBFShKgAAACXVJREFUeF7tmvuSFEUWh3kFDXAMQvJk9QChj7EhyMSsCLIwMR" +
+ "r7n4KgIHKTiyIIgqiIwIg6iOve3H2XZWZfafb3nc6srp5Ld1VP9whsn4gT1V15O3nuJys3jWE" +
+ "MYxjDGDYY7Eh43k6E3XYyvBY/Ep4Ke+xD/f8g7LJ3w3Op29MPbLS4GvYW98Kh1k8225pP+NAW" +
+ "Wj/b0gp86LjgfdS/eGAzxVf2ZjwbtqYpnw6IF8M2CG/NpY3+Tfj39Pyr8Nc+SL+MfxH+aAvFH" +
+ "ftTvGp7pSUvpGWePPCNz4UZEb7Y+ocIZ7NsAOQ3TOD9P4W/Cf9lS5MV9He0ZWbBDMbyzGN/ts" +
+ "V4PUymJZ8MkA2/6Bv/VRuH2F+EmXBQWlD8ICnet0NIsrhtB4qv7c0SpS3+/Ebvv1X7d3awmLM" +
+ "ZJO8alOfKzGSdhzKRa9ZKJPx+IMJ3th6JoLxpnu3fi8K3Wz/YTLxmb9h7tjkNqQ3xpE0UN2w/" +
+ "c2hO5uswF5Q2uGmcsIk0ZOPAjobNLC7VXnR1zYSh6j9J2p8PVzqKFhNohq/HGlVG3LfH8bS9m" +
+ "LqOHuLx8AKLOiEQkImZ18Zv2v74vm1JXYcO8aJtK+5pbdarmFshpsdPLKRuowPsvfUgLJSLZ/" +
+ "x+gwgQYE6ufW0za68PPWjeJduWug0fImoP96uSfyS8KxWUvaZuGwbFLdvhESfTwhNBjMoc3AZ" +
+ "ZJHtkFmXzR5s7uGGBMwFNqGik6Hxs79hwM0rZ9nZ3QHkhwtOd33fzGUrBZKEooyyu277UvH6I" +
+ "5+0lT1GZvCr54zZQVmZyonYmTMXzYRqHml4PDITB0iknGgtM4aMhmGU8rHxeki4lDwMG8Ljxt" +
+ "JKlW7bfk6EHclY/+jxLivELxV0lPl/YvnjYnk/dN9n7YUtxI+z35Ih64NPe6xVXrBBtnXwELV" +
+ "D+kZoHB4jokvy8JlZykpr7AgVRvKk5FCI9nQVhJtIif8gprv5ju3Jge+yw/aG4Gf7DmpP/Vpv" +
+ "SY5iUplwTyCKdzkSrxjyOHwympSUoHZ11Itk8kyoKWE27p4pDW3x8ZmDePP+p/sRQf887RRTN" +
+ "vySJL0nrKILa/Uilv+zPdEzK+7MGT4R1xfam5uZQXAmF236eEAKV6KTmnuCbJ5ev2KU/SZspd" +
+ "cn5Vd0Vn9nr1AFaZ1Z92ipMaM2Y163BALTNNS3TC+Nkdqm5OUgah5ygRBQqZTUdn2sOhOTxyu" +
+ "Wx/175gkxrO/2c+MywxIAoH5G69YTiS5lbLqASzQOZgR0LWyg2SmIahBbfSDVBQRKScmruCVp" +
+ "jsmQCGgAT2UjNteMFmQHONTFfVehS/NimUnN9UG0/7eqb1anmRPFyMI1pq3JCokiTalBEz5TM" +
+ "Y30YWNOWOWZj01U/E2Vmqbk+FF+Efb545iTZ1ZFOmFoLiltSwarTVJgT4xodacXrWhsHmZkgZ" +
+ "6hcZDo19wSvUhVmSwagPTXNpwQj9n8XHvviTIIEajg/aoXWPY3Ljo/FFcNTc21A+1TddZj/QA" +
+ "xQeEzNfcEPUyqRp0nYduCU1gnIDNDveLm/GsWrYe8KyX1if0zNtUERZMpDIIyEiXOa56S9lpr" +
+ "7As62iwFNNUA193S5eaFL4Gx/+/eF8+EIC5MzDOCBlTXu6WIAnrzBGcO6GUB89uwsb+R7MeBD" +
+ "252a1wSlt7POABbGbGrE7tUgfiwNQANhAPPctgOpqRasYEBjE1DI8dPZzID7tmTHbFdqXhXcb" +
+ "5D1VRnw+WC5eDwXptwEYQDht6EfcR+Q6YD+xibAQWTWAE1Cekp+nppXBRUvu0qppdAVB0xD4y" +
+ "WFYFLkzIAGmmTvhOeoBEsGYEJNBRHl8Vcw4EhvBvCJqyQ6M2CQ+CtQIdTO5piHON6k+DoaXm3" +
+ "JZ5UMEE2NHbEzIMfymhpA5BgaA6jqWJt52EADCXpBlDUR9Z8b4FyAvLvLCdbwASs0AMnVCJ3L" +
+ "IUqFtYEFl16WoJxyau4L8Vp4w0NxEkJTB+qwIgooDlufKDAsE8AB+niQ9RsyQAncQew+C2GgQ" +
+ "xEk5xtBAjBAYdBO9c7E/FsBksvjYMAAUcBT6Sz9hhoQT4QJ0ds+twRJxM4NUgip6HEuIgGIoB" +
+ "BScpSa14SuPADv27AW59hMRLfPHvPaMKAmIwtqCDae1/9Widi7A5wOUwrL7ttfX0BUqYYn9io" +
+ "uO080Rw7IGnwvIN6Xa2YGsHadOuR8eMmZxxgxQcJY4DA3NTcHP1jIxAj9MKTPURgHmN4/SxAn" +
+ "VFMLJL1JTIhSFqfLWJ8LSbK21Dt1XQEqgSdgdpfZruckCCiuqLBJm3fEni70NgO3wUxIhwmLH" +
+ "IYojK5ZSovZO7wfIUsxO55RJphL2szINQ5U1HcrJ8ul6tOf2uHYOr9P8jVWk7UdChOjijVOZf" +
+ "wcocoAxiJFFUbxU20u3QUib4hicnFXXpuTp2XnBpL6QTcnfFF7/QVCGqWy3y0iXebEmqyPduh" +
+ "kPb4HnBrSpzFJge/y7YkhhEMR+YfUvCp4Kqp+pToyjvH8p74gvOIo2Ry/wUeS/nXruvWh0rrg" +
+ "vW+sOkcel+eiPSF+a2ibB5B4aYttKdTSAr8cRUGSv9nl8VXM75HsLduRhnZB8VXYqX6dsLZ8j" +
+ "oyYj7LHQb9UrQn2XtjsnhWJJU1wO62ZWkqNX9HYP0tynU2ASJJD03mbLfp88WndsZe9LzQsnw" +
+ "PmKPIUo/wsTwjKm3duY8/y9qm5FhDfsXdSbK7LxEs23eS2F2aFzZNZkhOQqJHgcP6XuowOXJ3" +
+ "lVZ3jmQlSW23mybqpNUrgWoo2330RAdu9YdtTl2cfCrzy8mtwMOHm/xMTbttObbwTmtoasUgK" +
+ "i52mbs82OBOqmpAQPxGVkqZuzzYoCrSZkH1CRhIXxX95+ZHc1LJzYSvZXzzT7EvTSKDgG2D+F" +
+ "J0ZkOMz9wXT5+/1ZGZknRxxkXz5MRnnDZwzND3mHhVQ/JCfu1/IaWn2DUpcJtulMUXODNVlvB" +
+ "xe56uP1wPHwi4OMB35fVz1wWnVBxfCtNcI34QDrfnQvlyRL1BnZo/yKtwgoMTEVOwcIiqUWsA" +
+ "zmwjP/J6Mrh9Wx2fM4/lN4bRBlzIbAbc0lTrPitCV/qG6kdWw2pb7gp2xi9Kut7gh+kT4gF7g" +
+ "qSu2i3mQQP0mcwBzBQei0stR7+mT+v5X9v6Wl8Aqo7k1lqZ/uoAbm/GE7ZbUpqgByOe57MDXG" +
+ "k5sHfmNwyTXv6g+Z9V32JXdGMYwhjGMYQzLYNOm/wESzvR5z0LQ4QAAAABJRU5ErkJggg==";
+
+ protected static readonly new string Name = nameof(GitHubAssignedWidget);
+
+ protected override string GetTitleIconData()
+ {
+ return TitleIconData;
+ }
+
+ public override void RequestContentData()
+ {
+ var request = new SearchIssuesRequest()
+ {
+ Assignee = UserName,
+ };
+
+ RequestContentData(request);
+ }
+
+ public override string GetTemplatePath(WidgetPageState page)
+ {
+ return page switch
+ {
+ WidgetPageState.SignIn => @"Widgets\Templates\GitHubSignInTemplate.json",
+ WidgetPageState.Configure => @"Widgets\Templates\GitHubAssignedConfigurationTemplate.json",
+ WidgetPageState.Content => @"Widgets\Templates\GitHubAssignedTemplate.json",
+ WidgetPageState.Loading => @"Widgets\Templates\GitHubLoadingTemplate.json",
+ _ => throw new NotImplementedException(),
+ };
+ }
+}
diff --git a/src/GitHubExtension/Widgets/GitHubIssuesWidget.cs b/src/GitHubExtension/Widgets/GitHubIssuesWidget.cs
index 0205a66e..95fc7dda 100644
--- a/src/GitHubExtension/Widgets/GitHubIssuesWidget.cs
+++ b/src/GitHubExtension/Widgets/GitHubIssuesWidget.cs
@@ -1,15 +1,15 @@
-// Copyright (c) Microsoft Corporation and Contributors
-// Licensed under the MIT license.
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
using System.Text.Json.Nodes;
using GitHubExtension.Client;
using GitHubExtension.DataManager;
using GitHubExtension.Helpers;
using GitHubExtension.Widgets.Enums;
-using Microsoft.Windows.Widgets.Providers;
using Octokit;
namespace GitHubExtension.Widgets;
+
internal class GitHubIssuesWidget : GitHubRepositoryWidget
{
private readonly string issuesIconData = IconLoader.GetIconAsBase64("issues.png");
diff --git a/src/GitHubExtension/Widgets/GitHubMentionedInWidget.cs b/src/GitHubExtension/Widgets/GitHubMentionedInWidget.cs
index 524f1650..fbae0ed3 100644
--- a/src/GitHubExtension/Widgets/GitHubMentionedInWidget.cs
+++ b/src/GitHubExtension/Widgets/GitHubMentionedInWidget.cs
@@ -1,66 +1,67 @@
-// Copyright (c) Microsoft Corporation and Contributors
-// Licensed under the MIT license.
-
-using Octokit;
-
-namespace GitHubExtension.Widgets;
-internal class GitHubMentionedInWidget : GitHubUserWidget
-{
- private static readonly string TitleIconData =
- "iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAYAAACqaXHeAAAABGdBTUEAALGPC/xhBQAAAA" +
- "lwSFlzAAAOwgAADsIBFShKgAAABTBJREFUeF7tW/tvFFUUrn+CGK1KtESJ0obsbKf7mJ3H" +
- "zsw+uu2+t5s21JTWIn0ZQrGxRI1R8VGkCipoAiICSotVrEIp0FZQXv7I7k7/oOs5s9dH2r" +
- "JMW2p2JvdLTtrcuTNzznfPOfdM7tkaBgYGS+BeCTzh7hejXF/1iqkf6ElVfjjwvKNtFc+0" +
- "9igX06XgbIYEL1exXMkQ5VK6JIG+oHeWe1l4jJqxenjf1bYq08k+9VrWUOezxHZyLUuCM+" +
- "mSfzzcQE2yDt9YaJvyS6qk3cgR7Y82ol1vw4cReSpJpIlEWSarUM7FifJzimg32oh+O2/q" +
- "bpJwNMpR0x4Mfq+8WZ3NGNrvcPPVDBHPxgtNb6op94DYzPUKEddOQTeluwplp19HHfkRJS" +
- "Eca+7EsNVvtRF1IWvgolITK0M63dqDLoQsQuwXuN0POan8j/Afjmz/O4S1hZzBv6Y8Qy+t" +
- "jKa31OfAbRbVhRwmFKNxWN5ML9kWwtFoJ+YD/U6egBfk6fDKED6L7tDv5ok6lyXesXDlyT" +
- "aBuz9Qi4uJOUE81XKP6/ZvopeWI3Ai1qXfhpi5mjFcPevYQqoMsEUOakCAfD5B+BE5QYeX" +
- "I/A1EpDH5PcqHXIEkAAMAWkiTvi9UgsdXo7AyTIB4AGOJaDRCgGO9ACwixFglQBHhgDzAE" +
- "YAI4ARwAhgBFgjgG2DjABGACOADjkCjABGACOAEcAIYAQwAhgBjIBKBLi6fI+IJ2Nn6cmQ" +
- "8wi4kycyEFD5YMTJJ0NWQkA4Fu3EiXik3LRf2UKHbY/gbGYI7RK/ixfcg2ItHV4O73t6Tr" +
- "8JBMxniXi6tYcO2xq+g6F6XFAkQPiyuZMOrwx3v1gb/DVdUhfMPhsDb6aXbImm/cEtCrUH" +
- "CfAe0NvopfvDdyjcgMfj2vWceUweOBHz0Eu2gu/jcL0ynSqadoBHY88T1xe4v/v/F/L5xC" +
- "68EQWbC6TJxK7A8ViX/0i0wzcebveNR9p9hyMd3g9CeW6dfQTYtuL/NNLh+2QdgvqACKAf" +
- "6gnJrjd4CVbebPXJgfHpEjdQIfaXAvvrsMkIkoeB24f+Jwi4EDZOqb8BoxgiC/B3LkuwqY" +
- "Letmp4Pwy9KP+YLKrz9Jn47HUI6od6mvreBX1hAbHPyb1Heoq+cnXwfhTaJk0kepULySIw" +
- "SsxGSZQrGaKCYAcW/D9Ep1tG45D0pHiqtRsUXtTKXVwYbv8+f61yOUOUi2mC+qLe/s+jO7" +
- "he4XH62rWDH5Xr0OUxiwpfNb8kfh8v4Iv0W1AzzKQH6TRLEL6IcsGZTAm9p+xJWQMU3o01" +
- "CHrdmgV1wxAdC+X5UaWOvm5j4HlbzchTCdPdwDMG6HBF8K8H63BrBc8xE6x2E1Z+LmfA1v" +
- "sCnWIfNO6RYtJk3Gw9s0KAB4xULqSKGDI6Gg4rL52LF/jR4Mau1EaB3ye1YsfVgwjguoVN" +
- "4rct2HhZ3lYh2WF2xo8ubF+j0+wHKwT4DobrsU/3n1iHLK1Mp4sQPs/TKfYFPwwETAIBsN" +
- "UsJQCLDUxKuNIY59iwjAUVdmy6uvyP0mn2Br9PjpsesCQJYlEDRVMBVxtjXYO/8g+Jovd9" +
- "zX6JrhL4YdkMAVxh2H8Nzxtqyn8o3K5BVkejTZeHuMcKEj4/n6a3OQfYQS7BpyWWmdiIDH" +
- "W2+XsCNN5MdnNZw38ksp1Odyag9m4AD1g0f1QBnmA2WUN5HPim5V7jiPIsneZsCMdjHvmn" +
- "ZBE9QJ5KFrH0dFXqxnYisOz0HtBybqufmgwMDAwMDFWCmpq/ANfVYnfzsINAAAAAAElFTkSuQmCC";
-
- protected static readonly new string Name = nameof(GitHubMentionedInWidget);
-
- protected override string GetTitleIconData()
- {
- return TitleIconData;
- }
-
- public override void RequestContentData()
- {
- var request = new SearchIssuesRequest()
- {
- Mentions = UserName,
- };
-
- RequestContentData(request);
- }
-
- public override string GetTemplatePath(WidgetPageState page)
- {
- return page switch
- {
- WidgetPageState.SignIn => @"Widgets\Templates\GitHubSignInTemplate.json",
- WidgetPageState.Configure => @"Widgets\Templates\GitHubMentionedInConfigurationTemplate.json",
- WidgetPageState.Content => @"Widgets\Templates\GitHubMentionedInTemplate.json",
- WidgetPageState.Loading => @"Widgets\Templates\GitHubLoadingTemplate.json",
- _ => throw new NotImplementedException(),
- };
- }
-}
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+using Octokit;
+
+namespace GitHubExtension.Widgets;
+
+internal class GitHubMentionedInWidget : GitHubUserWidget
+{
+ private static readonly string TitleIconData =
+ "iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAYAAACqaXHeAAAABGdBTUEAALGPC/xhBQAAAA" +
+ "lwSFlzAAAOwgAADsIBFShKgAAABTBJREFUeF7tW/tvFFUUrn+CGK1KtESJ0obsbKf7mJ3H" +
+ "zsw+uu2+t5s21JTWIn0ZQrGxRI1R8VGkCipoAiICSotVrEIp0FZQXv7I7k7/oOs5s9dH2r" +
+ "JMW2p2JvdLTtrcuTNzznfPOfdM7tkaBgYGS+BeCTzh7hejXF/1iqkf6ElVfjjwvKNtFc+0" +
+ "9igX06XgbIYEL1exXMkQ5VK6JIG+oHeWe1l4jJqxenjf1bYq08k+9VrWUOezxHZyLUuCM+" +
+ "mSfzzcQE2yDt9YaJvyS6qk3cgR7Y82ol1vw4cReSpJpIlEWSarUM7FifJzimg32oh+O2/q" +
+ "bpJwNMpR0x4Mfq+8WZ3NGNrvcPPVDBHPxgtNb6op94DYzPUKEddOQTeluwplp19HHfkRJS" +
+ "Eca+7EsNVvtRF1IWvgolITK0M63dqDLoQsQuwXuN0POan8j/Afjmz/O4S1hZzBv6Y8Qy+t" +
+ "jKa31OfAbRbVhRwmFKNxWN5ML9kWwtFoJ+YD/U6egBfk6fDKED6L7tDv5ok6lyXesXDlyT" +
+ "aBuz9Qi4uJOUE81XKP6/ZvopeWI3Ai1qXfhpi5mjFcPevYQqoMsEUOakCAfD5B+BE5QYeX" +
+ "I/A1EpDH5PcqHXIEkAAMAWkiTvi9UgsdXo7AyTIB4AGOJaDRCgGO9ACwixFglQBHhgDzAE" +
+ "YAI4ARwAhgBFgjgG2DjABGACOADjkCjABGACOAEcAIYAQwAhgBjIBKBLi6fI+IJ2Nn6cmQ" +
+ "8wi4kycyEFD5YMTJJ0NWQkA4Fu3EiXik3LRf2UKHbY/gbGYI7RK/ixfcg2ItHV4O73t6Tr" +
+ "8JBMxniXi6tYcO2xq+g6F6XFAkQPiyuZMOrwx3v1gb/DVdUhfMPhsDb6aXbImm/cEtCrUH" +
+ "CfAe0NvopfvDdyjcgMfj2vWceUweOBHz0Eu2gu/jcL0ynSqadoBHY88T1xe4v/v/F/L5xC" +
+ "68EQWbC6TJxK7A8ViX/0i0wzcebveNR9p9hyMd3g9CeW6dfQTYtuL/NNLh+2QdgvqACKAf" +
+ "6gnJrjd4CVbebPXJgfHpEjdQIfaXAvvrsMkIkoeB24f+Jwi4EDZOqb8BoxgiC/B3LkuwqY" +
+ "Letmp4Pwy9KP+YLKrz9Jn47HUI6od6mvreBX1hAbHPyb1Heoq+cnXwfhTaJk0kepULySIw" +
+ "SsxGSZQrGaKCYAcW/D9Ep1tG45D0pHiqtRsUXtTKXVwYbv8+f61yOUOUi2mC+qLe/s+jO7" +
+ "he4XH62rWDH5Xr0OUxiwpfNb8kfh8v4Iv0W1AzzKQH6TRLEL6IcsGZTAm9p+xJWQMU3o01" +
+ "CHrdmgV1wxAdC+X5UaWOvm5j4HlbzchTCdPdwDMG6HBF8K8H63BrBc8xE6x2E1Z+LmfA1v" +
+ "sCnWIfNO6RYtJk3Gw9s0KAB4xULqSKGDI6Gg4rL52LF/jR4Mau1EaB3ye1YsfVgwjguoVN" +
+ "4rct2HhZ3lYh2WF2xo8ubF+j0+wHKwT4DobrsU/3n1iHLK1Mp4sQPs/TKfYFPwwETAIBsN" +
+ "UsJQCLDUxKuNIY59iwjAUVdmy6uvyP0mn2Br9PjpsesCQJYlEDRVMBVxtjXYO/8g+Jovd9" +
+ "zX6JrhL4YdkMAVxh2H8Nzxtqyn8o3K5BVkejTZeHuMcKEj4/n6a3OQfYQS7BpyWWmdiIDH" +
+ "W2+XsCNN5MdnNZw38ksp1Odyag9m4AD1g0f1QBnmA2WUN5HPim5V7jiPIsneZsCMdjHvmn" +
+ "ZBE9QJ5KFrH0dFXqxnYisOz0HtBybqufmgwMDAwMDFWCmpq/ANfVYnfzsINAAAAAAElFTkSuQmCC";
+
+ protected static readonly new string Name = nameof(GitHubMentionedInWidget);
+
+ protected override string GetTitleIconData()
+ {
+ return TitleIconData;
+ }
+
+ public override void RequestContentData()
+ {
+ var request = new SearchIssuesRequest()
+ {
+ Mentions = UserName,
+ };
+
+ RequestContentData(request);
+ }
+
+ public override string GetTemplatePath(WidgetPageState page)
+ {
+ return page switch
+ {
+ WidgetPageState.SignIn => @"Widgets\Templates\GitHubSignInTemplate.json",
+ WidgetPageState.Configure => @"Widgets\Templates\GitHubMentionedInConfigurationTemplate.json",
+ WidgetPageState.Content => @"Widgets\Templates\GitHubMentionedInTemplate.json",
+ WidgetPageState.Loading => @"Widgets\Templates\GitHubLoadingTemplate.json",
+ _ => throw new NotImplementedException(),
+ };
+ }
+}
diff --git a/src/GitHubExtension/Widgets/GitHubPullsWidget.cs b/src/GitHubExtension/Widgets/GitHubPullsWidget.cs
index 318c4250..df5362d1 100644
--- a/src/GitHubExtension/Widgets/GitHubPullsWidget.cs
+++ b/src/GitHubExtension/Widgets/GitHubPullsWidget.cs
@@ -1,15 +1,15 @@
-// Copyright (c) Microsoft Corporation and Contributors
-// Licensed under the MIT license.
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
using System.Text.Json.Nodes;
using GitHubExtension.Client;
using GitHubExtension.DataManager;
using GitHubExtension.Helpers;
using GitHubExtension.Widgets.Enums;
-using Microsoft.Windows.Widgets.Providers;
using Octokit;
namespace GitHubExtension.Widgets;
+
internal class GitHubPullsWidget : GitHubRepositoryWidget
{
private readonly string pullsIconData = IconLoader.GetIconAsBase64("pulls.png");
diff --git a/src/GitHubExtension/Widgets/GitHubRepositoryWidget.cs b/src/GitHubExtension/Widgets/GitHubRepositoryWidget.cs
index 09b9501a..c8a10514 100644
--- a/src/GitHubExtension/Widgets/GitHubRepositoryWidget.cs
+++ b/src/GitHubExtension/Widgets/GitHubRepositoryWidget.cs
@@ -1,15 +1,12 @@
-// Copyright (c) Microsoft Corporation and Contributors
-// Licensed under the MIT license.
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
-using System.Text;
using System.Text.Json;
using System.Text.Json.Nodes;
using GitHubExtension.Client;
using GitHubExtension.DataManager;
-using GitHubExtension.DeveloperId;
using GitHubExtension.Helpers;
using GitHubExtension.Widgets.Enums;
-using Microsoft.Windows.DevHome.SDK;
using Microsoft.Windows.Widgets.Providers;
namespace GitHubExtension.Widgets;
diff --git a/src/GitHubExtension/Widgets/GitHubReviewWidget.cs b/src/GitHubExtension/Widgets/GitHubReviewWidget.cs
index 03907b95..9a248426 100644
--- a/src/GitHubExtension/Widgets/GitHubReviewWidget.cs
+++ b/src/GitHubExtension/Widgets/GitHubReviewWidget.cs
@@ -1,81 +1,82 @@
-// Copyright (c) Microsoft Corporation and Contributors
-// Licensed under the MIT license.
-
-using System.Text.Json.Nodes;
-using GitHubExtension.DataManager;
-using GitHubExtension.Helpers;
-using Microsoft.Windows.Widgets.Providers;
-using Octokit;
-
-namespace GitHubExtension.Widgets;
-internal class GitHubReviewWidget : GitHubUserWidget
-{
- protected static readonly new string Name = nameof(GitHubReviewWidget);
-
- public GitHubReviewWidget()
- : base()
- {
- // This widget doest not allow customization, so this value will not change.
- ShowCategory = SearchCategory.PullRequests;
- }
-
- public override void RequestContentData()
- {
- SearchIssuesRequest request = new SearchIssuesRequest($"review-requested:{UserName}");
-
- RequestContentData(request);
- }
-
- protected override string GetTitleIconData()
- {
- return IconLoader.GetIconAsBase64("pulls.png");
- }
-
- // This widget does not have "ShowCategory" as a variable.
- // So we override this method to not care about this data.
- protected override void ResetWidgetInfoFromState()
- {
- base.ResetWidgetInfoFromState();
- ShowCategory = SearchCategory.PullRequests;
- }
-
- // Overriding this method because this widget only cares about the account.
- public override void OnActionInvoked(WidgetActionInvokedArgs actionInvokedArgs)
- {
- if (actionInvokedArgs.Verb == "Submit")
- {
- var data = actionInvokedArgs.Data;
- var dataObject = JsonNode.Parse(data);
-
- if (dataObject == null)
- {
- return;
- }
-
- DeveloperLoginId = dataObject["account"]?.GetValue() ?? string.Empty;
-
- ConfigurationData = data;
-
- // If we got here during the customization flow, we need to LoadContentData again
- // so we can show the loading page rather than stale data.
- LoadContentData();
- UpdateActivityState();
- }
- else
- {
- base.OnActionInvoked(actionInvokedArgs);
- }
- }
-
- public override string GetTemplatePath(WidgetPageState page)
- {
- return page switch
- {
- WidgetPageState.SignIn => @"Widgets\Templates\GitHubSignInTemplate.json",
- WidgetPageState.Configure => @"Widgets\Templates\GitHubReviewConfigurationTemplate.json",
- WidgetPageState.Content => @"Widgets\Templates\GitHubReviewTemplate.json",
- WidgetPageState.Loading => @"Widgets\Templates\GitHubLoadingTemplate.json",
- _ => throw new NotImplementedException(),
- };
- }
-}
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+using System.Text.Json.Nodes;
+using GitHubExtension.DataManager;
+using GitHubExtension.Helpers;
+using Microsoft.Windows.Widgets.Providers;
+using Octokit;
+
+namespace GitHubExtension.Widgets;
+
+internal class GitHubReviewWidget : GitHubUserWidget
+{
+ protected static readonly new string Name = nameof(GitHubReviewWidget);
+
+ public GitHubReviewWidget()
+ : base()
+ {
+ // This widget does not allow customization, so this value will not change.
+ ShowCategory = SearchCategory.PullRequests;
+ }
+
+ public override void RequestContentData()
+ {
+ SearchIssuesRequest request = new SearchIssuesRequest($"review-requested:{UserName}");
+
+ RequestContentData(request);
+ }
+
+ protected override string GetTitleIconData()
+ {
+ return IconLoader.GetIconAsBase64("pulls.png");
+ }
+
+ // This widget does not have "ShowCategory" as a variable.
+ // So we override this method to not care about this data.
+ protected override void ResetWidgetInfoFromState()
+ {
+ base.ResetWidgetInfoFromState();
+ ShowCategory = SearchCategory.PullRequests;
+ }
+
+ // Overriding this method because this widget only cares about the account.
+ public override void OnActionInvoked(WidgetActionInvokedArgs actionInvokedArgs)
+ {
+ if (actionInvokedArgs.Verb == "Submit")
+ {
+ var data = actionInvokedArgs.Data;
+ var dataObject = JsonNode.Parse(data);
+
+ if (dataObject == null)
+ {
+ return;
+ }
+
+ DeveloperLoginId = dataObject["account"]?.GetValue() ?? string.Empty;
+
+ ConfigurationData = data;
+
+ // If we got here during the customization flow, we need to LoadContentData again
+ // so we can show the loading page rather than stale data.
+ LoadContentData();
+ UpdateActivityState();
+ }
+ else
+ {
+ base.OnActionInvoked(actionInvokedArgs);
+ }
+ }
+
+ public override string GetTemplatePath(WidgetPageState page)
+ {
+ return page switch
+ {
+ WidgetPageState.SignIn => @"Widgets\Templates\GitHubSignInTemplate.json",
+ WidgetPageState.Configure => @"Widgets\Templates\GitHubReviewConfigurationTemplate.json",
+ WidgetPageState.Content => @"Widgets\Templates\GitHubReviewTemplate.json",
+ WidgetPageState.Loading => @"Widgets\Templates\GitHubLoadingTemplate.json",
+ _ => throw new NotImplementedException(),
+ };
+ }
+}
diff --git a/src/GitHubExtension/Widgets/GitHubUserWidget.cs b/src/GitHubExtension/Widgets/GitHubUserWidget.cs
index d3487618..38796c4f 100644
--- a/src/GitHubExtension/Widgets/GitHubUserWidget.cs
+++ b/src/GitHubExtension/Widgets/GitHubUserWidget.cs
@@ -1,5 +1,5 @@
-// Copyright (c) Microsoft Corporation and Contributors
-// Licensed under the MIT license.
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
using System.Text.Json;
using System.Text.Json.Nodes;
@@ -12,6 +12,7 @@
using Octokit;
namespace GitHubExtension.Widgets;
+
internal abstract class GitHubUserWidget : GitHubWidget
{
protected static readonly new string Name = nameof(GitHubUserWidget);
@@ -318,11 +319,11 @@ public override string GetData(WidgetPageState page)
protected IDeveloperId? GetWidgetDeveloperId()
{
- foreach (var devid in DeveloperIdProvider.GetInstance().GetLoggedInDeveloperIds().DeveloperIds)
+ foreach (var devId in DeveloperIdProvider.GetInstance().GetLoggedInDeveloperIds().DeveloperIds)
{
- if (devid.LoginId == DeveloperLoginId)
+ if (devId.LoginId == DeveloperLoginId)
{
- return devid;
+ return devId;
}
}
diff --git a/src/GitHubExtension/Widgets/GitHubWidget.cs b/src/GitHubExtension/Widgets/GitHubWidget.cs
index 8d89ff4a..dc208403 100644
--- a/src/GitHubExtension/Widgets/GitHubWidget.cs
+++ b/src/GitHubExtension/Widgets/GitHubWidget.cs
@@ -1,9 +1,8 @@
-// Copyright (c) Microsoft Corporation and Contributors
-// Licensed under the MIT license.
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
using System.Text;
using System.Text.Json.Nodes;
-using GitHubExtension.Client;
using GitHubExtension.DataManager;
using GitHubExtension.DeveloperId;
using GitHubExtension.Helpers;
diff --git a/src/GitHubExtension/Widgets/Guids.cs b/src/GitHubExtension/Widgets/Guids.cs
index 78b08ee0..7a4a54d1 100644
--- a/src/GitHubExtension/Widgets/Guids.cs
+++ b/src/GitHubExtension/Widgets/Guids.cs
@@ -1,5 +1,5 @@
-// Copyright (c) Microsoft Corporation and Contributors
-// Licensed under the MIT license.
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
using System.Runtime.InteropServices;
diff --git a/src/GitHubExtension/Widgets/IWidgetImplFactory.cs b/src/GitHubExtension/Widgets/IWidgetImplFactory.cs
index b1aa02cb..5d07a78f 100644
--- a/src/GitHubExtension/Widgets/IWidgetImplFactory.cs
+++ b/src/GitHubExtension/Widgets/IWidgetImplFactory.cs
@@ -1,9 +1,10 @@
-// Copyright (c) Microsoft Corporation and Contributors
-// Licensed under the MIT license.
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
using Microsoft.Windows.Widgets.Providers;
namespace GitHubExtension.Widgets;
+
internal interface IWidgetImplFactory
{
public WidgetImpl Create(WidgetContext widgetContext, string state);
diff --git a/src/GitHubExtension/Widgets/Logging.cs b/src/GitHubExtension/Widgets/Logging.cs
index df2bea82..60ae63af 100644
--- a/src/GitHubExtension/Widgets/Logging.cs
+++ b/src/GitHubExtension/Widgets/Logging.cs
@@ -1,10 +1,11 @@
-// Copyright (c) Microsoft Corporation and Contributors
-// Licensed under the MIT license.
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
using DevHome.Logging;
using Windows.Storage;
namespace GitHubExtension.Widgets;
+
public class Log
{
private static Logger? _logger;
diff --git a/src/GitHubExtension/Widgets/Templates/GitHubAssignedConfigurationTemplate.json b/src/GitHubExtension/Widgets/Templates/GitHubAssignedConfigurationTemplate.json
index d55ebae2..dc270763 100644
--- a/src/GitHubExtension/Widgets/Templates/GitHubAssignedConfigurationTemplate.json
+++ b/src/GitHubExtension/Widgets/Templates/GitHubAssignedConfigurationTemplate.json
@@ -1,69 +1,69 @@
-{
- "type": "AdaptiveCard",
- "$schema": "http://adaptivecards.io/schemas/adaptive-card.json",
- "version": "1.5",
- "body": [
- {
- "type": "Input.ChoiceSet",
- "id": "account",
- "placeholder": "%Widget_Template/ChooseAccountPlaceholder%",
- "value": "${selectedDevId}",
- "choices": [
- {
- "$data": "${accounts}",
- "title": "${devid}",
- "value": "${devid}"
- }
- ]
- },
- {
- "type": "ColumnSet",
- "columns": [
- {
- "type": "Column",
- "width": "stretch",
- "items": [
- {
- "type": "Input.ChoiceSet",
- "id": "showCategory",
- "style": "compact",
- "isMultiSelect": false,
- "value": "${showCategory}",
- "choices": [
- {
- "title": "%Widget_Template/Issues%",
- "value": "Issues"
- },
- {
- "title": "%Widget_Template/PullRequests%",
- "value": "PullRequests"
- },
- {
- "title": "%Widget_Template/IssuesAndPullRequests%",
- "value": "IssuesAndPullRequests"
- }
- ]
- }
- ]
- },
- {
- "type": "Column",
- "width": "auto",
- "items": [
- {
- "type": "ActionSet",
- "actions": [
- {
- "type": "Action.Execute",
- "title": "%Widget_Template_Button/Submit%",
- "verb": "Submit",
- "associatedInputs": "auto"
- }
- ]
- }
- ]
- }
- ]
- }
- ]
+{
+ "type": "AdaptiveCard",
+ "$schema": "http://adaptivecards.io/schemas/adaptive-card.json",
+ "version": "1.5",
+ "body": [
+ {
+ "type": "Input.ChoiceSet",
+ "id": "account",
+ "placeholder": "%Widget_Template/ChooseAccountPlaceholder%",
+ "value": "${selectedDevId}",
+ "choices": [
+ {
+ "$data": "${accounts}",
+ "title": "${devid}",
+ "value": "${devid}"
+ }
+ ]
+ },
+ {
+ "type": "ColumnSet",
+ "columns": [
+ {
+ "type": "Column",
+ "width": "stretch",
+ "items": [
+ {
+ "type": "Input.ChoiceSet",
+ "id": "showCategory",
+ "style": "compact",
+ "isMultiSelect": false,
+ "value": "${showCategory}",
+ "choices": [
+ {
+ "title": "%Widget_Template/Issues%",
+ "value": "Issues"
+ },
+ {
+ "title": "%Widget_Template/PullRequests%",
+ "value": "PullRequests"
+ },
+ {
+ "title": "%Widget_Template/IssuesAndPullRequests%",
+ "value": "IssuesAndPullRequests"
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "type": "Column",
+ "width": "auto",
+ "items": [
+ {
+ "type": "ActionSet",
+ "actions": [
+ {
+ "type": "Action.Execute",
+ "title": "%Widget_Template_Button/Submit%",
+ "verb": "Submit",
+ "associatedInputs": "auto"
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ }
+ ]
}
\ No newline at end of file
diff --git a/src/GitHubExtension/Widgets/Templates/GitHubAssignedTemplate.json b/src/GitHubExtension/Widgets/Templates/GitHubAssignedTemplate.json
index 2a60c103..e2835d97 100644
--- a/src/GitHubExtension/Widgets/Templates/GitHubAssignedTemplate.json
+++ b/src/GitHubExtension/Widgets/Templates/GitHubAssignedTemplate.json
@@ -1,152 +1,152 @@
-{
- "type": "AdaptiveCard",
- "body": [
- {
- "type": "ColumnSet",
- "columns": [
- {
- "type": "Column",
- "width": "auto",
- "items": [
- {
- "type": "Image",
- "url": "data:image/png;base64,${titleIconUrl}",
- "size": "large"
- }
- ],
- "verticalContentAlignment": "Center"
- },
- {
- "type": "Column",
- "width": "stretch",
- "items": [
- {
- "type": "TextBlock",
- "text": "${userName}",
- "size": "Large",
- "style": "Heading",
- "wrap": true
- }
- ],
- "verticalContentAlignment": "Center"
- }
- ]
- },
- {
- "type": "Container",
- "$when": "${(count(items) == 0)}",
- "items": [
- {
- "type": "TextBlock",
- "text": "${if(is_loading_data, '%Widget_Template/ContentLoading%', '%Widget_Template/EmptyAssigned%')}",
- "wrap": true,
- "weight": "bolder",
- "horizontalAlignment": "center"
- }
- ],
- "spacing": "medium",
- "verticalContentAlignment": "center"
- },
- {
- "$data": "${items}",
- "type": "ColumnSet",
- "style": "emphasis",
- "spacing": "default",
- "selectAction": {
- "type": "Action.OpenUrl",
- "url": "${url}",
- "tooltip": "%Widget_Template_Tooltip/OpenIssue%"
- },
- "columns": [
- {
- "type": "Column",
- "items": [
- {
- "type": "Image",
- "url": "data:image/png;base64,${iconUrl}",
- "size": "medium"
- }
- ],
- "width": "12px"
- },
- {
- "type": "Column",
- "width": "stretch",
- "items": [
- {
- "type": "TextBlock",
- "size": "medium",
- "weight": "bolder",
- "text": "${title}",
- "wrap": true,
- "maxLines": 2
- },
- {
- "type": "ColumnSet",
- "spacing": "None",
- "wrap": true,
- "columns": [
- {
- "type": "Column",
- "width": "12px",
- "items": [
- {
- "type": "Image",
- "style": "Person",
- "url": "${avatar}",
- "size": "small"
- }
- ]
- },
- {
- "type": "Column",
- "width": "stretch",
- "items": [
- {
- "type": "TextBlock",
- "text": "${user}",
- "isSubtle": true,
- "size": "small",
- "spacing": "None",
- "weight": "bolder"
- }
- ]
- }
- ]
- },
- {
- "type": "TextBlock",
- "size": "small",
- "spacing": "small",
- "text": "#${number} %Widget_Template/Updated% ${date}",
- "isSubtle": true,
- "wrap": true,
- "maxLines": 2
- },
- {
- "type": "TextBlock",
- "size": "small",
- "spacing": "small",
- "text": "${repo}",
- "isSubtle": true,
- "wrap": true,
- "maxLines": 2
- },
- {
- "type": "LabelGroup",
- "labels": [
- {
- "$data": "${labels}",
- "text": "${name}",
- "color": "${color}"
- }
- ]
- }
- ]
- }
- ]
- }
- ],
- "$schema": "http://adaptivecards.io/schemas/adaptive-card.json",
- "version": "1.5"
-}
+{
+ "type": "AdaptiveCard",
+ "body": [
+ {
+ "type": "ColumnSet",
+ "columns": [
+ {
+ "type": "Column",
+ "width": "auto",
+ "items": [
+ {
+ "type": "Image",
+ "url": "data:image/png;base64,${titleIconUrl}",
+ "size": "large"
+ }
+ ],
+ "verticalContentAlignment": "Center"
+ },
+ {
+ "type": "Column",
+ "width": "stretch",
+ "items": [
+ {
+ "type": "TextBlock",
+ "text": "${userName}",
+ "size": "Large",
+ "style": "Heading",
+ "wrap": true
+ }
+ ],
+ "verticalContentAlignment": "Center"
+ }
+ ]
+ },
+ {
+ "type": "Container",
+ "$when": "${(count(items) == 0)}",
+ "items": [
+ {
+ "type": "TextBlock",
+ "text": "${if(is_loading_data, '%Widget_Template/ContentLoading%', '%Widget_Template/EmptyAssigned%')}",
+ "wrap": true,
+ "weight": "bolder",
+ "horizontalAlignment": "center"
+ }
+ ],
+ "spacing": "medium",
+ "verticalContentAlignment": "center"
+ },
+ {
+ "$data": "${items}",
+ "type": "ColumnSet",
+ "style": "emphasis",
+ "spacing": "default",
+ "selectAction": {
+ "type": "Action.OpenUrl",
+ "url": "${url}",
+ "tooltip": "%Widget_Template_Tooltip/OpenIssue%"
+ },
+ "columns": [
+ {
+ "type": "Column",
+ "items": [
+ {
+ "type": "Image",
+ "url": "data:image/png;base64,${iconUrl}",
+ "size": "medium"
+ }
+ ],
+ "width": "12px"
+ },
+ {
+ "type": "Column",
+ "width": "stretch",
+ "items": [
+ {
+ "type": "TextBlock",
+ "size": "medium",
+ "weight": "bolder",
+ "text": "${title}",
+ "wrap": true,
+ "maxLines": 2
+ },
+ {
+ "type": "ColumnSet",
+ "spacing": "None",
+ "wrap": true,
+ "columns": [
+ {
+ "type": "Column",
+ "width": "12px",
+ "items": [
+ {
+ "type": "Image",
+ "style": "Person",
+ "url": "${avatar}",
+ "size": "small"
+ }
+ ]
+ },
+ {
+ "type": "Column",
+ "width": "stretch",
+ "items": [
+ {
+ "type": "TextBlock",
+ "text": "${user}",
+ "isSubtle": true,
+ "size": "small",
+ "spacing": "None",
+ "weight": "bolder"
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "type": "TextBlock",
+ "size": "small",
+ "spacing": "small",
+ "text": "#${number} %Widget_Template/Updated% ${date}",
+ "isSubtle": true,
+ "wrap": true,
+ "maxLines": 2
+ },
+ {
+ "type": "TextBlock",
+ "size": "small",
+ "spacing": "small",
+ "text": "${repo}",
+ "isSubtle": true,
+ "wrap": true,
+ "maxLines": 2
+ },
+ {
+ "type": "LabelGroup",
+ "labels": [
+ {
+ "$data": "${labels}",
+ "text": "${name}",
+ "color": "${color}"
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ }
+ ],
+ "$schema": "http://adaptivecards.io/schemas/adaptive-card.json",
+ "version": "1.5"
+}
diff --git a/src/GitHubExtension/Widgets/Templates/GitHubMentionedInConfigurationTemplate.json b/src/GitHubExtension/Widgets/Templates/GitHubMentionedInConfigurationTemplate.json
index bd7d646c..70becf0b 100644
--- a/src/GitHubExtension/Widgets/Templates/GitHubMentionedInConfigurationTemplate.json
+++ b/src/GitHubExtension/Widgets/Templates/GitHubMentionedInConfigurationTemplate.json
@@ -1,68 +1,68 @@
-{
- "type": "AdaptiveCard",
- "$schema": "http://adaptivecards.io/schemas/adaptive-card.json",
- "version": "1.5",
- "body": [
- {
- "type": "Input.ChoiceSet",
- "id": "account",
- "placeholder": "%Widget_Template/ChooseAccountPlaceholder%",
- "value": "${selectedDevId}",
- "choices": [
- {
- "$data": "${accounts}",
- "title": "${devid}",
- "value": "${devid}"
- }
- ]
- },
- {
- "type": "ColumnSet",
- "columns": [
- {
- "type": "Column",
- "width": "stretch",
- "items": [
- {
- "type": "Input.ChoiceSet",
- "id": "showCategory",
- "isMultiSelect": false,
- "value": "${showCategory}",
- "choices": [
- {
- "title": "%Widget_Template/Issues%",
- "value": "Issues"
- },
- {
- "title": "%Widget_Template/PullRequests%",
- "value": "PullRequests"
- },
- {
- "title": "%Widget_Template/IssuesAndPullRequests%",
- "value": "IssuesAndPullRequests"
- }
- ]
- }
- ]
- },
- {
- "type": "Column",
- "width": "auto",
- "items": [
- {
- "type": "ActionSet",
- "actions": [
- {
- "type": "Action.Execute",
- "title": "%Widget_Template_Button/Submit%",
- "verb": "Submit",
- "associatedInputs": "auto"
- }
- ]
- }
- ]
- }
- ]
- }
- ]
+{
+ "type": "AdaptiveCard",
+ "$schema": "http://adaptivecards.io/schemas/adaptive-card.json",
+ "version": "1.5",
+ "body": [
+ {
+ "type": "Input.ChoiceSet",
+ "id": "account",
+ "placeholder": "%Widget_Template/ChooseAccountPlaceholder%",
+ "value": "${selectedDevId}",
+ "choices": [
+ {
+ "$data": "${accounts}",
+ "title": "${devid}",
+ "value": "${devid}"
+ }
+ ]
+ },
+ {
+ "type": "ColumnSet",
+ "columns": [
+ {
+ "type": "Column",
+ "width": "stretch",
+ "items": [
+ {
+ "type": "Input.ChoiceSet",
+ "id": "showCategory",
+ "isMultiSelect": false,
+ "value": "${showCategory}",
+ "choices": [
+ {
+ "title": "%Widget_Template/Issues%",
+ "value": "Issues"
+ },
+ {
+ "title": "%Widget_Template/PullRequests%",
+ "value": "PullRequests"
+ },
+ {
+ "title": "%Widget_Template/IssuesAndPullRequests%",
+ "value": "IssuesAndPullRequests"
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "type": "Column",
+ "width": "auto",
+ "items": [
+ {
+ "type": "ActionSet",
+ "actions": [
+ {
+ "type": "Action.Execute",
+ "title": "%Widget_Template_Button/Submit%",
+ "verb": "Submit",
+ "associatedInputs": "auto"
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ }
+ ]
}
\ No newline at end of file
diff --git a/src/GitHubExtension/Widgets/Templates/GitHubMentionedInTemplate.json b/src/GitHubExtension/Widgets/Templates/GitHubMentionedInTemplate.json
index 23f60725..ee19feea 100644
--- a/src/GitHubExtension/Widgets/Templates/GitHubMentionedInTemplate.json
+++ b/src/GitHubExtension/Widgets/Templates/GitHubMentionedInTemplate.json
@@ -1,153 +1,153 @@
-{
- "type": "AdaptiveCard",
- "body": [
- {
- "type": "ColumnSet",
- "columns": [
- {
- "type": "Column",
- "width": "auto",
- "items": [
- {
- "type": "Image",
- "url": "data:image/png;base64,${titleIconUrl}",
- "size": "large"
- }
- ],
- "verticalContentAlignment": "Center"
- },
- {
- "type": "Column",
- "width": "stretch",
- "items": [
- {
- "type": "TextBlock",
- "text": "${userName}",
- "size": "Large",
- "style": "Heading",
- "wrap": true
- }
- ],
- "verticalContentAlignment": "Center"
- }
- ]
- },
- {
- "type": "Container",
- "$when": "${(count(items) == 0)}",
- "items": [
- {
- "type": "TextBlock",
- "text": "${if(is_loading_data, '%Widget_Template/ContentLoading%', '%Widget_Template/EmptyMentioned%')}",
- "wrap": true,
- "weight": "bolder",
- "horizontalAlignment": "center"
- }
- ],
- "spacing": "medium",
- "verticalContentAlignment": "center"
- },
- {
- "$data": "${items}",
- "type": "ColumnSet",
- "style": "emphasis",
- "spacing": "default",
- "selectAction": {
- "type": "Action.OpenUrl",
- "url": "${url}",
- "tooltip": "%Widget_Template_Tooltip/OpenIssue%"
- },
- "columns": [
- {
- "type": "Column",
- "items": [
- {
- "type": "Image",
- "url": "data:image/png;base64,${iconUrl}",
- "size": "medium"
- }
- ],
- "width": "12px"
- },
- {
- "type": "Column",
- "width": "stretch",
- "items": [
- {
- "type": "TextBlock",
- "size": "medium",
- "wrap": true,
- "maxLines": 2,
- "weight": "Bolder",
- "text": "${title}"
- },
- {
- "type": "ColumnSet",
- "spacing": "None",
- "wrap": true,
- "columns": [
- {
- "type": "Column",
- "width": "12px",
- "items": [
- {
- "type": "Image",
- "style": "Person",
- "url": "${avatar}",
- "size": "small"
- }
- ]
- },
- {
- "type": "Column",
- "width": "stretch",
- "items": [
- {
- "type": "TextBlock",
- "text": "${user}",
- "isSubtle": true,
- "size": "small",
- "spacing": "None",
- "weight": "bolder"
- }
- ]
- }
- ]
- },
- {
- "type": "TextBlock",
- "size": "small",
- "spacing": "small",
- "spacing": "None",
- "text": "#${number} %Widget_Template/Updated% ${date}",
- "isSubtle": true,
- "wrap": true,
- "maxLines": 2
- },
- {
- "type": "TextBlock",
- "size": "small",
- "spacing": "small",
- "text": "${repo}",
- "isSubtle": true,
- "wrap": true,
- "maxLines": 2
- },
- {
- "type": "LabelGroup",
- "labels": [
- {
- "$data": "${labels}",
- "text": "${name}",
- "color": "${color}"
- }
- ]
- }
- ]
- }
- ]
- }
- ],
- "$schema": "http://adaptivecards.io/schemas/adaptive-card.json",
- "version": "1.5"
-}
+{
+ "type": "AdaptiveCard",
+ "body": [
+ {
+ "type": "ColumnSet",
+ "columns": [
+ {
+ "type": "Column",
+ "width": "auto",
+ "items": [
+ {
+ "type": "Image",
+ "url": "data:image/png;base64,${titleIconUrl}",
+ "size": "large"
+ }
+ ],
+ "verticalContentAlignment": "Center"
+ },
+ {
+ "type": "Column",
+ "width": "stretch",
+ "items": [
+ {
+ "type": "TextBlock",
+ "text": "${userName}",
+ "size": "Large",
+ "style": "Heading",
+ "wrap": true
+ }
+ ],
+ "verticalContentAlignment": "Center"
+ }
+ ]
+ },
+ {
+ "type": "Container",
+ "$when": "${(count(items) == 0)}",
+ "items": [
+ {
+ "type": "TextBlock",
+ "text": "${if(is_loading_data, '%Widget_Template/ContentLoading%', '%Widget_Template/EmptyMentioned%')}",
+ "wrap": true,
+ "weight": "bolder",
+ "horizontalAlignment": "center"
+ }
+ ],
+ "spacing": "medium",
+ "verticalContentAlignment": "center"
+ },
+ {
+ "$data": "${items}",
+ "type": "ColumnSet",
+ "style": "emphasis",
+ "spacing": "default",
+ "selectAction": {
+ "type": "Action.OpenUrl",
+ "url": "${url}",
+ "tooltip": "%Widget_Template_Tooltip/OpenIssue%"
+ },
+ "columns": [
+ {
+ "type": "Column",
+ "items": [
+ {
+ "type": "Image",
+ "url": "data:image/png;base64,${iconUrl}",
+ "size": "medium"
+ }
+ ],
+ "width": "12px"
+ },
+ {
+ "type": "Column",
+ "width": "stretch",
+ "items": [
+ {
+ "type": "TextBlock",
+ "size": "medium",
+ "wrap": true,
+ "maxLines": 2,
+ "weight": "Bolder",
+ "text": "${title}"
+ },
+ {
+ "type": "ColumnSet",
+ "spacing": "None",
+ "wrap": true,
+ "columns": [
+ {
+ "type": "Column",
+ "width": "12px",
+ "items": [
+ {
+ "type": "Image",
+ "style": "Person",
+ "url": "${avatar}",
+ "size": "small"
+ }
+ ]
+ },
+ {
+ "type": "Column",
+ "width": "stretch",
+ "items": [
+ {
+ "type": "TextBlock",
+ "text": "${user}",
+ "isSubtle": true,
+ "size": "small",
+ "spacing": "None",
+ "weight": "bolder"
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "type": "TextBlock",
+ "size": "small",
+ "spacing": "small",
+ "spacing": "None",
+ "text": "#${number} %Widget_Template/Updated% ${date}",
+ "isSubtle": true,
+ "wrap": true,
+ "maxLines": 2
+ },
+ {
+ "type": "TextBlock",
+ "size": "small",
+ "spacing": "small",
+ "text": "${repo}",
+ "isSubtle": true,
+ "wrap": true,
+ "maxLines": 2
+ },
+ {
+ "type": "LabelGroup",
+ "labels": [
+ {
+ "$data": "${labels}",
+ "text": "${name}",
+ "color": "${color}"
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ }
+ ],
+ "$schema": "http://adaptivecards.io/schemas/adaptive-card.json",
+ "version": "1.5"
+}
diff --git a/src/GitHubExtension/Widgets/Templates/GitHubReviewTemplate.json b/src/GitHubExtension/Widgets/Templates/GitHubReviewTemplate.json
index 936c9506..cc709001 100644
--- a/src/GitHubExtension/Widgets/Templates/GitHubReviewTemplate.json
+++ b/src/GitHubExtension/Widgets/Templates/GitHubReviewTemplate.json
@@ -1,152 +1,152 @@
-{
- "type": "AdaptiveCard",
- "body": [
- {
- "type": "ColumnSet",
- "columns": [
- {
- "type": "Column",
- "width": "auto",
- "items": [
- {
- "type": "Image",
- "url": "data:image/png;base64,${titleIconUrl}",
- "size": "large"
- }
- ],
- "verticalContentAlignment": "Center"
- },
- {
- "type": "Column",
- "width": "stretch",
- "items": [
- {
- "type": "TextBlock",
- "text": "${userName}",
- "size": "Large",
- "style": "Heading",
- "wrap": true
- }
- ],
- "verticalContentAlignment": "Center"
- }
- ]
- },
- {
- "type": "Container",
- "$when": "${(count(items) == 0)}",
- "items": [
- {
- "type": "TextBlock",
- "text": "${if(is_loading_data, '%Widget_Template/ContentLoading%', '%Widget_Template/EmptyReviews%')}",
- "wrap": true,
- "weight": "bolder",
- "horizontalAlignment": "center"
- }
- ],
- "spacing": "medium",
- "verticalContentAlignment": "center"
- },
- {
- "$data": "${items}",
- "type": "ColumnSet",
- "style": "emphasis",
- "spacing": "default",
- "selectAction": {
- "type": "Action.OpenUrl",
- "url": "${url}",
- "tooltip": "%Widget_Template_Tooltip/OpenIssue%"
- },
- "columns": [
- {
- "type": "Column",
- "items": [
- {
- "type": "Image",
- "url": "data:image/png;base64,${iconUrl}",
- "size": "medium"
- }
- ],
- "width": "12px"
- },
- {
- "type": "Column",
- "width": "stretch",
- "items": [
- {
- "type": "TextBlock",
- "size": "medium",
- "weight": "bolder",
- "text": "${title}",
- "wrap": true,
- "maxLines": 2
- },
- {
- "type": "ColumnSet",
- "spacing": "None",
- "wrap": true,
- "columns": [
- {
- "type": "Column",
- "width": "12px",
- "items": [
- {
- "type": "Image",
- "style": "Person",
- "url": "${avatar}",
- "size": "small"
- }
- ]
- },
- {
- "type": "Column",
- "width": "stretch",
- "items": [
- {
- "type": "TextBlock",
- "text": "${user}",
- "isSubtle": true,
- "size": "small",
- "spacing": "None",
- "weight": "bolder"
- }
- ]
- }
- ]
- },
- {
- "type": "TextBlock",
- "size": "small",
- "spacing": "small",
- "text": "#${number} %Widget_Template/Updated% ${date}",
- "isSubtle": true,
- "wrap": true,
- "maxLines": 2
- },
- {
- "type": "TextBlock",
- "size": "small",
- "spacing": "small",
- "text": "${repo}",
- "isSubtle": true,
- "wrap": true,
- "maxLines": 2
- },
- {
- "type": "LabelGroup",
- "labels": [
- {
- "$data": "${labels}",
- "text": "${name}",
- "color": "${color}"
- }
- ]
- }
- ]
- }
- ]
- }
- ],
- "$schema": "http://adaptivecards.io/schemas/adaptive-card.json",
- "version": "1.5"
+{
+ "type": "AdaptiveCard",
+ "body": [
+ {
+ "type": "ColumnSet",
+ "columns": [
+ {
+ "type": "Column",
+ "width": "auto",
+ "items": [
+ {
+ "type": "Image",
+ "url": "data:image/png;base64,${titleIconUrl}",
+ "size": "large"
+ }
+ ],
+ "verticalContentAlignment": "Center"
+ },
+ {
+ "type": "Column",
+ "width": "stretch",
+ "items": [
+ {
+ "type": "TextBlock",
+ "text": "${userName}",
+ "size": "Large",
+ "style": "Heading",
+ "wrap": true
+ }
+ ],
+ "verticalContentAlignment": "Center"
+ }
+ ]
+ },
+ {
+ "type": "Container",
+ "$when": "${(count(items) == 0)}",
+ "items": [
+ {
+ "type": "TextBlock",
+ "text": "${if(is_loading_data, '%Widget_Template/ContentLoading%', '%Widget_Template/EmptyReviews%')}",
+ "wrap": true,
+ "weight": "bolder",
+ "horizontalAlignment": "center"
+ }
+ ],
+ "spacing": "medium",
+ "verticalContentAlignment": "center"
+ },
+ {
+ "$data": "${items}",
+ "type": "ColumnSet",
+ "style": "emphasis",
+ "spacing": "default",
+ "selectAction": {
+ "type": "Action.OpenUrl",
+ "url": "${url}",
+ "tooltip": "%Widget_Template_Tooltip/OpenIssue%"
+ },
+ "columns": [
+ {
+ "type": "Column",
+ "items": [
+ {
+ "type": "Image",
+ "url": "data:image/png;base64,${iconUrl}",
+ "size": "medium"
+ }
+ ],
+ "width": "12px"
+ },
+ {
+ "type": "Column",
+ "width": "stretch",
+ "items": [
+ {
+ "type": "TextBlock",
+ "size": "medium",
+ "weight": "bolder",
+ "text": "${title}",
+ "wrap": true,
+ "maxLines": 2
+ },
+ {
+ "type": "ColumnSet",
+ "spacing": "None",
+ "wrap": true,
+ "columns": [
+ {
+ "type": "Column",
+ "width": "12px",
+ "items": [
+ {
+ "type": "Image",
+ "style": "Person",
+ "url": "${avatar}",
+ "size": "small"
+ }
+ ]
+ },
+ {
+ "type": "Column",
+ "width": "stretch",
+ "items": [
+ {
+ "type": "TextBlock",
+ "text": "${user}",
+ "isSubtle": true,
+ "size": "small",
+ "spacing": "None",
+ "weight": "bolder"
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "type": "TextBlock",
+ "size": "small",
+ "spacing": "small",
+ "text": "#${number} %Widget_Template/Updated% ${date}",
+ "isSubtle": true,
+ "wrap": true,
+ "maxLines": 2
+ },
+ {
+ "type": "TextBlock",
+ "size": "small",
+ "spacing": "small",
+ "text": "${repo}",
+ "isSubtle": true,
+ "wrap": true,
+ "maxLines": 2
+ },
+ {
+ "type": "LabelGroup",
+ "labels": [
+ {
+ "$data": "${labels}",
+ "text": "${name}",
+ "color": "${color}"
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ }
+ ],
+ "$schema": "http://adaptivecards.io/schemas/adaptive-card.json",
+ "version": "1.5"
}
\ No newline at end of file
diff --git a/src/GitHubExtension/Widgets/WidgetImpl.cs b/src/GitHubExtension/Widgets/WidgetImpl.cs
index f25454ce..c6ee2c8b 100644
--- a/src/GitHubExtension/Widgets/WidgetImpl.cs
+++ b/src/GitHubExtension/Widgets/WidgetImpl.cs
@@ -1,10 +1,11 @@
-// Copyright (c) Microsoft Corporation and Contributors
-// Licensed under the MIT license.
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
using GitHubExtension.Telemetry;
using Microsoft.Windows.Widgets.Providers;
namespace GitHubExtension.Widgets;
+
public abstract class WidgetImpl
{
private readonly ILogger logger;
diff --git a/src/GitHubExtension/Widgets/WidgetImplFactory.cs b/src/GitHubExtension/Widgets/WidgetImplFactory.cs
index 1090d059..b4ead9f3 100644
--- a/src/GitHubExtension/Widgets/WidgetImplFactory.cs
+++ b/src/GitHubExtension/Widgets/WidgetImplFactory.cs
@@ -1,9 +1,10 @@
-// Copyright (c) Microsoft Corporation and Contributors
-// Licensed under the MIT license.
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
using Microsoft.Windows.Widgets.Providers;
namespace GitHubExtension.Widgets;
+
internal class WidgetImplFactory : IWidgetImplFactory
where T : WidgetImpl, new()
{
diff --git a/src/GitHubExtension/Widgets/WidgetProvider.cs b/src/GitHubExtension/Widgets/WidgetProvider.cs
index 40066a57..74dce358 100644
--- a/src/GitHubExtension/Widgets/WidgetProvider.cs
+++ b/src/GitHubExtension/Widgets/WidgetProvider.cs
@@ -1,5 +1,5 @@
-// Copyright (c) Microsoft Corporation and Contributors
-// Licensed under the MIT license.
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
using System.Runtime.InteropServices;
using Microsoft.Windows.Widgets.Providers;
diff --git a/src/GitHubExtension/Widgets/WidgetProviderFactory.cs b/src/GitHubExtension/Widgets/WidgetProviderFactory.cs
index 197a07c2..a72d36d6 100644
--- a/src/GitHubExtension/Widgets/WidgetProviderFactory.cs
+++ b/src/GitHubExtension/Widgets/WidgetProviderFactory.cs
@@ -1,5 +1,5 @@
-// Copyright (c) Microsoft Corporation and Contributors
-// Licensed under the MIT license.
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
using System.Runtime.InteropServices;
using GitHubExtension.Widgets.COM;
diff --git a/src/GitHubExtension/Widgets/WidgetServer.cs b/src/GitHubExtension/Widgets/WidgetServer.cs
index fb2e3437..28a526c7 100644
--- a/src/GitHubExtension/Widgets/WidgetServer.cs
+++ b/src/GitHubExtension/Widgets/WidgetServer.cs
@@ -1,5 +1,5 @@
-// Copyright (c) Microsoft Corporation and Contributors
-// Licensed under the MIT license.
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
@@ -7,6 +7,7 @@
using Microsoft.Windows.Widgets.Providers;
namespace GitHubExtension.Widgets;
+
public sealed class WidgetServer : IDisposable
{
private readonly HashSet registrationCookies = new ();
diff --git a/src/GitHubExtensionServer/GitHubExtensionServer.csproj b/src/GitHubExtensionServer/GitHubExtensionServer.csproj
index bdf488cb..5eb4554b 100644
--- a/src/GitHubExtensionServer/GitHubExtensionServer.csproj
+++ b/src/GitHubExtensionServer/GitHubExtensionServer.csproj
@@ -26,6 +26,7 @@
false
true
Dev
+ portable
@@ -37,17 +38,6 @@
-
-
-
-
-
- all
- runtime; build; native; contentfiles; analyzers; buildtransitive
-
-
-
-
@@ -58,28 +48,4 @@
$(DefineConstants);CANARY_BUILD
$(DefineConstants);STABLE_BUILD
-
-
- portable
-
-
-
- portable
-
-
-
- portable
-
-
-
- portable
-
-
-
- portable
-
-
-
- portable
-
diff --git a/src/GitHubExtensionServer/Logging.cs b/src/GitHubExtensionServer/Logging.cs
index 206e05f5..f0a12cfd 100644
--- a/src/GitHubExtensionServer/Logging.cs
+++ b/src/GitHubExtensionServer/Logging.cs
@@ -1,10 +1,11 @@
-// Copyright (c) Microsoft Corporation and Contributors
-// Licensed under the MIT license.
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
using DevHome.Logging;
using Windows.Storage;
namespace GitHubExtension.ExtensionServer;
+
public class Log
{
private static Logger? _logger;
diff --git a/src/GitHubExtensionServer/Program.cs b/src/GitHubExtensionServer/Program.cs
index 0e32e29b..17b0a190 100644
--- a/src/GitHubExtensionServer/Program.cs
+++ b/src/GitHubExtensionServer/Program.cs
@@ -1,5 +1,5 @@
-// Copyright (c) Microsoft Corporation and Contributors
-// Licensed under the MIT license.
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
using GitHubExtension.ExtensionServer;
using Microsoft.Windows.AppLifecycle;
@@ -8,6 +8,7 @@
using Windows.Management.Deployment;
namespace GitHubExtension;
+
public sealed class Program
{
[MTAThread]
@@ -126,7 +127,7 @@ private static void HandleCOMServerActivation()
using var dataUpdater = new DataManager.DataUpdater(GitHubDataManager.Update);
_ = dataUpdater.Start();
- // This will make the main thread wait until the event is signalled by the extension class.
+ // This will make the main thread wait until the event is signaled by the extension class.
// Since we have single instance of the extension object, we exit as soon as it is disposed.
extensionDisposedEvent.WaitOne();
Log.Logger()?.ReportInfo($"Extension is disposed.");
@@ -148,7 +149,7 @@ private static void LogPackageInformation()
{
foreach (var package in packageManager.FindPackagesForUser(string.Empty, pfn))
{
- Log.Logger()?.ReportInfo($"{package.Id.FullName} Devmode: {package.IsDevelopmentMode} Signature: {package.SignatureKind}");
+ Log.Logger()?.ReportInfo($"{package.Id.FullName} DevMode: {package.IsDevelopmentMode} Signature: {package.SignatureKind}");
}
}
}
diff --git a/src/GitHubExtensionServer/Properties/PublishProfiles/win10-arm64.pubxml b/src/GitHubExtensionServer/Properties/PublishProfiles/win10-arm64.pubxml
index c5e8be62..2593bad1 100644
--- a/src/GitHubExtensionServer/Properties/PublishProfiles/win10-arm64.pubxml
+++ b/src/GitHubExtensionServer/Properties/PublishProfiles/win10-arm64.pubxml
@@ -1,17 +1,17 @@
-
-
-
-
- FileSystem
- arm64
- win10-arm64
- true
- False
- False
- True
- True
- True
-
+
+
+
+
+ FileSystem
+ arm64
+ win10-arm64
+ true
+ False
+ False
+ True
+ True
+ True
+
\ No newline at end of file
diff --git a/src/GitHubExtensionServer/Properties/PublishProfiles/win10-x64.pubxml b/src/GitHubExtensionServer/Properties/PublishProfiles/win10-x64.pubxml
index e8e2c0a3..8b6ea06a 100644
--- a/src/GitHubExtensionServer/Properties/PublishProfiles/win10-x64.pubxml
+++ b/src/GitHubExtensionServer/Properties/PublishProfiles/win10-x64.pubxml
@@ -1,17 +1,17 @@
-
-
-
-
- FileSystem
- x64
- win10-x64
- true
- False
- False
- True
- True
- True
-
+
+
+
+
+ FileSystem
+ x64
+ win10-x64
+ true
+ False
+ False
+ True
+ True
+ True
+
\ No newline at end of file
diff --git a/src/GitHubExtensionServer/Properties/PublishProfiles/win10-x86.pubxml b/src/GitHubExtensionServer/Properties/PublishProfiles/win10-x86.pubxml
index e601cec4..99985aca 100644
--- a/src/GitHubExtensionServer/Properties/PublishProfiles/win10-x86.pubxml
+++ b/src/GitHubExtensionServer/Properties/PublishProfiles/win10-x86.pubxml
@@ -1,17 +1,17 @@
-
-
-
-
- FileSystem
- x86
- win10-x86
- true
- False
- False
- True
- True
- True
-
+
+
+
+
+ FileSystem
+ x86
+ win10-x86
+ true
+ False
+ False
+ True
+ True
+ True
+
\ No newline at end of file
diff --git a/src/Logging/DevHome.Logging.csproj b/src/Logging/DevHome.Logging.csproj
index b88a011e..e6e1d303 100644
--- a/src/Logging/DevHome.Logging.csproj
+++ b/src/Logging/DevHome.Logging.csproj
@@ -1,4 +1,4 @@
-
+
@@ -14,16 +14,4 @@
Spectre
-
-
-
-
-
-
-
- all
- runtime; build; native; contentfiles; analyzers; buildtransitive
-
-
-
diff --git a/src/Logging/helpers/DictionaryExtensions.cs b/src/Logging/helpers/DictionaryExtensions.cs
index ef55d694..fdc54273 100644
--- a/src/Logging/helpers/DictionaryExtensions.cs
+++ b/src/Logging/helpers/DictionaryExtensions.cs
@@ -1,28 +1,28 @@
-// Copyright (c) Microsoft Corporation and Contributors
-// Licensed under the MIT license.
-
-namespace DevHome.Logging.Helpers;
-
-public static class DictionaryExtensions
-{
- public static void DisposeAll(this IDictionary dictionary)
- {
- if (dictionary is null)
- {
- throw new ArgumentNullException(nameof(dictionary));
- }
-
- foreach (var kv in dictionary)
- {
- if (kv.Key is IDisposable keyDisposable)
- {
- keyDisposable.Dispose();
- }
-
- if (kv.Value is IDisposable valDisposable)
- {
- valDisposable.Dispose();
- }
- }
- }
-}
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+namespace DevHome.Logging.Helpers;
+
+public static class DictionaryExtensions
+{
+ public static void DisposeAll(this IDictionary dictionary)
+ {
+ if (dictionary is null)
+ {
+ throw new ArgumentNullException(nameof(dictionary));
+ }
+
+ foreach (var kv in dictionary)
+ {
+ if (kv.Key is IDisposable keyDisposable)
+ {
+ keyDisposable.Dispose();
+ }
+
+ if (kv.Value is IDisposable valDisposable)
+ {
+ valDisposable.Dispose();
+ }
+ }
+ }
+}
diff --git a/src/Logging/helpers/FileSystem.cs b/src/Logging/helpers/FileSystem.cs
index 234bbc8e..c8679349 100644
--- a/src/Logging/helpers/FileSystem.cs
+++ b/src/Logging/helpers/FileSystem.cs
@@ -1,35 +1,36 @@
-// Copyright (c) Microsoft Corporation and Contributors
-// Licensed under the MIT license.
-
-namespace DevHome.Logging.Helpers;
-public class FileSystem
-{
- public static string BuildOutputFilename(string filename, string outputFolder, bool createPathIfNecessary = true)
- {
- var outputFilename = SubstituteOutputFilename(filename, outputFolder);
- var file = new FileInfo(outputFilename);
- if (createPathIfNecessary)
- {
- file.Directory?.Create();
- }
-
- return file.FullName;
- }
-
- public static string SubstituteNow(string s)
- {
- if (s.Contains("{now}", StringComparison.CurrentCulture))
- {
- var now = DateTime.Now;
- var nowAsString = $"{now:yyyyMMdd-HHmmss}";
- return s.Replace("{now}", nowAsString);
- }
-
- return s;
- }
-
- public static string SubstituteOutputFilename(string filename, string outputDirectory)
- {
- return Path.Combine(SubstituteNow(outputDirectory), SubstituteNow(filename));
- }
-}
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+namespace DevHome.Logging.Helpers;
+
+public class FileSystem
+{
+ public static string BuildOutputFilename(string filename, string outputFolder, bool createPathIfNecessary = true)
+ {
+ var outputFilename = SubstituteOutputFilename(filename, outputFolder);
+ var file = new FileInfo(outputFilename);
+ if (createPathIfNecessary)
+ {
+ file.Directory?.Create();
+ }
+
+ return file.FullName;
+ }
+
+ public static string SubstituteNow(string s)
+ {
+ if (s.Contains("{now}", StringComparison.CurrentCulture))
+ {
+ var now = DateTime.Now;
+ var nowAsString = $"{now:yyyyMMdd-HHmmss}";
+ return s.Replace("{now}", nowAsString);
+ }
+
+ return s;
+ }
+
+ public static string SubstituteOutputFilename(string filename, string outputDirectory)
+ {
+ return Path.Combine(SubstituteNow(outputDirectory), SubstituteNow(filename));
+ }
+}
diff --git a/src/Logging/helpers/StringExtensions.cs b/src/Logging/helpers/StringExtensions.cs
index bdc9acfc..24eb5c4d 100644
--- a/src/Logging/helpers/StringExtensions.cs
+++ b/src/Logging/helpers/StringExtensions.cs
@@ -1,15 +1,16 @@
-// Copyright (c) Microsoft Corporation and Contributors
-// Licensed under the MIT license.
-
-using System.Globalization;
-
-namespace DevHome.Logging.Helpers;
-public static class StringExtensions
-{
- public static string ToStringInvariant(this T value) => Convert.ToString(value, CultureInfo.InvariantCulture)!;
-
- public static string FormatInvariant(this string value, params object[] arguments)
- {
- return string.Format(CultureInfo.InvariantCulture, value, arguments);
- }
-}
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+using System.Globalization;
+
+namespace DevHome.Logging.Helpers;
+
+public static class StringExtensions
+{
+ public static string ToStringInvariant(this T value) => Convert.ToString(value, CultureInfo.InvariantCulture)!;
+
+ public static string FormatInvariant(this string value, params object[] arguments)
+ {
+ return string.Format(CultureInfo.InvariantCulture, value, arguments);
+ }
+}
diff --git a/src/Logging/listeners/DebugListener.cs b/src/Logging/listeners/DebugListener.cs
index 6eb7e1c0..2f5fa8f1 100644
--- a/src/Logging/listeners/DebugListener.cs
+++ b/src/Logging/listeners/DebugListener.cs
@@ -1,11 +1,12 @@
-// Copyright (c) Microsoft Corporation and Contributors
-// Licensed under the MIT license.
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
using System.Diagnostics;
using System.Globalization;
using System.Text;
namespace DevHome.Logging.Listeners;
+
public class DebugListener : ListenerBase
{
public DebugListener(string name)
diff --git a/src/Logging/listeners/DebugListenerOptions.cs b/src/Logging/listeners/DebugListenerOptions.cs
index dacd9b26..bdf9fd4a 100644
--- a/src/Logging/listeners/DebugListenerOptions.cs
+++ b/src/Logging/listeners/DebugListenerOptions.cs
@@ -1,7 +1,8 @@
-// Copyright (c) Microsoft Corporation and Contributors
-// Licensed under the MIT license.
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
namespace DevHome.Logging;
+
public partial class Options
{
public bool DebugListenerEnabled { get; set; } = true;
diff --git a/src/Logging/listeners/IListener.cs b/src/Logging/listeners/IListener.cs
index 65e574e5..6bb582ec 100644
--- a/src/Logging/listeners/IListener.cs
+++ b/src/Logging/listeners/IListener.cs
@@ -1,19 +1,20 @@
-// Copyright (c) Microsoft Corporation and Contributors
-// Licensed under the MIT license.
-
-namespace DevHome.Logging.Listeners;
-public interface IListener
-{
- string Name
- {
- get;
- }
-
- ILoggerHost? Host
- {
- get;
- set;
- }
-
- void HandleLogEvent(LogEvent evt);
-}
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+namespace DevHome.Logging.Listeners;
+
+public interface IListener
+{
+ string Name
+ {
+ get;
+ }
+
+ ILoggerHost? Host
+ {
+ get;
+ set;
+ }
+
+ void HandleLogEvent(LogEvent evt);
+}
diff --git a/src/Logging/listeners/ListenerBase.cs b/src/Logging/listeners/ListenerBase.cs
index 8b9c6be8..03c37bdc 100644
--- a/src/Logging/listeners/ListenerBase.cs
+++ b/src/Logging/listeners/ListenerBase.cs
@@ -1,28 +1,28 @@
-// Copyright (c) Microsoft Corporation and Contributors
-// Licensed under the MIT license.
-
-namespace DevHome.Logging.Listeners;
-
-public abstract class ListenerBase : IListener
-{
- public ILoggerHost? Host
- {
- get;
- set;
- }
-
- public Options? Options => Host?.Options;
-
- public string Name
- {
- get;
- }
-
- public ListenerBase(string name)
- {
- Host = null;
- Name = name;
- }
-
- public abstract void HandleLogEvent(LogEvent evt);
-}
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+namespace DevHome.Logging.Listeners;
+
+public abstract class ListenerBase : IListener
+{
+ public ILoggerHost? Host
+ {
+ get;
+ set;
+ }
+
+ public Options? Options => Host?.Options;
+
+ public string Name
+ {
+ get;
+ }
+
+ public ListenerBase(string name)
+ {
+ Host = null;
+ Name = name;
+ }
+
+ public abstract void HandleLogEvent(LogEvent evt);
+}
diff --git a/src/Logging/listeners/LogFileListener.cs b/src/Logging/listeners/LogFileListener.cs
index 8a293978..72d505e8 100644
--- a/src/Logging/listeners/LogFileListener.cs
+++ b/src/Logging/listeners/LogFileListener.cs
@@ -1,9 +1,10 @@
-// Copyright (c) Microsoft Corporation and Contributors
-// Licensed under the MIT license.
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
using System.Globalization;
namespace DevHome.Logging.Listeners;
+
public class LogFileListener : ListenerBase, IDisposable
{
private readonly TextWriter? writer;
diff --git a/src/Logging/listeners/LogFileListenerOptions.cs b/src/Logging/listeners/LogFileListenerOptions.cs
index 2e035bce..b30594bc 100644
--- a/src/Logging/listeners/LogFileListenerOptions.cs
+++ b/src/Logging/listeners/LogFileListenerOptions.cs
@@ -1,25 +1,26 @@
-// Copyright (c) Microsoft Corporation and Contributors
-// Licensed under the MIT license.
-
-namespace DevHome.Logging;
-public partial class Options
-{
- private const string LogFileNameDefault = "DevHomeGitHubExtension.log";
- private const string LogFileFolderNameDefault = "{now}";
-
- public string LogFileName { get; set; } = LogFileNameDefault;
-
- public string LogFileFolderName { get; set; } = LogFileFolderNameDefault;
-
- // The Temp Path is used for storage by default so tests can run this code without being packaged.
- // If we directly put in the ApplicationData folder, it would fail anytime the program was not packaged.
- // For use with packaged application, set in Options to:
- // ApplicationData.Current.TemporaryFolder.Path
- public string LogFileFolderRoot { get; set; } = Path.GetTempPath();
-
- public string LogFileFolderPath => Path.Combine(LogFileFolderRoot, LogFileFolderName);
-
- public bool LogFileEnabled { get; set; } = true;
-
- public SeverityLevel LogFileFilter { get; set; } = SeverityLevel.Info;
-}
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+namespace DevHome.Logging;
+
+public partial class Options
+{
+ private const string LogFileNameDefault = "DevHomeGitHubExtension.log";
+ private const string LogFileFolderNameDefault = "{now}";
+
+ public string LogFileName { get; set; } = LogFileNameDefault;
+
+ public string LogFileFolderName { get; set; } = LogFileFolderNameDefault;
+
+ // The Temp Path is used for storage by default so tests can run this code without being packaged.
+ // If we directly put in the ApplicationData folder, it would fail anytime the program was not packaged.
+ // For use with packaged application, set in Options to:
+ // ApplicationData.Current.TemporaryFolder.Path
+ public string LogFileFolderRoot { get; set; } = Path.GetTempPath();
+
+ public string LogFileFolderPath => Path.Combine(LogFileFolderRoot, LogFileFolderName);
+
+ public bool LogFileEnabled { get; set; } = true;
+
+ public SeverityLevel LogFileFilter { get; set; } = SeverityLevel.Info;
+}
diff --git a/src/Logging/listeners/StdoutListener.cs b/src/Logging/listeners/StdoutListener.cs
index 3a9ab4e9..c8e89543 100644
--- a/src/Logging/listeners/StdoutListener.cs
+++ b/src/Logging/listeners/StdoutListener.cs
@@ -1,132 +1,133 @@
-// Copyright (c) Microsoft Corporation and Contributors
-// Licensed under the MIT license.
-
-using System.Globalization;
-
-namespace DevHome.Logging.Listeners;
-public class StdoutListener : ListenerBase
-{
- private static readonly ConsoleColor CDefaultColor = ConsoleColor.White;
- private static readonly ConsoleColor CDebugColor = ConsoleColor.DarkGray;
- private static readonly ConsoleColor CInfoColor = ConsoleColor.White;
- private static readonly ConsoleColor CWarnColor = ConsoleColor.Yellow;
- private static readonly ConsoleColor CErrorColor = ConsoleColor.Red;
- private static readonly ConsoleColor CCriticalColor = ConsoleColor.Magenta;
- private static readonly ConsoleColor CExceptionColor = ConsoleColor.Red;
- private static readonly ConsoleColor CElapsedColor = ConsoleColor.Green;
- private static readonly ConsoleColor CSourceColor = ConsoleColor.Cyan;
-
- // Static lock object so different instances of the Stdout listener do not simultaneously write
- // to stdout and have interleaved tearing of messages.
- private static readonly object _stdoutLock = new ();
-
- public StdoutListener(string name)
- : base(name)
- {
- }
-
- public override void HandleLogEvent(LogEvent evt)
- {
- ConsoleHandleLogEvent(evt, true);
- }
-
- private void ConsoleHandleLogEvent(LogEvent evt, bool newline)
- {
- ConsoleHandleLogEvent(evt, newline, LogEvent.NoElapsed);
- }
-
- private void ConsoleHandleLogEvent(LogEvent evt, bool newline, TimeSpan elapsed)
- {
- if (!MeetsFilter(evt))
- {
- return;
- }
-
- var line = new List>
- {
- Tuple.Create(CDefaultColor, "["),
- Tuple.Create(CSourceColor, (evt.SubSource != null) ? $"{evt.Source}/{evt.SubSource}" : $"{evt.Source}"),
- Tuple.Create(CDefaultColor, "] "),
- Tuple.Create(GetSeverityColor(evt.Severity), evt.Severity.ToString().ToUpper(CultureInfo.InvariantCulture)),
- Tuple.Create(CDefaultColor, ": "),
- Tuple.Create(GetSeverityColor(evt.Severity), evt.Message),
- };
-
- if (elapsed != LogEvent.NoElapsed)
- {
- line.Add(Tuple.Create(CDefaultColor, " ["));
- line.Add(Tuple.Create(CElapsedColor, $"Elapsed: {elapsed:hh\\:mm\\:ss\\.ffffff}"));
- line.Add(Tuple.Create(CDefaultColor, "]"));
- }
-
- if (evt.Exception != null)
- {
- line.Add(Tuple.Create(CExceptionColor, $"{Environment.NewLine}{evt.Exception}"));
- }
-
- if (newline)
- {
- line.Add(Tuple.Create(CDefaultColor, Environment.NewLine));
- }
-
- // Do this in a static lock to prevent tearing.
- lock (_stdoutLock)
- {
- try
- {
- WriteColor(line);
- Console.ResetColor();
- Console.Out.Flush();
- }
- catch
- {
- }
- }
- }
-
- private bool MeetsFilter(LogEvent evt)
- {
- return evt.Severity >= Options?.LogStdoutFilter;
- }
-
- private void WriteColor(List> strings)
- {
- if (strings == null)
- {
- return;
- }
-
- foreach (var s in strings)
- {
- WriteColor(s);
- }
- }
-
- private void WriteColor(Tuple s)
- {
- if (Console.IsOutputRedirected)
- {
- Console.Write(s.Item2);
- }
- else
- {
- var currentColor = Console.ForegroundColor;
- Console.ForegroundColor = s.Item1;
- Console.Write(s.Item2);
- Console.ForegroundColor = currentColor;
- }
- }
-
- private ConsoleColor GetSeverityColor(SeverityLevel severity)
- {
- return severity switch
- {
- SeverityLevel.Debug => CDebugColor,
- SeverityLevel.Info => CInfoColor,
- SeverityLevel.Warn => CWarnColor,
- SeverityLevel.Error => CErrorColor,
- SeverityLevel.Critical => CCriticalColor,
- _ => CDefaultColor,
- };
- }
-}
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+using System.Globalization;
+
+namespace DevHome.Logging.Listeners;
+
+public class StdoutListener : ListenerBase
+{
+ private static readonly ConsoleColor CDefaultColor = ConsoleColor.White;
+ private static readonly ConsoleColor CDebugColor = ConsoleColor.DarkGray;
+ private static readonly ConsoleColor CInfoColor = ConsoleColor.White;
+ private static readonly ConsoleColor CWarnColor = ConsoleColor.Yellow;
+ private static readonly ConsoleColor CErrorColor = ConsoleColor.Red;
+ private static readonly ConsoleColor CCriticalColor = ConsoleColor.Magenta;
+ private static readonly ConsoleColor CExceptionColor = ConsoleColor.Red;
+ private static readonly ConsoleColor CElapsedColor = ConsoleColor.Green;
+ private static readonly ConsoleColor CSourceColor = ConsoleColor.Cyan;
+
+ // Static lock object so different instances of the Stdout listener do not simultaneously write
+ // to stdout and have interleaved tearing of messages.
+ private static readonly object _stdoutLock = new ();
+
+ public StdoutListener(string name)
+ : base(name)
+ {
+ }
+
+ public override void HandleLogEvent(LogEvent evt)
+ {
+ ConsoleHandleLogEvent(evt, true);
+ }
+
+ private void ConsoleHandleLogEvent(LogEvent evt, bool newline)
+ {
+ ConsoleHandleLogEvent(evt, newline, LogEvent.NoElapsed);
+ }
+
+ private void ConsoleHandleLogEvent(LogEvent evt, bool newline, TimeSpan elapsed)
+ {
+ if (!MeetsFilter(evt))
+ {
+ return;
+ }
+
+ var line = new List>
+ {
+ Tuple.Create(CDefaultColor, "["),
+ Tuple.Create(CSourceColor, (evt.SubSource != null) ? $"{evt.Source}/{evt.SubSource}" : $"{evt.Source}"),
+ Tuple.Create(CDefaultColor, "] "),
+ Tuple.Create(GetSeverityColor(evt.Severity), evt.Severity.ToString().ToUpper(CultureInfo.InvariantCulture)),
+ Tuple.Create(CDefaultColor, ": "),
+ Tuple.Create(GetSeverityColor(evt.Severity), evt.Message),
+ };
+
+ if (elapsed != LogEvent.NoElapsed)
+ {
+ line.Add(Tuple.Create(CDefaultColor, " ["));
+ line.Add(Tuple.Create(CElapsedColor, $"Elapsed: {elapsed:hh\\:mm\\:ss\\.ffffff}"));
+ line.Add(Tuple.Create(CDefaultColor, "]"));
+ }
+
+ if (evt.Exception != null)
+ {
+ line.Add(Tuple.Create(CExceptionColor, $"{Environment.NewLine}{evt.Exception}"));
+ }
+
+ if (newline)
+ {
+ line.Add(Tuple.Create(CDefaultColor, Environment.NewLine));
+ }
+
+ // Do this in a static lock to prevent tearing.
+ lock (_stdoutLock)
+ {
+ try
+ {
+ WriteColor(line);
+ Console.ResetColor();
+ Console.Out.Flush();
+ }
+ catch
+ {
+ }
+ }
+ }
+
+ private bool MeetsFilter(LogEvent evt)
+ {
+ return evt.Severity >= Options?.LogStdoutFilter;
+ }
+
+ private void WriteColor(List> strings)
+ {
+ if (strings == null)
+ {
+ return;
+ }
+
+ foreach (var s in strings)
+ {
+ WriteColor(s);
+ }
+ }
+
+ private void WriteColor(Tuple s)
+ {
+ if (Console.IsOutputRedirected)
+ {
+ Console.Write(s.Item2);
+ }
+ else
+ {
+ var currentColor = Console.ForegroundColor;
+ Console.ForegroundColor = s.Item1;
+ Console.Write(s.Item2);
+ Console.ForegroundColor = currentColor;
+ }
+ }
+
+ private ConsoleColor GetSeverityColor(SeverityLevel severity)
+ {
+ return severity switch
+ {
+ SeverityLevel.Debug => CDebugColor,
+ SeverityLevel.Info => CInfoColor,
+ SeverityLevel.Warn => CWarnColor,
+ SeverityLevel.Error => CErrorColor,
+ SeverityLevel.Critical => CCriticalColor,
+ _ => CDefaultColor,
+ };
+ }
+}
diff --git a/src/Logging/listeners/StdoutListenerOptions.cs b/src/Logging/listeners/StdoutListenerOptions.cs
index f0e1fb0d..bbfe3aad 100644
--- a/src/Logging/listeners/StdoutListenerOptions.cs
+++ b/src/Logging/listeners/StdoutListenerOptions.cs
@@ -1,10 +1,11 @@
-// Copyright (c) Microsoft Corporation and Contributors
-// Licensed under the MIT license.
-
-namespace DevHome.Logging;
-public partial class Options
-{
- public bool LogStdoutEnabled { get; set; } = true;
-
- public SeverityLevel LogStdoutFilter { get; set; } = SeverityLevel.Info;
-}
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+namespace DevHome.Logging;
+
+public partial class Options
+{
+ public bool LogStdoutEnabled { get; set; } = true;
+
+ public SeverityLevel LogStdoutFilter { get; set; } = SeverityLevel.Info;
+}
diff --git a/src/Logging/logger/ILoggerHost.cs b/src/Logging/logger/ILoggerHost.cs
index eaaa25c2..c0852831 100644
--- a/src/Logging/logger/ILoggerHost.cs
+++ b/src/Logging/logger/ILoggerHost.cs
@@ -1,70 +1,71 @@
-// Copyright (c) Microsoft Corporation and Contributors
-// Licensed under the MIT license.
-
-using DevHome.Logging.Listeners;
-
-namespace DevHome.Logging;
-public interface ILoggerHost : IDisposable
-{
- string Name
- {
- get;
- }
-
- Options Options
- {
- get;
- }
-
- void AddListener(IListener listener);
-
- void ReportEvent(LogEvent evt);
-
- void ReportEvent(string component, SeverityLevel severity, string message);
-
- void ReportEvent(string component, SeverityLevel severity, string message, System.Exception exception);
-
- void ReportEvent(string component, string subComponent, SeverityLevel severity, string message);
-
- void ReportEvent(string component, string subComponent, SeverityLevel severity, string message, System.Exception exception);
-
- void ReportDebug(string component, string message);
-
- void ReportDebug(string component, string message, Exception exception);
-
- void ReportDebug(string component, string subComponent, string message);
-
- void ReportDebug(string component, string subComponent, string message, Exception exception);
-
- void ReportInfo(string component, string message);
-
- void ReportInfo(string component, string message, Exception exception);
-
- void ReportInfo(string component, string subComponent, string message);
-
- void ReportInfo(string component, string subComponent, string message, Exception exception);
-
- void ReportWarn(string component, string message);
-
- void ReportWarn(string component, string message, Exception exception);
-
- void ReportWarn(string component, string subComponent, string message);
-
- void ReportWarn(string component, string subComponent, string message, Exception exception);
-
- void ReportError(string component, string message);
-
- void ReportError(string component, string message, Exception exception);
-
- void ReportError(string component, string subComponent, string message);
-
- void ReportError(string component, string subComponent, string message, Exception exception);
-
- void ReportCritical(string component, string message);
-
- void ReportCritical(string component, string message, Exception exception);
-
- void ReportCritical(string component, string subComponent, string message);
-
- void ReportCritical(string component, string subComponent, string message, Exception exception);
-}
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+using DevHome.Logging.Listeners;
+
+namespace DevHome.Logging;
+
+public interface ILoggerHost : IDisposable
+{
+ string Name
+ {
+ get;
+ }
+
+ Options Options
+ {
+ get;
+ }
+
+ void AddListener(IListener listener);
+
+ void ReportEvent(LogEvent evt);
+
+ void ReportEvent(string component, SeverityLevel severity, string message);
+
+ void ReportEvent(string component, SeverityLevel severity, string message, System.Exception exception);
+
+ void ReportEvent(string component, string subComponent, SeverityLevel severity, string message);
+
+ void ReportEvent(string component, string subComponent, SeverityLevel severity, string message, System.Exception exception);
+
+ void ReportDebug(string component, string message);
+
+ void ReportDebug(string component, string message, Exception exception);
+
+ void ReportDebug(string component, string subComponent, string message);
+
+ void ReportDebug(string component, string subComponent, string message, Exception exception);
+
+ void ReportInfo(string component, string message);
+
+ void ReportInfo(string component, string message, Exception exception);
+
+ void ReportInfo(string component, string subComponent, string message);
+
+ void ReportInfo(string component, string subComponent, string message, Exception exception);
+
+ void ReportWarn(string component, string message);
+
+ void ReportWarn(string component, string message, Exception exception);
+
+ void ReportWarn(string component, string subComponent, string message);
+
+ void ReportWarn(string component, string subComponent, string message, Exception exception);
+
+ void ReportError(string component, string message);
+
+ void ReportError(string component, string message, Exception exception);
+
+ void ReportError(string component, string subComponent, string message);
+
+ void ReportError(string component, string subComponent, string message, Exception exception);
+
+ void ReportCritical(string component, string message);
+
+ void ReportCritical(string component, string message, Exception exception);
+
+ void ReportCritical(string component, string subComponent, string message);
+
+ void ReportCritical(string component, string subComponent, string message, Exception exception);
+}
diff --git a/src/Logging/logger/LogEvent.cs b/src/Logging/logger/LogEvent.cs
index 9664afec..a555a411 100644
--- a/src/Logging/logger/LogEvent.cs
+++ b/src/Logging/logger/LogEvent.cs
@@ -1,108 +1,109 @@
-// Copyright (c) Microsoft Corporation and Contributors
-// Licensed under the MIT license.
-
-using DevHome.Logging.Helpers;
-
-namespace DevHome.Logging;
-public class LogEvent
-{
- public string Source
- {
- get;
- }
-
- public string? SubSource
- {
- get;
- }
-
- public SeverityLevel Severity
- {
- get;
- }
-
- public string Message
- {
- get;
- }
-
- public Exception? Exception
- {
- get;
- }
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+using DevHome.Logging.Helpers;
+
+namespace DevHome.Logging;
+
+public class LogEvent
+{
+ public string Source
+ {
+ get;
+ }
+
+ public string? SubSource
+ {
+ get;
+ }
+
+ public SeverityLevel Severity
+ {
+ get;
+ }
+
+ public string Message
+ {
+ get;
+ }
+
+ public Exception? Exception
+ {
+ get;
+ }
public DateTime Created
{
get;
}
-
- public TimeSpan Elapsed
- {
- get;
- private set;
- }
-
- internal void SetElapsed(TimeSpan elapsed) => Elapsed = elapsed;
-
- public static long NoElapsedTicks => -1L;
-
- public static TimeSpan NoElapsed => new (NoElapsedTicks);
-
- public bool HasElapsed => Elapsed.Ticks >= 0;
-
- private LogEvent(string source, string subSource, SeverityLevel severity, string message, Exception exception, TimeSpan elapsed)
- {
- Source = source;
- SubSource = subSource;
- Severity = severity;
- Message = message;
- Exception = exception;
+
+ public TimeSpan Elapsed
+ {
+ get;
+ private set;
+ }
+
+ internal void SetElapsed(TimeSpan elapsed) => Elapsed = elapsed;
+
+ public static long NoElapsedTicks => -1L;
+
+ public static TimeSpan NoElapsed => new (NoElapsedTicks);
+
+ public bool HasElapsed => Elapsed.Ticks >= 0;
+
+ private LogEvent(string source, string subSource, SeverityLevel severity, string message, Exception exception, TimeSpan elapsed)
+ {
+ Source = source;
+ SubSource = subSource;
+ Severity = severity;
+ Message = message;
+ Exception = exception;
Elapsed = elapsed;
- Created = DateTime.UtcNow;
- }
-
- public static LogEvent Create(string source, string subSource, SeverityLevel severity, string message) => Create(source, subSource, severity, message, null, NoElapsed);
-
- public static LogEvent Create(string source, string subSource, SeverityLevel severity, string message, Exception exception) => Create(source, subSource, severity, message, exception, NoElapsed);
-
- public static LogEvent Create(string source, string subSource, SeverityLevel severity, string message, TimeSpan elapsed) => Create(source, subSource, severity, message, null, elapsed);
-
- public static LogEvent Create(string source, string subSource, SeverityLevel severity, string message, Exception? exception, TimeSpan elapsed) => new (source, subSource, severity, message, exception!, elapsed);
-
- public string FullSourceName
- {
- get
- {
- if (SubSource != null)
- {
- return $"{Source}/{SubSource}";
- }
- else
- {
- return Source;
- }
- }
- }
-
- public override string ToString()
- {
- var hasException = Exception != null;
-
- if (hasException && HasElapsed)
- {
- return "[{0}] {1} {2} {3} {4}".FormatInvariant(FullSourceName, Severity.ToString(), Message, Exception!, Elapsed);
- }
- else if (hasException && !HasElapsed)
- {
- return "[{0}] {1} {2} {3}".FormatInvariant(FullSourceName, Severity.ToString(), Message, Exception!);
- }
- else if (!hasException && HasElapsed)
- {
- return "[{0}] {1} {2} {3}".FormatInvariant(FullSourceName, Severity.ToString(), Message, Elapsed);
- }
- else
- {
- return "[{0}] {1} {2}".FormatInvariant(FullSourceName, Severity.ToString(), Message);
- }
- }
-}
+ Created = DateTime.UtcNow;
+ }
+
+ public static LogEvent Create(string source, string subSource, SeverityLevel severity, string message) => Create(source, subSource, severity, message, null, NoElapsed);
+
+ public static LogEvent Create(string source, string subSource, SeverityLevel severity, string message, Exception exception) => Create(source, subSource, severity, message, exception, NoElapsed);
+
+ public static LogEvent Create(string source, string subSource, SeverityLevel severity, string message, TimeSpan elapsed) => Create(source, subSource, severity, message, null, elapsed);
+
+ public static LogEvent Create(string source, string subSource, SeverityLevel severity, string message, Exception? exception, TimeSpan elapsed) => new (source, subSource, severity, message, exception!, elapsed);
+
+ public string FullSourceName
+ {
+ get
+ {
+ if (SubSource != null)
+ {
+ return $"{Source}/{SubSource}";
+ }
+ else
+ {
+ return Source;
+ }
+ }
+ }
+
+ public override string ToString()
+ {
+ var hasException = Exception != null;
+
+ if (hasException && HasElapsed)
+ {
+ return "[{0}] {1} {2} {3} {4}".FormatInvariant(FullSourceName, Severity.ToString(), Message, Exception!, Elapsed);
+ }
+ else if (hasException && !HasElapsed)
+ {
+ return "[{0}] {1} {2} {3}".FormatInvariant(FullSourceName, Severity.ToString(), Message, Exception!);
+ }
+ else if (!hasException && HasElapsed)
+ {
+ return "[{0}] {1} {2} {3}".FormatInvariant(FullSourceName, Severity.ToString(), Message, Elapsed);
+ }
+ else
+ {
+ return "[{0}] {1} {2}".FormatInvariant(FullSourceName, Severity.ToString(), Message);
+ }
+ }
+}
diff --git a/src/Logging/logger/Logger.cs b/src/Logging/logger/Logger.cs
index f4ed48a2..1601c2ac 100644
--- a/src/Logging/logger/Logger.cs
+++ b/src/Logging/logger/Logger.cs
@@ -1,11 +1,12 @@
-// Copyright (c) Microsoft Corporation and Contributors
-// Licensed under the MIT license.
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
using System.Collections.Concurrent;
using DevHome.Logging.Helpers;
using DevHome.Logging.Listeners;
namespace DevHome.Logging;
+
public class Logger : ILoggerHost, IDisposable
{
public Logger(string name, Options options)
@@ -13,7 +14,7 @@ public Logger(string name, Options options)
Name = name;
Options = options;
- // Debug Listneer
+ // Debug listener
if (options.DebugListenerEnabled)
{
var debugListener = new DebugListener("Debug");
diff --git a/src/Logging/logger/Options.cs b/src/Logging/logger/Options.cs
index e7247484..d0cbfb12 100644
--- a/src/Logging/logger/Options.cs
+++ b/src/Logging/logger/Options.cs
@@ -1,10 +1,11 @@
-// Copyright (c) Microsoft Corporation and Contributors
-// Licensed under the MIT license.
-
-namespace DevHome.Logging;
-public partial class Options : ICloneable
-{
- public FailFastSeverityLevel FailFastSeverity { get; set; } = FailFastSeverityLevel.Critical;
-
- public object Clone() => MemberwiseClone();
-}
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+namespace DevHome.Logging;
+
+public partial class Options : ICloneable
+{
+ public FailFastSeverityLevel FailFastSeverity { get; set; } = FailFastSeverityLevel.Critical;
+
+ public object Clone() => MemberwiseClone();
+}
diff --git a/src/Logging/logger/SeverityLevel.cs b/src/Logging/logger/SeverityLevel.cs
index 0471f04f..a5565a3d 100644
--- a/src/Logging/logger/SeverityLevel.cs
+++ b/src/Logging/logger/SeverityLevel.cs
@@ -1,37 +1,38 @@
-// Copyright (c) Microsoft Corporation and Contributors
-// Licensed under the MIT license.
-
-namespace DevHome.Logging;
-public enum SeverityLevel
-{
- Debug,
- Info,
- Warn,
- Error,
- Critical,
-}
-
-// For setting fail-fast behavior, at what level of failure will we conduct a fail-fast?
-// This is mostly intended for specifying whether any error or any critical error causes an FailFast.
-// By default we assume any critical failure is by definition something we should not continue after detecting.
-public enum FailFastSeverityLevel
-{
- Ignore = -1,
- Warning = SeverityLevel.Warn,
- Error = SeverityLevel.Error,
- Critical = SeverityLevel.Critical,
-}
-
-public class FailFast
-{
- public static bool IsFailFastSeverityLevel(SeverityLevel severity, FailFastSeverityLevel failFastSeverity)
- {
- return failFastSeverity switch
- {
- FailFastSeverityLevel.Warning => severity >= SeverityLevel.Warn,
- FailFastSeverityLevel.Error => severity >= SeverityLevel.Error,
- FailFastSeverityLevel.Critical => severity >= SeverityLevel.Critical,
- _ => false,
- };
- }
-}
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+namespace DevHome.Logging;
+
+public enum SeverityLevel
+{
+ Debug,
+ Info,
+ Warn,
+ Error,
+ Critical,
+}
+
+// For setting fail-fast behavior, at what level of failure will we conduct a fail-fast?
+// This is mostly intended for specifying whether any error or any critical error causes an FailFast.
+// By default we assume any critical failure is by definition something we should not continue after detecting.
+public enum FailFastSeverityLevel
+{
+ Ignore = -1,
+ Warning = SeverityLevel.Warn,
+ Error = SeverityLevel.Error,
+ Critical = SeverityLevel.Critical,
+}
+
+public class FailFast
+{
+ public static bool IsFailFastSeverityLevel(SeverityLevel severity, FailFastSeverityLevel failFastSeverity)
+ {
+ return failFastSeverity switch
+ {
+ FailFastSeverityLevel.Warning => severity >= SeverityLevel.Warn,
+ FailFastSeverityLevel.Error => severity >= SeverityLevel.Error,
+ FailFastSeverityLevel.Critical => severity >= SeverityLevel.Critical,
+ _ => false,
+ };
+ }
+}
diff --git a/src/Telemetry/GitHubExtension.Telemetry.csproj b/src/Telemetry/GitHubExtension.Telemetry.csproj
index 7b46d781..5647434e 100644
--- a/src/Telemetry/GitHubExtension.Telemetry.csproj
+++ b/src/Telemetry/GitHubExtension.Telemetry.csproj
@@ -1,28 +1,16 @@
-
-
-
-
- GitHubExtension.Telemetry
- x86;x64;arm64
- win10-x86;win10-x64;win10-arm64
- true
-
-
-
-
- Guard
- Spectre
-
-
-
-
-
-
-
-
-
- all
- runtime; build; native; contentfiles; analyzers; buildtransitive
-
-
-
+
+
+
+
+ GitHubExtension.Telemetry
+ x86;x64;arm64
+ win10-x86;win10-x64;win10-arm64
+
+
+
+
+ Guard
+ Spectre
+
+
+
diff --git a/src/Telemetry/ILogger.cs b/src/Telemetry/ILogger.cs
index 2a14d53d..965b543b 100644
--- a/src/Telemetry/ILogger.cs
+++ b/src/Telemetry/ILogger.cs
@@ -1,67 +1,67 @@
-// Copyright (c) Microsoft Corporation and Contributors
-// Licensed under the MIT license.
-
-using System;
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+using System;
using System.Diagnostics.CodeAnalysis;
-
-namespace GitHubExtension.Telemetry;
-
-///
-/// To create an instance call LoggerFactory.Get()
-///
-public interface ILogger
-{
- ///
- /// Add a string that we should try stripping out of some of our telemetry for sensitivity reasons (ex. VM name, etc.).
- /// We can never be 100% sure we can remove every string, but this should greatly reduce us collecting PII.
- /// Note that the order in which AddSensitive is called matters, as later when we call ReplaceSensitiveStrings, it will try
- /// finding and replacing the earlier strings first. This can be helpful, since we can target specific
- /// strings (like username) first, which should help preserve more information helpful for diagnosis.
- ///
- /// Sensitive string to add (ex. "c:\xyz")
- /// string to replace it with (ex. "-path-")
- public void AddSensitiveString(string name, string replaceWith);
-
- ///
- /// Gets a value indicating whether telemetry is on
- /// For future use if we add a registry key or some other setting to check if telemetry is turned on.
- public bool IsTelemetryOn { get; }
-
- ///
- /// Logs an exception at Measure level. To log at Critical level, the event name needs approval.
- ///
- /// What we trying to do when the exception occurred.
- /// Exception object
- /// Optional relatedActivityId which will allow to correlate this telemetry with other telemetry in the same action/activity or thread and corelate them
- public void LogException(string action, Exception e, Guid? relatedActivityId = null);
-
- ///
- /// Log the time an action took (ex. time spent on a tool).
- ///
- /// The measurement we're performing (ex. "DeployTime").
- /// How long the action took in milliseconds.
- /// Optional relatedActivityId which will allow to correlate this telemetry with other telemetry in the same action/activity or thread and corelate them
- public void LogTimeTaken(string eventName, uint timeTakenMilliseconds, Guid? relatedActivityId = null);
-
- ///
- /// Log an informational event. Typically used for just a single event that's only called one place in the code.
- /// If you are logging the same event multiple times, it's best to add a helper method in Logger
- ///
- /// Name of the error event
- /// Determines whether to upload the data to our servers, and on how many machines.
- /// Values to send to the telemetry system.
- /// Optional relatedActivityId which will allow to correlate this telemetry with other telemetry in the same action/activity or thread and corelate them
- /// Anonymous type.
- public void Log<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicProperties)] T>(string eventName, LogLevel level, T data, Guid? relatedActivityId = null);
-
- ///
- /// Log an error event. Typically used for just a single event that's only called one place in the code.
- /// If you are logging the same event multiple times, it's best to add a helper method in Logger
- ///
- /// Name of the error event
- /// Determines whether to upload the data to our servers, and on how many machines.
- /// Values to send to the telemetry system.
- /// Optional Optional relatedActivityId which will allow to correlate this telemetry with other telemetry in the same action/activity or thread and corelate them
- /// Anonymous type.
- public void LogError<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicProperties)] T>(string eventName, LogLevel level, T data, Guid? relatedActivityId = null);
-}
+
+namespace GitHubExtension.Telemetry;
+
+///
+/// To create an instance call LoggerFactory.Get()
+///
+public interface ILogger
+{
+ ///
+ /// Add a string that we should try stripping out of some of our telemetry for sensitivity reasons (ex. VM name, etc.).
+ /// We can never be 100% sure we can remove every string, but this should greatly reduce us collecting PII.
+ /// Note that the order in which AddSensitive is called matters, as later when we call ReplaceSensitiveStrings, it will try
+ /// finding and replacing the earlier strings first. This can be helpful, since we can target specific
+ /// strings (like username) first, which should help preserve more information helpful for diagnosis.
+ ///
+ /// Sensitive string to add (ex. "c:\xyz")
+ /// string to replace it with (ex. "-path-")
+ public void AddSensitiveString(string name, string replaceWith);
+
+ ///
+ /// Gets a value indicating whether telemetry is on
+ /// For future use if we add a registry key or some other setting to check if telemetry is turned on.
+ public bool IsTelemetryOn { get; }
+
+ ///
+ /// Logs an exception at Measure level. To log at Critical level, the event name needs approval.
+ ///
+ /// What we trying to do when the exception occurred.
+ /// Exception object
+ /// Optional relatedActivityId which will allow to correlate this telemetry with other telemetry in the same action/activity or thread and corelate them
+ public void LogException(string action, Exception e, Guid? relatedActivityId = null);
+
+ ///
+ /// Log the time an action took (ex. time spent on a tool).
+ ///
+ /// The measurement we're performing (ex. "DeployTime").
+ /// How long the action took in milliseconds.
+ /// Optional relatedActivityId which will allow to correlate this telemetry with other telemetry in the same action/activity or thread and corelate them
+ public void LogTimeTaken(string eventName, uint timeTakenMilliseconds, Guid? relatedActivityId = null);
+
+ ///
+ /// Log an informational event. Typically used for just a single event that's only called one place in the code.
+ /// If you are logging the same event multiple times, it's best to add a helper method in Logger
+ ///
+ /// Name of the error event
+ /// Determines whether to upload the data to our servers, and on how many machines.
+ /// Values to send to the telemetry system.
+ /// Optional relatedActivityId which will allow to correlate this telemetry with other telemetry in the same action/activity or thread and corelate them
+ /// Anonymous type.
+ public void Log<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicProperties)] T>(string eventName, LogLevel level, T data, Guid? relatedActivityId = null);
+
+ ///
+ /// Log an error event. Typically used for just a single event that's only called one place in the code.
+ /// If you are logging the same event multiple times, it's best to add a helper method in Logger
+ ///
+ /// Name of the error event
+ /// Determines whether to upload the data to our servers, and on how many machines.
+ /// Values to send to the telemetry system.
+ /// Optional Optional relatedActivityId which will allow to correlate this telemetry with other telemetry in the same action/activity or thread and corelate them
+ /// Anonymous type.
+ public void LogError<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicProperties)] T>(string eventName, LogLevel level, T data, Guid? relatedActivityId = null);
+}
diff --git a/src/Telemetry/LogLevel.cs b/src/Telemetry/LogLevel.cs
index 0917717e..6acd6347 100644
--- a/src/Telemetry/LogLevel.cs
+++ b/src/Telemetry/LogLevel.cs
@@ -1,39 +1,39 @@
-// Copyright (c) Microsoft Corporation and Contributors
-// Licensed under the MIT license.
-
-namespace GitHubExtension.Telemetry;
-
-///
-/// Telemetry Levels.
-/// These levels are defined by our telemetry system, so it's possible the sampling
-/// could change in the future.
-/// There aren't any convenient enums we can consume, so create our own.
-///
-public enum LogLevel
-{
- ///
- /// Local.
- /// Only log telemetry locally on the machine (similar to an ETW event).
- ///
- Local,
-
- ///
- /// Info.
- /// Send telemetry from internal and flighted machines, but no external retail machines.
- ///
- Info,
-
- ///
- /// Measure.
- /// Send telemetry from internal and flighted machines, plus a small, sample % of retail machines.
- /// Should only be used for telemetry we use to derive measures from.
- ///
- Measure,
-
- ///
- /// Critical.
- /// Send telemetry from all devices sampled at 100%.
- /// Should only be used for approved events.
- ///
- Critical,
-}
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+namespace GitHubExtension.Telemetry;
+
+///
+/// Telemetry Levels.
+/// These levels are defined by our telemetry system, so it's possible the sampling
+/// could change in the future.
+/// There aren't any convenient enums we can consume, so create our own.
+///
+public enum LogLevel
+{
+ ///
+ /// Local.
+ /// Only log telemetry locally on the machine (similar to an ETW event).
+ ///
+ Local,
+
+ ///
+ /// Info.
+ /// Send telemetry from internal and flighted machines, but no external retail machines.
+ ///
+ Info,
+
+ ///
+ /// Measure.
+ /// Send telemetry from internal and flighted machines, plus a small, sample % of retail machines.
+ /// Should only be used for telemetry we use to derive measures from.
+ ///
+ Measure,
+
+ ///
+ /// Critical.
+ /// Send telemetry from all devices sampled at 100%.
+ /// Should only be used for approved events.
+ ///
+ Critical,
+}
diff --git a/src/Telemetry/Logger.cs b/src/Telemetry/Logger.cs
index fb223746..21af0ee8 100644
--- a/src/Telemetry/Logger.cs
+++ b/src/Telemetry/Logger.cs
@@ -1,266 +1,266 @@
-// Copyright (c) Microsoft Corporation and Contributors
-// Licensed under the MIT license.
-
-using System;
-using System.Collections.Generic;
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+using System;
+using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
-using System.Diagnostics.Tracing;
-using System.IO;
-using System.Linq;
-using System.Text;
-using Microsoft.Diagnostics.Telemetry;
-
-namespace GitHubExtension.Telemetry;
-
-internal class Logger : ILogger
-{
- private const string ProviderName = "Microsoft.GitHubExtension";
-
- ///
- /// Time Taken Event Name
- ///
- private const string TimeTakenEventName = "TimeTaken";
-
- ///
- /// Exception Thrown Event Name
- ///
- private const string ExceptionThrownEventName = "ExceptionThrown";
-
- private static readonly Guid DefaultRelatedActivityId = Guid.Empty;
-
- ///
- /// Can only have one EventSource alive per process, so just create one statically.
- ///
- private static readonly EventSource TelemetryEventSourceInstance = new TelemetryEventSource(ProviderName);
-
- ///
- /// Logs telemetry locally, but shouldn't upload it. Similar to an ETW event.
- /// Should be the same as EventSourceOptions(), as Verbose is the default level.
- ///
- private static readonly EventSourceOptions LocalOption = new () { Level = EventLevel.Verbose };
-
- ///
- /// Logs error telemetry locally, but shouldn't upload it. Similar to an ETW event.
- ///
- private static readonly EventSourceOptions LocalErrorOption = new () { Level = EventLevel.Error };
-
- ///
- /// Logs telemetry.
- /// Currently this is at 0% sampling for both internal and external retail devices.
- ///
- private static readonly EventSourceOptions InfoOption = new () { Keywords = TelemetryEventSource.TelemetryKeyword };
-
- ///
- /// Logs error telemetry.
- /// Currently this is at 0% sampling for both internal and external retail devices.
- ///
- private static readonly EventSourceOptions InfoErrorOption = new () { Level = EventLevel.Error, Keywords = TelemetryEventSource.TelemetryKeyword };
-
- ///
- /// Logs measure telemetry.
- /// This should be sent back on internal devices, and a small, sampled % of external retail devices.
- ///
- private static readonly EventSourceOptions MeasureOption = new () { Keywords = TelemetryEventSource.MeasuresKeyword };
-
- ///
- /// Logs measure error telemetry.
- /// This should be sent back on internal devices, and a small, sampled % of external retail devices.
- ///
- private static readonly EventSourceOptions MeasureErrorOption = new () { Level = EventLevel.Error, Keywords = TelemetryEventSource.MeasuresKeyword };
-
- ///
- /// Logs critical telemetry.
- /// This should be sent back on all devices sampled at 100%.
- ///
- private static readonly EventSourceOptions CriticalDataOption = new () { Keywords = TelemetryEventSource.CriticalDataKeyword };
-
- ///
- /// Logs critical error telemetry.
- /// This should be sent back on all devices sampled at 100%.
- ///
- private static readonly EventSourceOptions CriticalDataErrorOption = new () { Level = EventLevel.Error, Keywords = TelemetryEventSource.CriticalDataKeyword };
-
- ///
- /// ActivityId so we can correlate all events in the same run
- ///
- private static Guid activityId = Guid.NewGuid();
-
- ///
- /// List of strings we should try removing for sensitivity reasons.
- ///
- private readonly List> sensitiveStrings = new ();
-
- ///
- /// Initializes a new instance of the class.
- /// Prevents a default instance of the Logger class from being created.
- ///
- internal Logger()
- {
- }
-
- ///
- /// Gets a value indicating whether telemetry is on
- /// For future use if we add a registry key or some other setting to check if telemetry is turned on.
- public bool IsTelemetryOn => true;
-
- ///
- /// Add a string that we should try stripping out of some of our telemetry for sensitivity reasons (ex. VM name, etc.).
- /// We can never be 100% sure we can remove every string, but this should greatly reduce us collecting PII.
- /// Note that the order in which AddSensitive is called matters, as later when we call ReplaceSensitiveStrings, it will try
- /// finding and replacing the earlier strings first. This can be helpful, since we can target specific
- /// strings (like username) first, which should help preserve more information helpful for diagnosis.
- ///
- /// Sensitive string to add (ex. "c:\xyz")
- /// string to replace it with (ex. "-path-")
- public void AddSensitiveString(string name, string replaceWith)
- {
- // Make sure the name isn't blank, hasn't already been added, and is greater than three characters.
- // Otherwise they could name their VM "a", and then we would end up replacing every "a" with another string.
- if (!string.IsNullOrWhiteSpace(name) && name.Length > 3 && !sensitiveStrings.Exists(item => name.Equals(item.Key, StringComparison.Ordinal)))
- {
- sensitiveStrings.Add(new KeyValuePair(name, replaceWith ?? string.Empty));
- }
- }
-
- ///
- /// Logs an exception at Measure level. To log at Critical level, the event name needs approval.
- ///
- /// What we trying to do when the exception occurred.
- /// Exception object
- /// Optional relatedActivityId which will allow to correlate this telemetry with other telemetry in the same action/activity or thread and corelate them
- public void LogException(string action, Exception e, Guid? relatedActivityId = null)
- {
- var innerMessage = ReplaceSensitiveStrings(e.InnerException?.Message);
- var innerStackTrace = new StringBuilder();
- var innerException = e.InnerException;
- while (innerException != null)
- {
- innerStackTrace.Append(innerException.StackTrace);
-
- // Separating by 2 new lines to distinguish between different exceptions.
- innerStackTrace.AppendLine();
- innerStackTrace.AppendLine();
- innerException = innerException.InnerException;
- }
-
- LogError(
- ExceptionThrownEventName,
- LogLevel.Measure,
- new
- {
- action,
- name = e.GetType().Name,
- stackTrace = e.StackTrace,
- innerName = e.InnerException?.GetType().Name,
- innerMessage,
- innerStackTrace = innerStackTrace.ToString(),
- message = ReplaceSensitiveStrings(e.Message),
- },
- relatedActivityId ?? DefaultRelatedActivityId);
- }
-
- ///
- /// Log the time an action took (ex. deploy time).
- ///
- /// The measurement we're performing (ex. "DeployTime").
- /// How long the action took in milliseconds.
- /// Optional relatedActivityId which will allow to correlate this telemetry with other telemetry in the same action/activity or thread and corelate them
- public void LogTimeTaken(string eventName, uint timeTakenMilliseconds, Guid? relatedActivityId = null)
- {
- Log(
- TimeTakenEventName,
- LogLevel.Critical,
- new
- {
- eventName,
- timeTakenMilliseconds,
- },
- relatedActivityId ?? DefaultRelatedActivityId);
- }
-
- ///
- /// Log an informational event. Typically used for just a single event that's only called one place in the code.
- ///
- /// Name of the error event
- /// Determines whether to upload the data to our servers, and on how many machines.
- /// Values to send to the telemetry system.
- /// Optional relatedActivityId which will allow to correlate this telemetry with other telemetry in the same action/activity or thread and corelate them
- /// Anonymous type.
- public void Log<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicProperties)] T>(string eventName, LogLevel level, T data, Guid? relatedActivityId = null)
- {
- WriteTelemetryEvent(eventName, level, relatedActivityId ?? DefaultRelatedActivityId, false, data);
- }
-
- ///
- /// Log an error event. Typically used for just a single event that's only called one place in the code.
- ///
- /// Name of the error event
- /// Determines whether to upload the data to our servers, and on how many machines.
- /// Values to send to the telemetry system.
- /// Optional Optional relatedActivityId which will allow to correlate this telemetry with other telemetry in the same action/activity or thread and corelate them
- /// Anonymous type.
- public void LogError<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicProperties)] T>(string eventName, LogLevel level, T data, Guid? relatedActivityId = null)
- {
- WriteTelemetryEvent(eventName, level, relatedActivityId ?? DefaultRelatedActivityId, true, data);
- }
-
- ///
- /// Replaces sensitive strings in a string with non sensitive strings.
- ///
- /// Before, unstripped string.
- /// After, stripped string
- private string ReplaceSensitiveStrings(string message)
- {
- if (message != null)
- {
- foreach (var pair in sensitiveStrings)
- {
- // There's no String.Replace() with case insensitivity.
- // We could use Regular Expressions here for searching for case-insensitive string matches,
- // but it's not easy to specify the RegEx timeout value for .net 4.0. And we were worried
- // about rare cases where the user could accidentally lock us up with RegEx, since we're using strings
- // provided by the user, so just use a simple non-RegEx replacement algorithm instead.
- var sb = new StringBuilder();
- var i = 0;
- while (true)
- {
- // Find the string to strip out.
- var foundPosition = message.IndexOf(pair.Key, i, StringComparison.OrdinalIgnoreCase);
- if (foundPosition < 0)
- {
- sb.Append(message, i, message.Length - i);
- message = sb.ToString();
- break;
- }
-
- // Replace the string.
- sb.Append(message, i, foundPosition - i);
- sb.Append(pair.Value);
- i = foundPosition + pair.Key.Length;
- }
- }
- }
-
- return message;
+using System.Diagnostics.Tracing;
+using System.IO;
+using System.Linq;
+using System.Text;
+using Microsoft.Diagnostics.Telemetry;
+
+namespace GitHubExtension.Telemetry;
+
+internal class Logger : ILogger
+{
+ private const string ProviderName = "Microsoft.GitHubExtension";
+
+ ///
+ /// Time Taken Event Name
+ ///
+ private const string TimeTakenEventName = "TimeTaken";
+
+ ///
+ /// Exception Thrown Event Name
+ ///
+ private const string ExceptionThrownEventName = "ExceptionThrown";
+
+ private static readonly Guid DefaultRelatedActivityId = Guid.Empty;
+
+ ///
+ /// Can only have one EventSource alive per process, so just create one statically.
+ ///
+ private static readonly EventSource TelemetryEventSourceInstance = new TelemetryEventSource(ProviderName);
+
+ ///
+ /// Logs telemetry locally, but shouldn't upload it. Similar to an ETW event.
+ /// Should be the same as EventSourceOptions(), as Verbose is the default level.
+ ///
+ private static readonly EventSourceOptions LocalOption = new () { Level = EventLevel.Verbose };
+
+ ///
+ /// Logs error telemetry locally, but shouldn't upload it. Similar to an ETW event.
+ ///
+ private static readonly EventSourceOptions LocalErrorOption = new () { Level = EventLevel.Error };
+
+ ///
+ /// Logs telemetry.
+ /// Currently this is at 0% sampling for both internal and external retail devices.
+ ///
+ private static readonly EventSourceOptions InfoOption = new () { Keywords = TelemetryEventSource.TelemetryKeyword };
+
+ ///
+ /// Logs error telemetry.
+ /// Currently this is at 0% sampling for both internal and external retail devices.
+ ///
+ private static readonly EventSourceOptions InfoErrorOption = new () { Level = EventLevel.Error, Keywords = TelemetryEventSource.TelemetryKeyword };
+
+ ///
+ /// Logs measure telemetry.
+ /// This should be sent back on internal devices, and a small, sampled % of external retail devices.
+ ///
+ private static readonly EventSourceOptions MeasureOption = new () { Keywords = TelemetryEventSource.MeasuresKeyword };
+
+ ///
+ /// Logs measure error telemetry.
+ /// This should be sent back on internal devices, and a small, sampled % of external retail devices.
+ ///
+ private static readonly EventSourceOptions MeasureErrorOption = new () { Level = EventLevel.Error, Keywords = TelemetryEventSource.MeasuresKeyword };
+
+ ///
+ /// Logs critical telemetry.
+ /// This should be sent back on all devices sampled at 100%.
+ ///
+ private static readonly EventSourceOptions CriticalDataOption = new () { Keywords = TelemetryEventSource.CriticalDataKeyword };
+
+ ///
+ /// Logs critical error telemetry.
+ /// This should be sent back on all devices sampled at 100%.
+ ///
+ private static readonly EventSourceOptions CriticalDataErrorOption = new () { Level = EventLevel.Error, Keywords = TelemetryEventSource.CriticalDataKeyword };
+
+ ///
+ /// ActivityId so we can correlate all events in the same run
+ ///
+ private static Guid activityId = Guid.NewGuid();
+
+ ///
+ /// List of strings we should try removing for sensitivity reasons.
+ ///
+ private readonly List> sensitiveStrings = new ();
+
+ ///
+ /// Initializes a new instance of the class.
+ /// Prevents a default instance of the Logger class from being created.
+ ///
+ internal Logger()
+ {
}
- ///
- /// Writes the telemetry event info using the TraceLogging API.
- ///
- /// Anonymous type.
- /// Name of the event.
- /// Determines whether to upload the data to our servers, and the sample set of host machines.
- /// Set to true if an error condition raised this event.
+ ///
+ /// Gets a value indicating whether telemetry is on
+ /// For future use if we add a registry key or some other setting to check if telemetry is turned on.
+ public bool IsTelemetryOn => true;
+
+ ///
+ /// Add a string that we should try stripping out of some of our telemetry for sensitivity reasons (ex. VM name, etc.).
+ /// We can never be 100% sure we can remove every string, but this should greatly reduce us collecting PII.
+ /// Note that the order in which AddSensitive is called matters, as later when we call ReplaceSensitiveStrings, it will try
+ /// finding and replacing the earlier strings first. This can be helpful, since we can target specific
+ /// strings (like username) first, which should help preserve more information helpful for diagnosis.
+ ///
+ /// Sensitive string to add (ex. "c:\xyz")
+ /// string to replace it with (ex. "-path-")
+ public void AddSensitiveString(string name, string replaceWith)
+ {
+ // Make sure the name isn't blank, hasn't already been added, and is greater than three characters.
+ // Otherwise they could name their VM "a", and then we would end up replacing every "a" with another string.
+ if (!string.IsNullOrWhiteSpace(name) && name.Length > 3 && !sensitiveStrings.Exists(item => name.Equals(item.Key, StringComparison.Ordinal)))
+ {
+ sensitiveStrings.Add(new KeyValuePair(name, replaceWith ?? string.Empty));
+ }
+ }
+
+ ///
+ /// Logs an exception at Measure level. To log at Critical level, the event name needs approval.
+ ///
+ /// What we trying to do when the exception occurred.
+ /// Exception object
+ /// Optional relatedActivityId which will allow to correlate this telemetry with other telemetry in the same action/activity or thread and corelate them
+ public void LogException(string action, Exception e, Guid? relatedActivityId = null)
+ {
+ var innerMessage = ReplaceSensitiveStrings(e.InnerException?.Message);
+ var innerStackTrace = new StringBuilder();
+ var innerException = e.InnerException;
+ while (innerException != null)
+ {
+ innerStackTrace.Append(innerException.StackTrace);
+
+ // Separating by 2 new lines to distinguish between different exceptions.
+ innerStackTrace.AppendLine();
+ innerStackTrace.AppendLine();
+ innerException = innerException.InnerException;
+ }
+
+ LogError(
+ ExceptionThrownEventName,
+ LogLevel.Measure,
+ new
+ {
+ action,
+ name = e.GetType().Name,
+ stackTrace = e.StackTrace,
+ innerName = e.InnerException?.GetType().Name,
+ innerMessage,
+ innerStackTrace = innerStackTrace.ToString(),
+ message = ReplaceSensitiveStrings(e.Message),
+ },
+ relatedActivityId ?? DefaultRelatedActivityId);
+ }
+
+ ///
+ /// Log the time an action took (ex. deploy time).
+ ///
+ /// The measurement we're performing (ex. "DeployTime").
+ /// How long the action took in milliseconds.
+ /// Optional relatedActivityId which will allow to correlate this telemetry with other telemetry in the same action/activity or thread and corelate them
+ public void LogTimeTaken(string eventName, uint timeTakenMilliseconds, Guid? relatedActivityId = null)
+ {
+ Log(
+ TimeTakenEventName,
+ LogLevel.Critical,
+ new
+ {
+ eventName,
+ timeTakenMilliseconds,
+ },
+ relatedActivityId ?? DefaultRelatedActivityId);
+ }
+
+ ///
+ /// Log an informational event. Typically used for just a single event that's only called one place in the code.
+ ///
+ /// Name of the error event
+ /// Determines whether to upload the data to our servers, and on how many machines.
+ /// Values to send to the telemetry system.
+ /// Optional relatedActivityId which will allow to correlate this telemetry with other telemetry in the same action/activity or thread and corelate them
+ /// Anonymous type.
+ public void Log<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicProperties)] T>(string eventName, LogLevel level, T data, Guid? relatedActivityId = null)
+ {
+ WriteTelemetryEvent(eventName, level, relatedActivityId ?? DefaultRelatedActivityId, false, data);
+ }
+
+ ///
+ /// Log an error event. Typically used for just a single event that's only called one place in the code.
+ ///
+ /// Name of the error event
+ /// Determines whether to upload the data to our servers, and on how many machines.
+ /// Values to send to the telemetry system.
+ /// Optional Optional relatedActivityId which will allow to correlate this telemetry with other telemetry in the same action/activity or thread and corelate them
+ /// Anonymous type.
+ public void LogError<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicProperties)] T>(string eventName, LogLevel level, T data, Guid? relatedActivityId = null)
+ {
+ WriteTelemetryEvent(eventName, level, relatedActivityId ?? DefaultRelatedActivityId, true, data);
+ }
+
+ ///
+ /// Replaces sensitive strings in a string with non sensitive strings.
+ ///
+ /// Before, unstripped string.
+ /// After, stripped string
+ private string ReplaceSensitiveStrings(string message)
+ {
+ if (message != null)
+ {
+ foreach (var pair in sensitiveStrings)
+ {
+ // There's no String.Replace() with case insensitivity.
+ // We could use Regular Expressions here for searching for case-insensitive string matches,
+ // but it's not easy to specify the RegEx timeout value for .net 4.0. And we were worried
+ // about rare cases where the user could accidentally lock us up with RegEx, since we're using strings
+ // provided by the user, so just use a simple non-RegEx replacement algorithm instead.
+ var sb = new StringBuilder();
+ var i = 0;
+ while (true)
+ {
+ // Find the string to strip out.
+ var foundPosition = message.IndexOf(pair.Key, i, StringComparison.OrdinalIgnoreCase);
+ if (foundPosition < 0)
+ {
+ sb.Append(message, i, message.Length - i);
+ message = sb.ToString();
+ break;
+ }
+
+ // Replace the string.
+ sb.Append(message, i, foundPosition - i);
+ sb.Append(pair.Value);
+ i = foundPosition + pair.Key.Length;
+ }
+ }
+ }
+
+ return message;
+ }
+
+ ///
+ /// Writes the telemetry event info using the TraceLogging API.
+ ///
+ /// Anonymous type.
+ /// Name of the event.
+ /// Determines whether to upload the data to our servers, and the sample set of host machines.
+ /// Set to true if an error condition raised this event.
/// Values to send to the telemetry system.
[UnconditionalSuppressMessage(
"ReflectionAnalysis",
"IL2026:RequiresUnreferencedCode",
- Justification = "The type passed for data is an anonymous type consisting of primitive type properties declared in an assembly that is not marked trimmable.")]
- private void WriteTelemetryEvent<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicProperties)] T>(string eventName, LogLevel level, Guid relatedActivityId, bool isError, T data)
- {
- EventSourceOptions telemetryOptions;
- if (IsTelemetryOn)
- {
+ Justification = "The type passed for data is an anonymous type consisting of primitive type properties declared in an assembly that is not marked trimmable.")]
+ private void WriteTelemetryEvent<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicProperties)] T>(string eventName, LogLevel level, Guid relatedActivityId, bool isError, T data)
+ {
+ EventSourceOptions telemetryOptions;
+ if (IsTelemetryOn)
+ {
telemetryOptions = level switch
{
LogLevel.Critical => isError ? Logger.CriticalDataErrorOption : Logger.CriticalDataOption,
@@ -268,34 +268,34 @@ private string ReplaceSensitiveStrings(string message)
LogLevel.Info => isError ? Logger.InfoErrorOption : Logger.InfoOption,
_ => isError ? Logger.LocalErrorOption : Logger.LocalOption,
};
- }
- else
- {
- // The telemetry is not turned on, downgrade to local telemetry
- telemetryOptions = isError ? Logger.LocalErrorOption : Logger.LocalOption;
- }
-
- TelemetryEventSourceInstance.Write(eventName, ref telemetryOptions, ref activityId, ref relatedActivityId, ref data);
- }
-
- internal void AddWellKnownSensitiveStrings()
- {
- try
- {
- // This should convert "c:\users\johndoe" to "".
- var userDirectory = Directory.GetParent(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData)).FullName;
- AddSensitiveString(Directory.GetParent(userDirectory).ToString(), "");
-
- // Include both these names, since they should cover the logged on user, and the user who is running the tools built on top of these API's
- // These names should almost always be the same, but technically could be different.
- AddSensitiveString(Environment.UserName, "");
- var currentUserName = System.Security.Principal.WindowsIdentity.GetCurrent().Name.Split('\\').Last();
- AddSensitiveString(currentUserName, "");
- }
- catch (Exception e)
- {
- // Catch and log exception
- LogException("AddSensitiveStrings", e);
- }
- }
-}
+ }
+ else
+ {
+ // The telemetry is not turned on, downgrade to local telemetry
+ telemetryOptions = isError ? Logger.LocalErrorOption : Logger.LocalOption;
+ }
+
+ TelemetryEventSourceInstance.Write(eventName, ref telemetryOptions, ref activityId, ref relatedActivityId, ref data);
+ }
+
+ internal void AddWellKnownSensitiveStrings()
+ {
+ try
+ {
+ // This should convert "c:\users\johndoe" to "".
+ var userDirectory = Directory.GetParent(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData)).FullName;
+ AddSensitiveString(Directory.GetParent(userDirectory).ToString(), "");
+
+ // Include both these names, since they should cover the logged on user, and the user who is running the tools built on top of these API's
+ // These names should almost always be the same, but technically could be different.
+ AddSensitiveString(Environment.UserName, "");
+ var currentUserName = System.Security.Principal.WindowsIdentity.GetCurrent().Name.Split('\\').Last();
+ AddSensitiveString(currentUserName, "");
+ }
+ catch (Exception e)
+ {
+ // Catch and log exception
+ LogException("AddSensitiveStrings", e);
+ }
+ }
+}
diff --git a/src/Telemetry/LoggerFactory.cs b/src/Telemetry/LoggerFactory.cs
index 28a4abb1..600c85a9 100644
--- a/src/Telemetry/LoggerFactory.cs
+++ b/src/Telemetry/LoggerFactory.cs
@@ -1,5 +1,5 @@
-// Copyright (c) Microsoft Corporation and Contributors
-// Licensed under the MIT license.
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
namespace GitHubExtension.Telemetry;
diff --git a/src/Telemetry/TelemetryEventSource.cs b/src/Telemetry/TelemetryEventSource.cs
index 40a98a0a..46f4cbb1 100644
--- a/src/Telemetry/TelemetryEventSource.cs
+++ b/src/Telemetry/TelemetryEventSource.cs
@@ -1,343 +1,343 @@
-//
-// Copyright (c) Microsoft Corporation. All rights reserved.
-// Licensed under the MIT License. See LICENSE in the project root for license information.
-
-#if TELEMETRYEVENTSOURCE_USE_NUGET
-using Microsoft.Diagnostics.Tracing;
-#else
-using System.Diagnostics.Tracing;
-#endif
-using System;
-using SuppressMessageAttribute = System.Diagnostics.CodeAnalysis.SuppressMessageAttribute;
-
-#pragma warning disable 3021 // 'type' does not need a CLSCompliant attribute
-
-namespace Microsoft.Diagnostics.Telemetry
-{
- ///
- ///
- /// An EventSource with extra methods and constants commonly used in Microsoft's
- /// TraceLogging-based ETW. This class inherits from EventSource, and is exactly
- /// the same as EventSource except that it always enables
- /// EtwSelfDescribingEventFormat and never uses traits. It also provides several
- /// constants and helpers commonly used by Microsoft code.
- ///
- ///
- /// Different versions of this class use different provider traits. The provider
- /// traits in this class are empty. As a result, providers using this class will
- /// not join any ETW Provider Groups and will not be given any special treatment
- /// by group-sensitive ETW listeners.
- ///
- ///
- /// When including this class in your project, you may define the following
- /// conditional-compilation symbols to adjust the default behaviors:
- ///
- ///
- /// TELEMETRYEVENTSOURCE_USE_NUGET - use Microsoft.Diagnostics.Tracing instead
- /// of System.Diagnostics.Tracing.
- ///
- ///
- /// TELEMETRYEVENTSOURCE_PUBLIC - define TelemetryEventSource as public instead
- /// of internal.
- ///
- ///
-#if TELEMETRYEVENTSOURCE_PUBLIC
- public
-#else
- internal
-#endif
- class TelemetryEventSource
- : EventSource
- {
- ///
- /// Keyword 0x0000100000000000 is reserved for future definition. Do
- /// not use keyword 0x0000100000000000 in Microsoft-style ETW.
- ///
- public const EventKeywords Reserved44Keyword = (EventKeywords)0x0000100000000000;
-
- ///
- /// Add TelemetryKeyword to eventSourceOptions.Keywords to indicate that
- /// an event is for general-purpose telemetry.
- /// This keyword should not be combined with MeasuresKeyword or
- /// CriticalDataKeyword.
- ///
- public const EventKeywords TelemetryKeyword = (EventKeywords)0x0000200000000000;
-
- ///
- /// Add MeasuresKeyword to eventSourceOptions.Keywords to indicate that
- /// an event is for understanding measures and reporting scenarios.
- /// This keyword should not be combined with TelemetryKeyword or
- /// CriticalDataKeyword.
- ///
- public const EventKeywords MeasuresKeyword = (EventKeywords)0x0000400000000000;
-
- ///
- /// Add CriticalDataKeyword to eventSourceOptions.Keywords to indicate that
- /// an event powers user experiences or is critical to business intelligence.
- /// This keyword should not be combined with TelemetryKeyword or
- /// MeasuresKeyword.
- ///
- public const EventKeywords CriticalDataKeyword = (EventKeywords)0x0000800000000000;
-
- ///
- /// Add CostDeferredLatency to eventSourceOptions.Tags to indicate that an event
- /// should try to upload over free networks for a period of time before resorting
- /// to upload over costed networks.
- ///
- public const EventTags CostDeferredLatency = (EventTags)0x040000;
-
- ///
- /// Add CoreData to eventSourceOptions.Tags to indicate that an event
- /// contains high priority "core data".
- ///
- public const EventTags CoreData = (EventTags)0x00080000;
-
- ///
- /// Add InjectXToken to eventSourceOptions.Tags to indicate that an XBOX
- /// identity token should be injected into the event before the event is
- /// uploaded.
- ///
- public const EventTags InjectXToken = (EventTags)0x00100000;
-
- ///
- /// Add RealtimeLatency to eventSourceOptions.Tags to indicate that an event
- /// should be transmitted in real time (via any available connection).
- ///
- public const EventTags RealtimeLatency = (EventTags)0x0200000;
-
- ///
- /// Add NormalLatency to eventSourceOptions.Tags to indicate that an event
- /// should be transmitted via the preferred connection based on device policy.
- ///
- public const EventTags NormalLatency = (EventTags)0x0400000;
-
- ///
- /// Add CriticalPersistence to eventSourceOptions.Tags to indicate that an
- /// event should be deleted last when low on spool space.
- ///
- public const EventTags CriticalPersistence = (EventTags)0x0800000;
-
- ///
- /// Add NormalPersistence to eventSourceOptions.Tags to indicate that an event
- /// should be deleted first when low on spool space.
- ///
- public const EventTags NormalPersistence = (EventTags)0x1000000;
-
- ///
- /// Add DropPii to eventSourceOptions.Tags to indicate that an event contains
- /// PII and should be anonymized by the telemetry client. If this tag is
- /// present, PartA fields that might allow identification or cross-event
- /// correlation will be removed from the event.
- ///
- public const EventTags DropPii = (EventTags)0x02000000;
-
- ///
- /// Add HashPii to eventSourceOptions.Tags to indicate that an event contains
- /// PII and should be anonymized by the telemetry client. If this tag is
- /// present, PartA fields that might allow identification or cross-event
- /// correlation will be hashed (obfuscated).
- ///
- public const EventTags HashPii = (EventTags)0x04000000;
-
- ///
- /// Add MarkPii to eventSourceOptions.Tags to indicate that an event contains
- /// PII but may be uploaded as-is. If this tag is present, the event will be
- /// marked so that it will only appear on the private stream.
- ///
- public const EventTags MarkPii = (EventTags)0x08000000;
-
- ///
- /// Add DropPiiField to eventFieldAttribute.Tags to indicate that a field
- /// contains PII and should be dropped by the telemetry client.
- ///
- public const EventFieldTags DropPiiField = (EventFieldTags)0x04000000;
-
- ///
- /// Add HashPiiField to eventFieldAttribute.Tags to indicate that a field
- /// contains PII and should be hashed (obfuscated) prior to uploading.
- ///
- public const EventFieldTags HashPiiField = (EventFieldTags)0x08000000;
-
- ///
- /// Constructs a new instance of the TelemetryEventSource class with the
- /// specified name. Sets the EtwSelfDescribingEventFormat option.
- ///
- /// The name of the event source.
- [SuppressMessage("Microsoft.Performance", "CA1811", Justification = "Shared class with tiny helper methods - not all constructors/methods are used by all consumers")]
- public TelemetryEventSource(
- string eventSourceName)
- : base(
- eventSourceName,
- EventSourceSettings.EtwSelfDescribingEventFormat)
- {
- return;
- }
-
- ///
- /// For use by derived classes that set the eventSourceName via EventSourceAttribute.
- /// Sets the EtwSelfDescribingEventFormat option.
- ///
- [SuppressMessage("Microsoft.Performance", "CA1811", Justification = "Shared class with tiny helper methods - not all constructors/methods are used by all consumers")]
- protected TelemetryEventSource()
- : base(
- EventSourceSettings.EtwSelfDescribingEventFormat)
- {
- return;
- }
-
- ///
- /// Constructs a new instance of the TelemetryEventSource class with the
- /// specified name. Sets the EtwSelfDescribingEventFormat option.
- ///
- /// The name of the event source.
- /// The parameter is not used.
- [SuppressMessage("Microsoft.Performance", "CA1811", Justification = "Shared class with tiny helper methods - not all constructors/methods are used by all consumers")]
- [SuppressMessage("Style", "IDE0060:Remove unused parameter", Justification = "API compatibility")]
- public TelemetryEventSource(
- string eventSourceName,
- TelemetryGroup telemetryGroup)
- : base(
- eventSourceName,
- EventSourceSettings.EtwSelfDescribingEventFormat)
- {
- return;
- }
-
- ///
- /// Returns an instance of EventSourceOptions with the TelemetryKeyword set.
- ///
- /// Returns an instance of EventSourceOptions with the TelemetryKeyword set.
- [SuppressMessage("Microsoft.Performance", "CA1811", Justification = "Shared class with tiny helper methods - not all constructors/methods are used by all consumers")]
- public static EventSourceOptions TelemetryOptions()
- {
- return new EventSourceOptions { Keywords = TelemetryKeyword };
- }
-
- ///
- /// Returns an instance of EventSourceOptions with the MeasuresKeyword set.
- ///
- /// Returns an instance of EventSourceOptions with the MeasuresKeyword set.
- [SuppressMessage("Microsoft.Performance", "CA1811", Justification = "Shared class with tiny helper methods - not all constructors/methods are used by all consumers")]
- public static EventSourceOptions MeasuresOptions()
- {
- return new EventSourceOptions { Keywords = MeasuresKeyword };
- }
- }
-
- ///
- ///
- /// The PrivTags class defines privacy tags that can be used to specify the privacy
- /// category of an event. Add a privacy tag as a field with name "PartA_PrivTags".
- /// As a shortcut, you can use _1 as the field name, which will automatically be
- /// expanded to "PartA_PrivTags" at runtime.
- ///
- ///
- /// Multiple tags can be OR'ed together if necessary (rarely needed).
- ///
- ///
- ///
- /// Typical usage:
- ///
- /// es.Write("UsageEvent", new
- /// {
- /// _1 = PrivTags.ProductAndServiceUsage,
- /// field1 = fieldValue1,
- /// field2 = fieldValue2
- /// });
- ///
- ///
-#if TELEMETRYEVENTSOURCE_PUBLIC
- [CLSCompliant(false)]
- public
-#else
- internal
-#endif
- static class PrivTags
- {
- ///
- public const Internal.PartA_PrivTags BrowsingHistory = Internal.PartA_PrivTags.BrowsingHistory;
-
- ///
- public const Internal.PartA_PrivTags DeviceConnectivityAndConfiguration = Internal.PartA_PrivTags.DeviceConnectivityAndConfiguration;
-
- ///
- public const Internal.PartA_PrivTags InkingTypingAndSpeechUtterance = Internal.PartA_PrivTags.InkingTypingAndSpeechUtterance;
-
- ///
- public const Internal.PartA_PrivTags ProductAndServicePerformance = Internal.PartA_PrivTags.ProductAndServicePerformance;
-
- ///
- public const Internal.PartA_PrivTags ProductAndServiceUsage = Internal.PartA_PrivTags.ProductAndServiceUsage;
-
- ///
- public const Internal.PartA_PrivTags SoftwareSetupAndInventory = Internal.PartA_PrivTags.SoftwareSetupAndInventory;
- }
- ///
- /// Pass a TelemetryGroup value to the constructor of TelemetryEventSource
- /// to control which telemetry group should be joined.
- /// Note: has no effect in this version of TelemetryEventSource.
- ///
-#if TELEMETRYEVENTSOURCE_PUBLIC
- public
-#else
- internal
-#endif
- enum TelemetryGroup
- {
- ///
- /// The default group. Join this group to log normal, non-critical, non-coredata
- /// events.
- ///
- MicrosoftTelemetry,
-
- ///
- /// Join this group to log CriticalData, CoreData, or other specially approved
- /// events.
- ///
- WindowsCoreTelemetry
- }
-
-#pragma warning disable SA1403 // File may only contain a single namespace
- namespace Internal
-#pragma warning restore SA1403 // File may only contain a single namespace
- {
- ///
- /// The complete list of privacy tags supported for events.
- /// Multiple tags can be OR'ed together if an event belongs in multiple
- /// categories.
- /// Note that the PartA_PrivTags enum should not be used directly.
- /// Instead, use values from the PrivTags class.
- ///
- [Flags]
-#if TELEMETRYEVENTSOURCE_PUBLIC
- [CLSCompliant(false)]
- public
-#else
- internal
-#endif
- enum PartA_PrivTags
- : ulong
- {
- ///
- None = 0,
-
- ///
- BrowsingHistory = 0x0000000000000002u,
-
- ///
- DeviceConnectivityAndConfiguration = 0x0000000000000800u,
-
- ///
- InkingTypingAndSpeechUtterance = 0x0000000000020000u,
-
- ///
- ProductAndServicePerformance = 0x0000000001000000u,
-
- ///
- ProductAndServiceUsage = 0x0000000002000000u,
-
- ///
- SoftwareSetupAndInventory = 0x0000000080000000u,
- }
- }
-}
+//
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License. See LICENSE in the project root for license information.
+
+#if TELEMETRYEVENTSOURCE_USE_NUGET
+using Microsoft.Diagnostics.Tracing;
+#else
+using System.Diagnostics.Tracing;
+#endif
+using System;
+using SuppressMessageAttribute = System.Diagnostics.CodeAnalysis.SuppressMessageAttribute;
+
+#pragma warning disable 3021 // 'type' does not need a CLSCompliant attribute
+
+namespace Microsoft.Diagnostics.Telemetry
+{
+ ///
+ ///
+ /// An EventSource with extra methods and constants commonly used in Microsoft's
+ /// TraceLogging-based ETW. This class inherits from EventSource, and is exactly
+ /// the same as EventSource except that it always enables
+ /// EtwSelfDescribingEventFormat and never uses traits. It also provides several
+ /// constants and helpers commonly used by Microsoft code.
+ ///
+ ///
+ /// Different versions of this class use different provider traits. The provider
+ /// traits in this class are empty. As a result, providers using this class will
+ /// not join any ETW Provider Groups and will not be given any special treatment
+ /// by group-sensitive ETW listeners.
+ ///
+ ///
+ /// When including this class in your project, you may define the following
+ /// conditional-compilation symbols to adjust the default behaviors:
+ ///
+ ///
+ /// TELEMETRYEVENTSOURCE_USE_NUGET - use Microsoft.Diagnostics.Tracing instead
+ /// of System.Diagnostics.Tracing.
+ ///
+ ///
+ /// TELEMETRYEVENTSOURCE_PUBLIC - define TelemetryEventSource as public instead
+ /// of internal.
+ ///
+ ///
+#if TELEMETRYEVENTSOURCE_PUBLIC
+ public
+#else
+ internal
+#endif
+ class TelemetryEventSource
+ : EventSource
+ {
+ ///
+ /// Keyword 0x0000100000000000 is reserved for future definition. Do
+ /// not use keyword 0x0000100000000000 in Microsoft-style ETW.
+ ///
+ public const EventKeywords Reserved44Keyword = (EventKeywords)0x0000100000000000;
+
+ ///
+ /// Add TelemetryKeyword to eventSourceOptions.Keywords to indicate that
+ /// an event is for general-purpose telemetry.
+ /// This keyword should not be combined with MeasuresKeyword or
+ /// CriticalDataKeyword.
+ ///
+ public const EventKeywords TelemetryKeyword = (EventKeywords)0x0000200000000000;
+
+ ///
+ /// Add MeasuresKeyword to eventSourceOptions.Keywords to indicate that
+ /// an event is for understanding measures and reporting scenarios.
+ /// This keyword should not be combined with TelemetryKeyword or
+ /// CriticalDataKeyword.
+ ///
+ public const EventKeywords MeasuresKeyword = (EventKeywords)0x0000400000000000;
+
+ ///
+ /// Add CriticalDataKeyword to eventSourceOptions.Keywords to indicate that
+ /// an event powers user experiences or is critical to business intelligence.
+ /// This keyword should not be combined with TelemetryKeyword or
+ /// MeasuresKeyword.
+ ///
+ public const EventKeywords CriticalDataKeyword = (EventKeywords)0x0000800000000000;
+
+ ///
+ /// Add CostDeferredLatency to eventSourceOptions.Tags to indicate that an event
+ /// should try to upload over free networks for a period of time before resorting
+ /// to upload over costed networks.
+ ///
+ public const EventTags CostDeferredLatency = (EventTags)0x040000;
+
+ ///
+ /// Add CoreData to eventSourceOptions.Tags to indicate that an event
+ /// contains high priority "core data".
+ ///
+ public const EventTags CoreData = (EventTags)0x00080000;
+
+ ///
+ /// Add InjectXToken to eventSourceOptions.Tags to indicate that an XBOX
+ /// identity token should be injected into the event before the event is
+ /// uploaded.
+ ///
+ public const EventTags InjectXToken = (EventTags)0x00100000;
+
+ ///
+ /// Add RealtimeLatency to eventSourceOptions.Tags to indicate that an event
+ /// should be transmitted in real time (via any available connection).
+ ///
+ public const EventTags RealtimeLatency = (EventTags)0x0200000;
+
+ ///
+ /// Add NormalLatency to eventSourceOptions.Tags to indicate that an event
+ /// should be transmitted via the preferred connection based on device policy.
+ ///
+ public const EventTags NormalLatency = (EventTags)0x0400000;
+
+ ///
+ /// Add CriticalPersistence to eventSourceOptions.Tags to indicate that an
+ /// event should be deleted last when low on spool space.
+ ///
+ public const EventTags CriticalPersistence = (EventTags)0x0800000;
+
+ ///
+ /// Add NormalPersistence to eventSourceOptions.Tags to indicate that an event
+ /// should be deleted first when low on spool space.
+ ///
+ public const EventTags NormalPersistence = (EventTags)0x1000000;
+
+ ///
+ /// Add DropPii to eventSourceOptions.Tags to indicate that an event contains
+ /// PII and should be anonymized by the telemetry client. If this tag is
+ /// present, PartA fields that might allow identification or cross-event
+ /// correlation will be removed from the event.
+ ///
+ public const EventTags DropPii = (EventTags)0x02000000;
+
+ ///
+ /// Add HashPii to eventSourceOptions.Tags to indicate that an event contains
+ /// PII and should be anonymized by the telemetry client. If this tag is
+ /// present, PartA fields that might allow identification or cross-event
+ /// correlation will be hashed (obfuscated).
+ ///
+ public const EventTags HashPii = (EventTags)0x04000000;
+
+ ///
+ /// Add MarkPii to eventSourceOptions.Tags to indicate that an event contains
+ /// PII but may be uploaded as-is. If this tag is present, the event will be
+ /// marked so that it will only appear on the private stream.
+ ///
+ public const EventTags MarkPii = (EventTags)0x08000000;
+
+ ///
+ /// Add DropPiiField to eventFieldAttribute.Tags to indicate that a field
+ /// contains PII and should be dropped by the telemetry client.
+ ///
+ public const EventFieldTags DropPiiField = (EventFieldTags)0x04000000;
+
+ ///
+ /// Add HashPiiField to eventFieldAttribute.Tags to indicate that a field
+ /// contains PII and should be hashed (obfuscated) prior to uploading.
+ ///
+ public const EventFieldTags HashPiiField = (EventFieldTags)0x08000000;
+
+ ///
+ /// Constructs a new instance of the TelemetryEventSource class with the
+ /// specified name. Sets the EtwSelfDescribingEventFormat option.
+ ///
+ /// The name of the event source.
+ [SuppressMessage("Microsoft.Performance", "CA1811", Justification = "Shared class with tiny helper methods - not all constructors/methods are used by all consumers")]
+ public TelemetryEventSource(
+ string eventSourceName)
+ : base(
+ eventSourceName,
+ EventSourceSettings.EtwSelfDescribingEventFormat)
+ {
+ return;
+ }
+
+ ///
+ /// For use by derived classes that set the eventSourceName via EventSourceAttribute.
+ /// Sets the EtwSelfDescribingEventFormat option.
+ ///
+ [SuppressMessage("Microsoft.Performance", "CA1811", Justification = "Shared class with tiny helper methods - not all constructors/methods are used by all consumers")]
+ protected TelemetryEventSource()
+ : base(
+ EventSourceSettings.EtwSelfDescribingEventFormat)
+ {
+ return;
+ }
+
+ ///
+ /// Constructs a new instance of the TelemetryEventSource class with the
+ /// specified name. Sets the EtwSelfDescribingEventFormat option.
+ ///
+ /// The name of the event source.
+ /// The parameter is not used.
+ [SuppressMessage("Microsoft.Performance", "CA1811", Justification = "Shared class with tiny helper methods - not all constructors/methods are used by all consumers")]
+ [SuppressMessage("Style", "IDE0060:Remove unused parameter", Justification = "API compatibility")]
+ public TelemetryEventSource(
+ string eventSourceName,
+ TelemetryGroup telemetryGroup)
+ : base(
+ eventSourceName,
+ EventSourceSettings.EtwSelfDescribingEventFormat)
+ {
+ return;
+ }
+
+ ///
+ /// Returns an instance of EventSourceOptions with the TelemetryKeyword set.
+ ///
+ /// Returns an instance of EventSourceOptions with the TelemetryKeyword set.
+ [SuppressMessage("Microsoft.Performance", "CA1811", Justification = "Shared class with tiny helper methods - not all constructors/methods are used by all consumers")]
+ public static EventSourceOptions TelemetryOptions()
+ {
+ return new EventSourceOptions { Keywords = TelemetryKeyword };
+ }
+
+ ///
+ /// Returns an instance of EventSourceOptions with the MeasuresKeyword set.
+ ///
+ /// Returns an instance of EventSourceOptions with the MeasuresKeyword set.
+ [SuppressMessage("Microsoft.Performance", "CA1811", Justification = "Shared class with tiny helper methods - not all constructors/methods are used by all consumers")]
+ public static EventSourceOptions MeasuresOptions()
+ {
+ return new EventSourceOptions { Keywords = MeasuresKeyword };
+ }
+ }
+
+ ///
+ ///
+ /// The PrivTags class defines privacy tags that can be used to specify the privacy
+ /// category of an event. Add a privacy tag as a field with name "PartA_PrivTags".
+ /// As a shortcut, you can use _1 as the field name, which will automatically be
+ /// expanded to "PartA_PrivTags" at runtime.
+ ///
+ ///
+ /// Multiple tags can be OR'ed together if necessary (rarely needed).
+ ///
+ ///
+ ///
+ /// Typical usage:
+ ///
+ /// es.Write("UsageEvent", new
+ /// {
+ /// _1 = PrivTags.ProductAndServiceUsage,
+ /// field1 = fieldValue1,
+ /// field2 = fieldValue2
+ /// });
+ ///
+ ///
+#if TELEMETRYEVENTSOURCE_PUBLIC
+ [CLSCompliant(false)]
+ public
+#else
+ internal
+#endif
+ static class PrivTags
+ {
+ ///
+ public const Internal.PartA_PrivTags BrowsingHistory = Internal.PartA_PrivTags.BrowsingHistory;
+
+ ///
+ public const Internal.PartA_PrivTags DeviceConnectivityAndConfiguration = Internal.PartA_PrivTags.DeviceConnectivityAndConfiguration;
+
+ ///
+ public const Internal.PartA_PrivTags InkingTypingAndSpeechUtterance = Internal.PartA_PrivTags.InkingTypingAndSpeechUtterance;
+
+ ///
+ public const Internal.PartA_PrivTags ProductAndServicePerformance = Internal.PartA_PrivTags.ProductAndServicePerformance;
+
+ ///
+ public const Internal.PartA_PrivTags ProductAndServiceUsage = Internal.PartA_PrivTags.ProductAndServiceUsage;
+
+ ///
+ public const Internal.PartA_PrivTags SoftwareSetupAndInventory = Internal.PartA_PrivTags.SoftwareSetupAndInventory;
+ }
+ ///
+ /// Pass a TelemetryGroup value to the constructor of TelemetryEventSource
+ /// to control which telemetry group should be joined.
+ /// Note: has no effect in this version of TelemetryEventSource.
+ ///
+#if TELEMETRYEVENTSOURCE_PUBLIC
+ public
+#else
+ internal
+#endif
+ enum TelemetryGroup
+ {
+ ///
+ /// The default group. Join this group to log normal, non-critical, non-coredata
+ /// events.
+ ///
+ MicrosoftTelemetry,
+
+ ///
+ /// Join this group to log CriticalData, CoreData, or other specially approved
+ /// events.
+ ///
+ WindowsCoreTelemetry
+ }
+
+#pragma warning disable SA1403 // File may only contain a single namespace
+ namespace Internal
+#pragma warning restore SA1403 // File may only contain a single namespace
+ {
+ ///
+ /// The complete list of privacy tags supported for events.
+ /// Multiple tags can be OR'ed together if an event belongs in multiple
+ /// categories.
+ /// Note that the PartA_PrivTags enum should not be used directly.
+ /// Instead, use values from the PrivTags class.
+ ///
+ [Flags]
+#if TELEMETRYEVENTSOURCE_PUBLIC
+ [CLSCompliant(false)]
+ public
+#else
+ internal
+#endif
+ enum PartA_PrivTags
+ : ulong
+ {
+ ///
+ None = 0,
+
+ ///
+ BrowsingHistory = 0x0000000000000002u,
+
+ ///
+ DeviceConnectivityAndConfiguration = 0x0000000000000800u,
+
+ ///
+ InkingTypingAndSpeechUtterance = 0x0000000000020000u,
+
+ ///
+ ProductAndServicePerformance = 0x0000000001000000u,
+
+ ///
+ ProductAndServiceUsage = 0x0000000002000000u,
+
+ ///
+ SoftwareSetupAndInventory = 0x0000000080000000u,
+ }
+ }
+}
diff --git a/test/Console/GitHubExtension.TestConsole.csproj b/test/Console/GitHubExtension.TestConsole.csproj
index 858ae271..cc2ab6f7 100644
--- a/test/Console/GitHubExtension.TestConsole.csproj
+++ b/test/Console/GitHubExtension.TestConsole.csproj
@@ -39,20 +39,7 @@
False
-
-
-
-
-
-
-
-
- all
- runtime; build; native; contentfiles; analyzers; buildtransitive
-
-
-
diff --git a/test/Console/Program.cs b/test/Console/Program.cs
index 6f99f5e1..d6d9c0b5 100644
--- a/test/Console/Program.cs
+++ b/test/Console/Program.cs
@@ -1,5 +1,5 @@
-// Copyright (c) Microsoft Corporation and Contributors
-// Licensed under the MIT license.
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
using GitHubExtension;
diff --git a/test/GitHubExtension/DataStore/DataManagerTests.cs b/test/GitHubExtension/DataStore/DataManagerTests.cs
index ebddafd8..fc9313f8 100644
--- a/test/GitHubExtension/DataStore/DataManagerTests.cs
+++ b/test/GitHubExtension/DataStore/DataManagerTests.cs
@@ -1,5 +1,5 @@
-// Copyright (c) Microsoft Corporation and Contributors
-// Licensed under the MIT license.
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
namespace GitHubExtension.Test;
diff --git a/test/GitHubExtension/DataStore/DataObjectTests.cs b/test/GitHubExtension/DataStore/DataObjectTests.cs
index 90504ce8..8af75741 100644
--- a/test/GitHubExtension/DataStore/DataObjectTests.cs
+++ b/test/GitHubExtension/DataStore/DataObjectTests.cs
@@ -1,5 +1,5 @@
-// Copyright (c) Microsoft Corporation and Contributors
-// Licensed under the MIT license.
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
using Dapper.Contrib.Extensions;
using DevHome.Logging;
@@ -446,9 +446,9 @@ public void ReadAndWriteCheckRun()
}
// Verify objects work.
- var pullrequest = DataModel.PullRequest.GetById(dataStore, 1);
- Assert.IsNotNull(pullrequest);
- var checksForPullRequest = pullrequest.Checks;
+ var pullRequest = DataModel.PullRequest.GetById(dataStore, 1);
+ Assert.IsNotNull(pullRequest);
+ var checksForPullRequest = pullRequest.Checks;
Assert.IsNotNull(checksForPullRequest);
Assert.AreEqual(2, checksForPullRequest.Count());
foreach (var check in checksForPullRequest)
@@ -457,12 +457,12 @@ public void ReadAndWriteCheckRun()
Assert.IsTrue(check.Completed);
}
- var failedChecks = pullrequest.FailedChecks;
+ var failedChecks = pullRequest.FailedChecks;
Assert.IsNotNull(failedChecks);
Assert.AreEqual(1, failedChecks.Count());
- Assert.AreEqual(CheckStatus.Completed, pullrequest.ChecksStatus);
- Assert.AreEqual(CheckConclusion.Failure, pullrequest.ChecksConclusion);
+ Assert.AreEqual(CheckStatus.Completed, pullRequest.ChecksStatus);
+ Assert.AreEqual(CheckConclusion.Failure, pullRequest.ChecksConclusion);
testListener.PrintEventCounts();
Assert.AreEqual(false, testListener.FoundErrors());
@@ -483,7 +483,7 @@ public void ReadAndWriteStatusAndNotification()
dataStore.Create();
Assert.IsNotNull(dataStore.Connection);
- // Add checkruns.
+ // Add CheckRuns.
var checks = new List
{
{ new CheckRun { HeadSha = "1234abcd", Name = "Build x86", InternalId = 16, ConclusionId = 1, StatusId = 3, DetailsUrl = "https://link/to/failed/build" } },
@@ -506,17 +506,16 @@ public void ReadAndWriteStatusAndNotification()
dataStore.Connection.Insert(new PullRequest { Title = "Fix the things", InternalId = 42, Number = 5, HeadSha = "1234abcd", AuthorId = 1, RepositoryId = 1 });
// Add PullRequestStatus
- var pullrequest = DataModel.PullRequest.GetById(dataStore, 1);
- Assert.IsNotNull(pullrequest);
- var prStatus = PullRequestStatus.Add(dataStore, pullrequest);
+ var pullRequest = DataModel.PullRequest.GetById(dataStore, 1);
+ Assert.IsNotNull(pullRequest);
+ var prStatus = PullRequestStatus.Add(dataStore, pullRequest);
TestContext?.WriteLine($" PR: {prStatus.PullRequest.Number} Status: {prStatus.Id}: {prStatus.Conclusion} - {prStatus.DetailsUrl}");
Assert.AreEqual("https://link/to/failed/build", prStatus.DetailsUrl);
Assert.AreEqual(1, prStatus.ConclusionId);
// Create notification from PR Status
- var notification = DataModel.Notification.Create(prStatus, NotificationType.CheckRunFailed);
- notification = DataModel.Notification.Add(dataStore, notification);
+ var notification = Notification.Create(dataStore, prStatus, NotificationType.CheckRunFailed);
Assert.IsNotNull(notification);
Assert.AreEqual("Fix the things", notification.Title);
Assert.AreEqual(1, notification.RepositoryId);
@@ -529,4 +528,70 @@ public void ReadAndWriteStatusAndNotification()
testListener.PrintEventCounts();
Assert.AreEqual(false, testListener.FoundErrors());
}
+
+ [TestMethod]
+ [TestCategory("Unit")]
+ public void ReadAndWriteReview()
+ {
+ using var log = new Logger("TestStore", TestOptions.LogOptions);
+ var testListener = new TestListener("TestListener", TestContext!);
+ log.AddListener(testListener);
+ Log.Attach(log);
+
+ using var dataStore = new DataStore("TestStore", TestHelpers.GetDataStoreFilePath(TestOptions), TestOptions.DataStoreOptions.DataStoreSchema!);
+ Assert.IsNotNull(dataStore);
+ dataStore.Create();
+ Assert.IsNotNull(dataStore.Connection);
+
+ using var tx = dataStore.Connection!.BeginTransaction();
+
+ var reviews = new List
+ {
+ { new Review { PullRequestId = 1, AuthorId = 2, Body = "Review 1", InternalId = 16, State = "Approved" } },
+ { new Review { PullRequestId = 1, AuthorId = 3, Body = "Review 2", InternalId = 47, State = "Rejected" } },
+ };
+
+ dataStore.Connection.Insert(reviews[0]);
+ dataStore.Connection.Insert(reviews[1]);
+
+ // Add User record
+ dataStore.Connection.Insert(new User { Login = "Kittens", InternalId = 6, AvatarUrl = "https://www.microsoft.com", Type = "Cat" });
+ dataStore.Connection.Insert(new User { Login = "Doggos", InternalId = 83, AvatarUrl = "https://www.microsoft.com", Type = "Dog" });
+ dataStore.Connection.Insert(new User { Login = "Lizards", InternalId = 3, AvatarUrl = "https://www.microsoft.com", Type = "Reptile" });
+
+ // Add repository record
+ dataStore.Connection.Insert(new Repository { OwnerId = 1, InternalId = 47, Name = "TestRepo1", Description = "Short Desc", HtmlUrl = "https://www.microsoft.com", DefaultBranch = "main", HasIssues = 1 });
+
+ // Add PullRequest record
+ dataStore.Connection.Insert(new PullRequest { Title = "Fix the things", InternalId = 42, HeadSha = "1234abcd", AuthorId = 1, RepositoryId = 1 });
+
+ tx.Commit();
+
+ // Verify retrieval and input into data objects.
+ var dataStoreReviews = dataStore.Connection.GetAll().ToList();
+ Assert.AreEqual(2, dataStoreReviews.Count);
+ foreach (var review in dataStoreReviews)
+ {
+ TestContext?.WriteLine($" Review: {review.Id}: {review.Body} - {review.State}");
+
+ Assert.IsTrue(review.Id == 1 || review.Id == 2);
+ Assert.AreEqual(review.Body, $"Review {review.Id}");
+ Assert.IsTrue(review.AuthorId == review.Id + 1);
+ }
+
+ // Verify objects work.
+ var pullRequest = PullRequest.GetById(dataStore, 1);
+ Assert.IsNotNull(pullRequest);
+ var reviewsForPullRequest = pullRequest.Reviews;
+ Assert.IsNotNull(reviewsForPullRequest);
+ Assert.AreEqual(2, reviewsForPullRequest.Count());
+ foreach (var review in reviewsForPullRequest)
+ {
+ TestContext?.WriteLine($" PR 1 - Review: {review}");
+ Assert.IsTrue(review.PullRequestId == 1);
+ }
+
+ testListener.PrintEventCounts();
+ Assert.AreEqual(false, testListener.FoundErrors());
+ }
}
diff --git a/test/GitHubExtension/DataStore/DataStoreTestsSetup.cs b/test/GitHubExtension/DataStore/DataStoreTestsSetup.cs
index 2f7c0554..45e5b77b 100644
--- a/test/GitHubExtension/DataStore/DataStoreTestsSetup.cs
+++ b/test/GitHubExtension/DataStore/DataStoreTestsSetup.cs
@@ -1,5 +1,5 @@
-// Copyright (c) Microsoft Corporation and Contributors
-// Licensed under the MIT license.
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
namespace GitHubExtension.Test;
diff --git a/test/GitHubExtension/DataStore/OctokitIngestionTests.cs b/test/GitHubExtension/DataStore/OctokitIngestionTests.cs
index 64c26379..f916d6da 100644
--- a/test/GitHubExtension/DataStore/OctokitIngestionTests.cs
+++ b/test/GitHubExtension/DataStore/OctokitIngestionTests.cs
@@ -1,5 +1,5 @@
-// Copyright (c) Microsoft Corporation and Contributors
-// Licensed under the MIT license.
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
using Dapper.Contrib.Extensions;
using GitHubExtension.Client;
@@ -528,4 +528,53 @@ public void AddCheckRunFromOctokit()
testListener.PrintEventCounts();
Assert.AreEqual(false, testListener.FoundErrors());
}
+
+ [TestMethod]
+ [TestCategory("LiveData")]
+ public void AddReviewFromOctokit()
+ {
+ using var log = new DevHome.Logging.Logger("TestStore", TestOptions.LogOptions);
+ var testListener = new TestListener("TestListener", TestContext!);
+ log.AddListener(testListener);
+ Log.Attach(log);
+
+ using var dataStore = new DataStore("TestStore", TestHelpers.GetDataStoreFilePath(TestOptions), TestOptions.DataStoreOptions.DataStoreSchema!);
+ Assert.IsNotNull(dataStore);
+ dataStore.Create();
+ Assert.IsNotNull(dataStore.Connection);
+
+ var client = GitHubClientProvider.Instance.GetClient();
+
+ using var tx = dataStore.Connection!.BeginTransaction();
+
+ var octoPull = client.PullRequest.Get("microsoft", "devhomegithubextension", 260).Result;
+ var dataStorePull = DataModel.PullRequest.GetOrCreateByOctokitPullRequest(dataStore, octoPull);
+
+ // Get reviews for pull
+ var octoReviews = client.PullRequest.Review.GetAll("microsoft", "devhomegithubextension", 260).Result;
+ Assert.IsNotNull(octoReviews);
+ TestContext?.WriteLine($"Found {octoReviews.Count}");
+ foreach (var review in octoReviews)
+ {
+ var dsReview = Review.GetOrCreateByOctokitReview(dataStore, review, dataStorePull.Id);
+ Assert.IsNotNull(dsReview);
+ }
+
+ tx.Commit();
+
+ // Verify retrieval and input into data objects and we get the same results.
+ var dataStoreReviews = dataStore.Connection.GetAll().ToList();
+ Assert.IsNotNull(dataStoreReviews);
+ var reviewsFromPull = dataStorePull.Reviews;
+ Assert.IsNotNull(reviewsFromPull);
+ Assert.AreEqual(dataStoreReviews.Count, reviewsFromPull.Count());
+
+ foreach (var review in reviewsFromPull)
+ {
+ TestContext?.WriteLine($" Id: {review.Id} PullId: {review.PullRequestId} InternalId: {review.InternalId} AuthorId: {review.AuthorId} Author:{review.Author.Login} State: {review.State} Submitted: {review.SubmittedAt}");
+ }
+
+ testListener.PrintEventCounts();
+ Assert.AreEqual(false, testListener.FoundErrors());
+ }
}
diff --git a/test/GitHubExtension/DeveloperId/CredentialVaultTests.cs b/test/GitHubExtension/DeveloperId/CredentialVaultTests.cs
new file mode 100644
index 00000000..125ea76e
--- /dev/null
+++ b/test/GitHubExtension/DeveloperId/CredentialVaultTests.cs
@@ -0,0 +1,106 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+using System.Net;
+using GitHubExtension.DeveloperId;
+
+namespace GitHubExtension.Test;
+
+// Unit Tests for CredentialVault
+public partial class DeveloperIdTests
+{
+ [TestMethod]
+ [TestCategory("Unit")]
+ public void CredentialVault_CreateSingleton()
+ {
+ var credentialVault1 = new CredentialVault("DevHomeGitHubExtensionTest");
+ Assert.IsNotNull(credentialVault1);
+
+ var credentialVault2 = new CredentialVault("DevHomeGitHubExtensionTest");
+ Assert.IsNotNull(credentialVault2);
+
+ Assert.AreNotEqual(credentialVault1, credentialVault2);
+
+ credentialVault1.RemoveAllCredentials();
+ Assert.AreEqual(0, credentialVault1.GetAllCredentials().Count());
+ }
+
+ [TestMethod]
+ [TestCategory("LiveData")]
+ [DataRow("testuser1")]
+ [DataRow("https://github.com/testuser2")]
+ [DataRow("https://RandomWebServer.example/testuser3")]
+ public void CredentialVault_SaveAndRetrieveCredential(string loginId)
+ {
+ var credentialVault = new CredentialVault("DevHomeGitHubExtensionTest");
+ Assert.IsNotNull(credentialVault);
+ Assert.AreEqual(0, credentialVault.GetAllCredentials().Count());
+
+ var nullCredential = credentialVault.GetCredentials(loginId);
+ Assert.IsNull(nullCredential);
+
+ var testCredential = "testcredential";
+
+ var credential = new NetworkCredential(null, testCredential).SecurePassword;
+ credentialVault.SaveCredentials(loginId, credential);
+
+ var retrievedCredential = credentialVault.GetCredentials(loginId);
+ Assert.IsNotNull(retrievedCredential);
+ Assert.AreEqual(testCredential, retrievedCredential.Password);
+
+ credentialVault.RemoveAllCredentials();
+ Assert.AreEqual(0, credentialVault.GetAllCredentials().Count());
+ }
+
+ [TestMethod]
+ [TestCategory("LiveData")]
+ [DataRow("testuser1")]
+ [DataRow("https://github.com/testuser2")]
+ [DataRow("https://RandomWebServer.example/testuser3")]
+ public void CredentialVault_RemoveAndRetrieveCredential(string loginId)
+ {
+ var credentialVault = new CredentialVault("DevHomeGitHubExtensionTest");
+ Assert.IsNotNull(credentialVault);
+
+ var testCredential = "testCredential";
+
+ var credential = new NetworkCredential(null, testCredential).SecurePassword;
+ credentialVault.SaveCredentials(loginId, credential);
+
+ var retrievedCredential = credentialVault.GetCredentials(loginId);
+ Assert.IsNotNull(retrievedCredential);
+ Assert.AreEqual(testCredential, retrievedCredential.Password);
+
+ credentialVault.RemoveCredentials(loginId);
+
+ var nullCredential = credentialVault.GetCredentials(loginId);
+ Assert.IsNull(nullCredential);
+
+ Assert.AreEqual(0, credentialVault.GetAllCredentials().Count());
+ }
+
+ [TestMethod]
+ [TestCategory("LiveData")]
+ public void CredentialVault_GetAllCredentials()
+ {
+ var credentialVault = new CredentialVault("DevHomeGitHubExtensionTest");
+ Assert.IsNotNull(credentialVault);
+
+ Assert.AreEqual(0, credentialVault.GetAllCredentials().Count());
+
+ var testLoginId = "testuser1";
+ var testCredential = "testCredential";
+
+ var credential = new NetworkCredential(null, testCredential).SecurePassword;
+ credentialVault.SaveCredentials(testLoginId, credential);
+
+ Assert.AreEqual(1, credentialVault.GetAllCredentials().Count());
+
+ credentialVault.RemoveCredentials(testLoginId);
+
+ Assert.AreEqual(0, credentialVault.GetAllCredentials().Count());
+
+ var nullCredential = credentialVault.GetCredentials(testLoginId);
+ Assert.IsNull(nullCredential);
+ }
+}
diff --git a/test/GitHubExtension/DeveloperId/DeveloperIdProviderTests.cs b/test/GitHubExtension/DeveloperId/DeveloperIdProviderTests.cs
index b419d8d5..9a9889b9 100644
--- a/test/GitHubExtension/DeveloperId/DeveloperIdProviderTests.cs
+++ b/test/GitHubExtension/DeveloperId/DeveloperIdProviderTests.cs
@@ -1,11 +1,12 @@
-// Copyright (c) Microsoft Corporation and Contributors
-// Licensed under the MIT license.
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
using System.Net;
using GitHubExtension.DeveloperId;
using Microsoft.Windows.DevHome.SDK;
namespace GitHubExtension.Test;
+
public partial class DeveloperIdTests
{
private CredentialVault SetupCleanCredentialVaultClean()
@@ -56,6 +57,32 @@ private CredentialVault SetupCredentialVaultWithGHESTestUser()
return credentialVault;
}
+ /* Tests depend on the following environment variables:
+ * DEV_HOME_TEST_GITHUB_COM_USER : Url for a test user on github.com
+ * DEV_HOME_TEST_GITHUB_COM_PAT : Personal Access Token for the test user on github.com
+ * DEV_HOME_TEST_GITHUB_ENTERPRISE_SERVER_USER : Url for a test user on GHES
+ * DEV_HOME_TEST_GITHUB_ENTERPRISE_SERVER_PAT : Personal Access Token for the test user on the GHES
+ */
+ private CredentialVault SetupCredentialVaultWithMultipleTestUsers()
+ {
+ var credentialVault = SetupCleanCredentialVaultClean();
+
+ var testLoginId = Environment.GetEnvironmentVariable("DEV_HOME_TEST_GITHUB_COM_USER") ?? string.Empty;
+ var testPassword = Environment.GetEnvironmentVariable("DEV_HOME_TEST_GITHUB_COM_PAT");
+
+ var testGHESLoginId = Environment.GetEnvironmentVariable("DEV_HOME_TEST_GITHUB_ENTERPRISE_SERVER_USER") ?? string.Empty;
+ var testGHESPassword = Environment.GetEnvironmentVariable("DEV_HOME_TEST_GITHUB_ENTERPRISE_SERVER_PAT");
+
+ var password = new NetworkCredential(null, testPassword).SecurePassword;
+ credentialVault.SaveCredentials(testLoginId, password);
+
+ var ghesPassword = new NetworkCredential(null, testGHESPassword).SecurePassword;
+ credentialVault.SaveCredentials(testGHESLoginId, ghesPassword);
+
+ Assert.AreEqual(2, credentialVault.GetAllCredentials().Count());
+ return credentialVault;
+ }
+
private CredentialVault SetupCredentialVaultWithInvalidTestUser()
{
var credentialVault = SetupCleanCredentialVaultClean();
@@ -129,6 +156,31 @@ public void DeveloperIdProvider_RestoreAndGetDeveloperIds()
Assert.AreEqual(0, credentialVault.GetAllCredentials().Count());
}
+ [TestMethod]
+ [TestCategory("LiveData")]
+ public void DeveloperIdProvider_RestoreAndGetMultipleDeveloperIds()
+ {
+ // Setup CredentialVault with a dummy testuser and valid PAT for Github.com
+ var credentialVault = SetupCredentialVaultWithMultipleTestUsers();
+
+ // Test whether the DeveloperIdProvider can restore the saved credentials
+ var devIdProvider = DeveloperIdProvider.GetInstance();
+ Assert.IsNotNull(devIdProvider);
+ var result = devIdProvider.GetLoggedInDeveloperIds();
+
+ Assert.IsNotNull(result);
+ Assert.AreEqual(ProviderOperationStatus.Success, result.Result.Status);
+ Assert.AreEqual(2, result.DeveloperIds.Count());
+ Assert.AreNotEqual("dummytestuser1", result.DeveloperIds.First().LoginId);
+ Assert.AreNotEqual("dummytestuser1", result.DeveloperIds.Last().LoginId);
+ Assert.IsNotNull(new Uri(result.DeveloperIds.First().Url));
+ Assert.IsNotNull(new Uri(result.DeveloperIds.Last().Url));
+
+ // Cleanup
+ credentialVault.RemoveAllCredentials();
+ Assert.AreEqual(0, credentialVault.GetAllCredentials().Count());
+ }
+
[TestMethod]
[TestCategory("LiveData")]
public void DeveloperIdProvider_GetDeveloperIds_InvalidPAT()
diff --git a/test/GitHubExtension/DeveloperId/DeveloperIdTestsSetup.cs b/test/GitHubExtension/DeveloperId/DeveloperIdTestsSetup.cs
index 6a6c000a..950d82e6 100644
--- a/test/GitHubExtension/DeveloperId/DeveloperIdTestsSetup.cs
+++ b/test/GitHubExtension/DeveloperId/DeveloperIdTestsSetup.cs
@@ -1,5 +1,5 @@
-// Copyright (c) Microsoft Corporation and Contributors
-// Licensed under the MIT license.
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
using GitHubExtension.DeveloperId;
diff --git a/test/GitHubExtension/DeveloperId/FunctionalTests.cs b/test/GitHubExtension/DeveloperId/FunctionalTests.cs
index 5f6fa780..5c9dba5a 100644
--- a/test/GitHubExtension/DeveloperId/FunctionalTests.cs
+++ b/test/GitHubExtension/DeveloperId/FunctionalTests.cs
@@ -1,10 +1,11 @@
-// Copyright (c) Microsoft Corporation and Contributors
-// Licensed under the MIT license.
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
using GitHubExtension.DeveloperId;
using Microsoft.Windows.DevHome.SDK;
namespace GitHubExtension.Test;
+
public partial class DeveloperIdTests
{
[TestMethod]
diff --git a/test/GitHubExtension/DeveloperId/LoginUITests.cs b/test/GitHubExtension/DeveloperId/LoginUITests.cs
index 8ff7e854..618270b6 100644
--- a/test/GitHubExtension/DeveloperId/LoginUITests.cs
+++ b/test/GitHubExtension/DeveloperId/LoginUITests.cs
@@ -1,5 +1,5 @@
-// Copyright (c) Microsoft Corporation and Contributors
-// Licensed under the MIT license.
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
using GitHubExtension.DeveloperId;
using GitHubExtension.Test.Mocks;
diff --git a/test/GitHubExtension/GitHubExtension.Test.csproj b/test/GitHubExtension/GitHubExtension.Test.csproj
index aa425c2d..25c16d18 100644
--- a/test/GitHubExtension/GitHubExtension.Test.csproj
+++ b/test/GitHubExtension/GitHubExtension.Test.csproj
@@ -10,30 +10,18 @@
true
resources.pri
+
all
runtime; build; native; contentfiles; analyzers; buildtransitive
-
-
-
-
-
-
-
-
+
-
-
- all
- runtime; build; native; contentfiles; analyzers; buildtransitive
-
-
diff --git a/test/GitHubExtension/GitHubProviderTests.cs b/test/GitHubExtension/GitHubProviderTests.cs
index 68f50063..e7666748 100644
--- a/test/GitHubExtension/GitHubProviderTests.cs
+++ b/test/GitHubExtension/GitHubProviderTests.cs
@@ -1,9 +1,10 @@
-// Copyright (c) Microsoft Corporation and Contributors
-// Licensed under the MIT license.
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
using Microsoft.Windows.DevHome.SDK;
namespace GitHubExtension.Test;
+
[TestClass]
public partial class GitHubProviderTests
{
@@ -112,7 +113,7 @@ public void CanClone()
[TestMethod]
[TestCategory("Unit")]
- [Ignore("Ignoring right now until mock repo is implemeneted")]
+ [Ignore("Ignoring right now until mock repo is implemented")]
public void CloneViaMakingRepoObject()
{
/*
diff --git a/test/GitHubExtension/Helpers/FileHelpers.cs b/test/GitHubExtension/Helpers/FileHelpers.cs
index f2e9eeb6..db7561d2 100644
--- a/test/GitHubExtension/Helpers/FileHelpers.cs
+++ b/test/GitHubExtension/Helpers/FileHelpers.cs
@@ -1,19 +1,19 @@
-// Copyright (c) Microsoft Corporation and Contributors
-// Licensed under the MIT license.
-
-namespace GitHubExtension.Test;
-
-public partial class TestHelpers
-{
- public static string CreateUniqueFolderName(string prefix)
- {
- // This could potentially be too long of a path name,
- // but should be OK for now. Keep the prefix short.
- return $"{prefix}-{Guid.NewGuid()}";
- }
-
- public static string GetUniqueFolderPath(string prefix)
- {
- return Path.Combine(Path.GetTempPath(), CreateUniqueFolderName(prefix));
- }
-}
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+namespace GitHubExtension.Test;
+
+public partial class TestHelpers
+{
+ public static string CreateUniqueFolderName(string prefix)
+ {
+ // This could potentially be too long of a path name,
+ // but should be OK for now. Keep the prefix short.
+ return $"{prefix}-{Guid.NewGuid()}";
+ }
+
+ public static string GetUniqueFolderPath(string prefix)
+ {
+ return Path.Combine(Path.GetTempPath(), CreateUniqueFolderName(prefix));
+ }
+}
diff --git a/test/GitHubExtension/Helpers/TestOptions.cs b/test/GitHubExtension/Helpers/TestOptions.cs
index 9896b48f..a2b88652 100644
--- a/test/GitHubExtension/Helpers/TestOptions.cs
+++ b/test/GitHubExtension/Helpers/TestOptions.cs
@@ -1,10 +1,11 @@
-// Copyright (c) Microsoft Corporation and Contributors
-// Licensed under the MIT license.
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
using DevHome.Logging;
using GitHubExtension.DataModel;
namespace GitHubExtension.Test;
+
public partial class TestOptions
{
public Options LogOptions { get; set; }
diff --git a/test/GitHubExtension/Helpers/TestSetupHelpers.cs b/test/GitHubExtension/Helpers/TestSetupHelpers.cs
index 4a7c9c6a..c7a4a916 100644
--- a/test/GitHubExtension/Helpers/TestSetupHelpers.cs
+++ b/test/GitHubExtension/Helpers/TestSetupHelpers.cs
@@ -1,74 +1,74 @@
-// Copyright (c) Microsoft Corporation and Contributors
-// Licensed under the MIT license.
-
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
using DevHome.Logging;
using DevHome.Logging.Helpers;
using GitHubExtension.DataModel;
-namespace GitHubExtension.Test;
-
-public partial class TestHelpers
-{
- private const string DataBaseFileName = "GitHubExtension-Test.db";
- private const string LogFileName = "GitHubExtension-{now}.log";
-
- public static void CleanupTempTestOptions(TestOptions options, TestContext context)
- {
- // We put DataStore and Log into the same path.
- var path = options.DataStoreOptions.DataStoreFolderPath;
-
- // Directory delete will fail if a file has the name of the directory, so to be
- // thorough, check for file delete first.
- if (File.Exists(path))
- {
- context?.WriteLine($"Cleanup: Deleting file {path}");
- File.Delete(path);
- }
-
- if (Directory.Exists(path))
- {
- context?.WriteLine($"Cleanup: Deleting folder {path}");
- Directory.Delete(path, true);
- }
-
- // Intentionally not catching IO errors on cleanup, as that indicates a test problem.
- }
-
- public static TestOptions SetupTempTestOptions(TestContext context)
- {
- // Since all test created locations are ultimately captured in the Options, we will use
- // the Options as truth for storing the test location data to keep all of the
- // test locations in one data object to simplify test variables we are tracking and
- // to be consistent in test setup/cleanup.
- var path = GetUniqueFolderPath("GHPT");
+namespace GitHubExtension.Test;
+
+public partial class TestHelpers
+{
+ private const string DataBaseFileName = "GitHubExtension-Test.db";
+ private const string LogFileName = "GitHubExtension-{now}.log";
+
+ public static void CleanupTempTestOptions(TestOptions options, TestContext context)
+ {
+ // We put DataStore and Log into the same path.
+ var path = options.DataStoreOptions.DataStoreFolderPath;
+
+ // Directory delete will fail if a file has the name of the directory, so to be
+ // thorough, check for file delete first.
+ if (File.Exists(path))
+ {
+ context?.WriteLine($"Cleanup: Deleting file {path}");
+ File.Delete(path);
+ }
+
+ if (Directory.Exists(path))
+ {
+ context?.WriteLine($"Cleanup: Deleting folder {path}");
+ Directory.Delete(path, true);
+ }
+
+ // Intentionally not catching IO errors on cleanup, as that indicates a test problem.
+ }
+
+ public static TestOptions SetupTempTestOptions(TestContext context)
+ {
+ // Since all test created locations are ultimately captured in the Options, we will use
+ // the Options as truth for storing the test location data to keep all of the
+ // test locations in one data object to simplify test variables we are tracking and
+ // to be consistent in test setup/cleanup.
+ var path = GetUniqueFolderPath("GHPT");
var options = new TestOptions();
options.LogOptions.FailFastSeverity = FailFastSeverityLevel.Ignore;
options.LogOptions.LogFileFilter = SeverityLevel.Debug;
options.LogOptions.LogFileFolderRoot = path;
options.LogOptions.LogFileName = LogFileName;
- options.DataStoreOptions.DataStoreFileName = DataBaseFileName;
+ options.DataStoreOptions.DataStoreFileName = DataBaseFileName;
options.DataStoreOptions.DataStoreFolderPath = path;
- options.DataStoreOptions.DataStoreSchema = new GitHubDataStoreSchema();
-
- context?.WriteLine($"Temp folder for test run is: {GetTempTestFolderPath(options)}");
- context?.WriteLine($"Temp DataStore file path for test run is: {GetDataStoreFilePath(options)}");
- context?.WriteLine($"Temp Log file path for test run is: {GetLogFilePath(options)}");
- return options;
- }
-
- public static string GetTempTestFolderPath(TestOptions options)
- {
- // For simplicity putting log and datastore in same root folder.
- return options.DataStoreOptions.DataStoreFolderPath;
- }
-
- public static string GetDataStoreFilePath(TestOptions options)
- {
- return Path.Combine(options.DataStoreOptions.DataStoreFolderPath, options.DataStoreOptions.DataStoreFileName);
- }
-
- public static string GetLogFilePath(TestOptions options)
+ options.DataStoreOptions.DataStoreSchema = new GitHubDataStoreSchema();
+
+ context?.WriteLine($"Temp folder for test run is: {GetTempTestFolderPath(options)}");
+ context?.WriteLine($"Temp DataStore file path for test run is: {GetDataStoreFilePath(options)}");
+ context?.WriteLine($"Temp Log file path for test run is: {GetLogFilePath(options)}");
+ return options;
+ }
+
+ public static string GetTempTestFolderPath(TestOptions options)
+ {
+ // For simplicity putting log and datastore in same root folder.
+ return options.DataStoreOptions.DataStoreFolderPath;
+ }
+
+ public static string GetDataStoreFilePath(TestOptions options)
+ {
+ return Path.Combine(options.DataStoreOptions.DataStoreFolderPath, options.DataStoreOptions.DataStoreFileName);
+ }
+
+ public static string GetLogFilePath(TestOptions options)
{
- return FileSystem.SubstituteOutputFilename(options.LogOptions.LogFileName, options.LogOptions.LogFileFolderPath);
- }
-}
+ return FileSystem.SubstituteOutputFilename(options.LogOptions.LogFileName, options.LogOptions.LogFileFolderPath);
+ }
+}
diff --git a/test/GitHubExtension/Initialize.cs b/test/GitHubExtension/Initialize.cs
index 46e5962c..d6939da7 100644
--- a/test/GitHubExtension/Initialize.cs
+++ b/test/GitHubExtension/Initialize.cs
@@ -1,5 +1,5 @@
-// Copyright (c) Microsoft Corporation and Contributors
-// Licensed under the MIT license.
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
using Microsoft.Windows.ApplicationModel.DynamicDependency;
diff --git a/test/GitHubExtension/Mocks/DeveloperIdProvider.cs b/test/GitHubExtension/Mocks/DeveloperIdProvider.cs
index cdca1a29..4800dfef 100644
--- a/test/GitHubExtension/Mocks/DeveloperIdProvider.cs
+++ b/test/GitHubExtension/Mocks/DeveloperIdProvider.cs
@@ -1,5 +1,5 @@
-// Copyright (c) Microsoft Corporation and Contributors
-// Licensed under the MIT license.
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
using System.Security;
using GitHubExtension.DeveloperId;
diff --git a/test/GitHubExtension/Mocks/Repository.cs b/test/GitHubExtension/Mocks/Repository.cs
index f3899836..0db54163 100644
--- a/test/GitHubExtension/Mocks/Repository.cs
+++ b/test/GitHubExtension/Mocks/Repository.cs
@@ -1,10 +1,11 @@
-// Copyright (c) Microsoft Corporation and Contributors
-// Licensed under the MIT license.
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
using Microsoft.Windows.DevHome.SDK;
using Windows.Foundation;
namespace GitHubExtension.Test.Mocks;
+
public class MockRepository : IRepository
{
public string DisplayName => "Mock Repository";
diff --git a/test/GitHubExtension/TestClass.cs b/test/GitHubExtension/TestClass.cs
index d395478f..1bb75d52 100644
--- a/test/GitHubExtension/TestClass.cs
+++ b/test/GitHubExtension/TestClass.cs
@@ -1,5 +1,5 @@
-// Copyright (c) Microsoft Corporation and Contributors
-// Licensed under the MIT license.
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
using System.Diagnostics;
using GitHubExtension.DeveloperId;
diff --git a/test/GitHubExtension/TestListener.cs b/test/GitHubExtension/TestListener.cs
index a21b5a90..c08f48ec 100644
--- a/test/GitHubExtension/TestListener.cs
+++ b/test/GitHubExtension/TestListener.cs
@@ -1,85 +1,85 @@
-// Copyright (c) Microsoft Corporation and Contributors
-// Licensed under the MIT license.
-
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
using System.Globalization;
using DevHome.Logging;
-using DevHome.Logging.Listeners;
-
-namespace GitHubExtension.Test;
-
-public class TestListener : ListenerBase
-{
- private TestContext? TestContext
- {
- get;
- set;
- }
-
- public Dictionary EventCounts { get; } = new Dictionary();
-
- public TestListener(string name, TestContext testContext)
- : base(name)
- {
- TestContext = testContext;
- EventCounts.Add(SeverityLevel.Critical, 0);
- EventCounts.Add(SeverityLevel.Error, 0);
- EventCounts.Add(SeverityLevel.Warn, 0);
- EventCounts.Add(SeverityLevel.Info, 0);
- EventCounts.Add(SeverityLevel.Debug, 0);
- }
-
- public void Reset()
- {
- foreach (var kvp in EventCounts)
- {
- EventCounts[kvp.Key] = 0;
- }
- }
-
- public bool FoundErrors()
- {
- return EventCounts[SeverityLevel.Critical] > 0 || EventCounts[SeverityLevel.Error] > 0;
- }
-
- public override void HandleLogEvent(LogEvent evt)
- {
- switch (evt.Severity)
- {
- case SeverityLevel.Critical:
- ++EventCounts[SeverityLevel.Critical];
- PrintEvent(evt);
- break;
- case SeverityLevel.Error:
- ++EventCounts[SeverityLevel.Error];
- PrintEvent(evt);
- break;
- case SeverityLevel.Warn:
- ++EventCounts[SeverityLevel.Warn];
- PrintEvent(evt);
- break;
- case SeverityLevel.Info:
- ++EventCounts[SeverityLevel.Info];
- PrintEvent(evt);
- break;
- case SeverityLevel.Debug:
- ++EventCounts[SeverityLevel.Debug];
-
- PrintEvent(evt);
- break;
- }
- }
-
- private void PrintEvent(LogEvent evt)
- {
- TestContext?.WriteLine($"[{evt.Source}] {evt.Severity.ToString().ToUpper(CultureInfo.InvariantCulture)}: {evt.Message}");
- if (evt.Exception != null)
- {
- TestContext?.WriteLine(evt.Exception.ToString());
- }
- }
-
- public void PrintEventCounts()
- {
- TestContext?.WriteLine($"Critical: {EventCounts[SeverityLevel.Critical]} Error: {EventCounts[SeverityLevel.Error]} Warning: {EventCounts[SeverityLevel.Warn]}");
- }
-}
+using DevHome.Logging.Listeners;
+
+namespace GitHubExtension.Test;
+
+public class TestListener : ListenerBase
+{
+ private TestContext? TestContext
+ {
+ get;
+ set;
+ }
+
+ public Dictionary EventCounts { get; } = new Dictionary();
+
+ public TestListener(string name, TestContext testContext)
+ : base(name)
+ {
+ TestContext = testContext;
+ EventCounts.Add(SeverityLevel.Critical, 0);
+ EventCounts.Add(SeverityLevel.Error, 0);
+ EventCounts.Add(SeverityLevel.Warn, 0);
+ EventCounts.Add(SeverityLevel.Info, 0);
+ EventCounts.Add(SeverityLevel.Debug, 0);
+ }
+
+ public void Reset()
+ {
+ foreach (var kvp in EventCounts)
+ {
+ EventCounts[kvp.Key] = 0;
+ }
+ }
+
+ public bool FoundErrors()
+ {
+ return EventCounts[SeverityLevel.Critical] > 0 || EventCounts[SeverityLevel.Error] > 0;
+ }
+
+ public override void HandleLogEvent(LogEvent evt)
+ {
+ switch (evt.Severity)
+ {
+ case SeverityLevel.Critical:
+ ++EventCounts[SeverityLevel.Critical];
+ PrintEvent(evt);
+ break;
+ case SeverityLevel.Error:
+ ++EventCounts[SeverityLevel.Error];
+ PrintEvent(evt);
+ break;
+ case SeverityLevel.Warn:
+ ++EventCounts[SeverityLevel.Warn];
+ PrintEvent(evt);
+ break;
+ case SeverityLevel.Info:
+ ++EventCounts[SeverityLevel.Info];
+ PrintEvent(evt);
+ break;
+ case SeverityLevel.Debug:
+ ++EventCounts[SeverityLevel.Debug];
+
+ PrintEvent(evt);
+ break;
+ }
+ }
+
+ private void PrintEvent(LogEvent evt)
+ {
+ TestContext?.WriteLine($"[{evt.Source}] {evt.Severity.ToString().ToUpper(CultureInfo.InvariantCulture)}: {evt.Message}");
+ if (evt.Exception != null)
+ {
+ TestContext?.WriteLine(evt.Exception.ToString());
+ }
+ }
+
+ public void PrintEventCounts()
+ {
+ TestContext?.WriteLine($"Critical: {EventCounts[SeverityLevel.Critical]} Error: {EventCounts[SeverityLevel.Error]} Warning: {EventCounts[SeverityLevel.Warn]}");
+ }
+}
diff --git a/test/GitHubExtension/Usings.cs b/test/GitHubExtension/Usings.cs
index 77a0d4c5..b5ac66bd 100644
--- a/test/GitHubExtension/Usings.cs
+++ b/test/GitHubExtension/Usings.cs
@@ -1,5 +1,5 @@
-// Copyright (c) Microsoft Corporation and Contributors
-// Licensed under the MIT license.
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
global using Microsoft.VisualStudio.TestTools.UnitTesting;
global using Microsoft.VisualStudio.TestTools.UnitTesting.AppContainer;
diff --git a/test/GitHubExtension/Widgets/Icons.cs b/test/GitHubExtension/Widgets/Icons.cs
index bf69ce7a..bc745f1f 100644
--- a/test/GitHubExtension/Widgets/Icons.cs
+++ b/test/GitHubExtension/Widgets/Icons.cs
@@ -1,8 +1,10 @@
-// Copyright (c) Microsoft Corporation and Contributors
-// Licensed under the MIT license.
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
using DevHome.Logging;
namespace GitHubExtension.Test;
+
public partial class WidgetTests
{
[TestMethod]
diff --git a/test/GitHubExtension/Widgets/Validation.cs b/test/GitHubExtension/Widgets/Validation.cs
index cc0c1523..4f8cc0d9 100644
--- a/test/GitHubExtension/Widgets/Validation.cs
+++ b/test/GitHubExtension/Widgets/Validation.cs
@@ -1,8 +1,10 @@
-// Copyright (c) Microsoft Corporation and Contributors
-// Licensed under the MIT license.
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
using DevHome.Logging;
namespace GitHubExtension.Test;
+
public partial class WidgetTests
{
[TestMethod]
diff --git a/test/GitHubExtension/Widgets/WidgetTestsSetup.cs b/test/GitHubExtension/Widgets/WidgetTestsSetup.cs
index a5153810..a6eb4c83 100644
--- a/test/GitHubExtension/Widgets/WidgetTestsSetup.cs
+++ b/test/GitHubExtension/Widgets/WidgetTestsSetup.cs
@@ -1,5 +1,5 @@
-// Copyright (c) Microsoft Corporation and Contributors
-// Licensed under the MIT license.
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
namespace GitHubExtension.Test;
diff --git a/test/UITest/GitHubExtension.UITest.csproj b/test/UITest/GitHubExtension.UITest.csproj
index 284309e9..62cfac20 100644
--- a/test/UITest/GitHubExtension.UITest.csproj
+++ b/test/UITest/GitHubExtension.UITest.csproj
@@ -10,24 +10,19 @@
true
resources.pri
+
all
runtime; build; native; contentfiles; analyzers; buildtransitive
-
+
-
-
- all
- runtime; build; native; contentfiles; analyzers; buildtransitive
-
-
\ No newline at end of file
diff --git a/test/UITest/GitHubExtensionScenarioStandard.cs b/test/UITest/GitHubExtensionScenarioStandard.cs
index e45e70f9..3f26704e 100644
--- a/test/UITest/GitHubExtensionScenarioStandard.cs
+++ b/test/UITest/GitHubExtensionScenarioStandard.cs
@@ -1,5 +1,5 @@
-// Copyright (c) Microsoft Corporation and Contributors
-// Licensed under the MIT license.
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
using Microsoft.VisualStudio.TestTools.UnitTesting;
diff --git a/test/UITest/GitHubExtensionSession.cs b/test/UITest/GitHubExtensionSession.cs
index 6205732f..c3f83347 100644
--- a/test/UITest/GitHubExtensionSession.cs
+++ b/test/UITest/GitHubExtensionSession.cs
@@ -1,5 +1,5 @@
-// Copyright (c) Microsoft Corporation and Contributors
-// Licensed under the MIT license.
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
using Microsoft.VisualStudio.TestTools.UnitTesting;
using OpenQA.Selenium.Appium;