diff --git a/action.yml b/action.yml index 61e3f56..8b543ab 100644 --- a/action.yml +++ b/action.yml @@ -29,6 +29,10 @@ inputs: description: "The version of Wrangler to use" required: false default: "2" + includeLogs: + description: "Include logs from failed deployments in the deployment summary" + required: false + default: "false" runs: using: "node16" main: "index.js" diff --git a/src/index.ts b/src/index.ts index a63f38e..b4937f7 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,9 +1,9 @@ -import { getInput, setOutput, setFailed, summary } from "@actions/core"; -import type { Project, Deployment } from "@cloudflare/types"; -import { context, getOctokit } from "@actions/github"; +import {getInput, setFailed, setOutput, summary} from "@actions/core"; +import type {Deployment, Project, LogMessage, UnifiedDeploymentLogMessages} from "@cloudflare/types"; +import {context, getOctokit} from "@actions/github"; import shellac from "shellac"; -import { fetch } from "undici"; -import { env } from "process"; +import {fetch} from "undici"; +import {env} from "process"; import path from "node:path"; type Octokit = ReturnType; @@ -17,6 +17,7 @@ try { const branch = getInput("branch", { required: false }); const workingDirectory = getInput("workingDirectory", { required: false }); const wranglerVersion = getInput("wranglerVersion", { required: false }); + const includeLogs = getInput("includeLogs", {required: false}); const getProject = async () => { const response = await fetch( @@ -109,8 +110,9 @@ try { }); }; - const createJobSummary = async ({ deployment, aliasUrl }: { deployment: Deployment; aliasUrl: string }) => { + const getDeploymentStatus = async({deployment}: {deployment: Deployment}) => { const deployStage = deployment.stages.find((stage) => stage.name === "deploy"); + let failure: boolean = false; let status = "⚡️ Deployment in progress..."; if (deployStage?.status === "success") { @@ -119,6 +121,43 @@ try { status = "🚫 Deployment failed"; } + return [failure, status] as const; + } + + const getDeploymentLogs = async({failure, deployment}: {failure: boolean, deployment: Deployment}) => { + if (!failure && includeLogs) { + let messages: LogMessage[] = []; + return {data: messages, total: 0, includes_container_logs: false} as UnifiedDeploymentLogMessages; + } + + const deploymentIdentifier = deployment.id + + const response = await fetch( + `https://api.cloudflare.com/client/v4/accounts/${accountId}/pages/projects/${projectName}/deployments/${deploymentIdentifier}/history/logs`, + { headers: { Authorization: `Bearer ${apiToken}` } } + ); + if (response.status !== 200) { + console.error(`Cloudflare API returned non-200: ${response.status}`); + const json = await response.text(); + console.error(`API returned: ${json}`); + throw new Error("Failed to get Pages Deployment Logs, API returned non-200"); + } + + const { + result: [logs], + } = (await response.json()) as { result: UnifiedDeploymentLogMessages }; + + return logs; + } + + const createJobSummary = async ({ deployment, aliasUrl, status, logs }: { deployment: Deployment; aliasUrl: string, status: string, logs: UnifiedDeploymentLogMessages }) => { + let logLines: string = '' + if (logs.total > 0 ){ + for (let message of logs.data) { + logLines = logLines.concat(`${message.ts} ${message.line}\n`) + } + } + await summary .addRaw( ` @@ -130,6 +169,9 @@ try { | **Status**: | ${status} | | **Preview URL**: | ${deployment.url} | | **Branch Preview URL**: | ${aliasUrl} | + +## Logs +${logLines} ` ) .write(); @@ -159,7 +201,10 @@ try { } setOutput("alias", alias); - await createJobSummary({ deployment: pagesDeployment, aliasUrl: alias }); + const [failure, pagesDeploymentStatus] = await getDeploymentStatus( {deployment: pagesDeployment}); + const logs: UnifiedDeploymentLogMessages = getDeploymentLogs({failure: failure, deployment: pagesDeployment}) + + await createJobSummary( { deployment: pagesDeployment, aliasUrl: alias, status: pagesDeploymentStatus, logs: logs }); if (gitHubDeployment) { const octokit = getOctokit(gitHubToken);