Skip to content

Commit 51c9d85

Browse files
committed
Add github actions log groups
1 parent a2c689c commit 51c9d85

9 files changed

+140
-16
lines changed

CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,11 @@
22

33
## Unreleased
44

5+
### Added
6+
7+
- A new environment variable called `DOTNET_R_CHILDPROCESS` which is set to `true` when executing a script. Use this to check if you're running inside `dotnet r` or not.
8+
- Support for [GitHub Actions log groups](https://docs.github.com/en/actions/using-workflows/workflow-commands-for-github-actions#grouping-log-lines)
9+
510
## [0.4.0](https://github.com/xt0rted/dotnet-run-script/compare/v0.3.0...v0.4.0) - 2022-08-12
611

712
> **Note**

src/CommandRunner.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@ public async Task<int> RunAsync(string name, string cmd, string[]? args)
3232
process.StartInfo.WorkingDirectory = _processContext.WorkingDirectory;
3333
process.StartInfo.FileName = _processContext.Shell;
3434

35+
process.StartInfo.Environment[EnvironmentVariables.RunScriptChildProcess] = "true";
36+
3537
var outStream = new StreamForwarder();
3638
var errStream = new StreamForwarder();
3739
Task? taskOut = null;

src/EnvironmentVariables.cs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
namespace RunScript;
2+
3+
internal static class EnvironmentVariables
4+
{
5+
public static string GitHubActions => "GITHUB_ACTIONS";
6+
7+
public static string RunScriptChildProcess => "DOTNET_R_CHILDPROCESS";
8+
}

src/Logging/GitHubActionsLogGroup.cs

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
namespace RunScript.Logging;
2+
3+
internal sealed class GitHubActionsLogGroup : IDisposable
4+
{
5+
private readonly IConsoleWriter _writer;
6+
7+
public GitHubActionsLogGroup(IConsoleWriter writer, string name)
8+
{
9+
_writer = writer ?? throw new ArgumentNullException(nameof(writer));
10+
11+
_writer.Raw("::group::" + EscapeData("dotnet r " + name) + Environment.NewLine);
12+
}
13+
14+
public void Dispose()
15+
=> _writer.Raw("::endgroup::" + Environment.NewLine);
16+
17+
private static string EscapeData(string value)
18+
=> value
19+
.Replace("%", "%25", StringComparison.OrdinalIgnoreCase)
20+
.Replace("\r", "%0D", StringComparison.OrdinalIgnoreCase)
21+
.Replace("\n", "%0A", StringComparison.OrdinalIgnoreCase);
22+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
namespace RunScript.Logging;
2+
3+
internal static class IConsoleWriterExtensions
4+
{
5+
public static IDisposable Group(this IConsoleWriter writer, IEnvironment environment, string name)
6+
{
7+
var isRunningOnActions = string.Equals(
8+
environment.GetEnvironmentVariable(EnvironmentVariables.GitHubActions),
9+
"true",
10+
StringComparison.OrdinalIgnoreCase);
11+
12+
var isChildProcess = string.Equals(
13+
environment.GetEnvironmentVariable(EnvironmentVariables.RunScriptChildProcess),
14+
"true",
15+
StringComparison.OrdinalIgnoreCase);
16+
17+
return isRunningOnActions && !isChildProcess
18+
? new GitHubActionsLogGroup(writer, name)
19+
: new SilentLogGroup();
20+
}
21+
}

src/Logging/SilentLogGroup.cs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
namespace RunScript.Logging;
2+
3+
internal sealed class SilentLogGroup : IDisposable
4+
{
5+
public void Dispose()
6+
{
7+
}
8+
}

src/RunScriptCommand.cs

Lines changed: 21 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ namespace RunScript;
44

55
using DotNet.Globbing;
66

7+
using RunScript.Logging;
8+
79
internal class RunScriptCommand : RootCommand, ICommandHandler
810
{
911
private readonly IEnvironment _environment;
@@ -99,29 +101,32 @@ public async Task<int> InvokeAsync(InvocationContext context)
99101

100102
foreach (var script in scriptsToRun)
101103
{
102-
if (!script.Exists)
104+
using (var logGroup = writer.Group(_environment, script.Name))
103105
{
104-
writer.Banner($"Skipping script {script.Name}");
106+
if (!script.Exists)
107+
{
108+
writer.Banner($"Skipping script {script.Name}");
105109

106-
continue;
107-
}
110+
continue;
111+
}
108112

109-
// UnparsedTokens is backed by string[] so if we cast
110-
// back to that we get a lot better perf down the line.
111-
// Hopefully this doesn't break in the future 🤞
112-
var scriptArgs = (string[])context.ParseResult.UnparsedTokens;
113+
// UnparsedTokens is backed by string[] so if we cast
114+
// back to that we get a lot better perf down the line.
115+
// Hopefully this doesn't break in the future 🤞
116+
var scriptArgs = (string[])context.ParseResult.UnparsedTokens;
113117

114-
var scriptRunner = builder.CreateGroupRunner(context.GetCancellationToken());
118+
var scriptRunner = builder.CreateGroupRunner(context.GetCancellationToken());
115119

116-
var result = await scriptRunner.RunAsync(
117-
script.Name,
118-
scriptArgs);
120+
var result = await scriptRunner.RunAsync(
121+
script.Name,
122+
scriptArgs);
119123

120-
runResults.Add(new(script.Name, result));
124+
runResults.Add(new(script.Name, result));
121125

122-
if (result != 0)
123-
{
124-
break;
126+
if (result != 0)
127+
{
128+
break;
129+
}
125130
}
126131
}
127132

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
{
2+
IsErrorRedirected: false,
3+
IsInputRedirected: false,
4+
IsOutputRedirected: false,
5+
Out:
6+
::group::dotnet r plain
7+
::endgroup::
8+
::group::dotnet r percent: %2525
9+
::endgroup::
10+
::group::dotnet r carriage return: %0D
11+
::endgroup::
12+
::group::dotnet r line feed: %0A
13+
::endgroup::
14+
::group::dotnet r everything: %25%0D%0A
15+
::endgroup::
16+
17+
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
namespace RunScript.Logging;
2+
3+
using System.CommandLine.IO;
4+
using System.CommandLine.Rendering;
5+
6+
[Trait("category", "unit")]
7+
[UsesVerify]
8+
public class GitHubActionsLogGroupTests
9+
{
10+
[Fact]
11+
public async Task Should_escape_group_name()
12+
{
13+
// Given
14+
var console = new TestConsole();
15+
var consoleFormatProvider = new ConsoleFormatInfo
16+
{
17+
SupportsAnsiCodes = false,
18+
};
19+
var consoleWriter = new ConsoleWriter(console, consoleFormatProvider, verbose: false);
20+
21+
// When
22+
createGroup("plain");
23+
createGroup("percent: %25");
24+
createGroup("carriage return: \r");
25+
createGroup("line feed: \n");
26+
createGroup("everything: %\r\n");
27+
28+
// Then
29+
await Verify(console);
30+
31+
void createGroup(string groupName)
32+
{
33+
using var _ = new GitHubActionsLogGroup(consoleWriter, groupName);
34+
}
35+
}
36+
}

0 commit comments

Comments
 (0)