mirror of
				https://github.com/actions/download-artifact.git
				synced 2025-10-31 20:13:42 +00:00 
			
		
		
		
	Merge pull request #416 from actions/single-artifact-id-download-path
fix: inconsistent path behavior for single artifact downloads by ID
This commit is contained in:
		
						commit
						634f93cb29
					
				
							
								
								
									
										20
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										20
									
								
								README.md
									
									
									
									
									
								
							| @ -8,6 +8,7 @@ See also [upload-artifact](https://github.com/actions/upload-artifact). | |||||||
|   - [v4 - What's new](#v4---whats-new) |   - [v4 - What's new](#v4---whats-new) | ||||||
|     - [Improvements](#improvements) |     - [Improvements](#improvements) | ||||||
|     - [Breaking Changes](#breaking-changes) |     - [Breaking Changes](#breaking-changes) | ||||||
|  |   - [Note](#note) | ||||||
|   - [Usage](#usage) |   - [Usage](#usage) | ||||||
|     - [Inputs](#inputs) |     - [Inputs](#inputs) | ||||||
|     - [Outputs](#outputs) |     - [Outputs](#outputs) | ||||||
| @ -89,6 +90,7 @@ You are welcome to still raise bugs in this repo. | |||||||
|     # When multiple artifacts are matched, this changes the behavior of the destination directories. |     # When multiple artifacts are matched, this changes the behavior of the destination directories. | ||||||
|     # If true, the downloaded artifacts will be in the same directory specified by path. |     # If true, the downloaded artifacts will be in the same directory specified by path. | ||||||
|     # If false, the downloaded artifacts will be extracted into individual named directories within the specified path. |     # If false, the downloaded artifacts will be extracted into individual named directories within the specified path. | ||||||
|  |     # Note: When downloading a single artifact (by name or ID), it will always be extracted directly to the specified path. | ||||||
|     # Optional. Default is 'false' |     # Optional. Default is 'false' | ||||||
|     merge-multiple: |     merge-multiple: | ||||||
| 
 | 
 | ||||||
| @ -145,6 +147,8 @@ steps: | |||||||
| 
 | 
 | ||||||
| The `artifact-ids` input allows downloading artifacts using their unique ID rather than name. This is particularly useful when working with immutable artifacts from `actions/upload-artifact@v4` which assigns a unique ID to each artifact. | The `artifact-ids` input allows downloading artifacts using their unique ID rather than name. This is particularly useful when working with immutable artifacts from `actions/upload-artifact@v4` which assigns a unique ID to each artifact. | ||||||
| 
 | 
 | ||||||
|  | Download a single artifact by ID to the current working directory (`$GITHUB_WORKSPACE`): | ||||||
|  | 
 | ||||||
| ```yaml | ```yaml | ||||||
| steps: | steps: | ||||||
| - uses: actions/download-artifact@v4 | - uses: actions/download-artifact@v4 | ||||||
| @ -154,6 +158,20 @@ steps: | |||||||
|   run: ls -R |   run: ls -R | ||||||
| ``` | ``` | ||||||
| 
 | 
 | ||||||
|  | Download a single artifact by ID to a specific directory: | ||||||
|  | 
 | ||||||
|  | ```yaml | ||||||
|  | steps: | ||||||
|  | - uses: actions/download-artifact@v4 | ||||||
|  |   with: | ||||||
|  |     artifact-ids: 12345 | ||||||
|  |     path: your/destination/dir | ||||||
|  | - name: Display structure of downloaded files | ||||||
|  |   run: ls -R your/destination/dir | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | When downloading a single artifact by ID, the behavior is identical to downloading by name - the artifact contents are extracted directly to the specified path without creating a subdirectory. | ||||||
|  | 
 | ||||||
| Multiple artifacts can be downloaded by providing a comma-separated list of IDs: | Multiple artifacts can be downloaded by providing a comma-separated list of IDs: | ||||||
| 
 | 
 | ||||||
| ```yaml | ```yaml | ||||||
| @ -166,7 +184,7 @@ steps: | |||||||
|   run: ls -R path/to/artifacts |   run: ls -R path/to/artifacts | ||||||
| ``` | ``` | ||||||
| 
 | 
 | ||||||
| This will download multiple artifacts to separate directories (similar to downloading multiple artifacts by name). | When downloading multiple artifacts by ID, each artifact will be extracted into its own subdirectory named after the artifact (similar to downloading multiple artifacts by name). | ||||||
| 
 | 
 | ||||||
| ### Download All Artifacts | ### Download All Artifacts | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -1,4 +1,5 @@ | |||||||
| import * as core from '@actions/core' | import * as core from '@actions/core' | ||||||
|  | import * as path from 'path' | ||||||
| import artifact, {ArtifactNotFoundError} from '@actions/artifact' | import artifact, {ArtifactNotFoundError} from '@actions/artifact' | ||||||
| import {run} from '../src/download-artifact' | import {run} from '../src/download-artifact' | ||||||
| import {Inputs} from '../src/constants' | import {Inputs} from '../src/constants' | ||||||
| @ -371,4 +372,38 @@ describe('download', () => { | |||||||
|       "Inputs 'name' and 'artifact-ids' cannot be used together. Please specify only one." |       "Inputs 'name' and 'artifact-ids' cannot be used together. Please specify only one." | ||||||
|     ) |     ) | ||||||
|   }) |   }) | ||||||
|  | 
 | ||||||
|  |   test('downloads single artifact by ID to same path as by name', async () => { | ||||||
|  |     const mockArtifact = { | ||||||
|  |       id: 456, | ||||||
|  |       name: 'test-artifact', | ||||||
|  |       size: 1024, | ||||||
|  |       digest: 'def456' | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     const testPath = '/test/path' | ||||||
|  |     mockInputs({ | ||||||
|  |       [Inputs.Name]: '', | ||||||
|  |       [Inputs.Pattern]: '', | ||||||
|  |       [Inputs.ArtifactIds]: '456', | ||||||
|  |       [Inputs.Path]: testPath | ||||||
|  |     }) | ||||||
|  | 
 | ||||||
|  |     jest.spyOn(artifact, 'listArtifacts').mockImplementation(() => | ||||||
|  |       Promise.resolve({ | ||||||
|  |         artifacts: [mockArtifact] | ||||||
|  |       }) | ||||||
|  |     ) | ||||||
|  | 
 | ||||||
|  |     await run() | ||||||
|  | 
 | ||||||
|  |     // Verify it downloads directly to the specified path (not nested in artifact name subdirectory)
 | ||||||
|  |     expect(artifact.downloadArtifact).toHaveBeenCalledWith( | ||||||
|  |       456, | ||||||
|  |       expect.objectContaining({ | ||||||
|  |         path: path.resolve(testPath), // Should be the resolved path directly, not nested
 | ||||||
|  |         expectedHash: mockArtifact.digest | ||||||
|  |       }) | ||||||
|  |     ) | ||||||
|  |   }) | ||||||
| }) | }) | ||||||
|  | |||||||
							
								
								
									
										6
									
								
								dist/index.js
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										6
									
								
								dist/index.js
									
									
									
									
										vendored
									
									
								
							| @ -118883,7 +118883,9 @@ function run() { | |||||||
|         } |         } | ||||||
|         const downloadPromises = artifacts.map(artifact => ({ |         const downloadPromises = artifacts.map(artifact => ({ | ||||||
|             name: artifact.name, |             name: artifact.name, | ||||||
|             promise: artifact_1.default.downloadArtifact(artifact.id, Object.assign(Object.assign({}, options), { path: isSingleArtifactDownload || inputs.mergeMultiple |             promise: artifact_1.default.downloadArtifact(artifact.id, Object.assign(Object.assign({}, options), { path: isSingleArtifactDownload || | ||||||
|  |                     inputs.mergeMultiple || | ||||||
|  |                     artifacts.length === 1 | ||||||
|                     ? resolvedPath |                     ? resolvedPath | ||||||
|                     : path.join(resolvedPath, artifact.name), expectedHash: artifact.digest })) |                     : path.join(resolvedPath, artifact.name), expectedHash: artifact.digest })) | ||||||
|         })); |         })); | ||||||
| @ -128958,4 +128960,4 @@ module.exports = JSON.parse('[[[0,44],"disallowed_STD3_valid"],[[45,46],"valid"] | |||||||
| /******/ 	module.exports = __webpack_exports__; | /******/ 	module.exports = __webpack_exports__; | ||||||
| /******/ 	 | /******/ 	 | ||||||
| /******/ })() | /******/ })() | ||||||
| ; | ; | ||||||
| @ -174,7 +174,9 @@ export async function run(): Promise<void> { | |||||||
|     promise: artifactClient.downloadArtifact(artifact.id, { |     promise: artifactClient.downloadArtifact(artifact.id, { | ||||||
|       ...options, |       ...options, | ||||||
|       path: |       path: | ||||||
|         isSingleArtifactDownload || inputs.mergeMultiple |         isSingleArtifactDownload || | ||||||
|  |         inputs.mergeMultiple || | ||||||
|  |         artifacts.length === 1 | ||||||
|           ? resolvedPath |           ? resolvedPath | ||||||
|           : path.join(resolvedPath, artifact.name), |           : path.join(resolvedPath, artifact.name), | ||||||
|       expectedHash: artifact.digest |       expectedHash: artifact.digest | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user