diff --git a/.editorconfig b/.editorconfig
index fb98354..351c4f2 100644
--- a/.editorconfig
+++ b/.editorconfig
@@ -7,9 +7,12 @@ root = true
[*]
charset = utf-8
indent_style = space
-indent_size = 2
+indent_size = 4
insert_final_newline = true
trim_trailing_whitespace = true
+dotnet_style_operator_placement_when_wrapping = beginning_of_line
+tab_width = 4
+end_of_line = crlf
[*.{cs,js,ts,sql,tql}]
@@ -21,15 +24,42 @@ csharp_space_between_method_call_parameter_list_parentheses = true
csharp_space_between_method_declaration_parameter_list_parentheses = true
csharp_space_after_keywords_in_control_flow_statements = false
csharp_space_between_parentheses = control_flow_statements
-# Motive: May be weird at first, but it improve readability.
+csharp_space_around_binary_operators = before_and_after
+# Motive: May be weird at first, but it improves readability.
csharp_style_prefer_primary_constructors = false:suggestion
# Primary constructors should be used only for very simple classes. May be record is a good choice.
+csharp_indent_labels = no_change
+# When using goto, labels should be explicitly positioned based on the algorithm.
+
+csharp_using_directive_placement = outside_namespace:silent
+# Rather standard placement of using in C#.
+
+csharp_indent_case_contents_when_block = false;
+# switch case block don't need another indent.
+
+csharp_prefer_braces = true:silent
+
+csharp_style_prefer_method_group_conversion = true:silent
+csharp_style_expression_bodied_methods = false:silent
+csharp_style_expression_bodied_constructors = false:silent
+csharp_style_expression_bodied_operators = false:silent
+csharp_style_expression_bodied_properties = true:silent
+csharp_style_expression_bodied_indexers = true:silent
+csharp_style_expression_bodied_accessors = true:silent
+csharp_style_expression_bodied_lambdas = true:silent
+
+csharp_style_prefer_top_level_statements = true:suggestion
+# Applies to Main().
+
+csharp_style_namespace_declarations=file_scoped:suggestion
+#Motive: Less useless space.
+
# internal and private fields should be _camelCase
dotnet_naming_rule.camel_case_for_private_internal_fields.severity = suggestion
dotnet_naming_rule.camel_case_for_private_internal_fields.symbols = private_internal_fields
-dotnet_naming_rule.camel_case_for_private_internal_fields.style = camel_case_underscore_style
+dotnet_naming_rule.camel_case_for_private_internal_fields.style = camel_case_underscore_style
dotnet_naming_symbols.private_internal_fields.applicable_kinds = field
dotnet_naming_symbols.private_internal_fields.applicable_accessibilities = private, internal
@@ -51,17 +81,20 @@ dotnet_diagnostic.CA1816.severity = none
csharp_prefer_simple_using_statement = false:none
# Motive: Most of the time, the 'not simple' using scope is better.
-# CA1031: Do not catch general exception types.
-dotnet_diagnostic.CA1031.severity = none
-
# IDE0057: Use range operator.
csharp_style_prefer_range_operator = false:suggestion
# Motive: Use it if you want but this is should not show a message.
+csharp_style_namespace_declarations = file_scoped:warning
+# Motive: Less whitespace for editable files (this doesn't apply to generated code).
+
# IDE0060: Remove unused parameter
dotnet_code_quality_unused_parameters = all:silent
# Motive: Emit messages where the parameter are necessary.
+# CA1031: Do not catch general exception types.
+dotnet_diagnostic.CA1031.severity = none
+
# IDE0040: Add accessibility modifiers
dotnet_style_require_accessibility_modifiers = omit_if_default:silent
# Motive: 'private' is one more word that can be omitted.
@@ -112,6 +145,5 @@ dotnet_diagnostic.VSTHRD101.severity = error
# VSTHRD003: Avoid awaiting foreign Tasks
dotnet_diagnostic.VSTHRD003.severity = none
-
# /Signature-Code .editorconfig
diff --git a/CK.DB.User.UserGitLab.AuthScope/CK.DB.User.UserGitLab.AuthScope.csproj b/CK.DB.User.UserGitLab.AuthScope/CK.DB.User.UserGitLab.AuthScope.csproj
index 59d7152..d933174 100644
--- a/CK.DB.User.UserGitLab.AuthScope/CK.DB.User.UserGitLab.AuthScope.csproj
+++ b/CK.DB.User.UserGitLab.AuthScope/CK.DB.User.UserGitLab.AuthScope.csproj
@@ -1,17 +1,13 @@
- net6.0
+ net8.0
This package adds a ScopeSetId column to CK.tUserGitLab table.
- true
-
+
-
-
-
-
+
\ No newline at end of file
diff --git a/CK.DB.User.UserGitLab.AuthScope/IUserGitLabInfo.cs b/CK.DB.User.UserGitLab.AuthScope/IUserGitLabInfo.cs
index 21698e9..f8def95 100644
--- a/CK.DB.User.UserGitLab.AuthScope/IUserGitLabInfo.cs
+++ b/CK.DB.User.UserGitLab.AuthScope/IUserGitLabInfo.cs
@@ -1,19 +1,18 @@
using CK.Core;
using System;
-namespace CK.DB.User.UserGitLab.AuthScope
+namespace CK.DB.User.UserGitLab.AuthScope;
+
+///
+/// Extends with ScopeSet identifier.
+///
+public interface IUserGitLabInfo : UserGitLab.IUserGitLabInfo
{
///
- /// Extends with ScopeSet identifier.
+ /// Gets or sets the scope set identifier.
+ /// Note that the ScopeSetId is intrinsic: a new ScopeSetId is acquired
+ /// and set only when a new UserGitLab is created (by copy from
+ /// the default one - the ScopeSet of the UserGitLab 0).
///
- public interface IUserGitLabInfo : UserGitLab.IUserGitLabInfo
- {
- ///
- /// Gets or sets the scope set identifier.
- /// Note that the ScopeSetId is intrinsic: a new ScopeSetId is acquired
- /// and set only when a new UserGitLab is created (by copy from
- /// the default one - the ScopeSet of the UserGitLab 0).
- ///
- int ScopeSetId { get; set; }
- }
+ int ScopeSetId { get; set; }
}
diff --git a/CK.DB.User.UserGitLab.AuthScope/Package.cs b/CK.DB.User.UserGitLab.AuthScope/Package.cs
index 66e9eba..f883d98 100644
--- a/CK.DB.User.UserGitLab.AuthScope/Package.cs
+++ b/CK.DB.User.UserGitLab.AuthScope/Package.cs
@@ -5,58 +5,57 @@
using System;
using System.Threading.Tasks;
-namespace CK.DB.User.UserGitLab.AuthScope
+namespace CK.DB.User.UserGitLab.AuthScope;
+
+///
+/// Package that adds AuthScope support to GitLab authentication.
+///
+[SqlPackage( Schema = "CK", ResourcePath = "Res" )]
+[Versions( "1.0.0" )]
+[SqlObjectItem( "transform:sUserGitLabUCL, transform:sUserGitLabDestroy" )]
+public class Package : SqlPackage
{
+ AuthScopeSetTable _scopeSetTable;
+ UserGitLabTable _googleTable;
+
+ void StObjConstruct( AuthScopeSetTable scopeSetTable, UserGitLabTable googleTable )
+ {
+ _scopeSetTable = scopeSetTable;
+ _googleTable = googleTable;
+ }
+
+ ///
+ /// Gets the .
+ ///
+ public UserGitLabTable UserGitLabTable => _googleTable;
+
///
- /// Package that adds AuthScope support to GitLab authentication.
+ /// Gets the .
///
- [SqlPackage( Schema = "CK", ResourcePath = "Res" )]
- [Versions("1.0.0")]
- [SqlObjectItem( "transform:sUserGitLabUCL, transform:sUserGitLabDestroy" )]
- public class Package : SqlPackage
+ public AuthScopeSetTable AuthScopeSetTable => _scopeSetTable;
+
+ ///
+ /// Reads the of a user.
+ ///
+ /// The call context to use.
+ /// The user identifier.
+ /// The scope set or null if the user is not a GitLab user.
+ public Task ReadScopeSetAsync( ISqlCallContext ctx, int userId )
{
- AuthScopeSetTable _scopeSetTable;
- UserGitLabTable _googleTable;
-
- void StObjConstruct( AuthScopeSetTable scopeSetTable, UserGitLabTable googleTable )
- {
- _scopeSetTable = scopeSetTable;
- _googleTable = googleTable;
- }
-
- ///
- /// Gets the .
- ///
- public UserGitLabTable UserGitLabTable => _googleTable;
-
- ///
- /// Gets the .
- ///
- public AuthScopeSetTable AuthScopeSetTable => _scopeSetTable;
-
- ///
- /// Reads the of a user.
- ///
- /// The call context to use.
- /// The user identifier.
- /// The scope set or null if the user is not a GitLab user.
- public Task ReadScopeSetAsync( ISqlCallContext ctx, int userId )
- {
- if( userId <= 0 ) throw new ArgumentException( nameof( userId ) );
- var cmd = _scopeSetTable.CreateReadCommand( $"select ScopeSetId from CK.tUserGitLab where UserId = {userId}" );
- return _scopeSetTable.RawReadAuthScopeSetAsync( ctx, cmd );
- }
-
- ///
- /// Reads the default that is the template for new users.
- ///
- /// The call context to use.
- /// The default scope set.
- public Task ReadDefaultScopeSetAsync( ISqlCallContext ctx )
- {
- var cmd = _scopeSetTable.CreateReadCommand( "select ScopeSetId from CK.tUserGitLab where UserId = 0" );
- return _scopeSetTable.RawReadAuthScopeSetAsync( ctx, cmd );
- }
+ if( userId <= 0 ) throw new ArgumentException( nameof( userId ) );
+ var cmd = _scopeSetTable.CreateReadCommand( $"select ScopeSetId from CK.tUserGitLab where UserId = {userId}" );
+ return _scopeSetTable.RawReadAuthScopeSetAsync( ctx, cmd );
+ }
+ ///
+ /// Reads the default that is the template for new users.
+ ///
+ /// The call context to use.
+ /// The default scope set.
+ public Task ReadDefaultScopeSetAsync( ISqlCallContext ctx )
+ {
+ var cmd = _scopeSetTable.CreateReadCommand( "select ScopeSetId from CK.tUserGitLab where UserId = 0" );
+ return _scopeSetTable.RawReadAuthScopeSetAsync( ctx, cmd );
}
+
}
diff --git a/CK.DB.User.UserGitLab/CK.DB.User.UserGitLab.csproj b/CK.DB.User.UserGitLab/CK.DB.User.UserGitLab.csproj
index 7d46723..2fed23d 100644
--- a/CK.DB.User.UserGitLab/CK.DB.User.UserGitLab.csproj
+++ b/CK.DB.User.UserGitLab/CK.DB.User.UserGitLab.csproj
@@ -1,16 +1,12 @@
- net6.0
+ net8.0
This package defines tUserGitLab table.
- true
-
+
-
-
-
-
+
\ No newline at end of file
diff --git a/CK.DB.User.UserGitLab/IUserGitLabInfo.cs b/CK.DB.User.UserGitLab/IUserGitLabInfo.cs
index a7b903a..a838e4c 100644
--- a/CK.DB.User.UserGitLab/IUserGitLabInfo.cs
+++ b/CK.DB.User.UserGitLab/IUserGitLabInfo.cs
@@ -1,16 +1,14 @@
using CK.Core;
-namespace CK.DB.User.UserGitLab
+namespace CK.DB.User.UserGitLab;
+
+///
+/// Holds information stored for a GitLab user.
+///
+public interface IUserGitLabInfo : IPoco
{
///
- /// Holds information stored for a GitLab user.
+ /// Gets or sets the GitLab account identifier.
///
- public interface IUserGitLabInfo : IPoco
- {
- ///
- /// Gets or sets the GitLab account identifier.
- ///
- string GitLabAccountId { get; set; }
- }
-
+ string GitLabAccountId { get; set; }
}
diff --git a/CK.DB.User.UserGitLab/Package.cs b/CK.DB.User.UserGitLab/Package.cs
index 7a144e7..fc5ed5a 100644
--- a/CK.DB.User.UserGitLab/Package.cs
+++ b/CK.DB.User.UserGitLab/Package.cs
@@ -1,17 +1,16 @@
using CK.Core;
-namespace CK.DB.User.UserGitLab
+namespace CK.DB.User.UserGitLab;
+
+///
+/// Package that adds GitLab authentication support for users.
+///
+[SqlPackage( Schema = "CK", ResourcePath = "Res" )]
+[Versions( "1.0.0" )]
+[SqlObjectItem( "transform:vUserAuthProvider" )]
+public class Package : SqlPackage
{
- ///
- /// Package that adds GitLab authentication support for users.
- ///
- [SqlPackage( Schema = "CK", ResourcePath = "Res" )]
- [Versions("1.0.0")]
- [SqlObjectItem( "transform:vUserAuthProvider" )]
- public class Package : SqlPackage
+ void StObjConstruct( Actor.Package actorPackage, Auth.Package authPackage )
{
- void StObjConstruct( Actor.Package actorPackage, Auth.Package authPackage )
- {
- }
}
}
diff --git a/CK.DB.User.UserGitLab/UserGitLabTable.Sync.cs b/CK.DB.User.UserGitLab/UserGitLabTable.Sync.cs
index 5fec54a..cda8627 100644
--- a/CK.DB.User.UserGitLab/UserGitLabTable.Sync.cs
+++ b/CK.DB.User.UserGitLab/UserGitLabTable.Sync.cs
@@ -2,89 +2,88 @@
using CK.SqlServer;
using CK.Core;
-namespace CK.DB.User.UserGitLab
+namespace CK.DB.User.UserGitLab;
+
+public abstract partial class UserGitLabTable
{
- public abstract partial class UserGitLabTable
+ ///
+ /// Creates or updates a user entry for this provider.
+ /// This is the "binding account" feature since it binds an external identity to
+ /// an already existing user that may already be registered into other authencation providers.
+ ///
+ /// The call context to use.
+ /// The acting actor identifier.
+ /// The user identifier that must be registered.
+ /// Provider specific data: the poco.
+ /// Optionnaly configures Create, Update only or WithLogin behavior.
+ /// The result.
+ public UCLResult CreateOrUpdateGitLabUser( ISqlCallContext ctx, int actorId, int userId, IUserGitLabInfo info, UCLMode mode = UCLMode.CreateOrUpdate )
{
- ///
- /// Creates or updates a user entry for this provider.
- /// This is the "binding account" feature since it binds an external identity to
- /// an already existing user that may already be registered into other authencation providers.
- ///
- /// The call context to use.
- /// The acting actor identifier.
- /// The user identifier that must be registered.
- /// Provider specific data: the poco.
- /// Optionnaly configures Create, Update only or WithLogin behavior.
- /// The result.
- public UCLResult CreateOrUpdateGitLabUser( ISqlCallContext ctx, int actorId, int userId, IUserGitLabInfo info, UCLMode mode = UCLMode.CreateOrUpdate )
- {
- return UserGitLabUCL( ctx, actorId, userId, info, mode );
- }
+ return UserGitLabUCL( ctx, actorId, userId, info, mode );
+ }
- ///
- /// Challenges data to identify a user.
- /// Note that a successful challenge may have side effects such as updating claims, access tokens or other data
- /// related to the user and this provider.
- ///
- /// The call context to use.
- /// The payload to challenge.
- /// Set it to false to avoid login side-effect (such as updating the LastLoginTime) on success.
- /// The login result.
- public LoginResult LoginUser( ISqlCallContext ctx, IUserGitLabInfo info, bool actualLogin = true )
- {
- var mode = actualLogin
- ? UCLMode.UpdateOnly | UCLMode.WithActualLogin
- : UCLMode.UpdateOnly | UCLMode.WithCheckLogin;
- var r = UserGitLabUCL( ctx, 1, 0, info, mode );
- return r.LoginResult;
- }
+ ///
+ /// Challenges data to identify a user.
+ /// Note that a successful challenge may have side effects such as updating claims, access tokens or other data
+ /// related to the user and this provider.
+ ///
+ /// The call context to use.
+ /// The payload to challenge.
+ /// Set it to false to avoid login side-effect (such as updating the LastLoginTime) on success.
+ /// The login result.
+ public LoginResult LoginUser( ISqlCallContext ctx, IUserGitLabInfo info, bool actualLogin = true )
+ {
+ var mode = actualLogin
+ ? UCLMode.UpdateOnly | UCLMode.WithActualLogin
+ : UCLMode.UpdateOnly | UCLMode.WithCheckLogin;
+ var r = UserGitLabUCL( ctx, 1, 0, info, mode );
+ return r.LoginResult;
+ }
- ///
- /// Destroys a GitLabUser for a user.
- ///
- /// The call context to use.
- /// The acting actor identifier.
- /// The user identifier for which GitLab account information must be destroyed.
- /// The awaitable.
- [SqlProcedure( "sUserGitLabDestroy" )]
- public abstract void DestroyGitLabUser( ISqlCallContext ctx, int actorId, int userId );
+ ///
+ /// Destroys a GitLabUser for a user.
+ ///
+ /// The call context to use.
+ /// The acting actor identifier.
+ /// The user identifier for which GitLab account information must be destroyed.
+ /// The awaitable.
+ [SqlProcedure( "sUserGitLabDestroy" )]
+ public abstract void DestroyGitLabUser( ISqlCallContext ctx, int actorId, int userId );
- ///
- /// Finds a user by its GitLab account identifier.
- /// Returns null if no such user exists.
- ///
- /// The call context to use.
- /// The google account identifier.
- /// A or null if not found.
- public IdentifiedUserInfo? FindKnownUserInfo( ISqlCallContext ctx, string googleAccountId )
+ ///
+ /// Finds a user by its GitLab account identifier.
+ /// Returns null if no such user exists.
+ ///
+ /// The call context to use.
+ /// The google account identifier.
+ /// A or null if not found.
+ public IdentifiedUserInfo? FindKnownUserInfo( ISqlCallContext ctx, string googleAccountId )
+ {
+ using( var c = CreateReaderCommand( googleAccountId ) )
{
- using( var c = CreateReaderCommand( googleAccountId ) )
- {
- return ctx[Database].ExecuteSingleRow( c, r => r == null
- ? null
- : DoCreateUserUnfo( googleAccountId, r ) );
- }
+ return ctx[Database].ExecuteSingleRow( c, r => r == null
+ ? null
+ : DoCreateUserUnfo( googleAccountId, r ) );
}
+ }
- ///
- /// Raw call to manage GitLabUser. Since this should not be used directly, it is protected.
- /// Actual implementation of the centralized update, create or login procedure.
- ///
- /// The call context to use.
- /// The acting actor identifier.
- /// The user identifier for which a GitLab account must be created or updated.
- /// User information to create or update.
- /// Configures Create, Update only or WithCheck/ActualLogin behavior.
- /// The result.
- [SqlProcedure( "sUserGitLabUCL" )]
- protected abstract UCLResult UserGitLabUCL(
- ISqlCallContext ctx,
- int actorId,
- int userId,
- [ParameterSource]IUserGitLabInfo info,
- UCLMode mode );
+ ///
+ /// Raw call to manage GitLabUser. Since this should not be used directly, it is protected.
+ /// Actual implementation of the centralized update, create or login procedure.
+ ///
+ /// The call context to use.
+ /// The acting actor identifier.
+ /// The user identifier for which a GitLab account must be created or updated.
+ /// User information to create or update.
+ /// Configures Create, Update only or WithCheck/ActualLogin behavior.
+ /// The result.
+ [SqlProcedure( "sUserGitLabUCL" )]
+ protected abstract UCLResult UserGitLabUCL(
+ ISqlCallContext ctx,
+ int actorId,
+ int userId,
+ [ParameterSource] IUserGitLabInfo info,
+ UCLMode mode );
- }
}
diff --git a/CK.DB.User.UserGitLab/UserGitLabTable.cs b/CK.DB.User.UserGitLab/UserGitLabTable.cs
index 1b40a98..2aba6a4 100644
--- a/CK.DB.User.UserGitLab/UserGitLabTable.cs
+++ b/CK.DB.User.UserGitLab/UserGitLabTable.cs
@@ -8,215 +8,214 @@
using CK.DB.Auth;
using System.Diagnostics.CodeAnalysis;
-namespace CK.DB.User.UserGitLab
+namespace CK.DB.User.UserGitLab;
+
+///
+/// GitLab authentication provider.
+///
+[SqlTable( "tUserGitLab", Package = typeof( Package ) )]
+[Versions( "2.0.1" )]
+[SqlObjectItem( "transform:sUserDestroy" )]
+public abstract partial class UserGitLabTable : SqlTable, IGenericAuthenticationProvider
{
+ [AllowNull]
+ IPocoFactory _infoFactory;
+
///
- /// GitLab authentication provider.
+ /// Gets "GitLab" that is the name of the GitLab provider.
///
- [SqlTable( "tUserGitLab", Package = typeof( Package ) )]
- [Versions( "2.0.1" )]
- [SqlObjectItem( "transform:sUserDestroy" )]
- public abstract partial class UserGitLabTable : SqlTable, IGenericAuthenticationProvider
+ public string ProviderName => "GitLab";
+
+ void StObjConstruct( IPocoFactory infoFactory )
{
- [AllowNull]
- IPocoFactory _infoFactory;
+ _infoFactory = infoFactory;
+ }
- ///
- /// Gets "GitLab" that is the name of the GitLab provider.
- ///
- public string ProviderName => "GitLab";
+ public bool CanCreatePayload => true;
- void StObjConstruct( IPocoFactory infoFactory )
- {
- _infoFactory = infoFactory;
- }
+ object IGenericAuthenticationProvider.CreatePayload() => _infoFactory.Create();
- public bool CanCreatePayload => true;
-
- object IGenericAuthenticationProvider.CreatePayload() => _infoFactory.Create();
-
- IUserGitLabInfo IGenericAuthenticationProvider.CreatePayload() => _infoFactory.Create();
-
- ///
- /// Creates a poco.
- ///
- /// A new instance.
- public T CreateUserInfo() where T : IUserGitLabInfo => (T)_infoFactory.Create();
-
- ///
- /// Creates or updates a user entry for this provider.
- /// This is the "binding account" feature since it binds an external identity to
- /// an already existing user that may already be registered into other authencation providers.
- ///
- /// The call context to use.
- /// The acting actor identifier.
- /// The user identifier that must be registered.
- /// Provider specific data: the poco.
- /// Optionnaly configures Create, Update only or WithLogin behavior.
- /// Optional cancellation token.
- /// The result.
- public async Task CreateOrUpdateGitLabUserAsync( ISqlCallContext ctx, int actorId, int userId, IUserGitLabInfo info, UCLMode mode = UCLMode.CreateOrUpdate, CancellationToken cancellationToken = default )
- {
- var r = await GitLabUserUCLAsync( ctx, actorId, userId, info, mode, cancellationToken ).ConfigureAwait( false );
- return r;
- }
+ IUserGitLabInfo IGenericAuthenticationProvider.CreatePayload() => _infoFactory.Create();
- ///
- /// Challenges data to identify a user.
- /// Note that a successful challenge may have side effects such as updating claims, access tokens or other data
- /// related to the user and this provider.
- ///
- /// The call context to use.
- /// The payload to challenge.
- /// Set it to false to avoid login side-effect (such as updating the LastLoginTime) on success.
- /// Optional cancellation token.
- /// The .
- public async Task LoginUserAsync( ISqlCallContext ctx, IUserGitLabInfo info, bool actualLogin = true, CancellationToken cancellationToken = default )
- {
- var mode = actualLogin
- ? UCLMode.UpdateOnly | UCLMode.WithActualLogin
- : UCLMode.UpdateOnly | UCLMode.WithCheckLogin;
- var r = await GitLabUserUCLAsync( ctx, 1, 0, info, mode, cancellationToken ).ConfigureAwait( false );
- return r.LoginResult;
- }
+ ///
+ /// Creates a poco.
+ ///
+ /// A new instance.
+ public T CreateUserInfo() where T : IUserGitLabInfo => (T)_infoFactory.Create();
- ///
- /// Destroys a GitLabUser for a user.
- ///
- /// The call context to use.
- /// The acting actor identifier.
- /// The user identifier for which GitLab account information must be destroyed.
- /// Optional cancellation token.
- /// The awaitable.
- [SqlProcedure( "sUserGitLabDestroy" )]
- public abstract Task DestroyGitLabUserAsync( ISqlCallContext ctx, int actorId, int userId, CancellationToken cancellationToken = default );
-
- ///
- /// Raw call to manage GitLabUser. Since this should not be used directly, it is protected.
- /// Actual implementation of the centralized update, create or login procedure.
- ///
- /// The call context to use.
- /// The acting actor identifier.
- /// The user identifier for which a GitLab account must be created or updated.
- /// User information to create or update.
- /// Configures Create, Update only or WithCheck/ActualLogin behavior.
- /// Optional cancellation token.
- /// The result.
- [SqlProcedure( "sUserGitLabUCL" )]
- protected abstract Task GitLabUserUCLAsync(
- ISqlCallContext ctx,
- int actorId,
- int userId,
- [ParameterSource]IUserGitLabInfo info,
- UCLMode mode,
- CancellationToken cancellationToken );
-
- ///
- /// Finds a user by its GitLab account identifier.
- /// Returns null if no such user exists.
- ///
- /// The call context to use.
- /// The google account identifier.
- /// Optional cancellation token.
- /// A object or null if not found.
- public async Task?> FindKnownUserInfoAsync( ISqlCallContext ctx, string googleAccountId, CancellationToken cancellationToken = default )
- {
- using( var c = CreateReaderCommand( googleAccountId ) )
- {
- return await ctx[Database].ExecuteSingleRowAsync( c, r => r == null
- ? null
- : DoCreateUserUnfo( googleAccountId, r ), cancellationToken )
- .ConfigureAwait( false );
- }
- }
+ ///
+ /// Creates or updates a user entry for this provider.
+ /// This is the "binding account" feature since it binds an external identity to
+ /// an already existing user that may already be registered into other authencation providers.
+ ///
+ /// The call context to use.
+ /// The acting actor identifier.
+ /// The user identifier that must be registered.
+ /// Provider specific data: the poco.
+ /// Optionnaly configures Create, Update only or WithLogin behavior.
+ /// Optional cancellation token.
+ /// The result.
+ public async Task CreateOrUpdateGitLabUserAsync( ISqlCallContext ctx, int actorId, int userId, IUserGitLabInfo info, UCLMode mode = UCLMode.CreateOrUpdate, CancellationToken cancellationToken = default )
+ {
+ var r = await GitLabUserUCLAsync( ctx, actorId, userId, info, mode, cancellationToken ).ConfigureAwait( false );
+ return r;
+ }
- ///
- /// Creates a the reader command parametrized with the GitLab account identifier.
- /// Single-row returned columns are defined by .
- ///
- /// GitLab account identifier to look for.
- /// A ready to use reader command.
- SqlCommand CreateReaderCommand( string googleAccountId )
- {
- StringBuilder b = new StringBuilder( "select " );
- AppendUserInfoColumns( b ).Append( " from CK.tUserGitLab where GitLabAccountId=@A" );
- var c = new SqlCommand( b.ToString() );
- c.Parameters.Add( new SqlParameter( "@A", googleAccountId ) );
- return c;
- }
+ ///
+ /// Challenges data to identify a user.
+ /// Note that a successful challenge may have side effects such as updating claims, access tokens or other data
+ /// related to the user and this provider.
+ ///
+ /// The call context to use.
+ /// The payload to challenge.
+ /// Set it to false to avoid login side-effect (such as updating the LastLoginTime) on success.
+ /// Optional cancellation token.
+ /// The .
+ public async Task LoginUserAsync( ISqlCallContext ctx, IUserGitLabInfo info, bool actualLogin = true, CancellationToken cancellationToken = default )
+ {
+ var mode = actualLogin
+ ? UCLMode.UpdateOnly | UCLMode.WithActualLogin
+ : UCLMode.UpdateOnly | UCLMode.WithCheckLogin;
+ var r = await GitLabUserUCLAsync( ctx, 1, 0, info, mode, cancellationToken ).ConfigureAwait( false );
+ return r.LoginResult;
+ }
- IdentifiedUserInfo DoCreateUserUnfo( string googleAccountId, SqlDataRow r )
- {
- var info = _infoFactory.Create();
- info.GitLabAccountId = googleAccountId;
- FillUserGitLabInfo( info, r, 1 );
- return new IdentifiedUserInfo( r.GetInt32( 0 ), info );
- }
+ ///
+ /// Destroys a GitLabUser for a user.
+ ///
+ /// The call context to use.
+ /// The acting actor identifier.
+ /// The user identifier for which GitLab account information must be destroyed.
+ /// Optional cancellation token.
+ /// The awaitable.
+ [SqlProcedure( "sUserGitLabDestroy" )]
+ public abstract Task DestroyGitLabUserAsync( ISqlCallContext ctx, int actorId, int userId, CancellationToken cancellationToken = default );
- ///
- /// Adds the columns name to read.
- ///
- /// The string builder.
- /// The string builder.
- protected virtual StringBuilder AppendUserInfoColumns( StringBuilder b )
- {
- var props = _infoFactory.PocoClassType.GetProperties().Where( p => p.Name != nameof( IUserGitLabInfo.GitLabAccountId ) );
- return props.Any() ? b.Append( "UserId, " ).AppendStrings( props.Select( p => p.Name ) ) : b.Append( "UserId " );
- }
+ ///
+ /// Raw call to manage GitLabUser. Since this should not be used directly, it is protected.
+ /// Actual implementation of the centralized update, create or login procedure.
+ ///
+ /// The call context to use.
+ /// The acting actor identifier.
+ /// The user identifier for which a GitLab account must be created or updated.
+ /// User information to create or update.
+ /// Configures Create, Update only or WithCheck/ActualLogin behavior.
+ /// Optional cancellation token.
+ /// The result.
+ [SqlProcedure( "sUserGitLabUCL" )]
+ protected abstract Task GitLabUserUCLAsync(
+ ISqlCallContext ctx,
+ int actorId,
+ int userId,
+ [ParameterSource] IUserGitLabInfo info,
+ UCLMode mode,
+ CancellationToken cancellationToken );
- ///
- /// Fill UserInfo properties from reader.
- ///
- /// The info to fill.
- /// The record.
- /// The index of the first column.
- /// The updated index.
- protected virtual int FillUserGitLabInfo( IUserGitLabInfo info, SqlDataRow r, int idx )
+ ///
+ /// Finds a user by its GitLab account identifier.
+ /// Returns null if no such user exists.
+ ///
+ /// The call context to use.
+ /// The google account identifier.
+ /// Optional cancellation token.
+ /// A object or null if not found.
+ public async Task?> FindKnownUserInfoAsync( ISqlCallContext ctx, string googleAccountId, CancellationToken cancellationToken = default )
+ {
+ using( var c = CreateReaderCommand( googleAccountId ) )
{
- var props = _infoFactory.PocoClassType.GetProperties().Where( p => p.Name != nameof( IUserGitLabInfo.GitLabAccountId ) );
- foreach( var p in props )
- {
- p.SetValue( info, r.GetValue( idx++ ) );
- }
- return idx;
+ return await ctx[Database].ExecuteSingleRowAsync( c, r => r == null
+ ? null
+ : DoCreateUserUnfo( googleAccountId, r ), cancellationToken )
+ .ConfigureAwait( false );
}
+ }
+
+ ///
+ /// Creates a the reader command parametrized with the GitLab account identifier.
+ /// Single-row returned columns are defined by .
+ ///
+ /// GitLab account identifier to look for.
+ /// A ready to use reader command.
+ SqlCommand CreateReaderCommand( string googleAccountId )
+ {
+ StringBuilder b = new StringBuilder( "select " );
+ AppendUserInfoColumns( b ).Append( " from CK.tUserGitLab where GitLabAccountId=@A" );
+ var c = new SqlCommand( b.ToString() );
+ c.Parameters.Add( new SqlParameter( "@A", googleAccountId ) );
+ return c;
+ }
- #region IGenericAuthenticationProvider explicit implementation.
+ IdentifiedUserInfo DoCreateUserUnfo( string googleAccountId, SqlDataRow r )
+ {
+ var info = _infoFactory.Create();
+ info.GitLabAccountId = googleAccountId;
+ FillUserGitLabInfo( info, r, 1 );
+ return new IdentifiedUserInfo( r.GetInt32( 0 ), info );
+ }
- UCLResult IGenericAuthenticationProvider.CreateOrUpdateUser( ISqlCallContext ctx, int actorId, int userId, object payload, UCLMode mode )
- {
- IUserGitLabInfo info = _infoFactory.ExtractPayload( payload );
- return CreateOrUpdateGitLabUser( ctx, actorId, userId, info, mode );
- }
+ ///
+ /// Adds the columns name to read.
+ ///
+ /// The string builder.
+ /// The string builder.
+ protected virtual StringBuilder AppendUserInfoColumns( StringBuilder b )
+ {
+ var props = _infoFactory.PocoClassType.GetProperties().Where( p => p.Name != nameof( IUserGitLabInfo.GitLabAccountId ) );
+ return props.Any() ? b.Append( "UserId, " ).AppendStrings( props.Select( p => p.Name ) ) : b.Append( "UserId " );
+ }
- LoginResult IGenericAuthenticationProvider.LoginUser( ISqlCallContext ctx, object payload, bool actualLogin )
+ ///
+ /// Fill UserInfo properties from reader.
+ ///
+ /// The info to fill.
+ /// The record.
+ /// The index of the first column.
+ /// The updated index.
+ protected virtual int FillUserGitLabInfo( IUserGitLabInfo info, SqlDataRow r, int idx )
+ {
+ var props = _infoFactory.PocoClassType.GetProperties().Where( p => p.Name != nameof( IUserGitLabInfo.GitLabAccountId ) );
+ foreach( var p in props )
{
- IUserGitLabInfo info = _infoFactory.ExtractPayload( payload );
- return LoginUser( ctx, info, actualLogin );
+ p.SetValue( info, r.GetValue( idx++ ) );
}
+ return idx;
+ }
- Task IGenericAuthenticationProvider.CreateOrUpdateUserAsync( ISqlCallContext ctx, int actorId, int userId, object payload, UCLMode mode, CancellationToken cancellationToken )
- {
- IUserGitLabInfo info = _infoFactory.ExtractPayload( payload );
- return CreateOrUpdateGitLabUserAsync( ctx, actorId, userId, info, mode, cancellationToken );
- }
+ #region IGenericAuthenticationProvider explicit implementation.
- Task IGenericAuthenticationProvider.LoginUserAsync( ISqlCallContext ctx, object payload, bool actualLogin, CancellationToken cancellationToken )
- {
- IUserGitLabInfo info = _infoFactory.ExtractPayload( payload );
- return LoginUserAsync( ctx, info, actualLogin, cancellationToken );
- }
+ UCLResult IGenericAuthenticationProvider.CreateOrUpdateUser( ISqlCallContext ctx, int actorId, int userId, object payload, UCLMode mode )
+ {
+ IUserGitLabInfo info = _infoFactory.ExtractPayload( payload );
+ return CreateOrUpdateGitLabUser( ctx, actorId, userId, info, mode );
+ }
- void IGenericAuthenticationProvider.DestroyUser( ISqlCallContext ctx, int actorId, int userId, string? schemeSuffix )
- {
- DestroyGitLabUser( ctx, actorId, userId );
- }
+ LoginResult IGenericAuthenticationProvider.LoginUser( ISqlCallContext ctx, object payload, bool actualLogin )
+ {
+ IUserGitLabInfo info = _infoFactory.ExtractPayload( payload );
+ return LoginUser( ctx, info, actualLogin );
+ }
- Task IGenericAuthenticationProvider.DestroyUserAsync( ISqlCallContext ctx, int actorId, int userId, string? schemeSuffix, CancellationToken cancellationToken )
- {
- return DestroyGitLabUserAsync( ctx, actorId, userId, cancellationToken );
- }
+ Task IGenericAuthenticationProvider.CreateOrUpdateUserAsync( ISqlCallContext ctx, int actorId, int userId, object payload, UCLMode mode, CancellationToken cancellationToken )
+ {
+ IUserGitLabInfo info = _infoFactory.ExtractPayload( payload );
+ return CreateOrUpdateGitLabUserAsync( ctx, actorId, userId, info, mode, cancellationToken );
+ }
- #endregion
+ Task IGenericAuthenticationProvider.LoginUserAsync( ISqlCallContext ctx, object payload, bool actualLogin, CancellationToken cancellationToken )
+ {
+ IUserGitLabInfo info = _infoFactory.ExtractPayload( payload );
+ return LoginUserAsync( ctx, info, actualLogin, cancellationToken );
+ }
+
+ void IGenericAuthenticationProvider.DestroyUser( ISqlCallContext ctx, int actorId, int userId, string? schemeSuffix )
+ {
+ DestroyGitLabUser( ctx, actorId, userId );
}
+
+ Task IGenericAuthenticationProvider.DestroyUserAsync( ISqlCallContext ctx, int actorId, int userId, string? schemeSuffix, CancellationToken cancellationToken )
+ {
+ return DestroyGitLabUserAsync( ctx, actorId, userId, cancellationToken );
+ }
+
+ #endregion
}
diff --git a/CodeCakeBuilder/Abstractions/Artifact.cs b/CodeCakeBuilder/Abstractions/Artifact.cs
index ef4aed4..537e0c5 100644
--- a/CodeCakeBuilder/Abstractions/Artifact.cs
+++ b/CodeCakeBuilder/Abstractions/Artifact.cs
@@ -1,69 +1,68 @@
using System;
-namespace CodeCake.Abstractions
+namespace CodeCake.Abstractions;
+
+///
+/// An artifact is produced by a solution and can be of any type.
+///
+public readonly struct Artifact : IEquatable
{
///
- /// An artifact is produced by a solution and can be of any type.
+ /// Gets the artifact type.
///
- public readonly struct Artifact : IEquatable
- {
- ///
- /// Gets the artifact type.
- ///
- public string Type { get; }
+ public string Type { get; }
- ///
- /// Gets the artifact name.
- ///
- public string Name { get; }
+ ///
+ /// Gets the artifact name.
+ ///
+ public string Name { get; }
- ///
- /// Initializes a new .
- ///
- /// Artifact type.
- /// Artifact name.
- public Artifact( string type, string name )
- {
- Type = type ?? throw new ArgumentNullException( nameof( type ) );
- Name = name ?? throw new ArgumentNullException( nameof( name ) );
- }
+ ///
+ /// Initializes a new .
+ ///
+ /// Artifact type.
+ /// Artifact name.
+ public Artifact( string type, string name )
+ {
+ Type = type ?? throw new ArgumentNullException( nameof( type ) );
+ Name = name ?? throw new ArgumentNullException( nameof( name ) );
+ }
- ///
- /// Checks equality.
- ///
- /// The other artifact.
- /// True when equals, false otherwise.
- public bool Equals( Artifact other ) => Type == other.Type && Name == other.Name;
+ ///
+ /// Checks equality.
+ ///
+ /// The other artifact.
+ /// True when equals, false otherwise.
+ public bool Equals( Artifact other ) => Type == other.Type && Name == other.Name;
- ///
- /// Overridden to call .
- ///
- /// An object.
- /// True the object is an Artifact that is equal to this one, false otherwise.
- public override bool Equals( object? obj ) => obj is Artifact a ? Equals( a ) : false;
+ ///
+ /// Overridden to call .
+ ///
+ /// An object.
+ /// True the object is an Artifact that is equal to this one, false otherwise.
+ public override bool Equals( object? obj ) => obj is Artifact a ? Equals( a ) : false;
- ///
- /// Overridden to combine and .
- ///
- /// The hash code.
- public override int GetHashCode() => Type.GetHashCode() ^ Name.GetHashCode();
+ ///
+ /// Overridden to combine and .
+ ///
+ /// The hash code.
+ public override int GetHashCode() => Type.GetHashCode() ^ Name.GetHashCode();
- ///
- /// Implements == operator.
- ///
- /// First artifact.
- /// Second artifact.
- /// True if they are equal.
- public static bool operator ==( Artifact x, Artifact y ) => x.Equals( y );
+ ///
+ /// Implements == operator.
+ ///
+ /// First artifact.
+ /// Second artifact.
+ /// True if they are equal.
+ public static bool operator ==( Artifact x, Artifact y ) => x.Equals( y );
- ///
- /// Implements != operator.
- ///
- /// First artifact.
- /// Second artifact.
- /// True if they are not equal.
- public static bool operator !=( Artifact x, Artifact y ) => !x.Equals( y );
+ ///
+ /// Implements != operator.
+ ///
+ /// First artifact.
+ /// Second artifact.
+ /// True if they are not equal.
+ public static bool operator !=( Artifact x, Artifact y ) => !x.Equals( y );
- public override string ToString() => $"{Type}:{Name}";
- }
+ public override string ToString() => $"{Type}:{Name}";
}
diff --git a/CodeCakeBuilder/Abstractions/ArtifactFeed.cs b/CodeCakeBuilder/Abstractions/ArtifactFeed.cs
index 3db056c..9cdd7f6 100644
--- a/CodeCakeBuilder/Abstractions/ArtifactFeed.cs
+++ b/CodeCakeBuilder/Abstractions/ArtifactFeed.cs
@@ -2,46 +2,45 @@
using System.Collections.Generic;
using System.Threading.Tasks;
-namespace CodeCake.Abstractions
+namespace CodeCake.Abstractions;
+
+///
+/// Abstract feed associated to a .
+///
+public abstract class ArtifactFeed
{
+ protected ArtifactFeed( ArtifactType t )
+ {
+ ArtifactType = t;
+ }
+
///
- /// Abstract feed associated to a .
+ /// Gets the artifact type that handles this feed.
///
- public abstract class ArtifactFeed
- {
- protected ArtifactFeed( ArtifactType t )
- {
- ArtifactType = t;
- }
-
- ///
- /// Gets the artifact type that handles this feed.
- ///
- public ArtifactType ArtifactType { get; }
-
- ///
- /// Gets the cake context.
- ///
- protected ICakeContext Cake => ArtifactType.GlobalInfo.Cake;
-
- ///
- /// Name used to print the feed in the logs.
- ///
- public abstract string Name { get; }
-
- ///
- /// Creates a list of object from a set of .
- ///
- /// Set of artifacts.
- /// The set of push information.
- public abstract Task> CreatePushListAsync( IEnumerable artifacts );
-
- ///
- /// Pushes a set of artifacts previously computed by .
- ///
- /// The instances to push (that necessary target this feed).
- /// The awaitable.
- public abstract Task PushAsync( IEnumerable pushes );
+ public ArtifactType ArtifactType { get; }
+
+ ///
+ /// Gets the cake context.
+ ///
+ protected ICakeContext Cake => ArtifactType.GlobalInfo.Cake;
+
+ ///
+ /// Name used to print the feed in the logs.
+ ///
+ public abstract string Name { get; }
+
+ ///
+ /// Creates a list of object from a set of .
+ ///
+ /// Set of artifacts.
+ /// The set of push information.
+ public abstract Task> CreatePushListAsync( IEnumerable artifacts );
+
+ ///
+ /// Pushes a set of artifacts previously computed by .
+ ///
+ /// The instances to push (that necessary target this feed).
+ /// The awaitable.
+ public abstract Task PushAsync( IEnumerable pushes );
- }
}
diff --git a/CodeCakeBuilder/Abstractions/ArtifactInstance.cs b/CodeCakeBuilder/Abstractions/ArtifactInstance.cs
index 558ed47..7e9268a 100644
--- a/CodeCakeBuilder/Abstractions/ArtifactInstance.cs
+++ b/CodeCakeBuilder/Abstractions/ArtifactInstance.cs
@@ -1,73 +1,72 @@
using CSemVer;
using System;
-namespace CodeCake.Abstractions
+namespace CodeCake.Abstractions;
+
+///
+/// Defines the instance of an : its is known.
+///
+public readonly struct ArtifactInstance : IEquatable
{
///
- /// Defines the instance of an : its is known.
+ /// Initializes a new .
///
- public readonly struct ArtifactInstance : IEquatable
+ /// The artifact.
+ /// The version. Can not be null.
+ public ArtifactInstance( Artifact a, SVersion version )
{
- ///
- /// Initializes a new .
- ///
- /// The artifact.
- /// The version. Can not be null.
- public ArtifactInstance( Artifact a, SVersion version )
- {
- Artifact = a;
- Version = version ?? throw new ArgumentNullException( nameof( version ) );
- }
+ Artifact = a;
+ Version = version ?? throw new ArgumentNullException( nameof( version ) );
+ }
- ///
- /// Initializes a new .
- ///
- /// The artifact type. Can not be null.
- /// The artifact name. Can not be null.
- /// The version. Can not be null.
- public ArtifactInstance( string type, string name, SVersion version )
- : this( new Artifact( type, name ), version )
- {
- }
+ ///
+ /// Initializes a new .
+ ///
+ /// The artifact type. Can not be null.
+ /// The artifact name. Can not be null.
+ /// The version. Can not be null.
+ public ArtifactInstance( string type, string name, SVersion version )
+ : this( new Artifact( type, name ), version )
+ {
+ }
- ///
- /// Gets the artifact.
- ///
- public Artifact Artifact { get; }
+ ///
+ /// Gets the artifact.
+ ///
+ public Artifact Artifact { get; }
- ///
- /// Gets the artifact version.
- ///
- public SVersion Version { get; }
+ ///
+ /// Gets the artifact version.
+ ///
+ public SVersion Version { get; }
- ///
- /// Checks equality.
- ///
- /// The other instance.
- /// True when equals, false otherwise.
- public bool Equals( ArtifactInstance other ) => Artifact == other.Artifact && Version == other.Version;
+ ///
+ /// Checks equality.
+ ///
+ /// The other instance.
+ /// True when equals, false otherwise.
+ public bool Equals( ArtifactInstance other ) => Artifact == other.Artifact && Version == other.Version;
- public override bool Equals( object? obj ) => obj is ArtifactInstance a ? Equals( a ) : false;
+ public override bool Equals( object? obj ) => obj is ArtifactInstance a ? Equals( a ) : false;
- public override int GetHashCode() => Version.GetHashCode() ^ Artifact.GetHashCode();
+ public override int GetHashCode() => Version.GetHashCode() ^ Artifact.GetHashCode();
- public override string ToString() => $"{Artifact}/{Version.ToNormalizedString()}";
+ public override string ToString() => $"{Artifact}/{Version.ToNormalizedString()}";
- ///
- /// Implements == operator.
- ///
- /// First artifact instance.
- /// Second artifact instance.
- /// True if they are equal.
- public static bool operator ==( ArtifactInstance x, ArtifactInstance y ) => x.Equals( y );
+ ///
+ /// Implements == operator.
+ ///
+ /// First artifact instance.
+ /// Second artifact instance.
+ /// True if they are equal.
+ public static bool operator ==( ArtifactInstance x, ArtifactInstance y ) => x.Equals( y );
- ///
- /// Implements != operator.
- ///
- /// First artifact instance.
- /// Second artifact instance.
- /// True if they are not equal.
- public static bool operator !=( ArtifactInstance x, ArtifactInstance y ) => !x.Equals( y );
+ ///
+ /// Implements != operator.
+ ///
+ /// First artifact instance.
+ /// Second artifact instance.
+ /// True if they are not equal.
+ public static bool operator !=( ArtifactInstance x, ArtifactInstance y ) => !x.Equals( y );
- }
}
diff --git a/CodeCakeBuilder/Abstractions/ArtifactPush.cs b/CodeCakeBuilder/Abstractions/ArtifactPush.cs
index b5935d3..87d760f 100644
--- a/CodeCakeBuilder/Abstractions/ArtifactPush.cs
+++ b/CodeCakeBuilder/Abstractions/ArtifactPush.cs
@@ -1,46 +1,44 @@
using CSemVer;
using System.Collections.Generic;
-namespace CodeCake.Abstractions
+namespace CodeCake.Abstractions;
+
+///
+/// Represents the required push of a into a .
+/// This class may be specialized if Feed per Artifact data must be generated and circulate between
+/// the
+/// and .
+///
+public class ArtifactPush
{
///
- /// Represents the required push of a into a .
- /// This class may be specialized if Feed per Artifact data must be generated and circulate between
- /// the
- /// and .
+ /// Initializes a new instance.
///
- public class ArtifactPush
+ /// The artifact.
+ /// The target feed.
+ public ArtifactPush( ILocalArtifact local, ArtifactFeed feed )
{
- ///
- /// Initializes a new instance.
- ///
- /// The artifact.
- /// The target feed.
- public ArtifactPush( ILocalArtifact local, ArtifactFeed feed )
- {
- LocalArtifact = local;
- Feed = feed;
- }
-
- ///
- /// Gets the artifact.
- ///
- public ILocalArtifact LocalArtifact { get; }
+ LocalArtifact = local;
+ Feed = feed;
+ }
- ///
- /// Gets the artifact name.
- ///
- public string Name => LocalArtifact.ArtifactInstance.Artifact.Name;
+ ///
+ /// Gets the artifact.
+ ///
+ public ILocalArtifact LocalArtifact { get; }
- ///
- /// Gets the artifact's version.
- ///
- public SVersion Version => LocalArtifact.ArtifactInstance.Version;
+ ///
+ /// Gets the artifact name.
+ ///
+ public string Name => LocalArtifact.ArtifactInstance.Artifact.Name;
- ///
- /// Gets the feed.
- ///
- public ArtifactFeed Feed { get; }
- }
+ ///
+ /// Gets the artifact's version.
+ ///
+ public SVersion Version => LocalArtifact.ArtifactInstance.Version;
+ ///
+ /// Gets the feed.
+ ///
+ public ArtifactFeed Feed { get; }
}
diff --git a/CodeCakeBuilder/Abstractions/ArtifactType.cs b/CodeCakeBuilder/Abstractions/ArtifactType.cs
index a024be3..beded96 100644
--- a/CodeCakeBuilder/Abstractions/ArtifactType.cs
+++ b/CodeCakeBuilder/Abstractions/ArtifactType.cs
@@ -5,151 +5,150 @@
using System.Linq;
using System.Threading.Tasks;
-namespace CodeCake.Abstractions
+namespace CodeCake.Abstractions;
+
+///
+/// Abstract artifact Type that handles and defines
+/// how can be published into those feeds.
+///
+public abstract class ArtifactType
{
+ readonly StandardGlobalInfo _globalInfo;
+ readonly string _typeName;
+ List? _feeds;
+ List? _artifacts;
+ List? _pushes;
+
///
- /// Abstract artifact Type that handles and defines
- /// how can be published into those feeds.
+ /// Initializes a new artifact type and adds it into
+ /// the .
///
- public abstract class ArtifactType
+ /// The global object.
+ /// Name of the type.
+ protected ArtifactType( StandardGlobalInfo globalInfo, string typeName )
{
- readonly StandardGlobalInfo _globalInfo;
- readonly string _typeName;
- List? _feeds;
- List? _artifacts;
- List? _pushes;
-
- ///
- /// Initializes a new artifact type and adds it into
- /// the .
- ///
- /// The global object.
- /// Name of the type.
- protected ArtifactType( StandardGlobalInfo globalInfo, string typeName )
- {
- _globalInfo = globalInfo;
- _typeName = typeName;
- }
+ _globalInfo = globalInfo;
+ _typeName = typeName;
+ }
- ///
- /// Gets the artifact type name.
- ///
- public string TypeName => _typeName;
+ ///
+ /// Gets the artifact type name.
+ ///
+ public string TypeName => _typeName;
- ///
- /// Gets the global .
- ///
- public StandardGlobalInfo GlobalInfo => _globalInfo;
+ ///
+ /// Gets the global .
+ ///
+ public StandardGlobalInfo GlobalInfo => _globalInfo;
- ///
- /// Gets a mutable list of all the target feeds into which artifacts of this type should be pushed.
- ///
- /// The list of feeds.
- public IList GetTargetFeeds( bool reset = false )
+ ///
+ /// Gets a mutable list of all the target feeds into which artifacts of this type should be pushed.
+ ///
+ /// The list of feeds.
+ public IList GetTargetFeeds( bool reset = false )
+ {
+ if( _feeds == null || reset )
{
- if( _feeds == null || reset )
+ _feeds = new List();
+ if( GlobalInfo.LocalFeedPath != null )
{
- _feeds = new List();
- if( GlobalInfo.LocalFeedPath != null )
+ foreach( var f in GetLocalFeeds() )
{
- foreach( var f in GetLocalFeeds() )
+ GlobalInfo.Cake.Information( $"Adding local feed {f.Name}." );
+ if( f.ArtifactType != this )
{
- GlobalInfo.Cake.Information( $"Adding local feed {f.Name}." );
- if( f.ArtifactType != this )
- {
- throw new InvalidOperationException( $"Feed type mismatch." );
- }
- _feeds.Add( f );
+ throw new InvalidOperationException( $"Feed type mismatch." );
}
+ _feeds.Add( f );
}
- if( GlobalInfo.PushToRemote )
+ }
+ if( GlobalInfo.PushToRemote )
+ {
+ foreach( ArtifactFeed f in GetRemoteFeeds() )
{
- foreach( ArtifactFeed f in GetRemoteFeeds() )
+ GlobalInfo.Cake.Information( $"Adding remote feed: {f.Name}" );
+ if( f.ArtifactType != this )
{
- GlobalInfo.Cake.Information( $"Adding remote feed: {f.Name}" );
- if( f.ArtifactType != this )
- {
- throw new InvalidOperationException( $"Feed type mismatch." );
- }
- _feeds.Add( f );
+ throw new InvalidOperationException( $"Feed type mismatch." );
}
+ _feeds.Add( f );
}
}
- return _feeds;
}
+ return _feeds;
+ }
- ///
- /// Gets a mutable list of all locally produced artifacts of this type.
- ///
- /// True to recompute a list.
- /// The set of artifacts.
- public IList GetArtifacts( bool reset = false )
+ ///
+ /// Gets a mutable list of all locally produced artifacts of this type.
+ ///
+ /// True to recompute a list.
+ /// The set of artifacts.
+ public IList GetArtifacts( bool reset = false )
+ {
+ if( _artifacts == null || reset )
{
- if( _artifacts == null || reset )
+ _artifacts = new List();
+ foreach( var a in GetLocalArtifacts() )
{
- _artifacts = new List();
- foreach( var a in GetLocalArtifacts() )
+ if( a.ArtifactInstance.Artifact.Type != _typeName )
{
- if( a.ArtifactInstance.Artifact.Type != _typeName )
- {
- throw new InvalidOperationException( $"Artifact type mismatch: expected '{_typeName}' but got '{a.ArtifactInstance.Artifact.Type}'." );
- }
- _artifacts.Add( a );
+ throw new InvalidOperationException( $"Artifact type mismatch: expected '{_typeName}' but got '{a.ArtifactInstance.Artifact.Type}'." );
}
+ _artifacts.Add( a );
}
- return _artifacts;
}
+ return _artifacts;
+ }
- ///
- /// Gets a mutable list of all the pushes of artifacts into target feeds for this type.
- ///
- /// The set of pushes.
- public async Task> GetPushListAsync( bool reset = false )
+ ///
+ /// Gets a mutable list of all the pushes of artifacts into target feeds for this type.
+ ///
+ /// The set of pushes.
+ public async Task> GetPushListAsync( bool reset = false )
+ {
+ if( _pushes == null || reset )
{
- if( _pushes == null || reset )
+ _pushes = new List();
+ var locals = GetArtifacts();
+ var tasks = GetTargetFeeds().Select( f => f.CreatePushListAsync( locals ) ).ToArray();
+ foreach( var p in await Task.WhenAll( tasks ) )
{
- _pushes = new List();
- var locals = GetArtifacts();
- var tasks = GetTargetFeeds().Select( f => f.CreatePushListAsync( locals ) ).ToArray();
- foreach( var p in await Task.WhenAll( tasks ) )
- {
- _pushes.AddRange( p );
- }
+ _pushes.AddRange( p );
}
- return _pushes;
}
+ return _pushes;
+ }
- ///
- /// Must push all the required artifacts into all the target feeds.
- /// This uses the by default.
- ///
- /// Push details: defaults to the result of .
- public async Task PushAsync( IEnumerable? pushes = null )
- {
- if( pushes == null ) pushes = await GetPushListAsync();
- var tasks = pushes.GroupBy( p => p.Feed ).Select( g => g.Key.PushAsync( g ) ).ToArray();
- await Task.WhenAll( tasks );
- }
+ ///
+ /// Must push all the required artifacts into all the target feeds.
+ /// This uses the by default.
+ ///
+ /// Push details: defaults to the result of .
+ public async Task PushAsync( IEnumerable? pushes = null )
+ {
+ if( pushes == null ) pushes = await GetPushListAsync();
+ var tasks = pushes.GroupBy( p => p.Feed ).Select( g => g.Key.PushAsync( g ) ).ToArray();
+ await Task.WhenAll( tasks );
+ }
- ///
- /// Must get the remote target feeds into which artifacts of this
- /// type should be pushed.
- ///
- /// A set of remote feed.
- protected abstract IEnumerable GetRemoteFeeds();
+ ///
+ /// Must get the remote target feeds into which artifacts of this
+ /// type should be pushed.
+ ///
+ /// A set of remote feed.
+ protected abstract IEnumerable GetRemoteFeeds();
- ///
- /// Must get the local target feeds into which artifacts of this
- /// type should be pushed.
- ///
- /// A set of local feeds.
- protected abstract IEnumerable GetLocalFeeds();
+ ///
+ /// Must get the local target feeds into which artifacts of this
+ /// type should be pushed.
+ ///
+ /// A set of local feeds.
+ protected abstract IEnumerable GetLocalFeeds();
- ///
- /// Must get the locally produced artifacts of this type.
- ///
- /// A set of local artifacts.
- protected abstract IEnumerable GetLocalArtifacts();
+ ///
+ /// Must get the locally produced artifacts of this type.
+ ///
+ /// A set of local artifacts.
+ protected abstract IEnumerable GetLocalArtifacts();
- }
}
diff --git a/CodeCakeBuilder/Abstractions/ICIPublishWorkflow.cs b/CodeCakeBuilder/Abstractions/ICIPublishWorkflow.cs
index b3524e5..f9db7cd 100644
--- a/CodeCakeBuilder/Abstractions/ICIPublishWorkflow.cs
+++ b/CodeCakeBuilder/Abstractions/ICIPublishWorkflow.cs
@@ -1,12 +1,11 @@
-namespace CodeCake.Abstractions
+namespace CodeCake.Abstractions;
+
+interface ICIPublishWorkflow
{
- interface ICIPublishWorkflow
- {
- ///
- /// Pack the solution: it produce the artifacts.
- ///
- void Pack();
+ ///
+ /// Pack the solution: it produce the artifacts.
+ ///
+ void Pack();
- ArtifactType ArtifactType { get; }
- }
+ ArtifactType ArtifactType { get; }
}
diff --git a/CodeCakeBuilder/Abstractions/ICIWorkflow.cs b/CodeCakeBuilder/Abstractions/ICIWorkflow.cs
index f407304..1fa0abd 100644
--- a/CodeCakeBuilder/Abstractions/ICIWorkflow.cs
+++ b/CodeCakeBuilder/Abstractions/ICIWorkflow.cs
@@ -1,20 +1,19 @@
-namespace CodeCake.Abstractions
+namespace CodeCake.Abstractions;
+
+public interface ICIWorkflow
{
- public interface ICIWorkflow
- {
- ///
- /// Try to clean the folder, for example by deleting bin & obj.
- ///
- void Clean();
+ ///
+ /// Try to clean the folder, for example by deleting bin & obj.
+ ///
+ void Clean();
- ///
- /// Build the solution.
- ///
- void Build();
+ ///
+ /// Build the solution.
+ ///
+ void Build();
- ///
- /// Run the unit tests of the solution.
- ///
- void Test();
- }
+ ///
+ /// Run the unit tests of the solution.
+ ///
+ void Test();
}
diff --git a/CodeCakeBuilder/Abstractions/ILocalArtifact.cs b/CodeCakeBuilder/Abstractions/ILocalArtifact.cs
index b8a0d3a..cb198d9 100644
--- a/CodeCakeBuilder/Abstractions/ILocalArtifact.cs
+++ b/CodeCakeBuilder/Abstractions/ILocalArtifact.cs
@@ -1,16 +1,15 @@
-namespace CodeCake.Abstractions
+namespace CodeCake.Abstractions;
+
+///
+/// Defines a locally produced artifact.
+/// This exposes an instance (with the version) even if it is the exact same version for all
+/// the artifact inside a repository: exposing the version here MAY enable, if needed, a "local"
+/// version definition for an artifact that COULD differ from the repository's one.
+///
+public interface ILocalArtifact
{
///
- /// Defines a locally produced artifact.
- /// This exposes an instance (with the version) even if it is the exact same version for all
- /// the artifact inside a repository: exposing the version here MAY enable, if needed, a "local"
- /// version definition for an artifact that COULD differ from the repository's one.
+ /// Gets the artifact instance that is produced.
///
- public interface ILocalArtifact
- {
- ///
- /// Gets the artifact instance that is produced.
- ///
- ArtifactInstance ArtifactInstance { get; }
- }
+ ArtifactInstance ArtifactInstance { get; }
}
diff --git a/CodeCakeBuilder/Build.CreateStandardGlobalInfo.cs b/CodeCakeBuilder/Build.CreateStandardGlobalInfo.cs
index 187ebdc..c74f744 100644
--- a/CodeCakeBuilder/Build.CreateStandardGlobalInfo.cs
+++ b/CodeCakeBuilder/Build.CreateStandardGlobalInfo.cs
@@ -2,85 +2,84 @@
using Cake.Common.Diagnostics;
using SimpleGitVersion;
-namespace CodeCake
+namespace CodeCake;
+
+public partial class Build
{
- public partial class Build
+ ///
+ /// Creates a new initialized by the
+ /// current environment.
+ ///
+ /// A new info object.
+ StandardGlobalInfo CreateStandardGlobalInfo()
{
- ///
- /// Creates a new initialized by the
- /// current environment.
- ///
- /// A new info object.
- StandardGlobalInfo CreateStandardGlobalInfo()
+ var result = new StandardGlobalInfo( Cake, Cake.GetRepositoryInfo().FinalBuildInfo );
+ // By default:
+ if( result.IsValid )
{
- var result = new StandardGlobalInfo( Cake, Cake.GetRepositoryInfo().FinalBuildInfo );
- // By default:
- if( result.IsValid )
+ // gitInfo is valid: it is either ci or a release build.
+ var v = result.BuildInfo.Version;
+ // If a /LocalFeed/ directory exists above, we publish the packages in it.
+ var localFeedRoot = Cake.FindSiblingDirectoryAbove( Cake.Environment.WorkingDirectory.FullPath, "LocalFeed" );
+ if( localFeedRoot != null )
{
- // gitInfo is valid: it is either ci or a release build.
- var v = result.BuildInfo.Version;
- // If a /LocalFeed/ directory exists above, we publish the packages in it.
- var localFeedRoot = Cake.FindSiblingDirectoryAbove( Cake.Environment.WorkingDirectory.FullPath, "LocalFeed" );
- if( localFeedRoot != null )
+ if( v.AsCSVersion == null )
{
- if( v.AsCSVersion == null )
+ if( v.Prerelease.EndsWith( ".local" ) )
{
- if( v.Prerelease.EndsWith( ".local" ) )
- {
- // Local releases must not be pushed on any remote and are copied to LocalFeed/Local
- // feed (if LocalFeed/ directory above exists).
- result.IsLocalCIRelease = true;
- result.LocalFeedPath = System.IO.Path.Combine( localFeedRoot, "Local" );
- }
- else
- {
- // CI build versions are routed to LocalFeed/CI
- result.LocalFeedPath = System.IO.Path.Combine( localFeedRoot, "CI" );
- }
+ // Local releases must not be pushed on any remote and are copied to LocalFeed/Local
+ // feed (if LocalFeed/ directory above exists).
+ result.IsLocalCIRelease = true;
+ result.LocalFeedPath = System.IO.Path.Combine( localFeedRoot, "Local" );
}
else
{
- // Release or prerelease go to LocalFeed/Release
- result.LocalFeedPath = System.IO.Path.Combine( localFeedRoot, "Release" );
+ // CI build versions are routed to LocalFeed/CI
+ result.LocalFeedPath = System.IO.Path.Combine( localFeedRoot, "CI" );
}
- System.IO.Directory.CreateDirectory( result.LocalFeedPath );
}
- else result.IsLocalCIRelease = v.Prerelease.EndsWith( ".local" );
-
- // Creating the right remote feed.
- if( !result.IsLocalCIRelease
- && (Cake.InteractiveMode() == InteractiveMode.NoInteraction
- || Cake.ReadInteractiveOption( "PushToRemote", "Push to Remote feeds?", 'Y', 'N' ) == 'Y') )
+ else
{
- result.PushToRemote = true;
+ // Release or prerelease go to LocalFeed/Release
+ result.LocalFeedPath = System.IO.Path.Combine( localFeedRoot, "Release" );
}
+ System.IO.Directory.CreateDirectory( result.LocalFeedPath );
+ }
+ else result.IsLocalCIRelease = v.Prerelease.EndsWith( ".local" );
+
+ // Creating the right remote feed.
+ if( !result.IsLocalCIRelease
+ && (Cake.InteractiveMode() == InteractiveMode.NoInteraction
+ || Cake.ReadInteractiveOption( "PushToRemote", "Push to Remote feeds?", 'Y', 'N' ) == 'Y') )
+ {
+ result.PushToRemote = true;
+ }
+ }
+ else
+ {
+ if( Cake.InteractiveMode() != InteractiveMode.NoInteraction
+ && Cake.ReadInteractiveOption( "PublishDirtyRepo", "Repository is not ready to be published. Proceed anyway?", 'Y', 'N' ) == 'Y' )
+ {
+ Cake.Warning( "Unable to compute a valid version, but you choose to continue..." );
+ result.IgnoreNoArtifactsToProduce = true;
}
else
{
- if( Cake.InteractiveMode() != InteractiveMode.NoInteraction
- && Cake.ReadInteractiveOption( "PublishDirtyRepo", "Repository is not ready to be published. Proceed anyway?", 'Y', 'N' ) == 'Y' )
+ // On Appveyor, we let the build run: this gracefully handles Pull Requests.
+ if( Cake.AppVeyor().IsRunningOnAppVeyor )
{
- Cake.Warning( "Unable to compute a valid version, but you choose to continue..." );
result.IgnoreNoArtifactsToProduce = true;
}
else
{
- // On Appveyor, we let the build run: this gracefully handles Pull Requests.
- if( Cake.AppVeyor().IsRunningOnAppVeyor )
- {
- result.IgnoreNoArtifactsToProduce = true;
- }
- else
- {
- Cake.TerminateWithError( "Repository is not ready to be published." );
- }
+ Cake.TerminateWithError( "Repository is not ready to be published." );
}
- // When the gitInfo is not valid, we do not try to push any packages, even if the build continues
- // (either because the user choose to continue or if we are on the CI server).
- // We don't need to worry about feeds here.
}
- return result;
+ // When the gitInfo is not valid, we do not try to push any packages, even if the build continues
+ // (either because the user choose to continue or if we are on the CI server).
+ // We don't need to worry about feeds here.
}
-
+ return result;
}
+
}
diff --git a/CodeCakeBuilder/Build.cs b/CodeCakeBuilder/Build.cs
index 2b214e3..55a57d0 100644
--- a/CodeCakeBuilder/Build.cs
+++ b/CodeCakeBuilder/Build.cs
@@ -2,76 +2,75 @@
using Cake.Core;
using Cake.Core.Diagnostics;
-namespace CodeCake
-{
+namespace CodeCake;
+
- ///
- /// Sample build "script".
- /// Build scripts can be decorated with AddPath attributes that inject existing paths into the PATH environment variable.
- ///
+///
+/// Sample build "script".
+/// Build scripts can be decorated with AddPath attributes that inject existing paths into the PATH environment variable.
+///
- public partial class Build : CodeCakeHost
+public partial class Build : CodeCakeHost
+{
+ public Build()
{
- public Build()
- {
- Cake.Log.Verbosity = Verbosity.Diagnostic;
+ Cake.Log.Verbosity = Verbosity.Diagnostic;
+
+ StandardGlobalInfo globalInfo = CreateStandardGlobalInfo()
+ .AddDotnet()
+ .SetCIBuildTag();
+
+ Task( "Check-Repository" )
+ .Does( () =>
+ {
+ globalInfo.TerminateIfShouldStop();
+ } );
- StandardGlobalInfo globalInfo = CreateStandardGlobalInfo()
- .AddDotnet()
- .SetCIBuildTag();
+ Task( "Clean" )
+ .IsDependentOn( "Check-Repository" )
+ .Does( () =>
+ {
+ globalInfo.GetDotnetSolution().Clean();
+ Cake.CleanDirectories( globalInfo.ReleasesFolder.ToString() );
- Task( "Check-Repository" )
- .Does( () =>
- {
- globalInfo.TerminateIfShouldStop();
- } );
+ } );
- Task( "Clean" )
- .IsDependentOn( "Check-Repository" )
- .Does( () =>
- {
- globalInfo.GetDotnetSolution().Clean();
- Cake.CleanDirectories( globalInfo.ReleasesFolder.ToString() );
-
- } );
+ Task( "Build" )
+ .IsDependentOn( "Check-Repository" )
+ .IsDependentOn( "Clean" )
+ .Does( () =>
+ {
+ globalInfo.GetDotnetSolution().Build();
+ } );
- Task( "Build" )
- .IsDependentOn( "Check-Repository" )
- .IsDependentOn( "Clean" )
- .Does( () =>
- {
- globalInfo.GetDotnetSolution().Build();
- } );
+ Task( "Unit-Testing" )
+ .IsDependentOn( "Build" )
+ .WithCriteria( () => Cake.InteractiveMode() == InteractiveMode.NoInteraction
+ || Cake.ReadInteractiveOption( "RunUnitTests", "Run Unit Tests?", 'Y', 'N' ) == 'Y' )
+ .Does( () =>
+ {
- Task( "Unit-Testing" )
- .IsDependentOn( "Build" )
- .WithCriteria( () => Cake.InteractiveMode() == InteractiveMode.NoInteraction
- || Cake.ReadInteractiveOption( "RunUnitTests", "Run Unit Tests?", 'Y', 'N' ) == 'Y' )
- .Does( () =>
- {
-
- globalInfo.GetDotnetSolution().Test();
- } );
+ globalInfo.GetDotnetSolution().SolutionTest();
+ } );
- Task( "Create-NuGet-Packages" )
- .WithCriteria( () => globalInfo.IsValid )
- .IsDependentOn( "Unit-Testing" )
- .Does( () =>
- {
- globalInfo.GetDotnetSolution().Pack();
- } );
+ Task( "Create-NuGet-Packages" )
+ .WithCriteria( () => globalInfo.IsValid )
+ .IsDependentOn( "Unit-Testing" )
+ .Does( () =>
+ {
+ globalInfo.GetDotnetSolution().Pack();
+ } );
- Task( "Push-Artifacts" )
- .IsDependentOn( "Create-NuGet-Packages" )
- .WithCriteria( () => globalInfo.IsValid )
- .Does( async () =>
- {
- await globalInfo.PushArtifactsAsync();
- } );
+ Task( "Push-Artifacts" )
+ .IsDependentOn( "Create-NuGet-Packages" )
+ .WithCriteria( () => globalInfo.IsValid )
+ .Does( async () =>
+ {
+ await globalInfo.PushArtifactsAsync();
+ } );
- // The Default task for this script can be set here.
- Task( "Default" )
- .IsDependentOn( "Push-Artifacts" );
- }
+ // The Default task for this script can be set here.
+ Task( "Default" )
+ .IsDependentOn( "Push-Artifacts" );
}
}
diff --git a/CodeCakeBuilder/CodeCakeBuilder.csproj b/CodeCakeBuilder/CodeCakeBuilder.csproj
index 3ffdef4..4d0d3c3 100644
--- a/CodeCakeBuilder/CodeCakeBuilder.csproj
+++ b/CodeCakeBuilder/CodeCakeBuilder.csproj
@@ -1,23 +1,24 @@
- net6.0
+ net8.0
Exe
false
false
false
false
+ annotations
-
+
-
+
-
+
diff --git a/CodeCakeBuilder/Program.cs b/CodeCakeBuilder/Program.cs
index 76b49cd..adbb42f 100644
--- a/CodeCakeBuilder/Program.cs
+++ b/CodeCakeBuilder/Program.cs
@@ -2,31 +2,30 @@
using System.Linq;
using System.Threading.Tasks;
-namespace CodeCake
+namespace CodeCake;
+
+class Program
{
- class Program
- {
- ///
- /// Basic parameter that sets the solution directory as being the current directory
- /// instead of using the default lookup to "Solution/Builder/bin/[Configuration]/[targetFramework]" folder.
- /// Check of this argument uses .
- ///
- const string SolutionDirectoryIsCurrentDirectoryParameter = "SolutionDirectoryIsCurrentDirectory";
+ ///
+ /// Basic parameter that sets the solution directory as being the current directory
+ /// instead of using the default lookup to "Solution/Builder/bin/[Configuration]/[targetFramework]" folder.
+ /// Check of this argument uses .
+ ///
+ const string SolutionDirectoryIsCurrentDirectoryParameter = "SolutionDirectoryIsCurrentDirectory";
- ///
- /// CodeCakeBuilder entry point. This is a default, simple, implementation that can
- /// be extended as needed.
- ///
- /// The command line arguments.
- /// An error code (typically negative), 0 on success.
- static async Task Main( string[] args )
- {
- string? solutionDirectory = args.Contains( SolutionDirectoryIsCurrentDirectoryParameter, StringComparer.OrdinalIgnoreCase )
- ? Environment.CurrentDirectory
- : null;
- var app = new CodeCakeApplication( solutionDirectory );
- RunResult result = await app.RunAsync( args.Where( a => !StringComparer.OrdinalIgnoreCase.Equals( a, SolutionDirectoryIsCurrentDirectoryParameter ) ) );
- return result.ReturnCode;
- }
+ ///
+ /// CodeCakeBuilder entry point. This is a default, simple, implementation that can
+ /// be extended as needed.
+ ///
+ /// The command line arguments.
+ /// An error code (typically negative), 0 on success.
+ static async Task Main( string[] args )
+ {
+ string? solutionDirectory = args.Contains( SolutionDirectoryIsCurrentDirectoryParameter, StringComparer.OrdinalIgnoreCase )
+ ? Environment.CurrentDirectory
+ : null;
+ var app = new CodeCakeApplication( solutionDirectory );
+ RunResult result = await app.RunAsync( args.Where( a => !StringComparer.OrdinalIgnoreCase.Equals( a, SolutionDirectoryIsCurrentDirectoryParameter ) ) );
+ return result.ReturnCode;
}
}
diff --git a/CodeCakeBuilder/StandardGlobalInfo.cs b/CodeCakeBuilder/StandardGlobalInfo.cs
index 885eeac..929bc6d 100644
--- a/CodeCakeBuilder/StandardGlobalInfo.cs
+++ b/CodeCakeBuilder/StandardGlobalInfo.cs
@@ -15,247 +15,245 @@
using System.Net.Http;
using System.Threading.Tasks;
-namespace CodeCake
+namespace CodeCake;
+
+///
+/// Exposes global state information for the build script.
+///
+public class StandardGlobalInfo
{
+ readonly ICakeContext _ctx;
+ readonly HashSet _solutions = new HashSet();
+ List? _artifactPushes;
+ bool _ignoreNoArtifactsToProduce;
+
+ static StandardGlobalInfo()
+ {
+ SharedHttpClient = new HttpClient();
+ }
+
+ public StandardGlobalInfo( ICakeContext ctx, ICommitBuildInfo finalBuildInfo )
+ {
+ _ctx = ctx;
+ BuildInfo = finalBuildInfo;
+ ReleasesFolder = "CodeCakeBuilder/Releases";
+ Directory.CreateDirectory( ReleasesFolder );
+ }
+
+ public void RegisterSolution( ICIWorkflow solution )
+ {
+ _solutions.Add( solution );
+ }
+
///
- /// Exposes global state information for the build script.
+ /// Gets the Cake context.
///
- public class StandardGlobalInfo
- {
- readonly ICakeContext _ctx;
- readonly HashSet _solutions = new HashSet();
- List? _artifactPushes;
- bool _ignoreNoArtifactsToProduce;
+ public ICakeContext Cake => _ctx;
- static StandardGlobalInfo()
- {
- SharedHttpClient = new HttpClient();
- }
+ ///
+ /// Gets the for this commit.
+ /// This holds the and of this commit.
+ /// If is the then this is not really a
+ /// valid build.
+ ///
+ public ICommitBuildInfo BuildInfo { get; }
- public StandardGlobalInfo( ICakeContext ctx, ICommitBuildInfo finalBuildInfo )
- {
- _ctx = ctx;
- BuildInfo = finalBuildInfo;
- ReleasesFolder = "CodeCakeBuilder/Releases";
- Directory.CreateDirectory( ReleasesFolder );
- }
+ ///
+ /// Gets whether the is not the .
+ ///
+ public bool IsValid => BuildInfo.IsValid();
+
+ IEnumerable SolutionProducingArtifacts => Solutions.OfType();
+
+ ///
+ /// Gets the set of of the that have been registered.
+ ///
+ public IEnumerable ArtifactTypes => SolutionProducingArtifacts.Select( p => p.ArtifactType );
+
+ ///
+ /// Gets the release folder: "CodeCakeBuilder/Releases".
+ ///
+ public NormalizedPath ReleasesFolder { get; }
+
+ ///
+ /// Gets whether this is a purely local build.
+ ///
+ public bool IsLocalCIRelease { get; set; }
+
+ ///
+ /// Shared http client.
+ /// See: https://aspnetmonsters.com/2016/08/2016-08-27-httpclientwrong/
+ /// Do not add any default on it.
+ ///
+ public static readonly HttpClient SharedHttpClient;
- public void RegisterSolution( ICIWorkflow solution )
+ ///
+ /// Gets whether artifacts should be pushed to remote feeds.
+ ///
+ public bool PushToRemote { get; set; }
+
+ ///
+ /// Gets or sets the local feed path.
+ /// Can be null if no local feed exists or if local feed should be ignored.
+ ///
+ public string? LocalFeedPath { get; set; }
+
+ ///
+ /// Gets or sets whether should be ignored.
+ /// Defaults to false: by default if there is no packages to produce is true.
+ ///
+ public bool IgnoreNoArtifactsToProduce
+ {
+ get
{
- _solutions.Add( solution );
+ return Cake.Argument( "IgnoreNoArtifactsToProduce", 'N' ) == 'Y' || _ignoreNoArtifactsToProduce;
}
-
- ///
- /// Gets the Cake context.
- ///
- public ICakeContext Cake => _ctx;
-
- ///
- /// Gets the for this commit.
- /// This holds the and of this commit.
- /// If is the then this is not really a
- /// valid build.
- ///
- public ICommitBuildInfo BuildInfo { get; }
-
- ///
- /// Gets whether the is not the .
- ///
- public bool IsValid => BuildInfo.IsValid();
-
- IEnumerable SolutionProducingArtifacts => Solutions.OfType();
-
- ///
- /// Gets the set of of the that have been registered.
- ///
- public IEnumerable ArtifactTypes => SolutionProducingArtifacts.Select( p => p.ArtifactType );
-
- ///
- /// Gets the release folder: "CodeCakeBuilder/Releases".
- ///
- public NormalizedPath ReleasesFolder { get; }
-
- ///
- /// Gets whether this is a purely local build.
- ///
- public bool IsLocalCIRelease { get; set; }
-
- ///
- /// Shared http client.
- /// See: https://aspnetmonsters.com/2016/08/2016-08-27-httpclientwrong/
- /// Do not add any default on it.
- ///
- public static readonly HttpClient SharedHttpClient;
-
- ///
- /// Gets whether artifacts should be pushed to remote feeds.
- ///
- public bool PushToRemote { get; set; }
-
- ///
- /// Gets or sets the local feed path.
- /// Can be null if no local feed exists or if local feed should be ignored.
- ///
- public string? LocalFeedPath { get; set; }
-
- ///
- /// Gets or sets whether should be ignored.
- /// Defaults to false: by default if there is no packages to produce is true.
- ///
- public bool IgnoreNoArtifactsToProduce
+ set
{
- get
- {
- return Cake.Argument( "IgnoreNoArtifactsToProduce", 'N' ) == 'Y' || _ignoreNoArtifactsToProduce;
- }
- set
- {
- _ignoreNoArtifactsToProduce = value;
- }
+ _ignoreNoArtifactsToProduce = value;
}
+ }
+
+ ///
+ /// Gets whether is empty: all artifacts are already available in all
+ /// artifact repositories: unless is set to true, there is nothing to
+ /// do and is true.
+ ///
+ public bool NoArtifactsToProduce => !GetArtifactPushList().Any();
- ///
- /// Gets whether is empty: all artifacts are already available in all
- /// artifact repositories: unless is set to true, there is nothing to
- /// do and is true.
- ///
- public bool NoArtifactsToProduce => !GetArtifactPushList().Any();
-
- ///
- /// Gets a read only list of all the pushes of artifacts for all .
- ///
- ///
- /// True to recompute the list from all
- /// (without reseting them).
- ///
- /// The set of pushes.
- public IReadOnlyList GetArtifactPushList( bool reset = false )
+ ///
+ /// Gets a read only list of all the pushes of artifacts for all .
+ ///
+ ///
+ /// True to recompute the list from all
+ /// (without reseting them).
+ ///
+ /// The set of pushes.
+ public IReadOnlyList GetArtifactPushList( bool reset = false )
+ {
+ if( _artifactPushes == null || reset )
{
- if( _artifactPushes == null || reset )
+ _artifactPushes = new List();
+ var tasks = ArtifactTypes.Select( f => f.GetPushListAsync() ).ToArray();
+ Task.WaitAll( tasks );
+ foreach( var p in tasks.Select( t => t.Result ) )
{
- _artifactPushes = new List();
- var tasks = ArtifactTypes.Select( f => f.GetPushListAsync() ).ToArray();
- Task.WaitAll( tasks );
- foreach( var p in tasks.Select( t => t.Result ) )
- {
- _artifactPushes.AddRange( p );
- }
+ _artifactPushes.AddRange( p );
}
- return _artifactPushes;
}
+ return _artifactPushes;
+ }
- ///
- /// Gets whether there is no artifact to produce and is false.
- ///
- public bool ShouldStop => NoArtifactsToProduce && !IgnoreNoArtifactsToProduce;
+ ///
+ /// Gets whether there is no artifact to produce and is false.
+ ///
+ public bool ShouldStop => NoArtifactsToProduce && !IgnoreNoArtifactsToProduce;
- public IReadOnlyCollection Solutions => _solutions;
+ public IReadOnlyCollection Solutions => _solutions;
- #region Memory key support.
+ #region Memory key support.
- string MemoryFilePath => $"CodeCakeBuilder/MemoryKey.{BuildInfo.CommitSha}.txt";
+ string MemoryFilePath => $"CodeCakeBuilder/MemoryKey.{BuildInfo.CommitSha}.txt";
- public void WriteCommitMemoryKey( NormalizedPath key )
- {
- if( BuildInfo.IsValid() ) File.AppendAllLines( MemoryFilePath, new[] { key.ToString() } );
- }
+ public void WriteCommitMemoryKey( NormalizedPath key )
+ {
+ if( BuildInfo.IsValid() ) File.AppendAllLines( MemoryFilePath, new[] { key.ToString() } );
+ }
- public bool CheckCommitMemoryKey( NormalizedPath key )
+ public bool CheckCommitMemoryKey( NormalizedPath key )
+ {
+ bool done = File.Exists( MemoryFilePath )
+ ? Array.IndexOf( File.ReadAllLines( MemoryFilePath ), key.Path ) >= 0
+ : false;
+ if( done )
{
- bool done = File.Exists( MemoryFilePath )
- ? Array.IndexOf( File.ReadAllLines( MemoryFilePath ), key.Path ) >= 0
- : false;
- if( done )
+ if( !BuildInfo.IsValid() )
+ {
+ Cake.Information( $"Zero commit. Key exists but is ignored: {key}" );
+ done = false;
+ }
+ else
{
- if( !BuildInfo.IsValid() )
- {
- Cake.Information( $"Zero commit. Key exists but is ignored: {key}" );
- done = false;
- }
- else
- {
- Cake.Information( $"Key exists on this commit: {key}" );
- }
+ Cake.Information( $"Key exists on this commit: {key}" );
}
- return done;
}
+ return done;
+ }
+
+ #endregion
+
+ ///
+ /// Simply calls on each
+ /// with their correct typed artifacts.
+ ///
+ public Task PushArtifactsAsync( IEnumerable? pushes = null )
+ {
+ if( pushes == null ) pushes = GetArtifactPushList();
+ return Task.WhenAll( ArtifactTypes.Select( t => t.PushAsync( pushes.Where( a => a.Feed.ArtifactType == t ) ) ) );
+ }
- #endregion
+ ///
+ /// Tags the build when running on Appveyor or AzureDevOps (GitLab does not support this).
+ /// Note that if is true, " (Skipped)" is appended.
+ ///
+ /// This info object (allowing fluent syntax).
+ public StandardGlobalInfo SetCIBuildTag()
+ {
+ string AddSkipped( string s ) => ShouldStop ? s + " (Skipped)" : s;
- ///
- /// Simply calls on each
- /// with their correct typed artifacts.
- ///
- public Task PushArtifactsAsync( IEnumerable? pushes = null )
+ string ComputeAzurePipelineUpdateBuildVersion( ICommitBuildInfo buildInfo )
{
- if( pushes == null ) pushes = GetArtifactPushList();
- return Task.WhenAll( ArtifactTypes.Select( t => t.PushAsync( pushes.Where( a => a.Feed.ArtifactType == t ) ) ) );
+ // Azure (formerly VSTS, formerly VSO) analyzes the stdout to set its build number.
+ // On clash, the default Azure/VSTS/VSO build number is used: to ensure that the actual
+ // version will be always be available we need to inject a uniquifier.
+ string buildVersion = AddSkipped( $"{buildInfo.Version}_{DateTime.UtcNow:yyyyMMdd-HHmmss}" );
+ Cake.Information( $"Using Azure build number: {buildVersion}" );
+ return $"##vso[build.updatebuildnumber]{buildVersion}";
}
- ///
- /// Tags the build when running on Appveyor or AzureDevOps (GitLab does not support this).
- /// Note that if is true, " (Skipped)" is appended.
- ///
- /// This info object (allowing fluent syntax).
- public StandardGlobalInfo SetCIBuildTag()
+ void AzurePipelineUpdateBuildVersion( string buildInstruction )
{
- string AddSkipped( string s ) => ShouldStop ? s + " (Skipped)" : s;
-
- string ComputeAzurePipelineUpdateBuildVersion( ICommitBuildInfo buildInfo )
- {
- // Azure (formerly VSTS, formerly VSO) analyzes the stdout to set its build number.
- // On clash, the default Azure/VSTS/VSO build number is used: to ensure that the actual
- // version will be always be available we need to inject a uniquifier.
- string buildVersion = AddSkipped( $"{buildInfo.Version}_{DateTime.UtcNow:yyyyMMdd-HHmmss}" );
- Cake.Information( $"Using Azure build number: {buildVersion}" );
- return $"##vso[build.updatebuildnumber]{buildVersion}";
- }
+ Console.WriteLine();
+ Console.WriteLine( buildInstruction );
+ Console.WriteLine();
+ }
- void AzurePipelineUpdateBuildVersion( string buildInstruction )
+ IAppVeyorProvider appVeyor = Cake.AppVeyor();
+ IAzurePipelinesProvider azure = Cake.AzurePipelines();
+ try
+ {
+ if( appVeyor.IsRunningOnAppVeyor )
{
- Console.WriteLine();
- Console.WriteLine( buildInstruction );
- Console.WriteLine();
+ appVeyor.UpdateBuildVersion( AddSkipped( BuildInfo.Version.ToString() ) );
}
- IAppVeyorProvider appVeyor = Cake.AppVeyor();
- IAzurePipelinesProvider azure = Cake.AzurePipelines();
- try
- {
- if( appVeyor.IsRunningOnAppVeyor )
- {
- appVeyor.UpdateBuildVersion( AddSkipped( BuildInfo.Version.ToString() ) );
- }
-
- if( azure.IsRunningOnAzurePipelines )
- {
- string azureVersion = ComputeAzurePipelineUpdateBuildVersion( BuildInfo );
- AzurePipelineUpdateBuildVersion( azureVersion );
- }
- }
- catch( Exception e )
+ if( azure.IsRunningOnAzurePipelines )
{
- Cake.Warning( "Could not set the Build Version!" );
- Cake.Warning( e );
+ string azureVersion = ComputeAzurePipelineUpdateBuildVersion( BuildInfo );
+ AzurePipelineUpdateBuildVersion( azureVersion );
}
-
- return this;
}
-
- ///
- /// Terminates the script with success if is true.
- /// (Calls Cake.TerminateWithSuccess.)
- ///
- /// This info object (allowing fluent syntax).
- public StandardGlobalInfo TerminateIfShouldStop()
+ catch( Exception e )
{
- if( ShouldStop )
- {
- Cake.TerminateWithSuccess( "All packages from this commit are already available. Build skipped." );
- }
- return this;
+ Cake.Warning( "Could not set the Build Version!" );
+ Cake.Warning( e );
}
+ return this;
+ }
+
+ ///
+ /// Terminates the script with success if is true.
+ /// (Calls Cake.TerminateWithSuccess.)
+ ///
+ /// This info object (allowing fluent syntax).
+ public StandardGlobalInfo TerminateIfShouldStop()
+ {
+ if( ShouldStop )
+ {
+ Cake.TerminateWithSuccess( "All packages from this commit are already available. Build skipped." );
+ }
+ return this;
}
}
diff --git a/CodeCakeBuilder/dotnet/Build.NuGetArtifactType.cs b/CodeCakeBuilder/dotnet/Build.NuGetArtifactType.cs
index 89fea38..35ae52a 100644
--- a/CodeCakeBuilder/dotnet/Build.NuGetArtifactType.cs
+++ b/CodeCakeBuilder/dotnet/Build.NuGetArtifactType.cs
@@ -9,103 +9,102 @@
using System.Linq;
using static CodeCake.Build;
-namespace CodeCake
+namespace CodeCake;
+
+
+public partial class DotnetSolution : ICIPublishWorkflow
{
+ private ArtifactType? _artifactType;
- public partial class DotnetSolution : ICIPublishWorkflow
+ public ArtifactType ArtifactType
{
- private ArtifactType? _artifactType;
-
- public ArtifactType ArtifactType
+ get
{
- get
- {
- if( _artifactType == null ) _artifactType = new NuGetArtifactType( _globalInfo, this );
- return _artifactType;
- }
+ if( _artifactType == null ) _artifactType = new NuGetArtifactType( _globalInfo, this );
+ return _artifactType;
}
+ }
- public void Pack()
+ public void Pack()
+ {
+ var nugetInfo = _globalInfo.ArtifactTypes.OfType().Single();
+ var settings = new DotNetPackSettings().AddVersionArguments( _globalInfo.BuildInfo, c =>
{
- var nugetInfo = _globalInfo.ArtifactTypes.OfType().Single();
- var settings = new DotNetPackSettings().AddVersionArguments( _globalInfo.BuildInfo, c =>
- {
- c.NoBuild = true;
- // Includes the .pdb in package.
- c.IncludeSymbols = true;
- c.Configuration = _globalInfo.BuildInfo.BuildConfiguration;
- c.OutputDirectory = _globalInfo.ReleasesFolder.Path;
- } );
- foreach( var p in nugetInfo.GetNuGetArtifacts() )
- {
- _globalInfo.Cake.Information( p.ArtifactInstance );
- _globalInfo.Cake.DotNetPack( p.Project.Path.FullPath, settings );
- }
+ c.NoBuild = true;
+ // Includes the .pdb in package.
+ c.IncludeSymbols = true;
+ c.Configuration = _globalInfo.BuildInfo.BuildConfiguration;
+ c.OutputDirectory = _globalInfo.ReleasesFolder.Path;
+ } );
+ foreach( var p in nugetInfo.GetNuGetArtifacts() )
+ {
+ _globalInfo.Cake.Information( p.ArtifactInstance );
+ _globalInfo.Cake.DotNetPack( p.Project.Path.FullPath, settings );
}
}
+}
- public partial class Build
+public partial class Build
+{
+ ///
+ /// Implements NuGet package handling.
+ ///
+ public class NuGetArtifactType : ArtifactType
{
- ///
- /// Implements NuGet package handling.
- ///
- public class NuGetArtifactType : ArtifactType
- {
- readonly DotnetSolution _solution;
+ readonly DotnetSolution _solution;
- public class NuGetArtifact : ILocalArtifact
+ public class NuGetArtifact : ILocalArtifact
+ {
+ public NuGetArtifact( SolutionProject p, SVersion v )
{
- public NuGetArtifact( SolutionProject p, SVersion v )
- {
- Project = p;
- ArtifactInstance = new ArtifactInstance( "NuGet", p.Name, v );
- }
+ Project = p;
+ ArtifactInstance = new ArtifactInstance( "NuGet", p.Name, v );
+ }
- public ArtifactInstance ArtifactInstance { get; }
+ public ArtifactInstance ArtifactInstance { get; }
- public SolutionProject Project { get; }
- }
+ public SolutionProject Project { get; }
+ }
- public NuGetArtifactType( StandardGlobalInfo globalInfo, DotnetSolution solution )
- : base( globalInfo, "NuGet" )
- {
- _solution = solution;
- }
+ public NuGetArtifactType( StandardGlobalInfo globalInfo, DotnetSolution solution )
+ : base( globalInfo, "NuGet" )
+ {
+ _solution = solution;
+ }
- ///
- /// Downcasts the mutable list as a set of .
- ///
- /// The set of NuGet artifacts.
- public IEnumerable GetNuGetArtifacts() => GetArtifacts().Cast();
-
- ///
- /// Gets the remote target feeds.
- ///
- /// The set of remote NuGet feeds (in practice at most one).
- protected override IEnumerable GetRemoteFeeds()
- {if( GlobalInfo.BuildInfo.Version.PackageQuality >= CSemVer.PackageQuality.ReleaseCandidate ) yield return new RemoteFeed( this, "nuget.org", "https://api.nuget.org/v3/index.json", "NUGET_ORG_PUSH_API_KEY" );
-if( GlobalInfo.BuildInfo.Version.PackageQuality <= CSemVer.PackageQuality.Stable ) yield return new SignatureVSTSFeed( this, "Signature-OpenSource","NetCore3", "Feeds");
+ ///
+ /// Downcasts the mutable list as a set of .
+ ///
+ /// The set of NuGet artifacts.
+ public IEnumerable GetNuGetArtifacts() => GetArtifacts().Cast();
+
+ ///
+ /// Gets the remote target feeds.
+ ///
+ /// The set of remote NuGet feeds (in practice at most one).
+ protected override IEnumerable GetRemoteFeeds()
+ {if( GlobalInfo.BuildInfo.Version.PackageQuality >= CSemVer.PackageQuality.ReleaseCandidate ) yield return new RemoteFeed( this, "nuget.org", "https://api.nuget.org/v3/index.json", "NUGET_ORG_PUSH_API_KEY" );
+yield return new SignatureVSTSFeed( this, "Signature-OpenSource","NetCore3", "Feeds");
}
- ///
- /// Gets the local target feeds.
- ///
- /// The set of remote NuGet feeds (in practice at most one).
- protected override IEnumerable GetLocalFeeds()
- {
- return new NuGetHelper.NuGetFeed[] {
- new NugetLocalFeed( this, GlobalInfo.LocalFeedPath )
- };
- }
+ ///
+ /// Gets the local target feeds.
+ ///
+ /// The set of remote NuGet feeds (in practice at most one).
+ protected override IEnumerable GetLocalFeeds()
+ {
+ return new NuGetHelper.NuGetFeed[] {
+ new NugetLocalFeed( this, GlobalInfo.LocalFeedPath )
+ };
+ }
- protected override IEnumerable GetLocalArtifacts()
- {
- return _solution.ProjectsToPublish.Select( p => new NuGetArtifact( p, GlobalInfo.BuildInfo.Version ) );
- }
+ protected override IEnumerable GetLocalArtifacts()
+ {
+ return _solution.ProjectsToPublish.Select( p => new NuGetArtifact( p, GlobalInfo.BuildInfo.Version ) );
}
}
}
diff --git a/CodeCakeBuilder/dotnet/Build.NuGetHelper.cs b/CodeCakeBuilder/dotnet/Build.NuGetHelper.cs
index a3b7683..f6fa7cc 100644
--- a/CodeCakeBuilder/dotnet/Build.NuGetHelper.cs
+++ b/CodeCakeBuilder/dotnet/Build.NuGetHelper.cs
@@ -20,531 +20,531 @@
using System.Threading;
using System.Threading.Tasks;
-namespace CodeCake
+namespace CodeCake;
+
+public partial class Build
{
- public partial class Build
+ public static class NuGetHelper
{
- public static class NuGetHelper
+ static readonly SourceCacheContext _sourceCache;
+ static readonly List> _providers;
+ static readonly ISettings _settings;
+ static readonly PackageProviderProxy _sourceProvider;
+ static readonly List _vstsFeeds;
+ static ILogger _logger;
+
+ ///
+ /// Implements a IPackageSourceProvider that mixes sources from NuGet.config settings
+ /// and sources that are used by the build chain.
+ ///
+ class PackageProviderProxy : IPackageSourceProvider
{
- static readonly SourceCacheContext _sourceCache;
- static readonly List> _providers;
- static readonly ISettings _settings;
- static readonly PackageProviderProxy _sourceProvider;
- static readonly List _vstsFeeds;
- static ILogger _logger;
+ readonly IPackageSourceProvider _fromSettings;
+ readonly Lazy> _sources;
+ int _definedSourceCount;
- ///
- /// Implements a IPackageSourceProvider that mixes sources from NuGet.config settings
- /// and sources that are used by the build chain.
- ///
- class PackageProviderProxy : IPackageSourceProvider
+ public PackageProviderProxy( ISettings settings )
{
- readonly IPackageSourceProvider _fromSettings;
- readonly Lazy> _sources;
- int _definedSourceCount;
+ _fromSettings = new PackageSourceProvider( settings );
+ _sources = new Lazy>( () => new List( _fromSettings.LoadPackageSources() ) );
+ }
- public PackageProviderProxy( ISettings settings )
+ public PackageSource FindOrCreateFromUrl( string name, string urlV3 )
+ {
+ if( string.IsNullOrEmpty( urlV3 ) || (!new Uri( urlV3 ).IsFile && !urlV3.EndsWith( "/v3/index.json" )) )
{
- _fromSettings = new PackageSourceProvider( settings );
- _sources = new Lazy>( () => new List( _fromSettings.LoadPackageSources() ) );
+ throw new ArgumentException( "Feed requires a /v3/index.json url.", nameof( urlV3 ) );
}
-
- public PackageSource FindOrCreateFromUrl( string name, string urlV3 )
+ if( string.IsNullOrWhiteSpace( name ) )
{
- if( string.IsNullOrEmpty( urlV3 ) || (!new Uri( urlV3 ).IsFile && !urlV3.EndsWith( "/v3/index.json" )) )
- {
- throw new ArgumentException( "Feed requires a /v3/index.json url.", nameof( urlV3 ) );
- }
- if( string.IsNullOrWhiteSpace( name ) )
- {
- throw new ArgumentNullException( nameof( name ) );
- }
- var exists = _sources.Value.FirstOrDefault( s => !s.IsLocal && s.Source == urlV3 );
- if( exists != null ) return exists;
- exists = new PackageSource( urlV3, "CCB-" + name );
- _sources.Value.Insert( _definedSourceCount++, exists );
- return exists;
+ throw new ArgumentNullException( nameof( name ) );
}
+ var exists = _sources.Value.FirstOrDefault( s => !s.IsLocal && s.Source == urlV3 );
+ if( exists != null ) return exists;
+ exists = new PackageSource( urlV3, "CCB-" + name );
+ _sources.Value.Insert( _definedSourceCount++, exists );
+ return exists;
+ }
- public PackageSource FindOrCreateFromLocalPath( string localPath )
- {
- if( string.IsNullOrWhiteSpace( localPath ) ) throw new ArgumentNullException( nameof( localPath ) );
- NormalizedPath path = System.IO.Path.GetFullPath( localPath );
- var exists = _sources.Value.FirstOrDefault( s => s.IsLocal && new NormalizedPath( s.Source ) == path );
- if( exists != null ) return exists;
- exists = new PackageSource( path, "CCB-" + path.LastPart );
- _sources.Value.Insert( _definedSourceCount++, exists );
- return exists;
- }
-
- string IPackageSourceProvider.ActivePackageSourceName => _fromSettings.ActivePackageSourceName;
-
- string IPackageSourceProvider.DefaultPushSource => _fromSettings.DefaultPushSource;
-
- event EventHandler IPackageSourceProvider.PackageSourcesChanged { add { } remove { } }
+ public PackageSource FindOrCreateFromLocalPath( string localPath )
+ {
+ if( string.IsNullOrWhiteSpace( localPath ) ) throw new ArgumentNullException( nameof( localPath ) );
+ NormalizedPath path = System.IO.Path.GetFullPath( localPath );
+ var exists = _sources.Value.FirstOrDefault( s => s.IsLocal && new NormalizedPath( s.Source ) == path );
+ if( exists != null ) return exists;
+ exists = new PackageSource( path, "CCB-" + path.LastPart );
+ _sources.Value.Insert( _definedSourceCount++, exists );
+ return exists;
+ }
- ///
- /// Gets all the sources.
- ///
- ///
- public IEnumerable LoadPackageSources() => _sources.Value;
+ string IPackageSourceProvider.ActivePackageSourceName => _fromSettings.ActivePackageSourceName;
- bool IPackageSourceProvider.IsPackageSourceEnabled( string name ) => true;
+ string IPackageSourceProvider.DefaultPushSource => _fromSettings.DefaultPushSource;
- void IPackageSourceProvider.SaveActivePackageSource( PackageSource source )
- {
- throw new NotSupportedException( "Should not be called in this scenario." );
- }
+ event EventHandler IPackageSourceProvider.PackageSourcesChanged { add { } remove { } }
- void IPackageSourceProvider.SavePackageSources( IEnumerable sources )
- {
- throw new NotSupportedException( "Should not be called in this scenario." );
- }
+ ///
+ /// Gets all the sources.
+ ///
+ ///
+ public IEnumerable LoadPackageSources() => _sources.Value;
- PackageSource? IPackageSourceProvider.GetPackageSourceByName( string name ) => _sources.Value.FirstOrDefault( s => s.Name == name );
+ bool IPackageSourceProvider.IsPackageSourceEnabled( string name ) => true;
- PackageSource? IPackageSourceProvider.GetPackageSourceBySource( string source ) => _sources.Value.FirstOrDefault( s => s.Source == source );
+ void IPackageSourceProvider.SaveActivePackageSource( PackageSource source )
+ {
+ throw new NotSupportedException( "Should not be called in this scenario." );
+ }
- void IPackageSourceProvider.RemovePackageSource( string name )
- {
- throw new NotSupportedException( "Should not be called in this scenario." );
- }
+ void IPackageSourceProvider.SavePackageSources( IEnumerable sources )
+ {
+ throw new NotSupportedException( "Should not be called in this scenario." );
+ }
- void IPackageSourceProvider.EnablePackageSource( string name )
- {
- throw new NotSupportedException( "Should not be called in this scenario." );
- }
+ PackageSource? IPackageSourceProvider.GetPackageSourceByName( string name ) => _sources.Value.FirstOrDefault( s => s.Name == name );
- void IPackageSourceProvider.DisablePackageSource( string name )
- {
- throw new NotSupportedException( "Should not be called in this scenario." );
- }
+ PackageSource? IPackageSourceProvider.GetPackageSourceBySource( string source ) => _sources.Value.FirstOrDefault( s => s.Source == source );
- void IPackageSourceProvider.UpdatePackageSource( PackageSource source, bool updateCredentials, bool updateEnabled )
- {
- throw new NotSupportedException( "Should not be called in this scenario." );
- }
+ void IPackageSourceProvider.RemovePackageSource( string name )
+ {
+ throw new NotSupportedException( "Should not be called in this scenario." );
+ }
- void IPackageSourceProvider.AddPackageSource( PackageSource source )
- {
- throw new NotSupportedException( "Should not be called in this scenario." );
- }
+ void IPackageSourceProvider.EnablePackageSource( string name )
+ {
+ throw new NotSupportedException( "Should not be called in this scenario." );
+ }
- public IReadOnlyList LoadAuditSources()
- {
- throw new NotSupportedException( "Should not be called in this scenario." );
- }
+ void IPackageSourceProvider.DisablePackageSource( string name )
+ {
+ throw new NotSupportedException( "Should not be called in this scenario." );
}
- static NuGetHelper()
+ void IPackageSourceProvider.UpdatePackageSource( PackageSource source, bool updateCredentials, bool updateEnabled )
{
- _settings = Settings.LoadDefaultSettings( Environment.CurrentDirectory );
- _sourceProvider = new PackageProviderProxy( _settings );
- _vstsFeeds = new List();
- // Setting "NoCache" (?) here is required to be able to retry a push after a
- // failure. Without it, the PUT is canceled.
- _sourceCache = new SourceCacheContext().WithRefreshCacheTrue();
- _providers = new List>();
- _providers.AddRange( Repository.Provider.GetCoreV3() );
+ throw new NotSupportedException( "Should not be called in this scenario." );
}
- class Logger : ILogger
+ void IPackageSourceProvider.AddPackageSource( PackageSource source )
{
- readonly ICakeContext _ctx;
- readonly object _lock;
+ throw new NotSupportedException( "Should not be called in this scenario." );
+ }
- public Logger( ICakeContext ctx )
- {
- _ctx = ctx;
- _lock = new object();
- }
+ public IReadOnlyList LoadAuditSources()
+ {
+ throw new NotSupportedException( "Should not be called in this scenario." );
+ }
+ }
- public void LogDebug( string data ) { lock( _lock ) _ctx.Debug( $"NuGet: {data}" ); }
- public void LogVerbose( string data ) { lock( _lock ) _ctx.Verbose( $"NuGet: {data}" ); }
- public void LogInformation( string data ) { lock( _lock ) _ctx.Information( $"NuGet: {data}" ); }
- public void LogMinimal( string data ) { lock( _lock ) _ctx.Information( $"NuGet: {data}" ); }
- public void LogWarning( string data ) { lock( _lock ) _ctx.Warning( $"NuGet: {data}" ); }
- public void LogError( string data ) { lock( _lock ) _ctx.Error( $"NuGet: {data}" ); }
- public void LogSummary( string data ) { lock( _lock ) _ctx.Information( $"NuGet: {data}" ); }
- public void LogInformationSummary( string data ) { lock( _lock ) _ctx.Information( $"NuGet: {data}" ); }
- public void Log( NuGet.Common.LogLevel level, string data ) { lock( _lock ) _ctx.Information( $"NuGet ({level}): {data}" ); }
- public Task LogAsync( NuGet.Common.LogLevel level, string data )
- {
- Log( level, data );
- return System.Threading.Tasks.Task.CompletedTask;
- }
+ static NuGetHelper()
+ {
+ _settings = Settings.LoadDefaultSettings( Environment.CurrentDirectory );
+ _sourceProvider = new PackageProviderProxy( _settings );
+ _vstsFeeds = new List();
+ // Setting "NoCache" (?) here is required to be able to retry a push after a
+ // failure. Without it, the PUT is canceled.
+ _sourceCache = new SourceCacheContext().WithRefreshCacheTrue();
+ _providers = new List>();
+ _providers.AddRange( Repository.Provider.GetCoreV3() );
+ }
- public void Log( ILogMessage message )
- {
- lock( _lock ) _ctx.Information( $"NuGet ({message.Level}) - Code: {message.Code} - Project: {message.ProjectPath} - {message.Message}" );
- }
+ class Logger : ILogger
+ {
+ readonly ICakeContext _ctx;
+ readonly object _lock;
- public Task LogAsync( ILogMessage message )
- {
- Log( message );
- return System.Threading.Tasks.Task.CompletedTask;
- }
+ public Logger( ICakeContext ctx )
+ {
+ _ctx = ctx;
+ _lock = new object();
}
- static ILogger InitializeAndGetLogger( ICakeContext ctx )
+ public void LogDebug( string data ) { lock( _lock ) _ctx.Debug( $"NuGet: {data}" ); }
+ public void LogVerbose( string data ) { lock( _lock ) _ctx.Verbose( $"NuGet: {data}" ); }
+ public void LogInformation( string data ) { lock( _lock ) _ctx.Information( $"NuGet: {data}" ); }
+ public void LogMinimal( string data ) { lock( _lock ) _ctx.Information( $"NuGet: {data}" ); }
+ public void LogWarning( string data ) { lock( _lock ) _ctx.Warning( $"NuGet: {data}" ); }
+ public void LogError( string data ) { lock( _lock ) _ctx.Error( $"NuGet: {data}" ); }
+ public void LogSummary( string data ) { lock( _lock ) _ctx.Information( $"NuGet: {data}" ); }
+ public void LogInformationSummary( string data ) { lock( _lock ) _ctx.Information( $"NuGet: {data}" ); }
+ public void Log( NuGet.Common.LogLevel level, string data ) { lock( _lock ) _ctx.Information( $"NuGet ({level}): {data}" ); }
+ public Task LogAsync( NuGet.Common.LogLevel level, string data )
{
- if( _logger == null )
- {
- ctx.Information( $"Initializing with sources:" );
- foreach( var s in _sourceProvider.LoadPackageSources() )
- {
- ctx.Information( $"{s.Name} => {s.Source}" );
- }
- _logger = new Logger( ctx );
+ Log( level, data );
+ return System.Threading.Tasks.Task.CompletedTask;
+ }
- }
- return _logger;
+ public void Log( ILogMessage message )
+ {
+ lock( _lock ) _ctx.Information( $"NuGet ({message.Level}) - Code: {message.Code} - Project: {message.ProjectPath} - {message.Message}" );
}
- class Creds : ICredentialProvider
+ public Task LogAsync( ILogMessage message )
{
- private readonly ICakeContext _ctx;
+ Log( message );
+ return System.Threading.Tasks.Task.CompletedTask;
+ }
+ }
- public Creds( ICakeContext ctx )
+ static ILogger InitializeAndGetLogger( ICakeContext ctx )
+ {
+ if( _logger == null )
+ {
+ ctx.Information( $"Initializing with sources:" );
+ foreach( var s in _sourceProvider.LoadPackageSources() )
{
- _ctx = ctx;
+ ctx.Information( $"{s.Name} => {s.Source}" );
}
+ _logger = new Logger( ctx );
+
+ }
+ return _logger;
+ }
+
+ class Creds : ICredentialProvider
+ {
+ private readonly ICakeContext _ctx;
+
+ public Creds( ICakeContext ctx )
+ {
+ _ctx = ctx;
+ }
- public string Id { get; } = "Cake";
-
- public Task GetAsync(
- Uri uri,
- IWebProxy proxy,
- CredentialRequestType type,
- string message,
- bool isRetry,
- bool nonInteractive,
- CancellationToken cancellationToken ) =>
- System.Threading.Tasks.Task.FromResult(
- new CredentialResponse(
- new NetworkCredential(
- "CKli",
- _ctx.InteractiveEnvironmentVariable(
- _vstsFeeds.Single( p => new Uri( p.Url ).ToString() == uri.ToString() ).SecretKeyName
- )
+ public string Id { get; } = "Cake";
+
+ public Task GetAsync(
+ Uri uri,
+ IWebProxy proxy,
+ CredentialRequestType type,
+ string message,
+ bool isRetry,
+ bool nonInteractive,
+ CancellationToken cancellationToken ) =>
+ System.Threading.Tasks.Task.FromResult(
+ new CredentialResponse(
+ new NetworkCredential(
+ "CKli",
+ _ctx.InteractiveEnvironmentVariable(
+ _vstsFeeds.Single( p => new Uri( p.Url ).ToString() == uri.ToString() ).SecretKeyName
)
)
- );
- }
+ )
+ );
+ }
+ ///
+ /// Base class for NuGet feeds.
+ ///
+ public abstract class NuGetFeed : ArtifactFeed
+ {
+ readonly PackageSource _packageSource;
+ readonly SourceRepository _sourceRepository;
+ readonly AsyncLazy _updater;
///
- /// Base class for NuGet feeds.
+ /// Initialize a new remote feed.
+ /// Its final is the one of the existing feed if it appears in the existing
+ /// sources (from NuGet configuration files) or "CCB-" if this is
+ /// an unexisting source (CCB is for CodeCakeBuilder).
///
- public abstract class NuGetFeed : ArtifactFeed
+ /// The central NuGet handler.
+ /// Name of the feed.
+ /// Must be a v3/index.json url otherwise an argument exception is thrown.
+ protected NuGetFeed( NuGetArtifactType type, string name, string urlV3 )
+ : this( type, _sourceProvider.FindOrCreateFromUrl( name, urlV3 ) )
{
- readonly PackageSource _packageSource;
- readonly SourceRepository _sourceRepository;
- readonly AsyncLazy _updater;
- ///
- /// Initialize a new remote feed.
- /// Its final is the one of the existing feed if it appears in the existing
- /// sources (from NuGet configuration files) or "CCB-" if this is
- /// an unexisting source (CCB is for CodeCakeBuilder).
- ///
- /// The central NuGet handler.
- /// Name of the feed.
- /// Must be a v3/index.json url otherwise an argument exception is thrown.
- protected NuGetFeed( NuGetArtifactType type, string name, string urlV3 )
- : this( type, _sourceProvider.FindOrCreateFromUrl( name, urlV3 ) )
+ if( this is VSTSFeed f )
{
- if( this is VSTSFeed f )
+ if( HttpHandlerResourceV3.CredentialService == null )
{
- if( HttpHandlerResourceV3.CredentialService == null )
- {
- HttpHandlerResourceV3.CredentialService = new Lazy(
- () => new CredentialService(
- providers: new AsyncLazy>(
- () => System.Threading.Tasks.Task.FromResult>(
- new List { new Creds( Cake ) } )
- ),
- nonInteractive: true,
- handlesDefaultCredentials: true )
- );
- }
- _vstsFeeds.Add( f );
+ HttpHandlerResourceV3.CredentialService = new Lazy(
+ () => new CredentialService(
+ providers: new AsyncLazy>(
+ () => System.Threading.Tasks.Task.FromResult>(
+ new List { new Creds( Cake ) } )
+ ),
+ nonInteractive: true,
+ handlesDefaultCredentials: true )
+ );
}
+ _vstsFeeds.Add( f );
}
+ }
- ///
- /// Initialize a new local feed.
- /// Its final is the one of the existing feed if it appears in the existing
- /// sources (from NuGet configuration files) or "CCB-GetDirectoryName(localPath)" if this is
- /// an unexisting source (CCB is for CodeCakeBuilder).
- ///
- /// The central NuGet handler.
- /// Local path.
- protected NuGetFeed( NuGetArtifactType type, string localPath )
- : this( type, _sourceProvider.FindOrCreateFromLocalPath( localPath ) )
- {
- }
+ ///
+ /// Initialize a new local feed.
+ /// Its final is the one of the existing feed if it appears in the existing
+ /// sources (from NuGet configuration files) or "CCB-GetDirectoryName(localPath)" if this is
+ /// an unexisting source (CCB is for CodeCakeBuilder).
+ ///
+ /// The central NuGet handler.
+ /// Local path.
+ protected NuGetFeed( NuGetArtifactType type, string localPath )
+ : this( type, _sourceProvider.FindOrCreateFromLocalPath( localPath ) )
+ {
+ }
- NuGetFeed( NuGetArtifactType type, PackageSource s )
- : base( type )
+ NuGetFeed( NuGetArtifactType type, PackageSource s )
+ : base( type )
+ {
+ _packageSource = s;
+ _sourceRepository = new SourceRepository( _packageSource, _providers );
+ _updater = new AsyncLazy( async () =>
{
- _packageSource = s;
- _sourceRepository = new SourceRepository( _packageSource, _providers );
- _updater = new AsyncLazy( async () =>
- {
- var r = await _sourceRepository.GetResourceAsync();
- // TODO: Update for next NuGet version?
- // r.Settings = _settings;
- return r;
- } );
- }
+ var r = await _sourceRepository.GetResourceAsync();
+ // TODO: Update for next NuGet version?
+ // r.Settings = _settings;
+ return r;
+ } );
+ }
+
+ ///
+ /// Must provide the secret key name that must be found in the environment variables.
+ /// Without it push is skipped.
+ ///
+ public abstract string SecretKeyName { get; }
+
+ ///
+ /// The url of the source. Can be a local path.
+ ///
+ public string Url => _packageSource.Source;
+
+ ///
+ /// Gets whether this is a local feed (a directory).
+ ///
+ public bool IsLocal => _packageSource.IsLocal;
+
+ ///
+ /// Gets the source name.
+ /// If the source appears in NuGet configuration files, it is the configured name of the source, otherwise
+ /// it is prefixed with "CCB-" (CCB is for CodeCakeBuilder).
+ ///
+ public override string Name => _packageSource.Name;
- ///
- /// Must provide the secret key name that must be found in the environment variables.
- /// Without it push is skipped.
- ///
- public abstract string SecretKeyName { get; }
-
- ///
- /// The url of the source. Can be a local path.
- ///
- public string Url => _packageSource.Source;
-
- ///
- /// Gets whether this is a local feed (a directory).
- ///
- public bool IsLocal => _packageSource.IsLocal;
-
- ///
- /// Gets the source name.
- /// If the source appears in NuGet configuration files, it is the configured name of the source, otherwise
- /// it is prefixed with "CCB-" (CCB is for CodeCakeBuilder).
- ///
- public override string Name => _packageSource.Name;
-
- ///
- /// Creates a list of push entries from a set of local artifacts into this feed.
- ///
- /// Local artifacts.
- /// The set of push into this feed.
- public override async Task> CreatePushListAsync( IEnumerable artifacts )
+ ///
+ /// Creates a list of push entries from a set of local artifacts into this feed.
+ ///
+ /// Local artifacts.
+ /// The set of push into this feed.
+ public override async Task> CreatePushListAsync( IEnumerable artifacts )
+ {
+ var result = new List();
+ var logger = InitializeAndGetLogger( Cake );
+ MetadataResource meta = await _sourceRepository.GetResourceAsync();
+ foreach( var p in artifacts )
{
- var result = new List();
- var logger = InitializeAndGetLogger( Cake );
- MetadataResource meta = await _sourceRepository.GetResourceAsync();
- foreach( var p in artifacts )
+ var pId = new PackageIdentity( p.ArtifactInstance.Artifact.Name, new NuGetVersion( p.ArtifactInstance.Version.ToNormalizedString() ) );
+ if( await meta.Exists( pId, _sourceCache, logger, CancellationToken.None ) )
{
- var pId = new PackageIdentity( p.ArtifactInstance.Artifact.Name, new NuGetVersion( p.ArtifactInstance.Version.ToNormalizedString() ) );
- if( await meta.Exists( pId, _sourceCache, logger, CancellationToken.None ) )
- {
- Cake.Debug( $" ==> Feed '{Name}' already contains {p.ArtifactInstance}." );
- }
- else
- {
- Cake.Debug( $"Package {p.ArtifactInstance} must be published to remote feed '{Name}'." );
- result.Add( new ArtifactPush( p, this ) );
- }
+ Cake.Debug( $" ==> Feed '{Name}' already contains {p.ArtifactInstance}." );
}
- return result;
- }
-
- ///
- /// Pushes a set of packages from .nupkg files that must exist in .
- ///
- /// The instances to push (that necessary target this feed).
- /// The awaitable.
- public override async Task PushAsync( IEnumerable pushes )
- {
- string apiKey = null;
- if( !_packageSource.IsLocal )
+ else
{
- apiKey = ResolveAPIKey();
- if( string.IsNullOrEmpty( apiKey ) )
- {
- Cake.Information( $"Could not resolve API key. Push to '{Name}' => '{Url}' is skipped." );
- return;
- }
+ Cake.Debug( $"Package {p.ArtifactInstance} must be published to remote feed '{Name}'." );
+ result.Add( new ArtifactPush( p, this ) );
}
- Cake.Information( $"Pushing packages to '{Name}' => '{Url}'." );
- var logger = InitializeAndGetLogger( Cake );
- var updater = await _updater;
- var names = pushes.Select( p => p.Name + "." + p.Version.WithBuildMetaData( null ).ToNormalizedString() );
- var fullPaths = names.Select( n => ArtifactType.GlobalInfo.ReleasesFolder.AppendPart( n + ".nupkg" ).ToString() );
-
- await updater.Push(
- fullPaths.ToList(),
- string.Empty, // no Symbol source.
- 20, //20 seconds timeout
- disableBuffering: false,
- getApiKey: endpoint => apiKey,
- getSymbolApiKey: symbolsEndpoint => null,
- noServiceEndpoint: false,
- skipDuplicate: true,
- symbolPackageUpdateResource: null,
- log: logger );
- await OnAllArtifactsPushedAsync( pushes );
}
-
- ///
- /// Called once all the packages are pushed.
- /// Does nothing at this level.
- ///
- /// The instances to push (that necessary target this feed).
- /// The awaitable.
- protected virtual Task OnAllArtifactsPushedAsync( IEnumerable pushes )
- {
- return System.Threading.Tasks.Task.CompletedTask;
- }
-
- ///
- /// Must resolve the API key required to push the package.
- ///
- /// The secret (that can be null or empty).
- protected abstract string? ResolveAPIKey();
+ return result;
}
- }
-
- ///
- /// A basic VSTS feed uses "VSTS" for the API key and does not handle views.
- /// The https://github.com/Microsoft/artifacts-credprovider must be installed.
- /// A Personal Access Token, environment variable
- /// must be defined and contains the token.
- /// If this SecretKeyName is not defined or empty, push is skipped.
- ///
- class VSTSFeed : NuGetHelper.NuGetFeed
- {
- string? _azureFeedPAT;
///
- /// Initialize a new remote VSTS feed.
+ /// Pushes a set of packages from .nupkg files that must exist in .
///
- /// Name of the feed.
- /// Must be a v3/index.json url otherwise an argument exception is thrown.
- /// The secret key name. When null or empty, push is skipped.
- public VSTSFeed( NuGetArtifactType t, string name, string urlV3, string secretKeyName )
- : base( t, name, urlV3 )
+ /// The instances to push (that necessary target this feed).
+ /// The awaitable.
+ public override async Task PushAsync( IEnumerable pushes )
{
- SecretKeyName = secretKeyName;
+ string apiKey = null;
+ if( !_packageSource.IsLocal )
+ {
+ apiKey = ResolveAPIKey();
+ if( string.IsNullOrEmpty( apiKey ) )
+ {
+ Cake.Information( $"Could not resolve API key. Push to '{Name}' => '{Url}' is skipped." );
+ return;
+ }
+ }
+ Cake.Information( $"Pushing packages to '{Name}' => '{Url}'." );
+ var logger = InitializeAndGetLogger( Cake );
+ var updater = await _updater;
+ var names = pushes.Select( p => p.Name + "." + p.Version.WithBuildMetaData( null ).ToNormalizedString() );
+ var fullPaths = names.Select( n => ArtifactType.GlobalInfo.ReleasesFolder.AppendPart( n + ".nupkg" ).ToString() );
+
+ await updater.Push(
+ fullPaths.ToList(),
+ string.Empty, // no Symbol source.
+ 20, //20 seconds timeout
+ disableBuffering: false,
+ getApiKey: endpoint => apiKey,
+ getSymbolApiKey: symbolsEndpoint => null,
+ noServiceEndpoint: false,
+ skipDuplicate: true,
+ symbolPackageUpdateResource: null,
+ log: logger );
+ await OnAllArtifactsPushedAsync( pushes );
}
///
- /// Gets the name of the environment variable that must contain the
- /// Personal Access Token that allows push to this feed.
- /// The https://github.com/Microsoft/artifacts-credprovider VSS_NUGET_EXTERNAL_FEED_ENDPOINTS
- /// will be dynamically generated.
+ /// Called once all the packages are pushed.
+ /// Does nothing at this level.
///
- public override string SecretKeyName { get; }
+ /// The instances to push (that necessary target this feed).
+ /// The awaitable.
+ protected virtual Task OnAllArtifactsPushedAsync( IEnumerable pushes )
+ {
+ return System.Threading.Tasks.Task.CompletedTask;
+ }
///
- /// Looks up for the environment variable that is required to promote packages.
- /// If this variable is empty or not defined, push is skipped.
+ /// Must resolve the API key required to push the package.
///
- /// The Cake context.
- /// The "VSTS" API key or null to skip the push.
- protected override string? ResolveAPIKey()
- {
- _azureFeedPAT = Cake.InteractiveEnvironmentVariable( SecretKeyName );
- if( string.IsNullOrWhiteSpace( _azureFeedPAT ) )
- {
- Cake.Warning( $"No {SecretKeyName} environment variable found." );
- _azureFeedPAT = null;
- }
- // The API key for the Credential Provider must be "VSTS".
- return _azureFeedPAT != null ? "VSTS" : null;
- }
+ /// The secret (that can be null or empty).
+ protected abstract string? ResolveAPIKey();
}
+ }
+
+ ///
+ /// A basic VSTS feed uses "VSTS" for the API key and does not handle views.
+ /// The https://github.com/Microsoft/artifacts-credprovider must be installed.
+ /// A Personal Access Token, environment variable
+ /// must be defined and contains the token.
+ /// If this SecretKeyName is not defined or empty, push is skipped.
+ ///
+ class VSTSFeed : NuGetHelper.NuGetFeed
+ {
+ string? _azureFeedPAT;
///
- /// A SignatureVSTSFeed handles Stable, Latest, Preview and CI Azure feed views with
- /// package promotion based on the published version.
- /// The secret key name is built by :
- /// "AZURE_FEED_" + Organization.ToUpperInvariant().Replace( '-', '_' ).Replace( ' ', '_' ) + "_PAT".
+ /// Initialize a new remote VSTS feed.
///
- class SignatureVSTSFeed : VSTSFeed
+ /// Name of the feed.
+ /// Must be a v3/index.json url otherwise an argument exception is thrown.
+ /// The secret key name. When null or empty, push is skipped.
+ public VSTSFeed( NuGetArtifactType t, string name, string urlV3, string secretKeyName )
+ : base( t, name, urlV3 )
{
- ///
- /// Builds the standardized secret key name from the organization name: this is
- /// the Personal Access Token that allows push packages.
- ///
- /// Organization name.
- /// The secret key name to use.
- public static string GetSecretKeyName( string organization )
- => "AZURE_FEED_" + organization.ToUpperInvariant()
- .Replace( '-', '_' )
- .Replace( ' ', '_' )
- + "_PAT";
+ SecretKeyName = secretKeyName;
+ }
- ///
- /// Initialize a new SignatureVSTSFeed.
- /// Its is set to "-"
- /// (and may be prefixed with "CCB-" if it doesn't correspond to a source defined in the NuGet.config settings.
- ///
- /// Name of the organization.
- /// Identifier of the feed in Azure, inside the organization.
- public SignatureVSTSFeed( NuGetArtifactType t, string organization, string feedName, string? projectName )
- : base( t, organization + "-" + feedName,
- projectName != null
- ? $"https://pkgs.dev.azure.com/{organization}/{projectName}/_packaging/{feedName}/nuget/v3/index.json"
- : $"https://pkgs.dev.azure.com/{organization}/_packaging/{feedName}/nuget/v3/index.json",
- GetSecretKeyName( organization ) )
+ ///
+ /// Gets the name of the environment variable that must contain the
+ /// Personal Access Token that allows push to this feed.
+ /// The https://github.com/Microsoft/artifacts-credprovider VSS_NUGET_EXTERNAL_FEED_ENDPOINTS
+ /// will be dynamically generated.
+ ///
+ public override string SecretKeyName { get; }
+
+ ///
+ /// Looks up for the environment variable that is required to promote packages.
+ /// If this variable is empty or not defined, push is skipped.
+ ///
+ /// The Cake context.
+ /// The "VSTS" API key or null to skip the push.
+ protected override string? ResolveAPIKey()
+ {
+ _azureFeedPAT = Cake.InteractiveEnvironmentVariable( SecretKeyName );
+ if( string.IsNullOrWhiteSpace( _azureFeedPAT ) )
{
- Organization = organization;
- FeedName = feedName;
- ProjectName = projectName;
+ Cake.Warning( $"No {SecretKeyName} environment variable found." );
+ _azureFeedPAT = null;
}
+ // The API key for the Credential Provider must be "VSTS".
+ return _azureFeedPAT != null ? "VSTS" : null;
+ }
+ }
- ///
- /// Gets the organization name.
- ///
- public string Organization { get; }
+ ///
+ /// A SignatureVSTSFeed handles Stable, Latest, Preview and CI Azure feed views with
+ /// package promotion based on the published version.
+ /// The secret key name is built by :
+ /// "AZURE_FEED_" + Organization.ToUpperInvariant().Replace( '-', '_' ).Replace( ' ', '_' ) + "_PAT".
+ ///
+ class SignatureVSTSFeed : VSTSFeed
+ {
+ ///
+ /// Builds the standardized secret key name from the organization name: this is
+ /// the Personal Access Token that allows push packages.
+ ///
+ /// Organization name.
+ /// The secret key name to use.
+ public static string GetSecretKeyName( string organization )
+ => "AZURE_FEED_" + organization.ToUpperInvariant()
+ .Replace( '-', '_' )
+ .Replace( ' ', '_' )
+ + "_PAT";
- ///
- /// Gets the feed identifier.
- ///
- public string FeedName { get; }
+ ///
+ /// Initialize a new SignatureVSTSFeed.
+ /// Its is set to "-"
+ /// (and may be prefixed with "CCB-" if it doesn't correspond to a source defined in the NuGet.config settings.
+ ///
+ /// Name of the organization.
+ /// Identifier of the feed in Azure, inside the organization.
+ public SignatureVSTSFeed( NuGetArtifactType t, string organization, string feedName, string? projectName )
+ : base( t, organization + "-" + feedName,
+ projectName != null
+ ? $"https://pkgs.dev.azure.com/{organization}/{projectName}/_packaging/{feedName}/nuget/v3/index.json"
+ : $"https://pkgs.dev.azure.com/{organization}/_packaging/{feedName}/nuget/v3/index.json",
+ GetSecretKeyName( organization ) )
+ {
+ Organization = organization;
+ FeedName = feedName;
+ ProjectName = projectName;
+ }
- public string? ProjectName { get; }
+ ///
+ /// Gets the organization name.
+ ///
+ public string Organization { get; }
- ///
- /// Implements Package promotion in @CI, @Exploratory, @Preview, @Latest and @Stable views.
- ///
- /// The Cake context.
- /// The set of artifacts to promote.
- /// The awaitable.
- protected override async Task OnAllArtifactsPushedAsync( IEnumerable pushes )
+ ///
+ /// Gets the feed identifier.
+ ///
+ public string FeedName { get; }
+
+ public string? ProjectName { get; }
+
+ ///
+ /// Implements Package promotion in @CI, @Exploratory, @Preview, @Latest and @Stable views.
+ ///
+ /// The Cake context.
+ /// The set of artifacts to promote.
+ /// The awaitable.
+ protected override async Task OnAllArtifactsPushedAsync( IEnumerable pushes )
+ {
+ var basicAuth = Convert.ToBase64String( Encoding.ASCII.GetBytes( ":" + Cake.InteractiveEnvironmentVariable( SecretKeyName ) ) );
+ foreach( var p in pushes )
{
- var basicAuth = Convert.ToBase64String( Encoding.ASCII.GetBytes( ":" + Cake.InteractiveEnvironmentVariable( SecretKeyName ) ) );
- foreach( var p in pushes )
+ foreach( var view in p.Version.PackageQuality.GetAllQualities() )
{
- foreach( var view in p.Version.PackageQuality.GetAllQualities() )
+ var url = ProjectName != null ?
+ $"https://pkgs.dev.azure.com/{Organization}/{ProjectName}/_apis/packaging/feeds/{FeedName}/nuget/packagesBatch?api-version=5.0-preview.1"
+ : $"https://pkgs.dev.azure.com/{Organization}/_apis/packaging/feeds/{FeedName}/nuget/packagesBatch?api-version=5.0-preview.1";
+ using( HttpRequestMessage req = new HttpRequestMessage( HttpMethod.Post, url ) )
{
- var url = ProjectName != null ?
- $"https://pkgs.dev.azure.com/{Organization}/{ProjectName}/_apis/packaging/feeds/{FeedName}/nuget/packagesBatch?api-version=5.0-preview.1"
- : $"https://pkgs.dev.azure.com/{Organization}/_apis/packaging/feeds/{FeedName}/nuget/packagesBatch?api-version=5.0-preview.1";
- using( HttpRequestMessage req = new HttpRequestMessage( HttpMethod.Post, url ) )
+ req.Headers.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue( "Basic", basicAuth );
+ var body = GetPromotionJSONBody( p.Name, p.Version.ToNormalizedString(), view.ToString() );
+ req.Content = new StringContent( body, Encoding.UTF8, "application/json" );
+ using( var m = await StandardGlobalInfo.SharedHttpClient.SendAsync( req ) )
{
- req.Headers.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue( "Basic", basicAuth );
- var body = GetPromotionJSONBody( p.Name, p.Version.ToNormalizedString(), view.ToString() );
- req.Content = new StringContent( body, Encoding.UTF8, "application/json" );
- using( var m = await StandardGlobalInfo.SharedHttpClient.SendAsync( req ) )
+ if( m.IsSuccessStatusCode )
+ {
+ Cake.Information( $"Package '{p.Name}' promoted to view '@{view}'." );
+ }
+ else
{
- if( m.IsSuccessStatusCode )
- {
- Cake.Information( $"Package '{p.Name}' promoted to view '@{view}'." );
- }
- else
- {
- Cake.Error( $"Package '{p.Name}' promotion to view '@{view}' failed." );
- // Throws!
- m.EnsureSuccessStatusCode();
- }
+ Cake.Error( $"Package '{p.Name}' promotion to view '@{view}' failed." );
+ // Throws!
+ m.EnsureSuccessStatusCode();
}
}
}
}
}
+ }
- static string GetPromotionJSONBody( string packageName, string packageVersion, string viewId, bool npm = false )
- {
- var bodyFormat = @"{
+ static string GetPromotionJSONBody( string packageName, string packageVersion, string viewId, bool npm = false )
+ {
+ var bodyFormat = @"{
""data"": {
""viewId"": ""{viewId}""
},
@@ -555,69 +555,68 @@ static string GetPromotionJSONBody( string packageName, string packageVersion, s
""protocolType"": ""{NuGetOrNpm}""
}]
}";
- return bodyFormat.Replace( "{NuGetOrNpm}", npm ? "Npm" : "NuGet" )
- .Replace( "{viewId}", viewId )
- .Replace( "{packageName}", packageName )
- .Replace( "{packageVersion}", packageVersion );
- }
-
+ return bodyFormat.Replace( "{NuGetOrNpm}", npm ? "Npm" : "NuGet" )
+ .Replace( "{viewId}", viewId )
+ .Replace( "{packageName}", packageName )
+ .Replace( "{packageVersion}", packageVersion );
}
+ }
+
+ ///
+ /// A remote feed where push is controlled by its .
+ ///
+ class RemoteFeed : NuGetHelper.NuGetFeed
+ {
///
- /// A remote feed where push is controlled by its .
+ /// Initialize a new remote feed.
+ /// The push is controlled by an API key name that is the name of an environment variable
+ /// that must contain the actual API key to push packages.
///
- class RemoteFeed : NuGetHelper.NuGetFeed
+ /// Name of the feed.
+ /// Must be a v3/index.json url otherwise an argument exception is thrown.
+ /// The secret key name.
+ public RemoteFeed( NuGetArtifactType t, string name, string urlV3, string secretKeyName )
+ : base( t, name, urlV3 )
{
- ///
- /// Initialize a new remote feed.
- /// The push is controlled by an API key name that is the name of an environment variable
- /// that must contain the actual API key to push packages.
- ///
- /// Name of the feed.
- /// Must be a v3/index.json url otherwise an argument exception is thrown.
- /// The secret key name.
- public RemoteFeed( NuGetArtifactType t, string name, string urlV3, string secretKeyName )
- : base( t, name, urlV3 )
- {
- SecretKeyName = secretKeyName;
- }
-
- ///
- /// Gets or sets the push API key name.
- /// This is the environment variable name that must contain the NuGet API key required to push.
- ///
- public override string SecretKeyName { get; }
-
- ///
- /// Resolves the API key from environment variable.
- ///
- /// The Cake context.
- /// The API key or null.
- protected override string? ResolveAPIKey()
- {
- if( String.IsNullOrEmpty( SecretKeyName ) )
- {
- Cake.Information( $"Remote feed '{Name}' APIKeyName is null or empty." );
- return null;
- }
- return Cake.InteractiveEnvironmentVariable( SecretKeyName );
- }
+ SecretKeyName = secretKeyName;
}
///
- /// Local feed. Pushes are always possible.
+ /// Gets or sets the push API key name.
+ /// This is the environment variable name that must contain the NuGet API key required to push.
+ ///
+ public override string SecretKeyName { get; }
+
+ ///
+ /// Resolves the API key from environment variable.
///
- class NugetLocalFeed : NuGetHelper.NuGetFeed
+ /// The Cake context.
+ /// The API key or null.
+ protected override string? ResolveAPIKey()
{
- public NugetLocalFeed( NuGetArtifactType t, string path )
- : base( t, path )
+ if( String.IsNullOrEmpty( SecretKeyName ) )
{
+ Cake.Information( $"Remote feed '{Name}' APIKeyName is null or empty." );
+ return null;
}
+ return Cake.InteractiveEnvironmentVariable( SecretKeyName );
+ }
+ }
- public override string SecretKeyName => null;
-
- protected override string? ResolveAPIKey() => null;
+ ///
+ /// Local feed. Pushes are always possible.
+ ///
+ class NugetLocalFeed : NuGetHelper.NuGetFeed
+ {
+ public NugetLocalFeed( NuGetArtifactType t, string path )
+ : base( t, path )
+ {
}
+
+ public override string SecretKeyName => null;
+
+ protected override string? ResolveAPIKey() => null;
}
}
diff --git a/CodeCakeBuilder/dotnet/DotnetSolution.cs b/CodeCakeBuilder/dotnet/DotnetSolution.cs
index 9e4b5a4..600ab68 100644
--- a/CodeCakeBuilder/dotnet/DotnetSolution.cs
+++ b/CodeCakeBuilder/dotnet/DotnetSolution.cs
@@ -16,199 +16,215 @@
using System.Linq;
using System.Xml.Linq;
-namespace CodeCake
+namespace CodeCake;
+
+
+public static class StandardGlobalInfoDotnetExtension
{
+ public static StandardGlobalInfo AddDotnet( this StandardGlobalInfo globalInfo )
+ {
+ DotnetSolution sln = DotnetSolution.FromSolutionInCurrentWorkingDirectory( globalInfo );
+ globalInfo.RegisterSolution( sln );
+ return globalInfo;
+ }
- public static class StandardGlobalInfoDotnetExtension
+ public static DotnetSolution GetDotnetSolution( this StandardGlobalInfo globalInfo )
{
- public static StandardGlobalInfo AddDotnet( this StandardGlobalInfo globalInfo )
- {
- DotnetSolution sln = DotnetSolution.FromSolutionInCurrentWorkingDirectory( globalInfo );
- globalInfo.RegisterSolution( sln );
- return globalInfo;
- }
+ return globalInfo.Solutions.OfType().Single();
+ }
+}
- public static DotnetSolution GetDotnetSolution( this StandardGlobalInfo globalInfo )
- {
- return globalInfo.Solutions.OfType().Single();
- }
+public partial class DotnetSolution : ICIWorkflow
+{
+ readonly StandardGlobalInfo _globalInfo;
+ public readonly string SolutionFileName;
+ public readonly IReadOnlyList Projects;
+ public readonly IReadOnlyList ProjectsToPublish;
+
+ DotnetSolution( StandardGlobalInfo globalInfo,
+ string solutionFileName,
+ IReadOnlyList projects,
+ IReadOnlyList projectsToPublish )
+ {
+ _globalInfo = globalInfo;
+ SolutionFileName = solutionFileName;
+ Projects = projects;
+ ProjectsToPublish = projectsToPublish;
}
- public partial class DotnetSolution : ICIWorkflow
+ ///
+ /// Create a DotnetSolution from the sln.
+ ///
+ /// The StandardGlobalInfo
+ ///
+ /// The predicate used to filter the project to publish. By default the predicate is p => !p.Path.Segments.Contains
+ ///
+ ///
+ public static DotnetSolution FromSolutionInCurrentWorkingDirectory( StandardGlobalInfo globalInfo )
{
- readonly StandardGlobalInfo _globalInfo;
- public readonly string SolutionFileName;
- public readonly IReadOnlyList Projects;
- public readonly IReadOnlyList ProjectsToPublish;
-
- DotnetSolution( StandardGlobalInfo globalInfo,
- string solutionFileName,
- IReadOnlyList projects,
- IReadOnlyList projectsToPublish )
- {
- _globalInfo = globalInfo;
- SolutionFileName = solutionFileName;
- Projects = projects;
- ProjectsToPublish = projectsToPublish;
- }
+ string solutionFileName = System.IO.Path.GetFileName(
+ globalInfo.Cake.GetFiles( "*.sln",
+ new GlobberSettings
+ {
+ Predicate = p => !System.IO.Path.GetFileName( p.Path.FullPath )
+ .EndsWith( ".local.sln", StringComparison.OrdinalIgnoreCase )
+ } ).Single().FullPath
+ );
+ var sln = globalInfo.Cake.ParseSolution( solutionFileName );
+
+ var projects = sln
+ .Projects
+ .Where( p => p is not SolutionFolder && p.Name != "CodeCakeBuilder" )
+ .ToList();
+ var projectsToPublish = projects.Where(
+ p => ((bool?)XDocument.Load( p.Path.FullPath )
+ .Root!
+ .Elements( "PropertyGroup" )
+ .Elements( "IsPackable" ).LastOrDefault() ?? true) == true
+ )
+ .ToList();
+
+ return new DotnetSolution( globalInfo, solutionFileName, projects, projectsToPublish );
+ }
- ///
- /// Create a DotnetSolution from the sln.
- ///
- /// The StandardGlobalInfo
- ///
- /// The predicate used to filter the project to publish. By default the predicate is p => !p.Path.Segments.Contains
- ///
- ///
- public static DotnetSolution FromSolutionInCurrentWorkingDirectory( StandardGlobalInfo globalInfo )
- {
- string solutionFileName = System.IO.Path.GetFileName(
- globalInfo.Cake.GetFiles( "*.sln",
- new GlobberSettings
- {
- Predicate = p => !System.IO.Path.GetFileName( p.Path.FullPath )
- .EndsWith( ".local.sln", StringComparison.OrdinalIgnoreCase )
- } ).Single().FullPath
- );
- var sln = globalInfo.Cake.ParseSolution( solutionFileName );
-
- var projects = sln
- .Projects
- .Where( p => !(p is SolutionFolder)
- && p.Name != "CodeCakeBuilder" )
- .ToList();
- var projectsToPublish = projects.Where(
- p => ((bool?)XDocument.Load( p.Path.FullPath )
- .Root!
- .Elements( "PropertyGroup" )
- .Elements( "IsPackable" ).LastOrDefault() ?? true) == true
- )
- .ToList();
-
- return new DotnetSolution( globalInfo, solutionFileName, projects, projectsToPublish );
- }
+ ///
+ /// Cleans the bin/obj of the projects and the TestResults xml.
+ ///
+ public void Clean()
+ {
+ _globalInfo.Cake.CleanDirectories( Projects.Select( p => p.Path.GetDirectory().Combine( "bin" ) ) );
+ _globalInfo.Cake.CleanDirectories( Projects.Select( p => p.Path.GetDirectory().Combine( "obj" ) ) );
+ _globalInfo.Cake.DeleteFiles( "Tests/**/TestResult*.xml" );
+ }
- ///
- /// Cleans the bin/obj of the projects and the TestResults xml.
- ///
- public void Clean()
+ ///
+ /// Builds the solution without "CodeCakeBuilder" project itself and
+ /// optionally other projects.
+ ///
+ /// Optional project names (without path nor .csproj extension).
+ public void Build( params string[] excludedProjectsName )
+ {
+ using( var tempSln = _globalInfo.Cake.CreateTemporarySolutionFile( SolutionFileName ) )
{
- _globalInfo.Cake.CleanDirectories( Projects.Select( p => p.Path.GetDirectory().Combine( "bin" ) ) );
- _globalInfo.Cake.CleanDirectories( Projects.Select( p => p.Path.GetDirectory().Combine( "obj" ) ) );
- _globalInfo.Cake.DeleteFiles( "Tests/**/TestResult*.xml" );
+ var exclude = new List( excludedProjectsName ) { "CodeCakeBuilder" };
+ tempSln.ExcludeProjectsFromBuild( [.. exclude] );
+ _globalInfo.Cake.DotNetBuild( tempSln.FullPath.FullPath,
+ new DotNetBuildSettings().AddVersionArguments( _globalInfo.BuildInfo, s =>
+ {
+ s.Configuration = _globalInfo.BuildInfo.BuildConfiguration;
+ } ) );
}
+ }
- ///
- /// Builds the solution without "CodeCakeBuilder" project itself and
- /// optionally other projects.
- ///
- /// Optional project names (without path nor .csproj extension).
- public void Build( params string[] excludedProjectsName )
+ ///
+ /// Simply 'dotnet test --no-restore --no-build' the solution.
+ ///
+ public void SolutionTest()
+ {
+ var memKey = $"Test:{SolutionFileName}";
+ if( !_globalInfo.CheckCommitMemoryKey( memKey ) )
{
- using( var tempSln = _globalInfo.Cake.CreateTemporarySolutionFile( SolutionFileName ) )
+ var options = new DotNetTestSettings()
{
- var exclude = new List( excludedProjectsName ) { "CodeCakeBuilder" };
- tempSln.ExcludeProjectsFromBuild( exclude.ToArray() );
- _globalInfo.Cake.DotNetBuild( tempSln.FullPath.FullPath,
- new DotNetBuildSettings().AddVersionArguments( _globalInfo.BuildInfo, s =>
- {
- s.Configuration = _globalInfo.BuildInfo.BuildConfiguration;
- } ) );
- }
+ Configuration = _globalInfo.BuildInfo.BuildConfiguration,
+ NoRestore = true,
+ NoBuild = true,
+ Loggers = ["trx"]
+ };
+ _globalInfo.Cake.DotNetTest( null, options );
}
+ _globalInfo.WriteCommitMemoryKey( memKey );
+ }
- public void Test( IEnumerable? testProjects = null )
- {
- if( testProjects == null )
- {
- testProjects = Projects.Where( p => p.Name.EndsWith( ".Tests" ) );
- }
+ [Obsolete( "Use the simpler SolutionTest() that simply 'dotnet test --no-restore --no-build' the solution." )]
+ public void Test( IEnumerable? testProjects = null )
+ {
+ testProjects ??= Projects.Where( p => p.Name.EndsWith( ".Tests" ) );
- foreach( SolutionProject project in testProjects )
+ foreach( SolutionProject project in testProjects )
+ {
+ NormalizedPath projectPath = project.Path.GetDirectory().FullPath;
+ NormalizedPath binDir = projectPath.AppendPart( "bin" ).AppendPart( _globalInfo.BuildInfo.BuildConfiguration );
+ NormalizedPath objDir = projectPath.AppendPart( "obj" );
+ string assetsJson = File.ReadAllText( objDir.AppendPart( "project.assets.json" ) );
+ bool isNunitLite = assetsJson.Contains( "NUnitLite" );
+ bool isVSTest = assetsJson.Contains( "Microsoft.NET.Test.Sdk" );
+ foreach( NormalizedPath buildDir in
+ Directory.GetDirectories( binDir )
+ .Where( p => Directory.EnumerateFiles( p ).Any() )
+ )
{
- NormalizedPath projectPath = project.Path.GetDirectory().FullPath;
- NormalizedPath binDir = projectPath.AppendPart( "bin" ).AppendPart( _globalInfo.BuildInfo.BuildConfiguration );
- NormalizedPath objDir = projectPath.AppendPart( "obj" );
- string assetsJson = File.ReadAllText( objDir.AppendPart( "project.assets.json" ) );
- bool isNunitLite = assetsJson.Contains( "NUnitLite" );
- bool isVSTest = assetsJson.Contains( "Microsoft.NET.Test.Sdk" );
- foreach( NormalizedPath buildDir in
- Directory.GetDirectories( binDir )
- .Where( p => Directory.EnumerateFiles( p ).Any() )
- )
+ string framework = buildDir.LastPart;
+ bool isNetFramework = framework.StartsWith( "net" ) && framework.Length == 6 && int.TryParse( framework.AsSpan( 3 ), out var _ );
+ string fileWithoutExtension = buildDir.AppendPart( project.Name );
+ string testBinariesPath = "";
+ if( isNunitLite )
{
- string framework = buildDir.LastPart;
- bool isNetFramework = framework.StartsWith( "net" ) && framework.Length == 6 && int.TryParse( framework.Substring( 3 ), out var _ );
- string fileWithoutExtension = buildDir.AppendPart( project.Name );
- string testBinariesPath = "";
- if( isNunitLite )
+ // Using NUnitLite.
+ if( isNetFramework && File.Exists( (testBinariesPath = fileWithoutExtension + ".exe") ) )
{
- // Using NUnitLite.
- if( isNetFramework && File.Exists( (testBinariesPath = fileWithoutExtension + ".exe") ) )
- {
- _globalInfo.Cake.Information( $"Testing via NUnitLite ({framework}): {testBinariesPath}" );
- if( !_globalInfo.CheckCommitMemoryKey( testBinariesPath ) )
- {
- _globalInfo.Cake.NUnit3( new[] { testBinariesPath }, new NUnit3Settings
- {
- Results = new[] { new NUnit3Result() { FileName = FilePath.FromString( projectPath.AppendPart( "TestResult.Net461.xml" ) ) } }
- } );
- }
- }
- else
+ _globalInfo.Cake.Information( $"Testing via NUnitLite ({framework}): {testBinariesPath}" );
+ if( !_globalInfo.CheckCommitMemoryKey( testBinariesPath ) )
{
- testBinariesPath = fileWithoutExtension + ".dll";
- _globalInfo.Cake.Information( $"Testing via NUnitLite ({framework}): {testBinariesPath}" );
- if( !_globalInfo.CheckCommitMemoryKey( testBinariesPath ) )
+ _globalInfo.Cake.NUnit3( new[] { testBinariesPath }, new NUnit3Settings
{
- _globalInfo.Cake.DotNetExecute( testBinariesPath );
- }
+ Results = new[] { new NUnit3Result() { FileName = FilePath.FromString( projectPath.AppendPart( "TestResult.Net461.xml" ) ) } }
+ } );
}
}
- if( isVSTest )
+ else
{
testBinariesPath = fileWithoutExtension + ".dll";
- // VS Tests
- _globalInfo.Cake.Information( $"Testing via VSTest ({framework}): {testBinariesPath}" );
+ _globalInfo.Cake.Information( $"Testing via NUnitLite ({framework}): {testBinariesPath}" );
if( !_globalInfo.CheckCommitMemoryKey( testBinariesPath ) )
{
- var options = new DotNetTestSettings()
- {
- Configuration = _globalInfo.BuildInfo.BuildConfiguration,
- Framework = framework,
- NoRestore = true,
- NoBuild = true,
- Loggers = new List() { "trx" }
- };
- if( _globalInfo.Cake.Environment.GetEnvironmentVariable( "DisableNodeReUse" ) != null )
- {
- options.ArgumentCustomization = args => args.Append( "/nodeReuse:false" );
- }
- _globalInfo.Cake.DotNetTest( projectPath, options );
+ _globalInfo.Cake.DotNetExecute( testBinariesPath );
}
}
+ }
+ if( isVSTest )
+ {
+ testBinariesPath = fileWithoutExtension + ".dll";
+ // VS Tests
+ _globalInfo.Cake.Information( $"Testing via VSTest ({framework}): {testBinariesPath}" );
+ if( !_globalInfo.CheckCommitMemoryKey( testBinariesPath ) )
+ {
+ var options = new DotNetTestSettings()
+ {
+ Configuration = _globalInfo.BuildInfo.BuildConfiguration,
+ Framework = framework,
+ NoRestore = true,
+ NoBuild = true,
+ Loggers = ["trx"]
+ };
+ if( _globalInfo.Cake.Environment.GetEnvironmentVariable( "DisableNodeReUse" ) != null )
+ {
+ options.ArgumentCustomization = args => args.Append( "/nodeReuse:false" );
+ }
+ _globalInfo.Cake.DotNetTest( projectPath, options );
+ }
+ }
- if( !isVSTest && !isNunitLite )
+ if( !isVSTest && !isNunitLite )
+ {
+ testBinariesPath = fileWithoutExtension + ".dll";
+ _globalInfo.Cake.Information( "Testing via NUnit: {0}", testBinariesPath );
+ if( !_globalInfo.CheckCommitMemoryKey( testBinariesPath ) )
{
- testBinariesPath = fileWithoutExtension + ".dll";
- _globalInfo.Cake.Information( "Testing via NUnit: {0}", testBinariesPath );
- if( !_globalInfo.CheckCommitMemoryKey( testBinariesPath ) )
+ _globalInfo.Cake.NUnit( new[] { testBinariesPath }, new NUnitSettings()
{
- _globalInfo.Cake.NUnit( new[] { testBinariesPath }, new NUnitSettings()
- {
- Framework = "v4.5",
- ResultsFile = FilePath.FromString( projectPath.AppendPart( "TestResult.Net461.xml" ) )
- } );
+ Framework = "v4.5",
+ ResultsFile = FilePath.FromString( projectPath.AppendPart( "TestResult.Net461.xml" ) )
+ } );
- }
}
- _globalInfo.WriteCommitMemoryKey( testBinariesPath );
}
+ _globalInfo.WriteCommitMemoryKey( testBinariesPath );
}
}
+ }
- void ICIWorkflow.Build() => Build();
+ void ICIWorkflow.Build() => Build();
- void ICIWorkflow.Test() => Test();
- }
+ void ICIWorkflow.Test() => SolutionTest();
}
diff --git a/Directory.Build.props b/Directory.Build.props
index 2943ffc..462c47c 100644
--- a/Directory.Build.props
+++ b/Directory.Build.props
@@ -9,6 +9,8 @@
strict
+
+ enable
true
true
@@ -62,16 +64,16 @@
-
+
-
+
-
+