diff --git a/images/linux/scripts/SoftwareReport/SoftwareReport.Common.psm1 b/images/linux/scripts/SoftwareReport/SoftwareReport.Common.psm1 index debf9d8c3..86643fbd2 100644 --- a/images/linux/scripts/SoftwareReport/SoftwareReport.Common.psm1 +++ b/images/linux/scripts/SoftwareReport/SoftwareReport.Common.psm1 @@ -1,9 +1,3 @@ -Import-Module (Join-Path $PSScriptRoot "SoftwareReport.Helpers.psm1") -DisableNameChecking - -function Get-OSName { - lsb_release -ds -} - function Get-BashVersion { $version = bash -c 'echo ${BASH_VERSION}' return "Bash $version" diff --git a/images/linux/scripts/SoftwareReport/SoftwareReport.Generator.ps1 b/images/linux/scripts/SoftwareReport/SoftwareReport.Generator.ps1 index c36abad40..f9c2cfd35 100644 --- a/images/linux/scripts/SoftwareReport/SoftwareReport.Generator.ps1 +++ b/images/linux/scripts/SoftwareReport/SoftwareReport.Generator.ps1 @@ -11,7 +11,8 @@ Import-Module (Join-Path $PSScriptRoot "SoftwareReport.Browsers.psm1") -DisableN Import-Module (Join-Path $PSScriptRoot "SoftwareReport.CachedTools.psm1") -DisableNameChecking Import-Module (Join-Path $PSScriptRoot "SoftwareReport.Common.psm1") -DisableNameChecking Import-Module (Join-Path $PSScriptRoot "SoftwareReport.Databases.psm1") -DisableNameChecking -Import-Module (Join-Path $PSScriptRoot "SoftwareReport.Helpers.psm1") -DisableNameChecking +Import-Module "$PSScriptRoot/../helpers/SoftwareReport.Helpers.psm1" -DisableNameChecking +Import-Module "$PSScriptRoot/../helpers/Common.Helpers.psm1" -DisableNameChecking Import-Module (Join-Path $PSScriptRoot "SoftwareReport.Java.psm1") -DisableNameChecking Import-Module (Join-Path $PSScriptRoot "SoftwareReport.Rust.psm1") -DisableNameChecking Import-Module (Join-Path $PSScriptRoot "SoftwareReport.Tools.psm1") -DisableNameChecking diff --git a/images/linux/scripts/SoftwareReport/SoftwareReport.Rust.psm1 b/images/linux/scripts/SoftwareReport/SoftwareReport.Rust.psm1 index e822a5c38..f5f25a393 100644 --- a/images/linux/scripts/SoftwareReport/SoftwareReport.Rust.psm1 +++ b/images/linux/scripts/SoftwareReport/SoftwareReport.Rust.psm1 @@ -1,55 +1,55 @@ -function Initialize-RustEnvironment { - ln -sf "/usr/share/rust/.rustup" $HOME/.rustup - ln -sf "/usr/share/rust/.cargo" $HOME/.cargo -} - -function Get-RustVersion { - Initialize-RustEnvironment - $rustVersion = $(rustc --version) | Take-OutputPart -Part 1 - return "Rust $rustVersion" -} - -function Get-BindgenVersion { - $bindgenVersion = $(bindgen --version) | Take-OutputPart -Part 1 - return "Bindgen $bindgenVersion" -} - -function Get-CargoVersion { - $cargoVersion = $(cargo --version) | Take-OutputPart -Part 1 - return "Cargo $cargoVersion" -} - -function Get-CargoAuditVersion { - $cargoAuditVersion = $(cargo audit --version) | Take-OutputPart -Part 1 - return "Cargo audit $cargoAuditVersion" -} - -function Get-CargoOutdatedVersion { - $cargoOutdatedVersion = $(cargo outdated --version) | Take-OutputPart -Part 1 -Delimiter "v" - return "Cargo outdated $cargoOutdatedVersion" -} - -function Get-CargoClippyVersion { - $cargoClippyVersion = $(cargo-clippy --version) | Take-OutputPart -Part 1 - return "Cargo clippy $cargoClippyVersion" -} - -function Get-CbindgenVersion { - $cbindgenVersion = $(cbindgen --version) | Take-OutputPart -Part 1 - return "Cbindgen $cbindgenVersion" -} - -function Get-RustupVersion { - $rustupVersion = $(rustup --version) | Take-OutputPart -Part 1 - return "Rustup $rustupVersion" -} - -function Get-RustdocVersion { - $rustdocVersion = $(rustdoc --version) | Take-OutputPart -Part 1 - return "Rustdoc $rustdocVersion" -} - -function Get-RustfmtVersion { - $rustfmtVersion = $(rustfmt --version) | Take-OutputPart -Part 1 | Take-OutputPart -Part 0 -Delimiter "-" - return "Rustfmt $rustfmtVersion" +function Initialize-RustEnvironment { + ln -sf "/usr/share/rust/.rustup" $HOME/.rustup + ln -sf "/usr/share/rust/.cargo" $HOME/.cargo +} + +function Get-RustVersion { + Initialize-RustEnvironment + $rustVersion = $(rustc --version) | Take-OutputPart -Part 1 + return "Rust $rustVersion" +} + +function Get-BindgenVersion { + $bindgenVersion = $(bindgen --version) | Take-OutputPart -Part 1 + return "Bindgen $bindgenVersion" +} + +function Get-CargoVersion { + $cargoVersion = $(cargo --version) | Take-OutputPart -Part 1 + return "Cargo $cargoVersion" +} + +function Get-CargoAuditVersion { + $cargoAuditVersion = $(cargo audit --version) | Take-OutputPart -Part 1 + return "Cargo audit $cargoAuditVersion" +} + +function Get-CargoOutdatedVersion { + $cargoOutdatedVersion = $(cargo outdated --version) | Take-OutputPart -Part 1 -Delimiter "v" + return "Cargo outdated $cargoOutdatedVersion" +} + +function Get-CargoClippyVersion { + $cargoClippyVersion = $(cargo-clippy --version) | Take-OutputPart -Part 1 + return "Cargo clippy $cargoClippyVersion" +} + +function Get-CbindgenVersion { + $cbindgenVersion = $(cbindgen --version) | Take-OutputPart -Part 1 + return "Cbindgen $cbindgenVersion" +} + +function Get-RustupVersion { + $rustupVersion = $(rustup --version) | Take-OutputPart -Part 1 + return "Rustup $rustupVersion" +} + +function Get-RustdocVersion { + $rustdocVersion = $(rustdoc --version) | Take-OutputPart -Part 1 + return "Rustdoc $rustdocVersion" +} + +function Get-RustfmtVersion { + $rustfmtVersion = $(rustfmt --version) | Take-OutputPart -Part 1 | Take-OutputPart -Part 0 -Delimiter "-" + return "Rustfmt $rustfmtVersion" } \ No newline at end of file diff --git a/images/linux/scripts/SoftwareReport/SoftwareReport.Helpers.psm1 b/images/linux/scripts/helpers/Common.Helpers.psm1 similarity index 58% rename from images/linux/scripts/SoftwareReport/SoftwareReport.Helpers.psm1 rename to images/linux/scripts/helpers/Common.Helpers.psm1 index 9ef761d78..3f8ada885 100644 --- a/images/linux/scripts/SoftwareReport/SoftwareReport.Helpers.psm1 +++ b/images/linux/scripts/helpers/Common.Helpers.psm1 @@ -13,16 +13,8 @@ function Get-CommandResult { } } -function Take-OutputPart { - param ( - [Parameter(ValueFromPipeline)] - [string] $toolOutput, - [string] $Delimiter = " ", - [int[]] $Part - ) - $parts = $toolOutput.Split($Delimiter, [System.StringSplitOptions]::RemoveEmptyEntries) - $selectedParts = $parts[$Part] - return [string]::Join($Delimiter, $selectedParts) +function Get-OSName { + lsb_release -ds } function Test-IsUbuntu16 { @@ -40,16 +32,4 @@ function Test-IsUbuntu20 { function Get-ToolsetContent { $toolset = Join-Path $env:INSTALLER_SCRIPT_FOLDER "toolset.json" Get-Content $toolset -Raw | ConvertFrom-Json -} - -function New-MDNewLine { - param ( - [int] $Count = 1 - ) - $newLineSymbol = [System.Environment]::NewLine - return $newLineSymbol * $Count -} - -function Restore-UserOwner { - sudo chown -R ${env:USER}: $env:HOME } \ No newline at end of file diff --git a/images/linux/scripts/helpers/SoftwareReport.Helpers.psm1 b/images/linux/scripts/helpers/SoftwareReport.Helpers.psm1 new file mode 100644 index 000000000..4501dee05 --- /dev/null +++ b/images/linux/scripts/helpers/SoftwareReport.Helpers.psm1 @@ -0,0 +1,23 @@ +function Take-OutputPart { + param ( + [Parameter(ValueFromPipeline)] + [string] $toolOutput, + [string] $Delimiter = " ", + [int[]] $Part + ) + $parts = $toolOutput.Split($Delimiter, [System.StringSplitOptions]::RemoveEmptyEntries) + $selectedParts = $parts[$Part] + return [string]::Join($Delimiter, $selectedParts) +} + +function New-MDNewLine { + param ( + [int] $Count = 1 + ) + $newLineSymbol = [System.Environment]::NewLine + return $newLineSymbol * $Count +} + +function Restore-UserOwner { + sudo chown -R ${env:USER}: $env:HOME +} \ No newline at end of file diff --git a/images/linux/scripts/helpers/Tests.Helpers.psm1 b/images/linux/scripts/helpers/Tests.Helpers.psm1 new file mode 100644 index 000000000..20010a07d --- /dev/null +++ b/images/linux/scripts/helpers/Tests.Helpers.psm1 @@ -0,0 +1,67 @@ +Import-Module "$PSScriptRoot/../helpers/Common.Helpers.psm1" -DisableNameChecking + +# Validates that tool is installed and in PATH +function Validate-ToolExist($tool) { + Get-Command $tool -ErrorAction SilentlyContinue | Should -BeTrue +} + +function Invoke-PesterTests { + Param( + [Parameter(Mandatory)][string] $TestFile, + [string] $TestName + ) + + $testPath = "/imagegeneration/tests/${TestFile}.Tests.ps1" + if (-not (Test-Path $testPath)) { + throw "Unable to find test file '$TestFile' on '$testPath'." + } + + $configuration = [PesterConfiguration] @{ + Run = @{ Path = $testPath; PassThru = $true } + Output = @{ Verbosity = "Detailed" } + } + if ($TestName) { + $configuration.Filter.FullName = $TestName + } + + # Switch ErrorActionPreference to Stop temporary to make sure that tests will fail on silent errors too + $backupErrorActionPreference = $ErrorActionPreference + $ErrorActionPreference = "Stop" + $results = Invoke-Pester -Configuration $configuration + $ErrorActionPreference = $backupErrorActionPreference + + # Fail in case if no tests are run + if (-not ($results -and ($results.FailedCount -eq 0) -and ($results.PassedCount -gt 0))) { + $results + throw "Test run has failed" + } +} + +function ShouldReturnZeroExitCode { + Param( + [String] $ActualValue, + [switch] $Negate, + [string] $Because # This parameter is unused but we need it to match Pester asserts signature + ) + + $result = Get-CommandResult $ActualValue + + [bool]$succeeded = $result.ExitCode -eq 0 + if ($Negate) { $succeeded = -not $succeeded } + + if (-not $succeeded) + { + $commandOutputIndent = " " * 4 + $commandOutput = ($result.Output | ForEach-Object { "${commandOutputIndent}${_}" }) -join "`n" + $failureMessage = "Command '${ActualValue}' has finished with exit code`n${commandOutput}" + } + + return [PSCustomObject] @{ + Succeeded = $succeeded + FailureMessage = $failureMessage + } +} + +If (Get-Command -Name Add-AssertionOperator -ErrorAction SilentlyContinue) { + Add-AssertionOperator -Name ReturnZeroExitCode -InternalName ShouldReturnZeroExitCode -Test ${function:ShouldReturnZeroExitCode} +} \ No newline at end of file diff --git a/images/linux/scripts/helpers/invoke-tests.sh b/images/linux/scripts/helpers/invoke-tests.sh new file mode 100644 index 000000000..fb237bdcd --- /dev/null +++ b/images/linux/scripts/helpers/invoke-tests.sh @@ -0,0 +1,13 @@ +#!/bin/bash -e +################################################################################ +## File: invoke-tests.sh +## Desc: Helper function for invoking tests +################################################################################ + +invoke_tests() { + local TEST_FILE="$1" + local TEST_NAME="$2" + + pwsh -Command "Import-Module '$HELPER_SCRIPTS/Tests.Helpers.psm1' -DisableNameChecking + Invoke-PesterTests -TestFile $TEST_FILE -TestName $TEST_NAME" +} \ No newline at end of file diff --git a/images/linux/scripts/installers/7-zip.sh b/images/linux/scripts/installers/7-zip.sh index 0fa61bb29..787c06913 100644 --- a/images/linux/scripts/installers/7-zip.sh +++ b/images/linux/scripts/installers/7-zip.sh @@ -4,13 +4,11 @@ ## Desc: Installs 7-zip ################################################################################ +source $HELPER_SCRIPTS/invoke-tests.sh + # Install 7-Zip apt-get update -y apt-get install -y p7zip p7zip-full p7zip-rar # Run tests to determine that the software installed as expected -echo "Testing to make sure that script performed as expected, and basic scenarios work" -if ! command -v 7z; then - echo "7-Zip was not installed" - exit 1 -fi +invoke_tests "Tools" "7-Zip" \ No newline at end of file diff --git a/images/linux/scripts/installers/azcopy.sh b/images/linux/scripts/installers/azcopy.sh index 2d46bef95..ecaa13580 100644 --- a/images/linux/scripts/installers/azcopy.sh +++ b/images/linux/scripts/installers/azcopy.sh @@ -4,6 +4,8 @@ ## Desc: Installs AzCopy ################################################################################ +source $HELPER_SCRIPTS/invoke-tests.sh + # Install AzCopy7 wget -O azcopy.tar.gz https://aka.ms/downloadazcopylinux64 tar -xf azcopy.tar.gz @@ -17,13 +19,4 @@ mv /tmp/azcopy /usr/local/bin/azcopy10 chmod +x /usr/local/bin/azcopy10 # Run tests to determine that the software installed as expected -echo "Testing to make sure that script performed as expected, and basic scenarios work" -if ! command -v azcopy; then - echo "azcopy7 was not installed" - exit 1 -fi - -if ! command -v azcopy10; then - echo "azcopy10 was not installed" - exit 1 -fi +invoke_tests "Tools" "azcopy" \ No newline at end of file diff --git a/images/linux/scripts/tests/RunAll-Tests.ps1 b/images/linux/scripts/tests/RunAll-Tests.ps1 new file mode 100644 index 000000000..015491cd2 --- /dev/null +++ b/images/linux/scripts/tests/RunAll-Tests.ps1 @@ -0,0 +1,3 @@ +Import-Module "$PSScriptRoot/../helpers/Tests.Helpers.psm1" -DisableNameChecking + +Invoke-PesterTests "*" \ No newline at end of file diff --git a/images/linux/scripts/tests/Tools.Tests.ps1 b/images/linux/scripts/tests/Tools.Tests.ps1 new file mode 100644 index 000000000..2d257b128 --- /dev/null +++ b/images/linux/scripts/tests/Tools.Tests.ps1 @@ -0,0 +1,17 @@ +Describe "7-Zip" { + It "7z" { + "7z" | Should -ReturnZeroExitCode + } +} + +Describe "azcopy" { + It "azcopy" { + #(azcopy --version) command returns exit code 1 (see details: https://github.com/Azure/azure-storage-azcopy/releases) + $azcopyVersion = (Get-CommandResult "azcopy --version").Output + $azcopyVersion | Should -BeLike "*azcopy*" + } + + It "azcopy10" { + "azcopy10 --version" | Should -ReturnZeroExitCode + } +} \ No newline at end of file diff --git a/images/linux/ubuntu1604.json b/images/linux/ubuntu1604.json index 0d8230bba..038344859 100644 --- a/images/linux/ubuntu1604.json +++ b/images/linux/ubuntu1604.json @@ -99,6 +99,11 @@ "source": "{{ template_dir }}/post-generation", "destination": "{{user `image_folder`}}" }, + { + "type": "file", + "source": "{{template_dir}}/scripts/tests", + "destination": "{{user `image_folder`}}" + }, { "type": "file", "source": "{{ template_dir }}/scripts/SoftwareReport", @@ -141,6 +146,23 @@ ], "execute_command": "sudo sh -c '{{ .Vars }} {{ .Path }}'" }, + { + "type": "shell", + "scripts": [ + "{{template_dir}}/scripts/installers/powershellcore.sh" + ], + "execute_command": "sudo sh -c '{{ .Vars }} {{ .Path }}'" + }, + { + "type": "shell", + "scripts": [ + "{{template_dir}}/scripts/installers/Install-PowerShellModules.ps1" + ], + "environment_vars": [ + "INSTALLER_SCRIPT_FOLDER={{user `installer_script_folder`}}" + ], + "execute_command": "sudo sh -c '{{ .Vars }} pwsh -f {{ .Path }}'" + }, { "type": "shell", "scripts": [ @@ -190,7 +212,6 @@ "{{template_dir}}/scripts/installers/php.sh", "{{template_dir}}/scripts/installers/pollinate.sh", "{{template_dir}}/scripts/installers/postgresql.sh", - "{{template_dir}}/scripts/installers/powershellcore.sh", "{{template_dir}}/scripts/installers/pulumi.sh", "{{template_dir}}/scripts/installers/ruby.sh", "{{template_dir}}/scripts/installers/r.sh", @@ -285,20 +306,11 @@ "script": "{{template_dir}}/scripts/base/apt-mock-remove.sh", "execute_command": "sudo sh -c '{{ .Vars }} {{ .Path }}'" }, - { - "type": "shell", - "scripts": [ - "{{template_dir}}/scripts/installers/Install-PowerShellModules.ps1" - ], - "environment_vars": [ - "INSTALLER_SCRIPT_FOLDER={{user `installer_script_folder`}}" - ], - "execute_command": "sudo sh -c '{{ .Vars }} pwsh -f {{ .Path }}'" - }, { "type": "shell", "inline": [ - "pwsh -File {{user `image_folder`}}/SoftwareReport/SoftwareReport.Generator.ps1 -OutputDirectory {{user `image_folder`}}" + "pwsh -File {{user `image_folder`}}/SoftwareReport/SoftwareReport.Generator.ps1 -OutputDirectory {{user `image_folder`}}", + "pwsh -File {{user `image_folder`}}/tests/RunAll-Tests.ps1 -OutputDirectory {{user `image_folder`}}" ], "environment_vars": [ "IMAGE_VERSION={{user `image_version`}}", @@ -354,4 +366,4 @@ "execute_command": "sudo sh -c '{{ .Vars }} {{ .Path }}'" } ] -} +} \ No newline at end of file diff --git a/images/linux/ubuntu1804.json b/images/linux/ubuntu1804.json index 47ae52f4f..4d6ffe3c8 100644 --- a/images/linux/ubuntu1804.json +++ b/images/linux/ubuntu1804.json @@ -102,6 +102,11 @@ "source": "{{ template_dir }}/post-generation", "destination": "{{user `image_folder`}}" }, + { + "type": "file", + "source": "{{template_dir}}/scripts/tests", + "destination": "{{user `image_folder`}}" + }, { "type": "file", "source": "{{ template_dir }}/scripts/SoftwareReport", @@ -144,6 +149,23 @@ ], "execute_command": "sudo sh -c '{{ .Vars }} {{ .Path }}'" }, + { + "type": "shell", + "scripts": [ + "{{template_dir}}/scripts/installers/powershellcore.sh" + ], + "execute_command": "sudo sh -c '{{ .Vars }} {{ .Path }}'" + }, + { + "type": "shell", + "scripts": [ + "{{template_dir}}/scripts/installers/Install-PowerShellModules.ps1" + ], + "environment_vars": [ + "INSTALLER_SCRIPT_FOLDER={{user `installer_script_folder`}}" + ], + "execute_command": "sudo sh -c '{{ .Vars }} pwsh -f {{ .Path }}'" + }, { "type": "shell", "scripts": [ @@ -194,7 +216,6 @@ "{{template_dir}}/scripts/installers/php.sh", "{{template_dir}}/scripts/installers/pollinate.sh", "{{template_dir}}/scripts/installers/postgresql.sh", - "{{template_dir}}/scripts/installers/powershellcore.sh", "{{template_dir}}/scripts/installers/pulumi.sh", "{{template_dir}}/scripts/installers/ruby.sh", "{{template_dir}}/scripts/installers/r.sh", @@ -289,20 +310,11 @@ "script": "{{template_dir}}/scripts/base/apt-mock-remove.sh", "execute_command": "sudo sh -c '{{ .Vars }} {{ .Path }}'" }, - { - "type": "shell", - "scripts": [ - "{{template_dir}}/scripts/installers/Install-PowerShellModules.ps1" - ], - "environment_vars": [ - "INSTALLER_SCRIPT_FOLDER={{user `installer_script_folder`}}" - ], - "execute_command": "sudo sh -c '{{ .Vars }} pwsh -f {{ .Path }}'" - }, { "type": "shell", "inline": [ - "pwsh -File {{user `image_folder`}}/SoftwareReport/SoftwareReport.Generator.ps1 -OutputDirectory {{user `image_folder`}}" + "pwsh -File {{user `image_folder`}}/SoftwareReport/SoftwareReport.Generator.ps1 -OutputDirectory {{user `image_folder`}}", + "pwsh -File {{user `image_folder`}}/tests/RunAll-Tests.ps1 -OutputDirectory {{user `image_folder`}}" ], "environment_vars": [ "IMAGE_VERSION={{user `image_version`}}", @@ -358,4 +370,4 @@ "execute_command": "sudo sh -c '{{ .Vars }} {{ .Path }}'" } ] -} +} \ No newline at end of file diff --git a/images/linux/ubuntu2004.json b/images/linux/ubuntu2004.json index 8c5a5b45b..3f31be1a1 100644 --- a/images/linux/ubuntu2004.json +++ b/images/linux/ubuntu2004.json @@ -104,6 +104,11 @@ "source": "{{ template_dir }}/post-generation", "destination": "{{user `image_folder`}}" }, + { + "type": "file", + "source": "{{template_dir}}/scripts/tests", + "destination": "{{user `image_folder`}}" + }, { "type": "file", "source": "{{ template_dir }}/scripts/SoftwareReport", @@ -146,6 +151,23 @@ ], "execute_command": "sudo sh -c '{{ .Vars }} {{ .Path }}'" }, + { + "type": "shell", + "scripts": [ + "{{template_dir}}/scripts/installers/powershellcore.sh" + ], + "execute_command": "sudo sh -c '{{ .Vars }} {{ .Path }}'" + }, + { + "type": "shell", + "scripts": [ + "{{template_dir}}/scripts/installers/Install-PowerShellModules.ps1" + ], + "environment_vars": [ + "INSTALLER_SCRIPT_FOLDER={{user `installer_script_folder`}}" + ], + "execute_command": "sudo sh -c '{{ .Vars }} pwsh -f {{ .Path }}'" + }, { "type": "shell", "scripts": [ @@ -196,7 +218,6 @@ "{{template_dir}}/scripts/installers/php.sh", "{{template_dir}}/scripts/installers/pollinate.sh", "{{template_dir}}/scripts/installers/postgresql.sh", - "{{template_dir}}/scripts/installers/powershellcore.sh", "{{template_dir}}/scripts/installers/pulumi.sh", "{{template_dir}}/scripts/installers/ruby.sh", "{{template_dir}}/scripts/installers/r.sh", @@ -291,20 +312,11 @@ "script": "{{template_dir}}/scripts/base/apt-mock-remove.sh", "execute_command": "sudo sh -c '{{ .Vars }} {{ .Path }}'" }, - { - "type": "shell", - "scripts": [ - "{{template_dir}}/scripts/installers/Install-PowerShellModules.ps1" - ], - "environment_vars": [ - "INSTALLER_SCRIPT_FOLDER={{user `installer_script_folder`}}" - ], - "execute_command": "sudo sh -c '{{ .Vars }} pwsh -f {{ .Path }}'" - }, { "type": "shell", "inline": [ - "pwsh -File {{user `image_folder`}}/SoftwareReport/SoftwareReport.Generator.ps1 -OutputDirectory {{user `image_folder`}}" + "pwsh -File {{user `image_folder`}}/SoftwareReport/SoftwareReport.Generator.ps1 -OutputDirectory {{user `image_folder`}}", + "pwsh -File {{user `image_folder`}}/tests/RunAll-Tests.ps1 -OutputDirectory {{user `image_folder`}}" ], "environment_vars": [ "IMAGE_VERSION={{user `image_version`}}", @@ -360,4 +372,4 @@ "execute_command": "sudo sh -c '{{ .Vars }} {{ .Path }}'" } ] -} +} \ No newline at end of file