public void OnBuildCreated(NukeBuild build, IReadOnlyCollection <ExecutableTarget> executableTargets) { if (NukeBuild.IsServerBuild) { return; } var hasConfigurationChanged = GetGenerators(build) .Where(x => x.AutoGenerate) .AsParallel() .Select(HasConfigurationChanged).ToList(); if (hasConfigurationChanged.All(x => !x)) { return; } if (build.Help) { return; } Logger.Info("Press any key to continue..."); Console.ReadKey(); }
public void OnBuildInitialized( NukeBuild build, IReadOnlyCollection <ExecutableTarget> executableTargets, IReadOnlyCollection <ExecutableTarget> executionPlan) { object GetMappedValue(string name) => _targetType .GetField(name) .NotNull($"Type {_targetType} doesn't have a field {name}.") .GetValue(obj: null); if (Quiet != null) { VerbosityMapping.Mappings.Add(_targetType, (Verbosity.Quiet, GetMappedValue(Quiet))); } if (Minimal != null) { VerbosityMapping.Mappings.Add(_targetType, (Verbosity.Minimal, GetMappedValue(Minimal))); } if (Normal != null) { VerbosityMapping.Mappings.Add(_targetType, (Verbosity.Normal, GetMappedValue(Normal))); } if (Verbose != null) { VerbosityMapping.Mappings.Add(_targetType, (Verbosity.Verbose, GetMappedValue(Verbose))); } }
protected override IEnumerable <TeamCityBuildType> GetBuildTypes( NukeBuild build, ExecutableTarget executableTarget, TeamCityVcsRoot vcsRoot, LookupTable <ExecutableTarget, TeamCityBuildType> buildTypes, IReadOnlyCollection <ExecutableTarget> relevantTargets) { var dictionary = new Dictionary <string, string> { { nameof(Compile), "⚙️" }, { nameof(Test), "🚦" }, { nameof(Pack), "📦" }, { nameof(Coverage), "📊" }, { nameof(Publish), "🚚" }, { nameof(Announce), "🗣" } }; return(base.GetBuildTypes(build, executableTarget, vcsRoot, buildTypes, relevantTargets) .ForEachLazy(x => { var symbol = dictionary.GetValueOrDefault(x.InvokedTargets.Last()).NotNull("symbol != null"); x.Name = x.PartitionName == null ? $"{symbol} {x.Name}" : $"{symbol} {x.InvokedTargets.Last()} 🧩 {x.Partition}"; })); }
public static void Execute(NukeBuild build, [CanBeNull] IReadOnlyCollection <string> skippedTargets) { MarkSkippedTargets(build, skippedTargets); RequirementService.ValidateRequirements(build, build.ExecutingTargets.ToList()); var previouslyExecutedTargets = UpdateInvocationHash(); BuildManager.CancellationHandler += ExecuteAssuredTargets; try { build.ExecutionPlan.ForEach(x => Execute(build, x, previouslyExecutedTargets)); } catch { ExecuteAssuredTargets(); throw; } void ExecuteAssuredTargets() { var assuredTargets = build.ExecutionPlan.Where(x => x.AssuredAfterFailure && x.Status == ExecutionStatus.NotRun); assuredTargets.ForEach(x => Execute(build, x, previouslyExecutedTargets, failureMode: true)); } }
public void OnBuildFinished(NukeBuild build) { if (NukeBuild.IsServerBuild && ShouldNotify) { Notify(); } }
public static void ValidateRequirements(NukeBuild build, IReadOnlyCollection <ExecutableTarget> executingTargets) { foreach (var target in executingTargets) { foreach (var requirement in target.Requirements) { if (requirement is Expression <Func <bool> > boolExpression) { // TODO: same as HasSkippingCondition.GetSkipReason ControlFlow.Assert(boolExpression.Compile().Invoke(), $"Target '{target.Name}' requires '{requirement.Body}'."); } else if (IsMemberNull(requirement.GetMemberInfo(), build, target)) { ControlFlow.Fail($"Target '{target.Name}' requires member '{requirement.GetMemberInfo().Name}' to be not null."); } } } var requiredMembers = ValueInjectionUtility.GetInjectionMembers(build.GetType()) .Select(x => x.Member) .Where(x => x.HasCustomAttribute <RequiredAttribute>()); foreach (var member in requiredMembers) { if (IsMemberNull(member, build)) { ControlFlow.Fail($"Member '{member.Name}' is required to be not null."); } } }
private static IReadOnlyCollection <string> UpdateInvocationHash(NukeBuild build) { var continueParameterName = ParameterService.GetParameterMemberName(() => build.Continue); var invocation = EnvironmentInfo.CommandLineArguments .Where(x => !x.StartsWith("-") || x.TrimStart("-").EqualsOrdinalIgnoreCase(continueParameterName)) .JoinSpace(); var invocationHash = invocation.GetMD5Hash(); IReadOnlyCollection <string> GetPreviouslyExecutedTargets() { if (!build.Continue || !File.Exists(BuildAttemptFile)) { return(new string[0]); } var previousBuild = File.ReadAllLines(BuildAttemptFile); if (previousBuild.FirstOrDefault() != invocationHash) { Logger.Warn("Build invocation changed. Starting over..."); return(new string[0]); } return(previousBuild.Skip(1).ToArray()); } var previouslyExecutedTargets = GetPreviouslyExecutedTargets(); File.WriteAllLines(BuildAttemptFile, new[] { invocationHash }); return(previouslyExecutedTargets); }
public override object GetValue(MemberInfo member, NukeBuild build) { return(ProjectModelTasks.ParseSolution( GetSolutionFile(member.Name), Configuration, TargetFramework)); }
public static void Execute(NukeBuild build, [CanBeNull] IReadOnlyCollection <string> skippedTargets) { var invocationHash = GetInvocationHash(); var previouslyExecutedTargets = GetPreviouslyExecutedTargets(invocationHash); File.WriteAllLines(BuildAttemptFile, new[] { invocationHash }); MarkSkippedTargets(build, skippedTargets); BuildManager.CancellationHandler += ExecuteAssuredTargets; try { build.ExecutionPlan.ForEach(x => Execute(build, x, previouslyExecutedTargets)); } catch { ExecuteAssuredTargets(); throw; } void ExecuteAssuredTargets() { var assuredTargets = build.ExecutionPlan.Where(x => x.AssuredAfterFailure && x.Status == ExecutionStatus.NotRun); assuredTargets.ForEach(x => Execute(build, x, previouslyExecutedTargets, failureMode: true)); } }
private static void Execute( NukeBuild build, ExecutableTarget target, IReadOnlyCollection <string> previouslyExecutedTargets, bool failureMode = false) { if (target.Status == ExecutionStatus.Skipped || previouslyExecutedTargets.Contains(target.Name) || HasSkippingCondition(target, target.DynamicConditions)) { target.Status = ExecutionStatus.Skipped; build.ExecuteExtension <IOnTargetSkipped>(x => x.OnTargetSkipped(build, target)); AppendToBuildAttemptFile(target.Name); return; } if (target.Actions.Count == 0) { target.Status = ExecutionStatus.Collective; return; } using (Logging.SetTarget(target.Name)) using (build.WriteTarget(target.Name)) { target.Stopwatch.Start(); target.Status = ExecutionStatus.Running; build.ExecuteExtension <IOnTargetRunning>(x => x.OnTargetRunning(build, target)); try { target.Actions.ForEach(x => x()); target.Stopwatch.Stop(); target.Status = ExecutionStatus.Succeeded; build.ExecuteExtension <IOnTargetSucceeded>(x => x.OnTargetSucceeded(build, target)); AppendToBuildAttemptFile(target.Name); } catch (Exception exception) { exception = exception.Unwrap(); if (!target.SummaryInformation.Any()) { build.ReportSummary( target, _ => _.AddPair(exception.GetType().Name, exception.Message.SplitLineBreaks().First())); } Log.Error(exception, "Target {TargetName} has thrown an exception", target.Name); target.Stopwatch.Stop(); target.Status = ExecutionStatus.Failed; build.ExecuteExtension <IOnTargetFailed>(x => x.OnTargetFailed(build, target)); if (!target.ProceedAfterFailure && !failureMode) { throw new TargetExecutionException(target.Name, exception); } } } }
public void OnBuildFinished(NukeBuild build) { GetGenerators(build) // TODO: bool IsRunning .FirstOrDefault(x => x.HostType == NukeBuild.Host.GetType()) ?.SerializeState(); }
/// <inheritdoc /> public void OnBuildCreated(NukeBuild build, IReadOnlyCollection <ExecutableTarget> executableTargets) { if (!NukeBuild.IsLocalBuild) { return; } // We only care on local machines if (HookNames.Any(hook => !FileExists(NukeBuild.RootDirectory / $".git/hooks/{hook}"))) { Logger.Info("Git hooks not found..."); if (FileExists(NukeBuild.RootDirectory / "package.json")) { Logger.Info("package.json found running npm install to see if that installs any hooks"); ProcessTasks.StartProcess(ToolPathResolver.GetPathExecutable("npm"), "install").AssertWaitForExit() .AssertZeroExitCode(); } } foreach (var hook in HookNames) { if (!FileExists(NukeBuild.RootDirectory / $".git/hooks/{hook}")) { Logger.Info($"Was unable to install {hook} hook."); } } }
public void OnBeforeLogo( NukeBuild build, IReadOnlyCollection <ExecutableTarget> executableTargets) { var completionItems = new SortedDictionary <string, string[]>(); var targetNames = build.ExecutableTargets.Select(x => x.Name).OrderBy(x => x).ToList(); completionItems[Constants.InvokedTargetsParameterName] = targetNames.ToArray(); completionItems[Constants.SkippedTargetsParameterName] = targetNames.ToArray(); var parameters = InjectionUtility.GetParameterMembers(build.GetType(), includeUnlisted: false); foreach (var parameter in parameters) { var parameterName = ParameterService.GetParameterMemberName(parameter); if (completionItems.ContainsKey(parameterName)) { continue; } var subItems = ParameterService.GetParameterValueSet(parameter, build)?.Select(x => x.Text); completionItems[parameterName] = subItems?.ToArray(); } SerializationTasks.YamlSerializeToFile(completionItems, Constants.GetCompletionFile(NukeBuild.RootDirectory)); if (EnvironmentInfo.GetParameter <bool>(Constants.CompletionParameterName)) { Environment.Exit(exitCode: 0); } }
protected virtual TeamCityProject GetProject( NukeBuild build, IReadOnlyCollection <ExecutableTarget> executableTargets) { var relevantTargets = VcsTriggeredTargets.Concat(ManuallyTriggeredTargets) .SelectMany(x => ExecutionPlanner.GetExecutionPlan(executableTargets, new[] { x })) .Distinct() .Where(x => !ExcludedTargets.Contains(x.Name) && !NonEntryTargets.Contains(x.Name)).ToList(); var vcsRoot = GetVcsRoot(build); var lookupTable = new LookupTable <ExecutableTarget, TeamCityBuildType>(); var buildTypes = relevantTargets .SelectMany(x => GetBuildTypes(build, x, vcsRoot, lookupTable), (x, y) => (ExecutableTarget: x, BuildType: y)) .ForEachLazy(x => lookupTable.Add(x.ExecutableTarget, x.BuildType)) .Select(x => x.BuildType).ToArray(); var parameters = GetGlobalParameters(build); if (Platform == TeamCityAgentPlatform.Windows) { parameters = parameters .Concat(new TeamCityKeyValueParameter { Key = "teamcity.runner.commandline.stdstreams.encoding", Value = "IBM-437" }); } return(new TeamCityProject { VcsRoot = vcsRoot, BuildTypes = buildTypes, Parameters = parameters.ToArray() }); }
public void Execute(NukeBuild build) { object GetMappedValue(string name) => _targetType .GetField(name) .NotNull($"Type {_targetType} doesn't have a field {name}.") .GetValue(obj: null); if (Quiet != null) { VerbosityMapping.Mappings.Add(_targetType, (Verbosity.Quiet, GetMappedValue(Quiet))); } if (Minimal != null) { VerbosityMapping.Mappings.Add(_targetType, (Verbosity.Minimal, GetMappedValue(Minimal))); } if (Normal != null) { VerbosityMapping.Mappings.Add(_targetType, (Verbosity.Normal, GetMappedValue(Normal))); } if (Verbose != null) { VerbosityMapping.Mappings.Add(_targetType, (Verbosity.Verbose, GetMappedValue(Verbose))); } }
protected virtual TeamCityProject GetProject(NukeBuild build, IReadOnlyCollection <ExecutableTarget> relevantTargets) { var vcsRoot = GetVcsRoot(build); var lookupTable = new LookupTable <ExecutableTarget, TeamCityBuildType>(); var buildTypes = relevantTargets .SelectMany(x => GetBuildTypes(build, x, vcsRoot, lookupTable, relevantTargets), (x, y) => (ExecutableTarget: x, BuildType: y)) .ForEachLazy(x => lookupTable.Add(x.ExecutableTarget, x.BuildType)) .Select(x => x.BuildType).ToArray(); var parameters = GetGlobalParameters(build, relevantTargets); if (Platform == TeamCityAgentPlatform.Windows) { parameters = parameters .Concat(new TeamCityKeyValueParameter { Key = "teamcity.runner.commandline.stdstreams.encoding", Value = "UTF-8" }); } return(new TeamCityProject { VcsRoot = vcsRoot, BuildTypes = buildTypes, Parameters = parameters.ToArray() }); }
protected virtual IEnumerable <GithubActionsNukeParameter> GetParameters(NukeBuild build) { var parameters = build.GetType().GetMembers( BindingFlags.Instance | BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.FlattenHierarchy ) .Where(x => x.GetCustomAttribute <ParameterAttribute>() != null); foreach (var parameter in parameters) { if (Parameters.Any( z => z.Equals(parameter.Name, StringComparison.OrdinalIgnoreCase) || z.Equals( parameter.GetCustomAttribute <ParameterAttribute>().Name, StringComparison.OrdinalIgnoreCase ) )) { var value = parameter.GetValue(build); if (value is AbsolutePath) { value = null; } yield return(new GithubActionsNukeParameter() { Name = parameter.GetCustomAttribute <ParameterAttribute>().Name ?? parameter.Name, Default = value?.ToString() ?? "", }); } } }
public override ConfigurationEntity GetConfiguration(NukeBuild build, IReadOnlyCollection <ExecutableTarget> relevantTargets) { var parameters = GetGlobalParameters(build, relevantTargets); if (parameters.Any()) { var importSecrets = ImportSecrets; ImportSecrets = importSecrets.Concat(parameters.Select(p => p.Name)).Distinct().ToArray(); var config = (AzurePipelinesConfiguration)base.GetConfiguration(build, relevantTargets); ImportSecrets = importSecrets; return(new AzurePipelinesVariablesConfiguration { VariableGroups = config.VariableGroups, VcsPushTrigger = config.VcsPushTrigger, Stages = config.Stages, Variables = parameters.Where(p => !ImportSecrets.Contains(p.Name)).ToArray() }); } return(base.GetConfiguration(build, relevantTargets)); }
private static void TryInjectValueInteractive(MemberInfo member, NukeBuild build) { if (!member.HasCustomAttribute <ParameterAttribute>()) { return; } if (member is PropertyInfo property && !property.CanWrite) { return; } var memberType = member.GetMemberType(); var nameOrDescription = ParameterService.GetParameterDescription(member) ?? ParameterService.GetParameterMemberName(member); var text = $"{nameOrDescription.TrimEnd('.')}:"; while (member.GetValue(build) == null) { var valueSet = ParameterService.GetParameterValueSet(member, build); var value = valueSet == null ? ConsoleUtility.PromptForInput(text, defaultValue : null) : ConsoleUtility.PromptForChoice(text, valueSet.Select(x => (x.Object, x.Text)).ToArray()); member.SetValue(build, ReflectionService.Convert(value, memberType)); } }
private static void WriteCompletionFile(NukeBuild build) { var completionItems = new SortedDictionary <string, string[]>(); var targets = build.ExecutableTargets.OrderBy(x => x.Name).ToList(); completionItems[InvokedTargetsParameterName] = targets.Where(x => x.Listed).Select(x => x.Name).ToArray(); completionItems[SkippedTargetsParameterName] = targets.Select(x => x.Name).ToArray(); var parameters = ValueInjectionUtility.GetParameterMembers(build.GetType(), includeUnlisted: false); foreach (var parameter in parameters) { var parameterName = ParameterService.GetParameterMemberName(parameter); if (completionItems.ContainsKey(parameterName)) { continue; } var subItems = ParameterService.GetParameterValueSet(parameter, build)?.Select(x => x.Text); completionItems[parameterName] = subItems?.ToArray(); } SerializationTasks.YamlSerializeToFile(completionItems, GetCompletionFile(NukeBuild.RootDirectory)); }
public static void WriteBuildSchemaFile(NukeBuild build) { var buildSchemaFile = GetBuildSchemaFile(NukeBuild.RootDirectory); var buildSchema = GetBuildSchema(build); File.WriteAllText(buildSchemaFile, buildSchema.ToString()); }
public void OnBuildInitialized( NukeBuild build, IReadOnlyCollection <ExecutableTarget> executableTargets, IReadOnlyCollection <ExecutableTarget> executionPlan) { ControlFlow.AssertWarn(Task.Run(CheckConfiguration).Wait(TimeoutInMilliseconds), $"Could not complete checking build configurations within {TimeoutInMilliseconds} milliseconds.");
public void OnAfterLogo( NukeBuild build, IReadOnlyCollection <ExecutableTarget> executableTargets, IReadOnlyCollection <ExecutableTarget> executionPlan) { if (!AutoGenerate || NukeBuild.IsServerBuild) { return; } Logger.LogLevel = LogLevel.Trace; var previousHashes = GeneratedFiles .Where(File.Exists) .ToDictionary(x => x, FileSystemTasks.GetFileHash); var assembly = Assembly.GetEntryAssembly().NotNull("assembly != null"); ProcessTasks.StartProcess( assembly.Location, $"--{ConfigurationParameterName} --host {HostType}", logInvocation: false, logOutput: true) .AssertZeroExitCode(); var changedFiles = GeneratedFiles .Where(x => FileSystemTasks.GetFileHash(x) != previousHashes.GetValueOrDefault(x)) .Select(x => GetRelativePath(NukeBuild.RootDirectory, x)).ToList(); if (changedFiles.Count > 0) { Logger.Warn($"{HostType} configuration files have changed."); changedFiles.ForEach(x => Logger.Trace($"Updated {x}")); } }
public void Generate(NukeBuild build, IReadOnlyCollection <ExecutableTarget> executableTargets) { var relevantTargets = RelevantTargetNames .SelectMany(x => ExecutionPlanner.GetExecutionPlan(executableTargets, new[] { x })) .Distinct() .Where(x => !IrrelevantTargetNames.Contains(x.Name)).ToList(); var configuration = GetConfiguration(build, relevantTargets); using var stream = CreateStream(); var writer = CreateWriter(stream); writer.WriteComment("------------------------------------------------------------------------------"); writer.WriteComment("<auto-generated>"); writer.WriteComment(); writer.WriteComment(" This code was generated."); writer.WriteComment(); writer.WriteComment(" - To turn off auto-generation set:"); writer.WriteComment(); writer.WriteComment($" [{GetType().Name.TrimEnd(nameof(Attribute))} ({nameof(IConfigurationGenerator.AutoGenerate)} = false)]"); writer.WriteComment(); writer.WriteComment(" - To trigger manual generation invoke:"); writer.WriteComment(); writer.WriteComment($" nuke --{ConfigurationParameterName} {Id} --host {HostName}"); writer.WriteComment(); writer.WriteComment("</auto-generated>"); writer.WriteComment("------------------------------------------------------------------------------"); writer.WriteLine(); writer.Write(configuration.Write); }
public static void ValidateRequirements(NukeBuild build) { foreach (var target in build.ExecutionPlan) { foreach (var requirement in target.Requirements) { if (requirement is Expression <Func <bool> > boolExpression) { ControlFlow.Assert(boolExpression.Compile().Invoke(), $"Target '{target.Name}' requires '{requirement.Body}'."); } else if (IsMemberNull(requirement.GetMemberInfo(), build, target)) { ControlFlow.Fail($"Target '{target.Name}' requires member '{requirement.GetMemberInfo().Name}' to be not null."); } } } var requiredMembers = InjectionUtility.GetParameterMembers(build.GetType()).Where(x => x.HasCustomAttribute <RequiredAttribute>()); foreach (var member in requiredMembers) { if (IsMemberNull(member, build)) { ControlFlow.Fail($"Member '{member.Name}' is required to be not null."); } } }
private static IDictionary <string, string> GetBuildProperties(NukeBuild build) { var startTimeString = EnvironmentInfo.Variables.GetValueOrDefault(Constants.GlobalToolStartTimeEnvironmentKey); var compileTime = startTimeString != null ? DateTime.Now.Subtract(DateTime.Parse(startTimeString)) : default(TimeSpan?); return(new Dictionary <string, string> { ["compile_time"] = compileTime?.TotalSeconds.ToString("F0"), ["target_framework"] = EnvironmentInfo.Framework.ToString(), ["host"] = GetTypeName(NukeBuild.Host), ["build_type"] = NukeBuild.BuildProjectFile != null ? "Project" : "Global Tool", ["num_targets"] = build.ExecutableTargets.Count.ToString(), ["num_custom_extensions"] = build.BuildExtensions.Select(x => x.GetType()).Count(IsCustomType).ToString(), ["num_custom_components"] = build.GetType().GetInterfaces().Count(IsCustomType).ToString(), ["num_partitioned_targets"] = build.ExecutableTargets.Count(x => x.PartitionSize.HasValue).ToString(), ["num_secrets"] = ValueInjectionUtility.GetParameterMembers(build.GetType(), includeUnlisted: true) .Count(x => x.HasCustomAttribute <SecretAttribute>()).ToString(), ["config_generators"] = build.GetType().GetCustomAttributes <ConfigurationAttributeBase>() .Select(GetTypeName).Distinct().OrderBy(x => x).JoinCommaSpace(), ["build_components"] = build.GetType().GetInterfaces().Where(x => IsCommonType(x) && x != typeof(INukeBuild)) .Select(GetTypeName).Distinct().OrderBy(x => x).JoinCommaSpace() }); }
public static IReadOnlyCollection <TargetDefinition> GetExecutingTargets(NukeBuild build, [CanBeNull] string[] invokedTargetNames = null) { ControlFlow.Assert(build.TargetDefinitions.All(x => !x.Name.EqualsOrdinalIgnoreCase(BuildExecutor.DefaultTarget)), $"The name '{BuildExecutor.DefaultTarget}' cannot be used as target name."); var invokedTargets = invokedTargetNames?.Select(x => GetDefinition(x, build)).ToList() ?? new List <TargetDefinition>(); var executingTargets = GetUnfilteredExecutingTargets(build, invokedTargets); var skippedTargets = executingTargets .Where(x => !invokedTargets.Contains(x) && build.SkippedTargets != null && (build.SkippedTargets.Length == 0 || build.SkippedTargets.Contains(x.Name, StringComparer.OrdinalIgnoreCase))).ToList(); skippedTargets.ForEach(x => x.Skip = true); executingTargets .Where(x => x.DependencyBehavior == DependencyBehavior.Skip) .Where(x => x.Conditions.Any(y => !y())) .ForEach(x => SkipTargetAndDependencies(x, invokedTargets, executingTargets)); string[] GetNames(IEnumerable <TargetDefinition> targets) => targets.Select(x => x.Name).ToArray(); ReflectionService.SetValue(build, nameof(NukeBuild.InvokedTargets), GetNames(invokedTargets)); ReflectionService.SetValue(build, nameof(NukeBuild.SkippedTargets), GetNames(skippedTargets)); ReflectionService.SetValue(build, nameof(NukeBuild.ExecutingTargets), GetNames(executingTargets.Except(skippedTargets))); return(executingTargets); }
public void OnAfterLogo( NukeBuild build, IReadOnlyCollection <ExecutableTarget> executableTargets, IReadOnlyCollection <ExecutableTarget> executionPlan) { ValueInjectionUtility.InjectValues(build, x => !(x is ParameterAttribute)); }
public override ConfigurationEntity GetConfiguration(NukeBuild build, IReadOnlyCollection <ExecutableTarget> relevantTargets) { return(new AzurePipelinesConfiguration { Stages = _images.Select(x => GetStage(x, relevantTargets)).ToArray() }); }
public void OnBuildInitialized( NukeBuild build, IReadOnlyCollection<ExecutableTarget> executableTargets, IReadOnlyCollection<ExecutableTarget> executionPlan) { ProcessTasks.CheckPathEnvironmentVariable(); }