@@ -122,6 +122,39 @@ pub fn archive_files_step(
122122 . with_input ( "archiveFile" , archive_file)
123123}
124124
125+ /// Returns a [`TaskStep`] for `ExtractFiles@1`.
126+ ///
127+ /// Extracts archives matching `archive_file_patterns` into `destination_folder`.
128+ /// Supports `.zip`, `.tar.gz`, `.tar.bz2`, and 7-Zip formats (`.7z`, `.tar`,
129+ /// `.rar`, etc.) via the 7z utility bundled with the task on Windows agents,
130+ /// or the system 7z on Linux/macOS.
131+ ///
132+ /// - `archive_file_patterns` — glob pattern(s) that match the archives to
133+ /// extract. Patterns are evaluated from the root of the repository
134+ /// (equivalent to `$(Build.SourcesDirectory)`). Multiple patterns can be
135+ /// separated by newlines. Default: `**/*.zip`.
136+ /// - `destination_folder` — path to the folder where files will be extracted.
137+ /// **Required** — the task has no default for this input.
138+ ///
139+ /// Optional inputs (applied with `.with_input(…)` on the returned value):
140+ ///
141+ /// | Input key | Type | Default | Description |
142+ /// |---|---|---|---|
143+ /// | `cleanDestinationFolder` | bool string | `"true"` | Delete destination folder contents before extracting. |
144+ /// | `overwriteExistingFiles` | bool string | `"false"` | Overwrite files that already exist in the destination. |
145+ /// | `pathToSevenZipTool` | string | — | Absolute path to a custom `7z` binary (e.g. `/usr/local/bin/7z`). |
146+ ///
147+ /// ADO task reference:
148+ /// <https://learn.microsoft.com/en-us/azure/devops/pipelines/tasks/reference/extract-files-v1>
149+ pub fn extract_files_step (
150+ archive_file_patterns : impl Into < String > ,
151+ destination_folder : impl Into < String > ,
152+ ) -> TaskStep {
153+ TaskStep :: new ( "ExtractFiles@1" , "Extract Files" )
154+ . with_input ( "archiveFilePatterns" , archive_file_patterns)
155+ . with_input ( "destinationFolder" , destination_folder)
156+ }
157+
125158/// Returns a [`TaskStep`] for `PublishTestResults@2`.
126159///
127160/// Publishes test results to the ADO build summary and timeline.
@@ -446,4 +479,62 @@ mod tests {
446479 ) ;
447480 assert_eq ! ( t. inputs. len( ) , 4 ) ;
448481 }
482+
483+ // ── ExtractFiles@1 ───────────────────────────────────────────────────
484+
485+ #[ test]
486+ fn extract_files_step_sets_task_and_required_inputs ( ) {
487+ let t = extract_files_step ( "**/*.zip" , "$(Build.BinariesDirectory)" ) ;
488+ assert_eq ! ( t. task, "ExtractFiles@1" ) ;
489+ assert_eq ! ( t. display_name, "Extract Files" ) ;
490+ assert_eq ! (
491+ t. inputs. get( "archiveFilePatterns" ) . map( |s| s. as_str( ) ) ,
492+ Some ( "**/*.zip" )
493+ ) ;
494+ assert_eq ! (
495+ t. inputs. get( "destinationFolder" ) . map( |s| s. as_str( ) ) ,
496+ Some ( "$(Build.BinariesDirectory)" )
497+ ) ;
498+ // no optional inputs by default
499+ assert_eq ! ( t. inputs. len( ) , 2 ) ;
500+ }
501+
502+ #[ test]
503+ fn extract_files_step_accepts_optional_clean_and_overwrite ( ) {
504+ let t = extract_files_step ( "**/*.tar.gz" , "$(Agent.TempDirectory)/extracted" )
505+ . with_input ( "cleanDestinationFolder" , "false" )
506+ . with_input ( "overwriteExistingFiles" , "true" ) ;
507+ assert_eq ! ( t. task, "ExtractFiles@1" ) ;
508+ assert_eq ! (
509+ t. inputs. get( "cleanDestinationFolder" ) . map( |s| s. as_str( ) ) ,
510+ Some ( "false" )
511+ ) ;
512+ assert_eq ! (
513+ t. inputs. get( "overwriteExistingFiles" ) . map( |s| s. as_str( ) ) ,
514+ Some ( "true" )
515+ ) ;
516+ assert_eq ! ( t. inputs. len( ) , 4 ) ;
517+ }
518+
519+ #[ test]
520+ fn extract_files_step_accepts_custom_seven_zip_path ( ) {
521+ let t = extract_files_step ( "artifacts/**/*.7z" , "$(Build.BinariesDirectory)" )
522+ . with_input ( "pathToSevenZipTool" , "/usr/local/bin/7z" ) ;
523+ assert_eq ! ( t. task, "ExtractFiles@1" ) ;
524+ assert_eq ! (
525+ t. inputs. get( "pathToSevenZipTool" ) . map( |s| s. as_str( ) ) ,
526+ Some ( "/usr/local/bin/7z" )
527+ ) ;
528+ assert_eq ! ( t. inputs. len( ) , 3 ) ;
529+ }
530+
531+ #[ test]
532+ fn extract_files_step_multiline_patterns ( ) {
533+ let patterns = "**/*.zip\n **/*.tar.gz" ;
534+ let t = extract_files_step ( patterns, "$(Build.BinariesDirectory)" ) ;
535+ assert_eq ! (
536+ t. inputs. get( "archiveFilePatterns" ) . map( |s| s. as_str( ) ) ,
537+ Some ( "**/*.zip\n **/*.tar.gz" )
538+ ) ;
539+ }
449540}
0 commit comments