Skip to content

Instantly share code, notes, and snippets.

@nikeee
Last active February 4, 2024 00:47
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save nikeee/c2107b3e3d30ec8100b9fa83f1e2f4ac to your computer and use it in GitHub Desktop.
Save nikeee/c2107b3e3d30ec8100b9fa83f1e2f4ac to your computer and use it in GitHub Desktop.
<?php declare(strict_types = 1);
use Phan\Issue;
use Phan\PluginV3;
use Phan\CodeBase;
use Phan\IssueInstance;
use Phan\PluginV3\FinalizeProcessCapability;
use Phan\PluginV3\SubscribeEmitIssueCapability;
final class GitHubWorkflowCommandsPlugin extends PluginV3 implements FinalizeProcessCapability, SubscribeEmitIssueCapability {
/** @var IssueInstance[] */
private array $issues = [];
private readonly bool $enabled;
function __construct() {
$this->enabled = getenv('GITHUB_ACTIONS') === 'true';
}
function onEmitIssue(IssueInstance $issue_instance): bool {
$this->issues[] = $issue_instance;
return false;
}
function finalizeProcess(CodeBase $code_base): void {
if (!$this->enabled) {
return;
}
$minimumSeverity = \Phan\Config::getValue('minimum_severity');
$printedIssue = false;
foreach ($this->issues as $issue) {
if ($issue->getIssue()->getSeverity() < $minimumSeverity) {
return;
}
if (!$printedIssue) {
$printedIssue = true;
echo "\n"; // make sure the first commands starts in a new line
}
echo self::getCommandFromIssueInstance($issue)."\n";
}
}
private static function getCommandFromIssueInstance(IssueInstance $issue): string {
$command = match ($issue->getIssue()->getSeverity()) {
Issue::SEVERITY_LOW => 'notice',
Issue::SEVERITY_NORMAL => 'warning',
Issue::SEVERITY_CRITICAL => 'error',
};
$file = self::escapeProperty($issue->getDisplayedFile());
$line = $issue->getLine();
$column = $issue->getColumn();
$columnInstruction = $column !== 0
? ",col=$column"
: '';
$type = $issue->getIssue()->getType();
$message = $issue->getMessage();
$title = self::escapeData("$type: $message");
return "::$command file=$file,line=$line$columnInstruction::$title";
}
private static function escapeData(string $value): string {
// This is not encodeUriComponent, it is a subset (GH decided to not encode some characters)
// Refs:
// - https://github.com/actions/runner/blob/a4c57f27477077e57545af79851551ff7f5632bd/src/Runner.Common/ActionCommand.cs#L18-L22
// - https://github.com/actions/toolkit/blob/fe3e7ce9a7f995d29d1fcfd226a32bca407f9dc8/packages/core/src/command.ts#L80-L94
$res = '';
$len = strlen($value);
for ($i = 0; $i < $len; $i++) {
$char = $value[$i];
$res .= match ($char) {
"\r" => '%0D',
"\n" => '%0A',
'%' => '%25',
default => $char,
};
}
return $res;
}
private static function escapeProperty(string $value): string {
// This is not encodeUriComponent, it is a subset (GH decided to not encode some characters)
// Refs:
// - https://github.com/actions/runner/blob/a4c57f27477077e57545af79851551ff7f5632bd/src/Runner.Common/ActionCommand.cs#L25-L32
// - https://github.com/actions/toolkit/blob/fe3e7ce9a7f995d29d1fcfd226a32bca407f9dc8/packages/core/src/command.ts#L80-L94
$res = '';
$len = strlen($value);
for ($i = 0; $i < $len; $i++) {
$char = $value[$i];
$res .= match ($char) {
"\r" => '%0D',
"\n" => '%0A',
':' => '%3A',
',' => '%2C',
'%' => '%25',
default => $char,
};
}
return $res;
}
}
return new GitHubWorkflowCommandsPlugin();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment