Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -534,8 +534,8 @@ private void WriteCommandStep(
continue;

foreach (var input in githubManualTrigger.Inputs.Where(i => target
.RequiredParams
.Select(p => p.ArgName)
.Params
.Select(p => p.Param.ArgName)
.Any(p => p == i.Name)))
env[input.Name] = $"${{{{ parameters.{input.Name} }}}}";
}
Expand All @@ -545,12 +545,12 @@ private void WriteCommandStep(
$"$({buildDefinition.ParamDefinitions[consumedVariable.VariableName].ArgName})";

var requiredSecrets = target
.RequiredParams
.Where(x => x.IsSecret)
.Params
.Where(x => x.Param.IsSecret)
.Select(x => x)
.ToArray();

if (requiredSecrets.Any(x => x.IsSecret))
if (requiredSecrets.Any(x => x.Param.IsSecret))
{
foreach (var injectedSecret in workflow.Options.OfType<WorkflowSecretsSecretInjection>())
{
Expand Down Expand Up @@ -594,10 +594,10 @@ private void WriteCommandStep(
.Options
.Concat(workflowStep.Options)
.OfType<WorkflowSecretInjection>()
.FirstOrDefault(x => x.Value == requiredSecret.Name);
.FirstOrDefault(x => x.Value == requiredSecret.Param.Name);

if (injectedSecret is not null)
env[requiredSecret.ArgName] = $"$({requiredSecret.ArgName.ToUpper().Replace('-', '_')})";
env[requiredSecret.Param.ArgName] = $"$({requiredSecret.Param.ArgName.ToUpper().Replace('-', '_')})";
}

var environmentInjections = workflow.Options.OfType<WorkflowEnvironmentInjection>();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -487,8 +487,8 @@ private void WriteCommandStep(
continue;

foreach (var input in githubManualTrigger.Inputs.Where(i => target
.RequiredParams
.Select(p => p.ArgName)
.Params
.Select(p => p.Param.ArgName)
.Any(p => p == i.Name)))
env[input.Name] = $"${{{{ inputs.{input.Name} }}}}";
}
Expand All @@ -498,12 +498,12 @@ private void WriteCommandStep(
$"${{{{ needs.{consumedVariable.TargetName}.outputs.{buildDefinition.ParamDefinitions[consumedVariable.VariableName].ArgName} }}}}";

var requiredSecrets = target
.RequiredParams
.Where(x => x.IsSecret)
.Params
.Where(x => x.Param.IsSecret)
.Select(x => x)
.ToArray();

if (requiredSecrets.Any(x => x.IsSecret))
if (requiredSecrets.Any(x => x.Param.IsSecret))
{
foreach (var injectedSecret in workflow.Options.OfType<WorkflowSecretsSecretInjection>())
{
Expand Down Expand Up @@ -547,10 +547,10 @@ private void WriteCommandStep(
.Options
.Concat(workflowStep.Options)
.OfType<WorkflowSecretInjection>()
.FirstOrDefault(x => x.Value == requiredSecret.Name);
.FirstOrDefault(x => x.Value == requiredSecret.Param.Name);

if (injectedSecret is not null)
env[requiredSecret.ArgName] = $"${{{{ secrets.{requiredSecret.ArgName.ToUpper().Replace('-', '_')} }}}}";
env[requiredSecret.Param.ArgName] = $"${{{{ secrets.{requiredSecret.Param.ArgName.ToUpper().Replace('-', '_')} }}}}";
}

var environmentInjections = workflow.Options.OfType<WorkflowEnvironmentInjection>();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,11 +56,6 @@ private static void GenerateCode(
GeneratePartial(context, classSymbol, classDeclarationSyntax);
}

private static string SimpleName(string fullName) =>
fullName
.Split('.')
.Last();

private static void GeneratePartial(
SourceProductionContext context,
INamedTypeSymbol classSymbol,
Expand Down
35 changes: 35 additions & 0 deletions DecSm.Atom.Tests/BuildTests/Params/OptionalParamBuild.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
namespace DecSm.Atom.Tests.BuildTests.Params;

[BuildDefinition]
public partial class OptionalParamBuild : BuildDefinition, IOptionalParamTarget1
{
public string? ExecuteValue1 { get; set; }

public string? ExecuteValue2 { get; set; }
}

[TargetDefinition]
public partial interface IOptionalParamTarget1
{
[ParamDefinition("param-1", "Param 1")]
string? Param1 => GetParam(() => Param1);

[ParamDefinition("param-2", "Param 2")]
string? Param2 => GetParam(() => Param2);

string? ExecuteValue1 { get; set; }

string? ExecuteValue2 { get; set; }

Target OptionalParamTarget1 =>
t => t
.RequiresParam(nameof(Param1))
.UsesParam(nameof(Param2))
.Executes(() =>
{
ExecuteValue1 = Param1;
ExecuteValue2 = Param2;

return Task.CompletedTask;
});
}
25 changes: 25 additions & 0 deletions DecSm.Atom.Tests/BuildTests/Params/ParamTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -55,4 +55,29 @@ public void Param_WhenRequiredAndNotSupplied_StopsAndReturnsError()
.ToString()
.ShouldContain("Missing required parameter 'param-2' for target ParamTarget2");
}

[Test]
public void Param_WhenOptionalAndNotSupplied_UsesDefaultValue()
{
// Arrange
var loggerProvider = new TestLoggerProvider();

var host = CreateTestHost<OptionalParamBuild>(commandLineArgs: new(true,
[
new CommandArg(nameof(IOptionalParamTarget1.OptionalParamTarget1)),
new ParamArg("param-1", nameof(IOptionalParamTarget1.Param1), "TestValue"),
]),
configure: builder => builder.Logging.AddProvider(loggerProvider));

var build = (OptionalParamBuild)host.Services.GetRequiredService<IBuildDefinition>();

// Act
host.Run();

// Assert
TestContext.Out.WriteLine(loggerProvider.Logger.LogContent.ToString());

build.ExecuteValue1.ShouldBe("TestValue");
build.ExecuteValue2.ShouldBeNull();
}
}
2 changes: 1 addition & 1 deletion DecSm.Atom.Tests/ClassTests/Build/BuildExecutorTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ public async Task Execute_WhenBuildIsValid_SucceedsAndLogs()
return Task.CompletedTask;
},
],
RequiredParams = [],
Params = [],
ConsumedArtifacts = [],
ProducedArtifacts = [],
ConsumedVariables = [],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -111,9 +111,10 @@ public void RequiresParam_AddsRequiredParam()
targetDefinition.RequiresParam(paramName);

// Assert
targetDefinition.RequiredParams.ShouldSatisfyAllConditions(x => x.ShouldNotBeEmpty(),
targetDefinition.Params.ShouldSatisfyAllConditions(x => x.ShouldNotBeEmpty(),
x => x.Count.ShouldBe(1),
x => x[0]
.Param
.ShouldBe(paramName));
}

Expand Down
2 changes: 1 addition & 1 deletion DecSm.Atom.Tests/ClassTests/Build/Model/BuildModelTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ public void CurrentTarget_WhenNoTargets_ReturnsNull()
new("TargetModel", null, false)
{
Tasks = [],
RequiredParams = [],
Params = [],
ConsumedArtifacts = [],
ProducedArtifacts = [],
ConsumedVariables = [],
Expand Down
5 changes: 4 additions & 1 deletion DecSm.Atom.Tool/Model.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,10 @@

internal static class Model
{
public static readonly Argument<string[]> RunArgs = new("runArgs");
public static readonly Argument<string[]> RunArgs = new("runArgs")
{
DefaultValueFactory = _ => [],
};

public static readonly Option<string> ProjectOption = new("--project", "-p")
{
Expand Down
14 changes: 7 additions & 7 deletions DecSm.Atom/Build/BuildExecutor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -46,29 +46,29 @@ public async Task Execute(CancellationToken cancellationToken)

private void ValidateTargetParameters(TargetModel target)
{
foreach (var requiredParam in target.RequiredParams)
foreach (var requiredParam in target.Params.Where(x => x.Required))
{
var defaultValue = requiredParam.DefaultValue is { Length: > 0 }
? requiredParam.DefaultValue
var defaultValue = requiredParam.Param.DefaultValue is { Length: > 0 }
? requiredParam.Param.DefaultValue
: null;

string? value;

if (requiredParam.IsSecret)
if (requiredParam.Param.IsSecret)
{
value = paramService.GetParam(requiredParam.Name, defaultValue, x => x);
value = paramService.GetParam(requiredParam.Param.Name, defaultValue, x => x);
}
else
{
using var _ = paramService.CreateNoCacheScope();
value = paramService.GetParam(requiredParam.Name, defaultValue);
value = paramService.GetParam(requiredParam.Param.Name, defaultValue);
}

if (value is { Length: > 0 })
continue;

logger.LogError("Missing required parameter '{ParamName}' for target {TargetDefinitionName}",
requiredParam.ArgName,
requiredParam.Param.ArgName,
target.Name);

buildModel.TargetStates[target].Status = TargetRunState.Failed;
Expand Down
4 changes: 2 additions & 2 deletions DecSm.Atom/Build/BuildResolver.cs
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ public BuildModel Resolve()
.ApplyExtensions(buildDefinition))
.ToArray();

// Duplicate target names could result in undefined behavior
// Duplicate target names could result in undefined behavior,
// So we fail early if any are found
// Note: This doesn't include overriden or extended targets
var duplicateTargetNames = targetDefinitions
Expand All @@ -61,7 +61,7 @@ public BuildModel Resolve()
return new TargetModel(x.Name, x.Description, x.Hidden)
{
Tasks = x.Tasks,
RequiredParams = x.RequiredParams.ConvertAll(p => paramModels[p]),
Params = x.Params.ConvertAll(p => new UsedParam(paramModels[p.Param], p.Required)),
ConsumedArtifacts = x.ConsumedArtifacts,
ProducedArtifacts = x.ProducedArtifacts,
ConsumedVariables = x.ConsumedVariables,
Expand Down
3 changes: 3 additions & 0 deletions DecSm.Atom/Build/Definition/DefinedParam.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
namespace DecSm.Atom.Build.Definition;

public sealed record DefinedParam(string Param, bool Required);
26 changes: 19 additions & 7 deletions DecSm.Atom/Build/Definition/TargetDefinition.cs
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,9 @@ public sealed class TargetDefinition
public List<string> Dependencies { get; private set; } = [];

/// <summary>
/// Names of parameters that must be provided when invoking the target.
/// Names of parameters that may/must be provided when invoking the target.
/// </summary>
public List<string> RequiredParams { get; private set; } = [];
public List<DefinedParam> Params { get; private set; } = [];

/// <summary>
/// Artifacts that must be produced by other targets before this target can be executed.
Expand Down Expand Up @@ -108,7 +108,7 @@ internal TargetDefinition ApplyExtensions(IBuildDefinition buildDefinition)
{
Tasks.AddRange(targetToExtend.Tasks);
Dependencies.AddRange(targetToExtend.Dependencies);
RequiredParams.AddRange(targetToExtend.RequiredParams);
Params.AddRange(targetToExtend.Params);
ConsumedArtifacts.AddRange(targetToExtend.ConsumedArtifacts);
ProducedArtifacts.AddRange(targetToExtend.ProducedArtifacts);
ConsumedVariables.AddRange(targetToExtend.ConsumedVariables);
Expand All @@ -126,9 +126,9 @@ internal TargetDefinition ApplyExtensions(IBuildDefinition buildDefinition)
.Concat(Dependencies)
.ToList();

RequiredParams = targetToExtend
.RequiredParams
.Concat(RequiredParams)
Params = targetToExtend
.Params
.Concat(Params)
.ToList();

ConsumedArtifacts = targetToExtend
Expand Down Expand Up @@ -244,14 +244,26 @@ public TargetDefinition DependsOn(WorkflowTargetDefinition workflowTarget)
return this;
}

/// <summary>
/// Specifies that this target may use the provided parameters for execution.
/// </summary>
/// <param name="paramNames">An array of parameter names that may be used by the target.</param>
/// <returns>This target definition.</returns>
public TargetDefinition UsesParam(params IEnumerable<string> paramNames)
{
Params.AddRange(paramNames.Select(x => new DefinedParam(x, false)));

return this;
}

/// <summary>
/// Specifies that this target requires the provided parameters to be defined for execution.
/// </summary>
/// <param name="paramNames">An array of parameter names that are required by the target.</param>
/// <returns>This target definition.</returns>
public TargetDefinition RequiresParam(params IEnumerable<string> paramNames)
{
RequiredParams.AddRange(paramNames);
Params.AddRange(paramNames.Select(x => new DefinedParam(x, true)));

return this;
}
Expand Down
4 changes: 2 additions & 2 deletions DecSm.Atom/Build/Model/TargetModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,9 @@ public sealed record TargetModel(string Name, string? Description, bool IsHidden
public required IReadOnlyList<Func<CancellationToken, Task>> Tasks { get; init; }

/// <summary>
/// Represents the input parameters that are mandatory for the execution of the target.
/// Represents the input parameters that are used for the execution of the target.
/// </summary>
public required IReadOnlyList<ParamModel> RequiredParams { get; init; }
public required IReadOnlyList<UsedParam> Params { get; init; }

/// <summary>
/// Artifacts that are consumed by the target during the build process.
Expand Down
3 changes: 3 additions & 0 deletions DecSm.Atom/Build/Model/UsedParam.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
namespace DecSm.Atom.Build.Model;

public sealed record UsedParam(ParamModel Param, bool Required);
Loading
Loading