import { GitHubRelease } from "./types.ts";
export function isGitHubActions(): boolean {
return Deno.env.get("GITHUB_ACTIONS") === "true";
}
export function isVerboseMode(): boolean {
return Deno.env.get("RUNNER_DEBUG") === "1" ||
Deno.env.get("QUARTO_TEST_VERBOSE") === "true";
}
export function escapeData(s: string): string {
return s
.replace(/%/g, "%25")
.replace(/\r/g, "%0D")
.replace(/\n/g, "%0A");
}
export function escapeProperty(s: string): string {
return s
.replace(/%/g, "%25")
.replace(/\r/g, "%0D")
.replace(/\n/g, "%0A")
.replace(/:/g, "%3A")
.replace(/,/g, "%2C");
}
export interface AnnotationProperties {
file?: string;
line?: number;
endLine?: number;
title?: string;
}
function formatProperties(props: AnnotationProperties): string {
const parts: string[] = [];
if (props.file !== undefined) {
parts.push(`file=${escapeProperty(props.file)}`);
}
if (props.line !== undefined) parts.push(`line=${props.line}`);
if (props.endLine !== undefined) parts.push(`endLine=${props.endLine}`);
if (props.title !== undefined) {
parts.push(`title=${escapeProperty(props.title)}`);
}
return parts.length > 0 ? " " + parts.join(",") : "";
}
export function error(
message: string,
properties?: AnnotationProperties,
): void {
if (!isGitHubActions()) {
console.log(message);
return;
}
const props = properties ? formatProperties(properties) : "";
console.log(`::error${props}::${escapeData(message)}`);
}
export function warning(
message: string,
properties?: AnnotationProperties,
): void {
if (!isGitHubActions()) {
console.log(message);
return;
}
const props = properties ? formatProperties(properties) : "";
console.log(`::warning${props}::${escapeData(message)}`);
}
export function notice(
message: string,
properties?: AnnotationProperties,
): void {
if (!isGitHubActions()) {
console.log(message);
return;
}
const props = properties ? formatProperties(properties) : "";
console.log(`::notice${props}::${escapeData(message)}`);
}
export function startGroup(title: string): void {
if (!isGitHubActions()) return;
console.log(`::group::${escapeData(title)}`);
}
export function endGroup(): void {
if (!isGitHubActions()) return;
console.log("::endgroup::");
}
export function withGroup<T>(title: string, fn: () => T): T {
if (!isGitHubActions()) {
console.log(title);
return fn();
}
startGroup(title);
try {
return fn();
} finally {
endGroup();
}
}
export async function withGroupAsync<T>(
title: string,
fn: () => Promise<T>,
): Promise<T> {
if (!isGitHubActions()) {
console.log(title);
return await fn();
}
startGroup(title);
try {
return await fn();
} finally {
endGroup();
}
}
export async function group<T>(
title: string,
fn: () => Promise<T>,
): Promise<T> {
return await withGroupAsync(title, fn);
}
export async function getLatestRelease(repo: string): Promise<GitHubRelease> {
const url = `https://api.github.com/repos/${repo}/releases/latest`;
const headers = Deno.env.get("GH_TOKEN")
? { headers: { Authorization: "Bearer " + Deno.env.get("GH_TOKEN") } }
: undefined;
const response = await fetch(url, headers);
if (response.status !== 200) {
throw new Error(
`Unable to determine latest release for ${repo}\n${response.status} - ${response.statusText}`,
);
} else {
return response.json();
}
}