Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(deploy): print edge function logs url #6851

Merged
merged 6 commits into from
Oct 8, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
64 changes: 38 additions & 26 deletions src/commands/deploy/deploy.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { Stats } from 'fs'
import { type Stats } from 'fs'
import { stat } from 'fs/promises'
import { basename, resolve } from 'path'

import { runCoreSteps } from '@netlify/build'
import { OptionValues } from 'commander'
import { type NetlifyConfig, runCoreSteps } from '@netlify/build'
import { type OptionValues } from 'commander'
import inquirer from 'inquirer'
import isEmpty from 'lodash/isEmpty.js'
import isObject from 'lodash/isObject.js'
Expand Down Expand Up @@ -34,7 +34,6 @@ import {
import { DEFAULT_DEPLOY_TIMEOUT } from '../../utils/deploy/constants.js'
import { deploySite } from '../../utils/deploy/deploy-site.js'
import { getEnvelopeEnv } from '../../utils/env/index.js'
import { getFrameworksAPIPaths } from '../../utils/frameworks-api.js'
import { getFunctionsManifestPath, getInternalFunctionsDir } from '../../utils/functions/index.js'
import openBrowser from '../../utils/open-browser.js'
import BaseCommand from '../base-command.js'
Expand Down Expand Up @@ -446,6 +445,7 @@ const runDeploy = async ({
deployUrl: string
logsUrl: string
functionLogsUrl: string
edgeFunctionLogsUrl: string
}> => {
let results
let deployId
Expand Down Expand Up @@ -532,9 +532,11 @@ const runDeploy = async ({
const logsUrl = `${results.deploy.admin_url}/deploys/${results.deploy.id}`

let functionLogsUrl = `${results.deploy.admin_url}/logs/functions`
let edgeFunctionLogsUrl = `${results.deploy.admin_url}/logs/edge-functions`

if (!deployToProduction) {
functionLogsUrl += `?scope=deploy:${deployId}`
edgeFunctionLogsUrl += `?scope=deploy:${deployId}`
}

return {
Expand All @@ -545,6 +547,7 @@ const runDeploy = async ({
deployUrl,
logsUrl,
functionLogsUrl,
edgeFunctionLogsUrl,
}
}

Expand Down Expand Up @@ -624,30 +627,40 @@ const bundleEdgeFunctions = async (options, command: BaseCommand) => {
})
}

/**
*
* @param {object} config
* @param {boolean} config.deployToProduction
* @param {boolean} config.isIntegrationDeploy If the user ran netlify integration:deploy instead of just netlify deploy
* @param {boolean} config.json If the result should be printed as json message
* @param {boolean} config.runBuildCommand If the build command should be run
* @param {object} config.results
* @returns {void}
*/
// @ts-expect-error TS(7031) FIXME: Binding element 'deployToProduction' implicitly ha... Remove this comment to see the full error message
const printResults = ({ deployToProduction, isIntegrationDeploy, json, results, runBuildCommand }) => {
const msgData = {
interface JsonData {
site_id: string
site_name: string
deploy_id: string
deploy_url: string
logs: string
function_logs: string
edge_function_logs: string
url?: string
}

const printResults = ({
deployToProduction,
isIntegrationDeploy,
json,
results,
runBuildCommand,
}: {
deployToProduction: boolean
isIntegrationDeploy: boolean
json: boolean
results: Awaited<ReturnType<typeof prepAndRunDeploy>>
runBuildCommand: boolean
}): void => {
const msgData: Record<string, string> = {
'Build logs': results.logsUrl,
'Function logs': results.functionLogsUrl,
'Edge function Logs': results.edgeFunctionLogsUrl,
}

if (deployToProduction) {
// @ts-expect-error TS(7053) FIXME: Element implicitly has an 'any' type because expre... Remove this comment to see the full error message
msgData['Unique deploy URL'] = results.deployUrl
// @ts-expect-error TS(7053) FIXME: Element implicitly has an 'any' type because expre... Remove this comment to see the full error message
msgData['Website URL'] = results.siteUrl
} else {
// @ts-expect-error TS(7053) FIXME: Element implicitly has an 'any' type because expre... Remove this comment to see the full error message
msgData['Website draft URL'] = results.deployUrl
}

Expand All @@ -656,16 +669,16 @@ const printResults = ({ deployToProduction, isIntegrationDeploy, json, results,

// Json response for piping commands
if (json) {
const jsonData = {
name: results.name,
site_id: results.site_id,
eduardoboucas marked this conversation as resolved.
Show resolved Hide resolved
const jsonData: JsonData = {
site_id: results.siteId,
site_name: results.siteName,
deploy_id: results.deployId,
deploy_url: results.deployUrl,
logs: results.logsUrl,
function_logs: results.functionLogsUrl,
edge_function_logs: results.edgeFunctionLogsUrl,
}
Comment on lines 677 to +679
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would rather have suffixed these with _url but since logs was already named logs I erred toward internal consistency 😞.

if (deployToProduction) {
// @ts-expect-error TS(2339) FIXME: Property 'url' does not exist on type '{ name: any... Remove this comment to see the full error message
jsonData.url = results.siteUrl
}

Expand Down Expand Up @@ -853,8 +866,7 @@ export const deploy = async (options: OptionValues, command: BaseCommand) => {
defaultConfig: getDefaultConfig(settings),
currentDir: command.workingDir,
options,
// @ts-expect-error TS(7031) FIXME: Binding element 'netlifyConfig' implicitly has an ... Remove this comment to see the full error message
deployHandler: async ({ netlifyConfig }) => {
deployHandler: async ({ netlifyConfig }: { netlifyConfig: NetlifyConfig }) => {
results = await prepAndRunDeploy({
command,
options,
Expand Down
64 changes: 63 additions & 1 deletion tests/integration/commands/deploy/deploy.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,12 +38,23 @@ const validateDeploy = async ({
contentMessage?: string
siteName: string
content?: string
deploy: { site_name: string; deploy_url: string; deploy_id: string; logs: string }
deploy: {
site_id: string
site_name: string
deploy_url: string
deploy_id: string
logs: string
function_logs: string
edge_function_logs: string
}
}) => {
expect(deploy.site_id).toBeTruthy()
expect(deploy.site_name).toBeTruthy()
expect(deploy.deploy_url).toBeTruthy()
expect(deploy.deploy_id).toBeTruthy()
expect(deploy.logs).toBeTruthy()
expect(deploy.function_logs).toBeTruthy()
expect(deploy.edge_function_logs).toBeTruthy()
expect(deploy.site_name, contentMessage).toEqual(siteName)

await validateContent({ siteUrl: deploy.deploy_url, path: '', content })
Expand Down Expand Up @@ -263,6 +274,57 @@ describe.skipIf(process.env.NETLIFY_TEST_DISABLE_LIVE === 'true').concurrent('co
})
})

test('should print deploy-scoped URLs for build logs, function logs, and edge function logs', async (t) => {
await withSiteBuilder(t, async (builder) => {
const content = '<h1>Why Next.js is perfect, an essay</h1>'
builder.withContentFile({
path: 'public/index.html',
content,
})
await builder.build()

const deploy = await callCli(['deploy', '--json', '--dir', 'public'], {
cwd: builder.directory,
env: { NETLIFY_SITE_ID: context.siteId },
}).then((output) => JSON.parse(output))

await validateDeploy({ deploy, siteName: SITE_NAME, content })
expect(deploy).toHaveProperty('logs', `https://app.netlify.com/sites/${SITE_NAME}/deploys/${deploy.deploy_id}`)
expect(deploy).toHaveProperty(
'function_logs',
`https://app.netlify.com/sites/${SITE_NAME}/logs/functions?scope=deploy:${deploy.deploy_id}`,
)
expect(deploy).toHaveProperty(
'edge_function_logs',
`https://app.netlify.com/sites/${SITE_NAME}/logs/edge-functions?scope=deploy:${deploy.deploy_id}`,
)
})
})

test('should print production URLs for build logs, function logs, and edge function logs when --prod is passed', async (t) => {
await withSiteBuilder(t, async (builder) => {
const content = '<h1>Why Next.js is perfect, a novella</h1>'
builder.withContentFile({
path: 'public/index.html',
content,
})
await builder.build()

const deploy = await callCli(['deploy', '--json', '--dir', 'public', '--prod'], {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fun fact: this is the very first test coverage of ntl deploy --prod 😬😬😬

cwd: builder.directory,
env: { NETLIFY_SITE_ID: context.siteId },
}).then((output) => JSON.parse(output))

await validateDeploy({ deploy, siteName: SITE_NAME, content })
expect(deploy).toHaveProperty('logs', `https://app.netlify.com/sites/${SITE_NAME}/deploys/${deploy.deploy_id}`)
expect(deploy).toHaveProperty('function_logs', `https://app.netlify.com/sites/${SITE_NAME}/logs/functions`)
expect(deploy).toHaveProperty(
'edge_function_logs',
`https://app.netlify.com/sites/${SITE_NAME}/logs/edge-functions`,
)
})
})

test('should return valid json when both --build and --json are passed', async (t) => {
await withSiteBuilder(t, async (builder) => {
const content = '<h1>⊂◉‿◉つ</h1>'
Expand Down
Loading