Skip to content
This repository was archived by the owner on Jul 18, 2024. It is now read-only.

Commit 43b84a5

Browse files
Lots of minor fixes
1 parent 3e3b0dc commit 43b84a5

File tree

9 files changed

+144
-75
lines changed

9 files changed

+144
-75
lines changed

.gitignore

+1-2
Original file line numberDiff line numberDiff line change
@@ -5,5 +5,4 @@
55
*.user
66
.teamcity/target/
77
.reports/
8-
.packages
9-
.publish
8+
.packages

.run/Build.run.xml

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
<component name="ProjectRunConfigurationManager">
22
<configuration default="false" name="Build" type="DotNetProject" factoryName=".NET Project">
33
<option name="EXE_PATH" value="$PROJECT_DIR$/Build/bin/Debug/net8.0/Build.exe" />
4-
<option name="PROGRAM_PARAMETERS" value="-p:integrationTests=true -p:version=1.1.0-beta9" />
4+
<option name="PROGRAM_PARAMETERS" value="-p:integrationTests=true -p:version=1.1.0-beta11" />
55
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$" />
66
<option name="PASS_PARENT_ENVS" value="1" />
77
<option name="USE_EXTERNAL_CONSOLE" value="0" />

CSharpInteractive.HostApi/CommandLine.cs

+4-1
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,10 @@ public override string ToString()
6161
return sb.ToString();
6262
}
6363

64-
private static string Escape(string text) => !text.TrimStart().StartsWith("\"") && text.Contains(' ') ? $"\"{text}\"" : text;
64+
private static string Escape(string text) =>
65+
!text.TrimStart().StartsWith("\"") && text.Contains(' ')
66+
? $"\"{text}\""
67+
: text;
6568

6669
internal class CommandLineDebugView(IStartInfo startInfo)
6770
{

CSharpInteractive.HostApi/DockerCustom.cs

+4-1
Original file line numberDiff line numberDiff line change
@@ -35,5 +35,8 @@ public IStartInfo GetStartInfo(IHost host)
3535
.WithArgs(Args.ToArray());
3636
}
3737

38-
public override string ToString() => string.IsNullOrWhiteSpace(ShortName) ? ((ExecutablePath == string.Empty ? "docker" : Path.GetFileNameWithoutExtension(ExecutablePath)) + " " + Args.FirstOrDefault()).TrimEnd() : ShortName;
38+
public override string ToString() =>
39+
string.IsNullOrWhiteSpace(ShortName)
40+
? ((ExecutablePath == string.Empty ? "docker" : Path.GetFileNameWithoutExtension(ExecutablePath)) + " " + Args.FirstOrDefault()).TrimEnd()
41+
: ShortName;
3942
}

CSharpInteractive.HostApi/DockerRun.cs

+6-7
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,7 @@ public IStartInfo GetStartInfo(IHost host)
122122
("--name", Name ?? string.Empty),
123123
("--network", Network),
124124
("--platform", Platform),
125-
("--platform", Pull?.ToString() ?? string.Empty),
125+
("--pull", Pull?.ToString()?.ToLowerInvariant() ?? string.Empty),
126126
("--user", User),
127127
("--workdir", ContainerWorkingDirectory),
128128
("--env-file", EnvFile))
@@ -140,7 +140,10 @@ public IStartInfo GetStartInfo(IHost host)
140140
.WithVars(Vars.ToArray());
141141
}
142142

143-
public override string ToString() => !string.IsNullOrWhiteSpace(ShortName) ? ShortName : $"{CommandLine} in the docker container {Image}";
143+
public override string ToString() =>
144+
string.IsNullOrWhiteSpace(ShortName)
145+
? $"{CommandLine} in the docker container {Image}"
146+
: ShortName;
144147

145148
private class PathResolver(string platform, IDictionary<string, string> directoryMap) : IPathResolver
146149
{
@@ -174,10 +177,6 @@ public string ToAbsolutPath(string path)
174177
return path;
175178
}
176179

177-
private bool IsWindows()
178-
{
179-
return platform.ToLower().Contains("windows");
180-
}
181-
180+
private bool IsWindows() => platform.ToLower().Contains("windows");
182181
}
183182
}

CSharpInteractive.Templates/content/ConsoleApplication-CSharp/.template.config/template.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
"name": "Build App",
99
"generatorVersions": "[1.0.0.0-*)",
1010
"description": "A build project for creating a command-line application to run TeamCity C# script on Windows, Linux, macOS and under TeamCity build server.",
11-
"groupIdentity": "TeamCity.Projects",
11+
"groupIdentity": "Build.Projects",
1212
"precedence": "8000",
1313
"identity": "Build.Console",
1414
"shortName": "build",

CSharpInteractive.sln.DotSettings

+2
Original file line numberDiff line numberDiff line change
@@ -221,6 +221,8 @@
221221
<s:Int64 x:Key="/Default/Environment/General/WorkspaceHostInitializationTimeout/@EntryValue">2000</s:Int64>
222222
<s:String x:Key="/Default/Environment/Hierarchy/Build/SolBuilderDuo/UseMsbuildSolutionBuilder/@EntryValue">No</s:String>
223223
<s:Int64 x:Key="/Default/Environment/Hierarchy/Build/SolutionBuilderNext/ParallelProcessesCount2/@EntryValue">8</s:Int64>
224+
<s:String x:Key="/Default/Environment/Hierarchy/CSharpInteractiveOptions/ToolArguments/@EntryValue">csi</s:String>
225+
<s:String x:Key="/Default/Environment/Hierarchy/CSharpInteractiveOptions/ToolPath/@EntryValue">C:\Program Files\dotnet\dotnet.exe</s:String>
224226
<s:Boolean x:Key="/Default/Environment/OpenDocument/OpenDocumentAfterModification/@EntryValue">True</s:Boolean>
225227
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EApplication_002EExceptionReport_002EUserLoginInformationMigrateSettings/@EntryIndexedValue">True</s:Boolean>
226228
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EdotCover_002EInteractive_002ECore_002EFilterManagement_002EMigration_002EGlobalFilterSettingsManagerMigrateSettings/@EntryIndexedValue">True</s:Boolean>

CSharpInteractive/Host.cs

+83-26
Original file line numberDiff line numberDiff line change
@@ -130,44 +130,101 @@ public static Task<IBuildResult> BuildAsync(this ICommandLine commandLine, Actio
130130
ArgumentNullException.ThrowIfNull(commandLine);
131131
return Root.BuildRunner.RunAsync(commandLine, handler, cancellationToken);
132132
}
133-
134-
public static T EnsureSuccess<T>(
135-
this T result,
136-
Func<T, bool?>? isSuccess = default,
133+
134+
private static T EnsureSuccess<T, TResult>(
135+
T result,
136+
Func<TResult, bool?>? isSuccess = default,
137137
int? failureExitCode = 1)
138-
where T : ICommandLineResult
138+
where T : IEnumerable<TResult>
139+
where TResult: ICommandLineResult
139140
{
140141
ArgumentNullException.ThrowIfNull(result);
141142
isSuccess ??= r => r is ISuccessDeterminant successDeterminant ? successDeterminant.IsSuccess : true;
142-
switch (isSuccess(result))
143+
var hasError = false;
144+
foreach (var nextResult in result)
143145
{
144-
case true:
145-
return result;
146+
switch (isSuccess(nextResult))
147+
{
148+
case true:
149+
break;
146150

147-
case null:
148-
Root.Log.Warning($"{result}.");
149-
return result;
151+
case null:
152+
Root.Log.Warning($"{nextResult}.");
153+
break;
150154

151-
case false:
152-
Root.Log.Error(ErrorId.Build, $"{result}.");
153-
if (failureExitCode is not { } exitCode)
154-
{
155-
return result;
156-
}
157-
158-
Root.ExitTracker.Exit(exitCode);
159-
return result;
155+
case false:
156+
hasError = true;
157+
Root.Log.Error(ErrorId.Build, $"{nextResult}.");
158+
break;
159+
}
160+
}
161+
162+
if (hasError && failureExitCode is {} exitCode)
163+
{
164+
Root.ExitTracker.Exit(exitCode);
160165
}
166+
167+
return result;
168+
}
169+
170+
public static IEnumerable<TResult> EnsureSuccess<TResult>(
171+
this IEnumerable<TResult> results,
172+
Func<TResult, bool?>? isSuccess = default,
173+
int? failureExitCode = 1)
174+
where TResult: ICommandLineResult
175+
{
176+
ArgumentNullException.ThrowIfNull(results);
177+
return EnsureSuccess<IEnumerable<TResult>, TResult>(results, isSuccess, failureExitCode);
161178
}
162179

163-
public static async Task<T> EnsureSuccess<T>(
164-
this Task<T> resultTask,
165-
Func<T, bool?>? isSuccess = default,
180+
public static async Task<IEnumerable<TResult>> EnsureSuccess<TResult>(
181+
this Task<IEnumerable<TResult>> result,
182+
Func<TResult, bool?>? isSuccess = default,
166183
int? failureExitCode = 1)
167-
where T : ICommandLineResult
184+
where TResult: ICommandLineResult
168185
{
169-
ArgumentNullException.ThrowIfNull(resultTask);
170-
return EnsureSuccess(await resultTask, isSuccess, failureExitCode);
186+
ArgumentNullException.ThrowIfNull(result);
187+
return EnsureSuccess<IEnumerable<TResult>, TResult>(await result, isSuccess, failureExitCode);
188+
}
189+
190+
public static TResult[] EnsureSuccess<TResult>(
191+
this TResult[] results,
192+
Func<TResult, bool?>? isSuccess = default,
193+
int? failureExitCode = 1)
194+
where TResult: ICommandLineResult
195+
{
196+
ArgumentNullException.ThrowIfNull(results);
197+
return EnsureSuccess<TResult[], TResult>(results, isSuccess, failureExitCode);
198+
}
199+
200+
public static async Task<TResult[]> EnsureSuccess<TResult>(
201+
this Task<TResult[]> result,
202+
Func<TResult, bool?>? isSuccess = default,
203+
int? failureExitCode = 1)
204+
where TResult: ICommandLineResult
205+
{
206+
ArgumentNullException.ThrowIfNull(result);
207+
return EnsureSuccess<TResult[], TResult>(await result, isSuccess, failureExitCode);
208+
}
209+
210+
public static TResult EnsureSuccess<TResult>(
211+
this TResult result,
212+
Func<TResult, bool?>? isSuccess = default,
213+
int? failureExitCode = 1)
214+
where TResult : ICommandLineResult
215+
{
216+
ArgumentNullException.ThrowIfNull(result);
217+
return EnsureSuccess([result], isSuccess, failureExitCode).First();
218+
}
219+
220+
public static async Task<TResult> EnsureSuccess<TResult>(
221+
this Task<TResult> result,
222+
Func<TResult, bool?>? isSuccess = default,
223+
int? failureExitCode = 1)
224+
where TResult : ICommandLineResult
225+
{
226+
ArgumentNullException.ThrowIfNull(result);
227+
return EnsureSuccess(await result, isSuccess, failureExitCode);
171228
}
172229

173230
public static bool TryGet<T>(

Samples/MySampleLib/Build/Program.cs

+42-36
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
// API for Docker CLI
3131
await new DockerRun("ubuntu")
3232
.WithCommandLine(cmd)
33+
.WithPull(DockerPullType.Always)
3334
.WithAutoRemove(true)
3435
.RunAsync()
3536
.EnsureSuccess();
@@ -57,50 +58,55 @@
5758
}
5859

5960
// API for .NET CLI
60-
var buildResult = new DotNetBuild()
61-
.WithConfiguration(configuration)
62-
.WithNoLogo(true)
63-
.Build()
64-
.EnsureSuccess();
61+
var buildResult = new DotNetBuild().WithConfiguration(configuration).WithNoLogo(true)
62+
.Build().EnsureSuccess();
6563

66-
foreach (var warn in buildResult.Warnings
67-
.Where(warn => Path.GetFileName(warn.File) == "Calculator.cs")
68-
.Select(warn => $"{warn.Code}({warn.LineNumber}:{warn.ColumnNumber})")
69-
.Distinct())
64+
var warnings = buildResult.Warnings
65+
.Where(warn => Path.GetFileName(warn.File) == "Calculator.cs")
66+
.Select(warn => $"{warn.Code}({warn.LineNumber}:{warn.ColumnNumber})")
67+
.Distinct();
68+
69+
foreach (var warning in warnings)
7070
{
7171
await new HttpClient().GetAsync(
72-
"https://api.telegram.org/bot7102686717:AAEHw7HZinme_5kfIRV7TwXK4Xql9WPPpM3/sendMessage?chat_id=878745093&text=" +
73-
HttpUtility.UrlEncode(warn));
72+
"https://api.telegram.org/bot7102686717:AAEHw7HZinme_5kfIRV7TwXK4Xql9WPPpM3/" +
73+
"sendMessage?chat_id=878745093&text="
74+
+ HttpUtility.UrlEncode(warning));
7475
}
7576

76-
var publishDir = Path.GetFullPath(".publish");
77-
new DotNetPublish()
78-
.WithConfiguration(configuration).WithNoLogo(true).WithNoBuild(true)
79-
.WithFramework("net8.0").WithOutput(publishDir)
80-
.Build()
81-
.EnsureSuccess();
77+
// Asynchronous wayS
78+
var cts = new CancellationTokenSource();
79+
/*await new DotNetTest()
80+
.WithConfiguration(configuration)
81+
.WithNoLogo(true).WithNoBuild(true)
82+
.BuildAsync(CancellationOnFirstFailedTest, cts.Token)
83+
.EnsureSuccess();*/
84+
85+
void CancellationOnFirstFailedTest(BuildMessage message)
86+
{
87+
if (message.TestResult is { State: TestState.Failed }) cts.Cancel();
88+
}
8289

83-
var test = new DotNetTest()
84-
.WithWorkingDirectory(publishDir)
85-
.WithProject("MySampleLib.Tests.dll");
90+
// Parallel tests
91+
var tempDir = Directory.CreateTempSubdirectory();
92+
try
93+
{
94+
new DotNetPublish()
95+
.WithConfiguration(configuration).WithNoLogo(true).WithNoBuild(true)
96+
.WithFramework("net8.0").AddProps(("PublishDir", tempDir.FullName)).Build().EnsureSuccess();
8697

87-
test.Build().EnsureSuccess();
98+
var test = new VSTest().WithTestFileNames("*.Tests.dll");
8899

89-
// Asynchronous way
90-
var cts = new CancellationTokenSource();
91-
await new DotNetTest()
92-
.WithConfiguration(configuration)
93-
.WithNoLogo(true)
94-
.WithNoBuild(true)
95-
.BuildAsync(i =>
96-
{
97-
if (i.TestResult is { State: TestState.Failed })
98-
{
99-
cts.Cancel();
100-
}
101-
}, cts.Token)
102-
.EnsureSuccess();
100+
var tasks = from tagSuffix in new[] {"bookworm-slim", "alpine", "noble"}
101+
let image = $"mcr.microsoft.com/dotnet/sdk:8.0-{tagSuffix}"
102+
let dockerRun = new DockerRun(image).WithCommandLine(test).WithAutoRemove(true)
103+
.WithVolumes((tempDir.FullName, "/app")).WithContainerWorkingDirectory("/app")
104+
select dockerRun.BuildAsync(CancellationOnFirstFailedTest, cts.Token);
105+
106+
await Task.WhenAll(tasks).EnsureSuccess();
107+
}
108+
finally { tempDir.Delete(); }
103109

104110
#pragma warning disable CS9113 // Parameter is unread.
105111
class MyTool(INuGet nuGet);
106-
#pragma warning restore CS9113 // Parameter is unread.
112+
#pragma warning restore CS9113 // Parameter is unread.

0 commit comments

Comments
 (0)