diff --git a/packages/artifact/__tests__/upload-artifact.test.ts b/packages/artifact/__tests__/upload-artifact.test.ts index 9865815dc7..de4c584751 100644 --- a/packages/artifact/__tests__/upload-artifact.test.ts +++ b/packages/artifact/__tests__/upload-artifact.test.ts @@ -12,6 +12,7 @@ import {BlockBlobUploadStreamOptions} from '@azure/storage-blob' import * as fs from 'fs' import * as path from 'path' import unzip from 'unzip-stream' +import * as core from '@actions/core' const uploadStreamMock = jest.fn() const blockBlobClientMock = jest.fn().mockImplementation(() => ({ @@ -466,6 +467,71 @@ describe('upload-artifact', () => { expect(uploadedContent).toBe(expectedContent) }) + it('should not warn when uploading an empty file with skipArchive enabled', async () => { + jest + .spyOn(uploadZipSpecification, 'getUploadZipSpecification') + .mockRestore() + + const emptyFile = path.join(fixtures.uploadDirectory, 'empty.txt') + fs.writeFileSync(emptyFile, '') + + jest + .spyOn(ArtifactServiceClientJSON.prototype, 'CreateArtifact') + .mockReturnValue( + Promise.resolve({ + ok: true, + signedUploadUrl: 'https://signed-upload-url.local' + }) + ) + jest + .spyOn(ArtifactServiceClientJSON.prototype, 'FinalizeArtifact') + .mockReturnValue( + Promise.resolve({ + ok: true, + artifactId: '1' + }) + ) + + uploadStreamMock.mockImplementation( + async ( + stream: NodeJS.ReadableStream, + bufferSize?: number, + maxConcurrency?: number, + options?: BlockBlobUploadStreamOptions + ) => { + const {onProgress} = options || {} + onProgress?.({loadedBytes: 0}) + + return new Promise((resolve, reject) => { + stream.on('data', () => { + onProgress?.({loadedBytes: 0}) + }) + stream.on('end', () => { + onProgress?.({loadedBytes: 0}) + resolve({}) + }) + stream.on('error', err => { + reject(err) + }) + }) + } + ) + + const warningSpy = core.warning as jest.Mock + warningSpy.mockClear() + + await uploadArtifact( + fixtures.inputs.artifactName, + [emptyFile], + fixtures.uploadDirectory, + {skipArchive: true} + ) + + expect(warningSpy).not.toHaveBeenCalledWith( + 'No data was uploaded to blob storage. Reported upload byte count is 0.' + ) + }) + it('should use the correct MIME type when skipArchive is true', async () => { jest .spyOn(uploadZipSpecification, 'getUploadZipSpecification') diff --git a/packages/artifact/src/internal/upload/blob-upload.ts b/packages/artifact/src/internal/upload/blob-upload.ts index be6fcef59b..a7b4c65239 100644 --- a/packages/artifact/src/internal/upload/blob-upload.ts +++ b/packages/artifact/src/internal/upload/blob-upload.ts @@ -23,10 +23,15 @@ export interface BlobUploadResponse { sha256Hash?: string } +export interface BlobUploadOptions { + suppressZeroByteWarning?: boolean +} + export async function uploadToBlobStorage( authenticatedUploadURL: string, uploadStream: WaterMarkedUploadStream, - contentType: string + contentType: string, + options?: BlobUploadOptions ): Promise { let uploadByteCount = 0 let lastProgressTime = Date.now() @@ -61,7 +66,7 @@ export async function uploadToBlobStorage( lastProgressTime = Date.now() } - const options: BlockBlobUploadStreamOptions = { + const uploadOptions: BlockBlobUploadStreamOptions = { blobHTTPHeaders: {blobContentType: contentType}, onProgress: uploadCallback, abortSignal: abortController.signal @@ -82,7 +87,7 @@ export async function uploadToBlobStorage( blobUploadStream, bufferSize, maxConcurrency, - options + uploadOptions ), chunkTimer(getUploadChunkTimeout()) ]) @@ -101,7 +106,7 @@ export async function uploadToBlobStorage( sha256Hash = hashStream.read() as string core.info(`SHA256 digest of uploaded artifact is ${sha256Hash}`) - if (uploadByteCount === 0) { + if (uploadByteCount === 0 && !options?.suppressZeroByteWarning) { core.warning( `No data was uploaded to blob storage. Reported upload byte count is 0.` ) diff --git a/packages/artifact/src/internal/upload/upload-artifact.ts b/packages/artifact/src/internal/upload/upload-artifact.ts index c7a6e60b75..765daa4d35 100644 --- a/packages/artifact/src/internal/upload/upload-artifact.ts +++ b/packages/artifact/src/internal/upload/upload-artifact.ts @@ -32,6 +32,8 @@ export async function uploadArtifact( options?: UploadArtifactOptions | undefined ): Promise { let artifactFileName = `${name}.zip` + let suppressZeroByteWarning = false + if (options?.skipArchive) { if (files.length === 0) { throw new FilesNotFoundError([]) @@ -47,6 +49,7 @@ export async function uploadArtifact( throw new FilesNotFoundError(files) } + suppressZeroByteWarning = fs.statSync(files[0]).size === 0 artifactFileName = path.basename(files[0]) name = artifactFileName } @@ -114,7 +117,10 @@ export async function uploadArtifact( const uploadResult = await uploadToBlobStorage( createArtifactResp.signedUploadUrl, stream, - contentType + contentType, + { + suppressZeroByteWarning + } ) // finalize the artifact