-
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
fix(plugin-system): Resolved issue with instanciating the `PluginLoad…
…er` from the provided module
- Loading branch information
1 parent
18c1841
commit 778bb6d
Showing
14 changed files
with
957 additions
and
428 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,175 @@ | ||
import fs from "node:fs"; | ||
import os from "node:os"; | ||
import path from "node:path"; | ||
import archiver from "archiver"; | ||
import * as checkpoint from "checkpoint-client"; | ||
import globby from "globby"; | ||
import stripAnsi from "strip-ansi"; | ||
import tmp from "tmp"; | ||
import { P, match } from "ts-pattern"; | ||
|
||
import { | ||
type CreateErrorReportInput, | ||
createErrorReport, | ||
makeErrorReportCompleted, | ||
uploadZip | ||
} from "./errorReporting"; | ||
import type { MigrateTypes } from "./migrateTypes"; | ||
import type { RustPanic } from "./panic"; | ||
import { ErrorArea } from "./panic"; | ||
import { mapScalarValues, maskSchema } from "./utils/maskSchema"; | ||
|
||
// cleanup the temporary files even when an uncaught exception occurs | ||
tmp.setGracefulCleanup(); | ||
|
||
type SendPanic = { | ||
error: RustPanic; | ||
cliVersion: string; | ||
enginesVersion: string; | ||
|
||
// retrieve the database version for the given schema or url, without throwing any error | ||
getDatabaseVersionSafe: ( | ||
args: MigrateTypes.GetDatabaseVersionParams | ||
) => Promise<string | undefined>; | ||
}; | ||
export async function sendPanic({ | ||
error, | ||
cliVersion, | ||
enginesVersion, | ||
getDatabaseVersionSafe | ||
}: SendPanic): Promise<number> { | ||
const schema: string | undefined = match(error) | ||
.with({ schemaPath: P.not(P.nullish) }, (err) => { | ||
return fs.readFileSync(err.schemaPath, "utf-8"); | ||
}) | ||
.with({ schema: P.not(P.nullish) }, (err) => err.schema) | ||
.otherwise(() => undefined); | ||
|
||
const maskedSchema: string | undefined = schema ? maskSchema(schema) : undefined; | ||
|
||
let dbVersion: string | undefined; | ||
if (error.area === ErrorArea.LIFT_CLI) { | ||
// For a SQLite datasource like `url = "file:dev.db"` only schema will be defined | ||
const getDatabaseVersionParams: MigrateTypes.GetDatabaseVersionParams | undefined = match({ | ||
schema, | ||
introspectionUrl: error.introspectionUrl | ||
}) | ||
.with({ schema: P.not(undefined) }, ({ schema }) => { | ||
return { | ||
datasource: { | ||
tag: "SchemaString", | ||
schema | ||
} | ||
} as const; | ||
}) | ||
.with({ introspectionUrl: P.not(undefined) }, ({ introspectionUrl }) => { | ||
return { | ||
datasource: { | ||
tag: "ConnectionString", | ||
url: introspectionUrl | ||
} | ||
} as const; | ||
}) | ||
.otherwise(() => undefined); | ||
|
||
dbVersion = await getDatabaseVersionSafe(getDatabaseVersionParams); | ||
} | ||
|
||
const migrateRequest = error.request | ||
? JSON.stringify( | ||
mapScalarValues(error.request, (value) => { | ||
if (typeof value === "string") { | ||
return maskSchema(value); | ||
} | ||
return value; | ||
}) | ||
) | ||
: undefined; | ||
|
||
const params: CreateErrorReportInput = { | ||
area: error.area, | ||
kind: "PANIC", | ||
cliVersion, | ||
binaryVersion: enginesVersion, | ||
command: process.argv.slice(2).join(" "), | ||
jsStackTrace: stripAnsi(error.stack || error.message), | ||
rustStackTrace: error.rustStack, | ||
operatingSystem: `${os.arch()} ${os.platform()} ${os.release()}`, | ||
platform: process.platform, | ||
liftRequest: migrateRequest, | ||
schemaFile: maskedSchema, | ||
fingerprint: await checkpoint.getSignature(), | ||
sqlDump: undefined, | ||
dbVersion: dbVersion | ||
}; | ||
|
||
// Get an AWS S3 signed URL from the server, so we can upload a zip file | ||
const signedUrl = await createErrorReport(params); | ||
|
||
// Create & upload the zip file | ||
// only log if something fails | ||
try { | ||
if (error.schemaPath) { | ||
const zip = await makeErrorZip(error); | ||
await uploadZip(zip, signedUrl); | ||
} | ||
} catch (zipUploadError) { | ||
console.error(`Error uploading zip file: ${zipUploadError.message}`); | ||
} | ||
|
||
// Mark the error report as completed | ||
const id = await makeErrorReportCompleted(signedUrl); | ||
|
||
return id; | ||
} | ||
|
||
async function makeErrorZip(error: RustPanic): Promise<Buffer> { | ||
if (!error.schemaPath) { | ||
throw new Error(`Can't make zip without schema path`); | ||
} | ||
const schemaDir = path.dirname(error.schemaPath); | ||
const tmpFileObj = tmp.fileSync(); | ||
const outputFile = fs.createWriteStream(tmpFileObj.name); | ||
const zip = archiver("zip", { zlib: { level: 9 } }); | ||
|
||
zip.pipe(outputFile); | ||
|
||
// add schema file | ||
// Note: the following reads `error.schemaPath` for the second time, we could just re-use | ||
// `maskedSchema` from the `sendPanic` function's scope. | ||
const schemaFile = maskSchema(fs.readFileSync(error.schemaPath, "utf-8")); | ||
zip.append(schemaFile, { name: path.basename(error.schemaPath) }); | ||
|
||
if (fs.existsSync(schemaDir)) { | ||
const filePaths = await globby("migrations/**/*", { | ||
// globby doesn't have it in its types but it's part of mrmlnc/fast-glob | ||
// @ts-ignore | ||
cwd: schemaDir | ||
}); | ||
|
||
for (const filePath of filePaths) { | ||
let file = fs.readFileSync(path.resolve(schemaDir, filePath), "utf-8"); | ||
if ( | ||
filePath.endsWith("schema.prisma") || | ||
filePath.endsWith(path.basename(error.schemaPath)) | ||
) { | ||
// Remove credentials from schema datasource url | ||
file = maskSchema(file); | ||
} | ||
zip.append(file, { name: path.basename(filePath) }); | ||
} | ||
} | ||
|
||
zip.finalize(); | ||
|
||
return new Promise((resolve, reject) => { | ||
outputFile.on("close", () => { | ||
const buffer = fs.readFileSync(tmpFileObj.name); | ||
resolve(buffer); | ||
}); | ||
|
||
zip.on("error", (err) => { | ||
reject(err); | ||
}); | ||
}); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
import chalk from "chalk"; | ||
import terminalLink from "terminal-link"; | ||
|
||
/** | ||
* Create a link to a URL in the terminal. | ||
* | ||
* @param url - The URL to link to. | ||
* @returns A terminal link | ||
*/ | ||
export function link(url: string): string { | ||
return terminalLink(url, url, { | ||
fallback: (url) => chalk.underline(url) | ||
}); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,5 @@ | ||
export * from "./create-cli-options"; | ||
export * from "./execute"; | ||
export * from "./cli-link"; | ||
export * from "./is-ci"; | ||
export * from "./is-interactive"; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,77 @@ | ||
/** | ||
* Returns true if the current environment is a CI environment. | ||
* | ||
* @returns True if the current environment is a CI environment. | ||
*/ | ||
export const isCI = (): boolean => { | ||
const env = process.env; | ||
|
||
// From https://github.com/watson/ci-info/blob/44e98cebcdf4403f162195fbcf90b1f69fc6e047/index.js#L54-L61 | ||
// Evaluating at runtime makes it possible to change the values in our tests | ||
// This list is probably not exhaustive though `process.env.CI` should be enough | ||
// but since we were using this utility in the past, we want to keep the same behavior | ||
return !!( | ||
env.STORM_CI || // Custom CI | ||
env.CI || // Travis CI, CircleCI, Cirrus CI, GitLab CI, Appveyor, CodeShip, dsari | ||
env.CONTINUOUS_INTEGRATION || // Travis CI, Cirrus CI | ||
env.BUILD_NUMBER || // Jenkins, TeamCity | ||
env.RUN_ID || // TaskCluster, dsari | ||
// From `env` from v4.0.0 https://github.com/watson/ci-info/blob/3e1488e98680f1f776785fe8708a157b7f00e568/vendors.json | ||
env.AGOLA_GIT_REF || | ||
env.AC_APPCIRCLE || | ||
env.APPVEYOR || | ||
env.CODEBUILD || | ||
env.TF_BUILD || | ||
env.bamboo_planKey || | ||
env.BITBUCKET_COMMIT || | ||
env.BITRISE_IO || | ||
env.BUDDY_WORKSPACE_ID || | ||
env.BUILDKITE || | ||
env.CIRCLECI || | ||
env.CIRRUS_CI || | ||
env.CF_BUILD_ID || | ||
env.CM_BUILD_ID || | ||
env.CI_NAME || | ||
env.DRONE || | ||
env.DSARI || | ||
env.EARTHLY_CI || | ||
env.EAS_BUILD || | ||
env.GERRIT_PROJECT || | ||
env.GITEA_ACTIONS || | ||
env.GITHUB_ACTIONS || | ||
env.GITLAB_CI || | ||
env.GOCD || | ||
env.BUILDER_OUTPUT || | ||
env.HARNESS_BUILD_ID || | ||
env.JENKINS_URL || | ||
env.BUILD_ID || | ||
env.LAYERCI || | ||
env.MAGNUM || | ||
env.NETLIFY || | ||
env.NEVERCODE || | ||
env.PROW_JOB_ID || | ||
env.RELEASE_BUILD_ID || | ||
env.RENDER || | ||
env.SAILCI || | ||
env.HUDSON || | ||
env.JENKINS_URL || | ||
env.BUILD_ID || | ||
env.SCREWDRIVER || | ||
env.SEMAPHORE || | ||
env.SOURCEHUT || | ||
env.STRIDER || | ||
env.TASK_ID || | ||
env.RUN_ID || | ||
env.TEAMCITY_VERSION || | ||
env.TRAVIS || | ||
env.VELA || | ||
env.NOW_BUILDER || | ||
// See https://github.com/prisma/prisma/issues/22380 for why we commented it out | ||
// Users deploying on Vercel might have this env var set in the local dev env | ||
// env.VERCEL || | ||
env.APPCENTER_BUILD_ID || | ||
env.CI_XCODE_PROJECT || | ||
env.XCS || | ||
false | ||
); | ||
}; |
Oops, something went wrong.