Detect case insensitive uploads + Bump @actions/artifact to version 0.3.3 (#106)
* Detect case insensitive uploads * PR feedback
This commit is contained in:
		
							parent
							
								
									5ba29a7d5b
								
							
						
					
					
						commit
						c8879bf5ae
					
				
							
								
								
									
										25
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										25
									
								
								README.md
									
									
									
									
									
								
							| @ -205,6 +205,31 @@ In the top right corner of a workflow run, once the run is over, if you used thi | |||||||
| 
 | 
 | ||||||
| There is a trashcan icon that can be used to delete the artifact. This icon will only appear for users who have write permissions to the repository. | There is a trashcan icon that can be used to delete the artifact. This icon will only appear for users who have write permissions to the repository. | ||||||
| 
 | 
 | ||||||
|  | # Limitations | ||||||
|  | 
 | ||||||
|  | ### Permission Loss | ||||||
|  | 
 | ||||||
|  | :exclamation: File permissions are not maintained during artifact upload :exclamation: For example, if you make a file executable using `chmod` and then upload that file, post-download the file is no longer guaranteed to be set as an executable. | ||||||
|  | 
 | ||||||
|  | ### Case Insensitive Uploads | ||||||
|  | 
 | ||||||
|  | :exclamation: File uploads are case insensitive :exclamation: If you upload `A.txt` and `a.txt` with the same root path, only a single file will be saved and available during download. | ||||||
|  | 
 | ||||||
|  | ### Maintaining file permissions and case sensitive files | ||||||
|  | 
 | ||||||
|  | If file permissions and case sensitivity are required, you can `tar` all of your files together before artifact upload. Post download, the `tar` file will maintain file permissions and case sensitivity. | ||||||
|  | 
 | ||||||
|  | ```yaml | ||||||
|  |   - name: 'Tar files' | ||||||
|  |     run: tar -cvf my_files.tar /path/to/my/directory | ||||||
|  | 
 | ||||||
|  |   - name: 'Upload Artifact' | ||||||
|  |     uses: actions/upload-artifact@v2 | ||||||
|  |     with: | ||||||
|  |       name: my-artifact | ||||||
|  |       path: my_files.tar     | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
| ## Additional Documentation | ## Additional Documentation | ||||||
| 
 | 
 | ||||||
| See [persisting workflow data using artifacts](https://help.github.com/en/actions/configuring-and-managing-workflows/persisting-workflow-data-using-artifacts) for additional examples and tips. | See [persisting workflow data using artifacts](https://help.github.com/en/actions/configuring-and-managing-workflows/persisting-workflow-data-using-artifacts) for additional examples and tips. | ||||||
|  | |||||||
							
								
								
									
										29
									
								
								dist/index.js
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										29
									
								
								dist/index.js
									
									
									
									
										vendored
									
									
								
							| @ -4992,11 +4992,12 @@ const utils_1 = __webpack_require__(870); | |||||||
|  * Used for managing http clients during either upload or download |  * Used for managing http clients during either upload or download | ||||||
|  */ |  */ | ||||||
| class HttpManager { | class HttpManager { | ||||||
|     constructor(clientCount) { |     constructor(clientCount, userAgent) { | ||||||
|         if (clientCount < 1) { |         if (clientCount < 1) { | ||||||
|             throw new Error('There must be at least one client'); |             throw new Error('There must be at least one client'); | ||||||
|         } |         } | ||||||
|         this.clients = new Array(clientCount).fill(utils_1.createHttpClient()); |         this.userAgent = userAgent; | ||||||
|  |         this.clients = new Array(clientCount).fill(utils_1.createHttpClient(userAgent)); | ||||||
|     } |     } | ||||||
|     getClient(index) { |     getClient(index) { | ||||||
|         return this.clients[index]; |         return this.clients[index]; | ||||||
| @ -5005,7 +5006,7 @@ class HttpManager { | |||||||
|     // for more information see: https://github.com/actions/http-client/blob/04e5ad73cd3fd1f5610a32116b0759eddf6570d2/index.ts#L292
 |     // for more information see: https://github.com/actions/http-client/blob/04e5ad73cd3fd1f5610a32116b0759eddf6570d2/index.ts#L292
 | ||||||
|     disposeAndReplaceClient(index) { |     disposeAndReplaceClient(index) { | ||||||
|         this.clients[index].dispose(); |         this.clients[index].dispose(); | ||||||
|         this.clients[index] = utils_1.createHttpClient(); |         this.clients[index] = utils_1.createHttpClient(this.userAgent); | ||||||
|     } |     } | ||||||
|     disposeAndReplaceAllClients() { |     disposeAndReplaceAllClients() { | ||||||
|         for (const [index] of this.clients.entries()) { |         for (const [index] of this.clients.entries()) { | ||||||
| @ -6288,7 +6289,7 @@ function getMultiPathLCA(searchPaths) { | |||||||
|         } |         } | ||||||
|         return true; |         return true; | ||||||
|     } |     } | ||||||
|     // Loop over all the search paths until there is a non-common ancestor or we go out of bounds
 |     // loop over all the search paths until there is a non-common ancestor or we go out of bounds
 | ||||||
|     while (splitIndex < smallestPathLength) { |     while (splitIndex < smallestPathLength) { | ||||||
|         if (!isPathTheSame()) { |         if (!isPathTheSame()) { | ||||||
|             break; |             break; | ||||||
| @ -6304,6 +6305,11 @@ function findFilesToUpload(searchPath, globOptions) { | |||||||
|         const searchResults = []; |         const searchResults = []; | ||||||
|         const globber = yield glob.create(searchPath, globOptions || getDefaultGlobOptions()); |         const globber = yield glob.create(searchPath, globOptions || getDefaultGlobOptions()); | ||||||
|         const rawSearchResults = yield globber.glob(); |         const rawSearchResults = yield globber.glob(); | ||||||
|  |         /* | ||||||
|  |           Files are saved with case insensitivity. Uploading both a.txt and A.txt will files to be overwritten | ||||||
|  |           Detect any files that could be overwritten for user awareness | ||||||
|  |         */ | ||||||
|  |         const set = new Set(); | ||||||
|         /* |         /* | ||||||
|           Directories will be rejected if attempted to be uploaded. This includes just empty |           Directories will be rejected if attempted to be uploaded. This includes just empty | ||||||
|           directories so filter any directories out from the raw search results |           directories so filter any directories out from the raw search results | ||||||
| @ -6314,6 +6320,13 @@ function findFilesToUpload(searchPath, globOptions) { | |||||||
|             if (!fileStats.isDirectory()) { |             if (!fileStats.isDirectory()) { | ||||||
|                 core_1.debug(`File:${searchResult} was found using the provided searchPath`); |                 core_1.debug(`File:${searchResult} was found using the provided searchPath`); | ||||||
|                 searchResults.push(searchResult); |                 searchResults.push(searchResult); | ||||||
|  |                 // detect any files that would be overwritten because of case insensitivity
 | ||||||
|  |                 if (set.has(searchResult.toLowerCase())) { | ||||||
|  |                     core_1.info(`Uploads are case insensitive: ${searchResult} was detected that it will be overwritten by another file with the same path`); | ||||||
|  |                 } | ||||||
|  |                 else { | ||||||
|  |                     set.add(searchResult.toLowerCase()); | ||||||
|  |                 } | ||||||
|             } |             } | ||||||
|             else { |             else { | ||||||
|                 core_1.debug(`Removing ${searchResult} from rawSearchResults because it is a directory`); |                 core_1.debug(`Removing ${searchResult} from rawSearchResults because it is a directory`); | ||||||
| @ -6645,7 +6658,7 @@ const upload_gzip_1 = __webpack_require__(647); | |||||||
| const stat = util_1.promisify(fs.stat); | const stat = util_1.promisify(fs.stat); | ||||||
| class UploadHttpClient { | class UploadHttpClient { | ||||||
|     constructor() { |     constructor() { | ||||||
|         this.uploadHttpManager = new http_manager_1.HttpManager(config_variables_1.getUploadFileConcurrency()); |         this.uploadHttpManager = new http_manager_1.HttpManager(config_variables_1.getUploadFileConcurrency(), 'actions/upload-artifact'); | ||||||
|         this.statusReporter = new status_reporter_1.StatusReporter(10000); |         this.statusReporter = new status_reporter_1.StatusReporter(10000); | ||||||
|     } |     } | ||||||
|     /** |     /** | ||||||
| @ -7399,7 +7412,7 @@ const http_manager_1 = __webpack_require__(452); | |||||||
| const config_variables_1 = __webpack_require__(401); | const config_variables_1 = __webpack_require__(401); | ||||||
| class DownloadHttpClient { | class DownloadHttpClient { | ||||||
|     constructor() { |     constructor() { | ||||||
|         this.downloadHttpManager = new http_manager_1.HttpManager(config_variables_1.getDownloadFileConcurrency()); |         this.downloadHttpManager = new http_manager_1.HttpManager(config_variables_1.getDownloadFileConcurrency(), 'actions/download-artifact'); | ||||||
|         // downloads are usually significantly faster than uploads so display status information every second
 |         // downloads are usually significantly faster than uploads so display status information every second
 | ||||||
|         this.statusReporter = new status_reporter_1.StatusReporter(1000); |         this.statusReporter = new status_reporter_1.StatusReporter(1000); | ||||||
|     } |     } | ||||||
| @ -8034,8 +8047,8 @@ function getUploadHeaders(contentType, isKeepAlive, isGzip, uncompressedLength, | |||||||
|     return requestOptions; |     return requestOptions; | ||||||
| } | } | ||||||
| exports.getUploadHeaders = getUploadHeaders; | exports.getUploadHeaders = getUploadHeaders; | ||||||
| function createHttpClient() { | function createHttpClient(userAgent) { | ||||||
|     return new http_client_1.HttpClient('actions/artifact', [ |     return new http_client_1.HttpClient(userAgent, [ | ||||||
|         new auth_1.BearerCredentialHandler(config_variables_1.getRuntimeToken()) |         new auth_1.BearerCredentialHandler(config_variables_1.getRuntimeToken()) | ||||||
|     ]); |     ]); | ||||||
| } | } | ||||||
|  | |||||||
							
								
								
									
										6
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										6
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							| @ -5,9 +5,9 @@ | |||||||
|   "requires": true, |   "requires": true, | ||||||
|   "dependencies": { |   "dependencies": { | ||||||
|     "@actions/artifact": { |     "@actions/artifact": { | ||||||
|       "version": "0.3.2", |       "version": "0.3.3", | ||||||
|       "resolved": "https://registry.npmjs.org/@actions/artifact/-/artifact-0.3.2.tgz", |       "resolved": "https://registry.npmjs.org/@actions/artifact/-/artifact-0.3.3.tgz", | ||||||
|       "integrity": "sha512-KzUe5DEeVXprAodxfGKtx9f7ukuVKE6V6pge6t5GDGk0cdkfiMEfahoq7HfBsOsmVy4J7rr1YZQPUTvXveYinw==", |       "integrity": "sha512-sKC1uA5p6064C6Qypmmt6O8iKlpDyMTfqqDlS4/zfJX1Hs8NbbzPLLN81RpewuJPWQNnroeF52w4VCWypbSNaA==", | ||||||
|       "dev": true, |       "dev": true, | ||||||
|       "requires": { |       "requires": { | ||||||
|         "@actions/core": "^1.2.1", |         "@actions/core": "^1.2.1", | ||||||
|  | |||||||
| @ -29,7 +29,7 @@ | |||||||
|   }, |   }, | ||||||
|   "homepage": "https://github.com/actions/upload-artifact#readme", |   "homepage": "https://github.com/actions/upload-artifact#readme", | ||||||
|   "devDependencies": { |   "devDependencies": { | ||||||
|     "@actions/artifact": "^0.3.2", |     "@actions/artifact": "^0.3.3", | ||||||
|     "@actions/core": "^1.2.3", |     "@actions/core": "^1.2.3", | ||||||
|     "@actions/glob": "^0.1.0", |     "@actions/glob": "^0.1.0", | ||||||
|     "@actions/io": "^1.0.2", |     "@actions/io": "^1.0.2", | ||||||
|  | |||||||
| @ -66,7 +66,7 @@ function getMultiPathLCA(searchPaths: string[]): string { | |||||||
|     return true |     return true | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   // Loop over all the search paths until there is a non-common ancestor or we go out of bounds
 |   // loop over all the search paths until there is a non-common ancestor or we go out of bounds
 | ||||||
|   while (splitIndex < smallestPathLength) { |   while (splitIndex < smallestPathLength) { | ||||||
|     if (!isPathTheSame()) { |     if (!isPathTheSame()) { | ||||||
|       break |       break | ||||||
| @ -89,6 +89,12 @@ export async function findFilesToUpload( | |||||||
|   ) |   ) | ||||||
|   const rawSearchResults: string[] = await globber.glob() |   const rawSearchResults: string[] = await globber.glob() | ||||||
| 
 | 
 | ||||||
|  |   /* | ||||||
|  |     Files are saved with case insensitivity. Uploading both a.txt and A.txt will files to be overwritten | ||||||
|  |     Detect any files that could be overwritten for user awareness | ||||||
|  |   */ | ||||||
|  |   const set = new Set<string>() | ||||||
|  | 
 | ||||||
|   /* |   /* | ||||||
|     Directories will be rejected if attempted to be uploaded. This includes just empty |     Directories will be rejected if attempted to be uploaded. This includes just empty | ||||||
|     directories so filter any directories out from the raw search results |     directories so filter any directories out from the raw search results | ||||||
| @ -99,6 +105,15 @@ export async function findFilesToUpload( | |||||||
|     if (!fileStats.isDirectory()) { |     if (!fileStats.isDirectory()) { | ||||||
|       debug(`File:${searchResult} was found using the provided searchPath`) |       debug(`File:${searchResult} was found using the provided searchPath`) | ||||||
|       searchResults.push(searchResult) |       searchResults.push(searchResult) | ||||||
|  | 
 | ||||||
|  |       // detect any files that would be overwritten because of case insensitivity
 | ||||||
|  |       if (set.has(searchResult.toLowerCase())) { | ||||||
|  |         info( | ||||||
|  |           `Uploads are case insensitive: ${searchResult} was detected that it will be overwritten by another file with the same path` | ||||||
|  |         ) | ||||||
|  |       } else { | ||||||
|  |         set.add(searchResult.toLowerCase()) | ||||||
|  |       } | ||||||
|     } else { |     } else { | ||||||
|       debug( |       debug( | ||||||
|         `Removing ${searchResult} from rawSearchResults because it is a directory` |         `Removing ${searchResult} from rawSearchResults because it is a directory` | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user