Skip to content

Commit bf257aa

Browse files
committed
Do verify that the expected amount of bytes were written
Helpfully, Azure Pipelines reports an "artifact size", which is the total number of bytes to be extracted to disk. Since we had occasional problems due to incompletely downloaded or extracted artifacts, let's make use of this to ensure that the expected number of bytes was written to disk. Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
1 parent 58284b0 commit bf257aa

File tree

4 files changed

+38
-15
lines changed

4 files changed

+38
-15
lines changed

.vscode/settings.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
],
77
"cSpell.words": [
88
"Backoff",
9+
"artifactsize",
910
"autodrain",
1011
"dpkg",
1112
"localpath",

__tests__/downloader.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -214,6 +214,6 @@ test('can obtain build ID', async () => {
214214
'git-sdk-64-minimal',
215215
undefined
216216
)
217-
expect(fetch).toHaveBeenCalledTimes(1)
217+
expect(fetch).toHaveBeenCalledTimes(2)
218218
expect(cacheId).toEqual('git-for-windows.git-22-git-sdk-64-minimal-73427')
219219
})

main.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,13 @@ import {readdirSync, unlinkSync} from 'fs'
55

66
async function run(): Promise<void> {
77
try {
8-
const {artifactName, stripPrefix, download, cacheId} = await get(
8+
const {
9+
artifactName,
10+
stripPrefix,
11+
download,
12+
bytesToExtract,
13+
cacheId
14+
} = await get(
915
core.getInput('repository'),
1016
core.getInput('definitionId'),
1117
core.getInput('artifact'),
@@ -35,6 +41,7 @@ async function run(): Promise<void> {
3541
if (await restoreCache([storeZipAs], cacheId)) {
3642
await unzip(
3743
`file:${storeZipAs}`,
44+
bytesToExtract,
3845
stripPrefix,
3946
outputDirectory,
4047
verbose

src/downloader.ts

Lines changed: 28 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ function mkdirp(directoryPath: string): void {
3131

3232
export async function unzip(
3333
url: string,
34+
bytesToExtract: number,
3435
stripPrefix: string,
3536
outputDirectory: string,
3637
verbose: boolean | number,
@@ -86,12 +87,21 @@ export async function unzip(
8687
entry.autodrain()
8788
} else {
8889
progress(entryPath)
89-
entry.pipe(fs.createWriteStream(`${entryPath}`))
90+
entry
91+
.pipe(fs.createWriteStream(`${entryPath}`))
92+
.on('finish', () => {
93+
bytesToExtract -= fs.statSync(entryPath).size
94+
})
9095
}
9196
})
9297
.on('error', reject)
9398
.on('finish', progress)
94-
.on('finish', () => resolve(files))
99+
.on('finish', () => {
100+
bytesToExtract === 0
101+
? resolve(files)
102+
: // eslint-disable-next-line prefer-promise-reject-errors
103+
reject(`${bytesToExtract} bytes left to extract`)
104+
})
95105
}
96106
if (url.startsWith('file:')) {
97107
callback(fs.createReadStream(url.substring('file:'.length)))
@@ -109,6 +119,7 @@ export async function get(
109119
): Promise<{
110120
artifactName: string
111121
stripPrefix: string
122+
bytesToExtract: number
112123
cacheId: string
113124
download: (
114125
outputDirectory: string,
@@ -131,11 +142,15 @@ export async function get(
131142
if (data.count !== 1) {
132143
throw new Error(`Unexpected number of builds: ${data.count}`)
133144
}
134-
let url: string | undefined
135-
const getURL = async (): Promise<string> => {
145+
const getURL = async (): Promise<{url: string; bytesToExtract: number}> => {
136146
const data2 = await fetchJSONFromURL<{
137147
count: number
138-
value: [{name: string; resource: {downloadUrl: string}}]
148+
value: [
149+
{
150+
name: string
151+
resource: {downloadUrl: string; properties: {artifactsize: number}}
152+
}
153+
]
139154
}>(`${baseURL}/${data.value[0].id}/artifacts`)
140155
if (!artifactName) {
141156
if (data2.value.length !== 1) {
@@ -155,13 +170,15 @@ export async function get(
155170
.join(', ')}`
156171
)
157172
}
158-
return filtered[0].resource.downloadUrl
159-
}
160173

161-
if (!artifactName) {
162-
url = await getURL()
174+
return {
175+
url: filtered[0].resource.downloadUrl,
176+
bytesToExtract: filtered[0].resource.properties.artifactsize
177+
}
163178
}
164179

180+
const {url, bytesToExtract} = await getURL()
181+
165182
if (!stripPrefix) {
166183
stripPrefix = `${artifactName}/`
167184
}
@@ -171,14 +188,12 @@ export async function get(
171188
verbose: number | boolean = false,
172189
storeZipAs?: string
173190
): Promise<string[]> => {
174-
if (!url) {
175-
url = await getURL()
176-
}
177191
let delayInSeconds = 1
178192
for (;;) {
179193
try {
180194
return await unzip(
181195
url,
196+
bytesToExtract,
182197
stripPrefix || `${artifactName}/`,
183198
outputDirectory,
184199
verbose,
@@ -203,5 +218,5 @@ export async function get(
203218
'/',
204219
'.'
205220
)
206-
return {artifactName, stripPrefix, download, cacheId}
221+
return {artifactName, stripPrefix, download, bytesToExtract, cacheId}
207222
}

0 commit comments

Comments
 (0)