-
Notifications
You must be signed in to change notification settings - Fork 273
/
Copy pathartifacts.ts
115 lines (104 loc) · 3.15 KB
/
artifacts.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
/*
* Copyright (C) 2018-2024 Garden Technologies, Inc. <[email protected]>
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
import { join, relative } from "path"
import fsExtra from "fs-extra"
const { readFile, writeFile } = fsExtra
import type { Log } from "../logger/log-entry.js"
import type { Garden } from "../garden.js"
import { styles } from "../logger/styles.js"
const maxArtifactLogLines = 5 // max number of artifacts to list in console after run+test runs
/**
* @param type task | test
* @param name name of the task or test
* @param version the version of the module that the task/test belongs to
*/
export function getArtifactKey(type: "run" | "test", name: string, version: string) {
return `${type}.${name}.${version}`
}
/**
* Returns the file list from the artifact metadata file (under `.garden/artifacts/.metadata.<key>.json)
* for the given artifact key.
*
* Returns an empty array if the metadata file is not found or if we can't parse it.
*/
export async function getArtifactFileList({
artifactsPath,
key,
log,
}: {
artifactsPath: string
key: string
log: Log
}) {
const metadataPath = join(artifactsPath, `.metadata.${key}.json`)
let files: string[] = []
try {
const metadata = await readFile(metadataPath)
try {
files = JSON.parse(metadata.toString()).files || []
} catch (err) {
log.debug(`Failed parsing artifact metadata file: ${err}`)
}
} catch (err) {
log.debug(`Failed reading metadata file: ${err}`)
}
return files
}
/**
* Copies the artifacts exported by a plugin handler to the user's artifact directory.
*
* @param log LogEntry
* @param artifactsPath the temporary directory path given to the plugin handler
*/
export async function copyArtifacts({
garden,
log,
artifactsPath,
key,
}: {
garden: Garden
log: Log
artifactsPath: string
key: string
}) {
let files: string[] = []
// Note: lazy-loading for startup performance
const { default: cpy } = await import("cpy")
try {
files = await cpy("./**/*", garden.artifactsPath, { cwd: artifactsPath })
} catch (err) {
if (!(err instanceof Error)) {
throw err
}
// Ignore error thrown when the directory is empty
if (err.name !== "CpyError" || !err.message.includes("the file doesn't exist")) {
throw err
}
}
const count = files.length
if (count > 0) {
// Log the exported artifact paths (but don't spam the console)
if (count > maxArtifactLogLines) {
files = files.slice(0, maxArtifactLogLines)
}
for (const file of files) {
log.info(styles.primary(`→ Artifact: ${relative(garden.projectRoot, file)}`))
}
if (count > maxArtifactLogLines) {
log.info(styles.primary(`→ Artifact: … plus ${count - maxArtifactLogLines} more files`))
}
}
// Write list of files to a metadata file
const metadataPath = join(garden.artifactsPath, `.metadata.${key}.json`)
const metadata = {
key,
files: files.sort(),
}
await writeFile(metadataPath, JSON.stringify(metadata))
return files
}