diff --git a/.github/workflows/apbx.yaml b/.github/workflows/apbx.yaml index 7d2b46b8ad..fdb91bb36b 100644 --- a/.github/workflows/apbx.yaml +++ b/.github/workflows/apbx.yaml @@ -9,7 +9,7 @@ env: SXSC_REPO: "https://github.com/Atlas-OS/sxsc" jobs: - package-build: + build: runs-on: windows-latest steps: @@ -105,44 +105,23 @@ jobs: working-directory: src\playbook\Executables\AtlasModules\Packages if: env.runSxsc == 'true' - build: - needs: package-build - runs-on: ubuntu-latest - - steps: - - name: Checkout code - uses: actions/checkout@v4 - with: - ref: ${{ github.ref }} - - name: Validate YAML files run: 'yamllint -d "{extends: relaxed, rules: {empty-lines: disable, line-length: disable, new-line-at-end-of-file: disable, trailing-spaces: disable}}" src/playbook/.' - - name: Configure playbook - id: config-playbook - if: ${{ !startsWith(github.ref, 'refs/heads/na-') }} - run: | - cd src/playbook - echo "Making playbook display as unverified (remove ProductCode) so that it is not marked as malicious..." - sed -i '//d' playbook.conf - echo "Change description of playbook..." - sed -i 's|.*<\/Description>|Experimental testing version of the Atlas Playbook, built with GitHub Actions from commit ${{ github.sha }}. Be aware of these builds being potentially unstable and buggy!|g' playbook.conf - cd Configuration - echo "Enabling AME Wizard Live Log..." - sed -i '7s/ #//' custom.yml - - name: Create playbook (ZIP/APBX password is malte) - if: ${{ steps.config-playbook.outcome != 'skipped' }} + id: create-pb + if: ${{ !startsWith(github.ref, 'refs/heads/na-') }} run: | - cd src/playbook echo "Making a renamed password protected (malte) ZIP of playbook files..." - zip -r -P malte "Atlas Playbook ${GITHUB_SHA::8}.apbx" . -x "local-build.cmd" - echo "Move the .abpx playbook into the 'Release ZIP' to be released as an artifact with the additional files..." - mv "Atlas Playbook ${GITHUB_SHA::8}.apbx" "../release-zip" + $pbName = "Atlas Playbook $($env:GITHUB_SHA.Substring(0,8)).apbx" + & ..\local-build.ps1 -ReplaceOldPlaybook -AddLiveLog -Removals Verification, WinverRequirement -FileName $pbName + echo "Move the .abpx playbook into 'Release ZIP' to be released as an artifact with the additional files..." + Move-Item $pbName "../release-zip" + working-directory: src\playbook - name: Upload artifact uses: actions/upload-artifact@v4 - if: ${{ steps.config-playbook.outcome != 'skipped' }} + if: ${{ steps.create-pb.outcome != 'skipped' }} with: name: Atlas Playbook path: | diff --git a/.vscode/extensions.json b/.vscode/extensions.json new file mode 100644 index 0000000000..7d0c6b6bed --- /dev/null +++ b/.vscode/extensions.json @@ -0,0 +1,8 @@ +{ + "recommendations": [ + "ms-vscode.powershell", + "ionutvmi.reg", + "redhat.vscode-xml", + "redhat.vscode-yaml" + ] +} \ No newline at end of file diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000000..10ff03de6d --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,29 @@ +{ + "version": "0.2.0", + "configurations": [ + { + "type": "PowerShell", + "request": "launch", + "name": "Build Playbook (Test)", + "script": "& '${workspaceFolder}/src/local-build.ps1' -AddLiveLog -ReplaceOldPlaybook -Removals WinverRequirement, Verification", + "cwd": "${workspaceFolder}/src/playbook", + "args": [] + }, + { + "type": "PowerShell", + "request": "launch", + "name": "Build Playbook (Test w/o deps)", + "script": "& '${workspaceFolder}/src/local-build.ps1' -AddLiveLog -ReplaceOldPlaybook -Removals Dependencies, WinverRequirement, Verification", + "cwd": "${workspaceFolder}/src/playbook", + "args": [] + }, + { + "type": "PowerShell", + "request": "launch", + "name": "Build Playbook (Release)", + "script": "& '${workspaceFolder}/src/local-build.ps1'", + "cwd": "${workspaceFolder}/src/playbook", + "args": [] + } + ] +} diff --git a/src/local-build.ps1 b/src/local-build.ps1 new file mode 100644 index 0000000000..a778c0d006 --- /dev/null +++ b/src/local-build.ps1 @@ -0,0 +1,140 @@ +param ( + [switch]$AddLiveLog, + [switch]$ReplaceOldPlaybook, + [switch]$DontOpenPbLocation, + [ValidateSet('Dependencies', 'Requirements', 'WinverRequirement', 'Verification', IgnoreCase = $true)] + [array]$Removals, + [string]$FileName = "Atlas Test" +) + +$removals | % { Set-Variable -Name "remove$_" -Value $true } + +# check 7z +if (Get-Command '7z' -EA 0) { + $7zPath = '7z' +} elseif (Get-Command '7zz' -EA 0) { + $7zPath = '7zz' +} elseif (!$IsLinux -and !$IsMacOS -and (Test-Path "$([Environment]::GetFolderPath('ProgramFiles'))\7-Zip\7z.exe")) { + $7zPath = "$([Environment]::GetFolderPath('ProgramFiles'))\7-Zip\7z.exe" +} else { + throw "This script requires 7-Zip to be installed to continue." +} + +# check if playbook dir +if (!(Test-Path playbook.conf -PathType Leaf)) { + if (Test-Path playbook -PathType Container) { + $currentDir = $PWD + Set-Location playbook + if (!(Test-Path playbook.conf -PathType Leaf)) { throw "playbook.conf file not found in playbook directory." } + } else { + throw "playbook.conf file not found in the current directory." + } +} + +# check if old files are in use +$apbxFileName = "$fileName.apbx" +function GetNewName { + $num = 1 + while (Test-Path -Path "$fileName ($num).apbx") { + $num++ + $script:apbxFileName = "$fileName ($num).abpx" + } +} +if ($replaceOldPlaybook -and (Test-Path -Path $apbxFileName)) { + try { + $stream = [System.IO.File]::Open("$PWD\$apbxFileName", 'Open', 'Read', 'Write') + $stream.Close() + Remove-Item -Path $apbxFileName -Force -EA 0 + } catch { + Write-Warning "Couldn't replace '$apbxFileName', it's in use." + GetNewName + } +} elseif (Test-Path -Path $apbxFileName) { + GetNewName +} +$apbxPath = "$PWD\$fileName.apbx" + +# make temp directories +$rootTemp = New-Item (Join-Path -Path $([System.IO.Path]::GetTempPath()) -ChildPath $([System.Guid]::NewGuid())) -ItemType Directory -Force +if (!(Test-Path -Path "$rootTemp")) { throw "Failed to create temporary directory!" } +$playbookTemp = New-Item "$rootTemp\playbook" -Type Directory + +try { + # remove entries in playbook config that make it awkward for testing + $patterns = @() + # 0.6.5 has a bug where it will crash without the 'Requirements' field, but all of the requirements are removed + # "" and # "" + if ($removeRequirements) {$patterns += ""} + if ($removeWinverRequirement) {$patterns += "", "", ""} + if ($removeVerification) {$patterns += ""} + + $tempPbConfPath = "$playbookTemp\playbook.conf" + if ($patterns.Count -gt 0) { + Get-Content "playbook.conf" | Where-Object { $_ -notmatch ($patterns -join '|') } | Set-Content $tempPbConfPath + } + + $customYmlPath = "Configuration\custom.yml" + $tempCustomYmlPath = "$playbookTemp\$customYmlPath" + if ($AddLiveLog) { + if (Test-Path $customYmlPath -PathType Leaf) { + New-Item (Split-Path $tempCustomYmlPath -Parent) -ItemType Directory -Force | Out-Null + Copy-Item -Path $customYmlPath -Destination $tempCustomYmlPath -Force + $customYml = Get-Content -Path $tempCustomYmlPath + + $actionsIndex = $customYml.IndexOf('actions:') + $newCustomYml = $customYml[0..$actionsIndex] + ` + " - !powerShell: {command: 'gc -Wait Logs\TIOutput.txt -EA 0 | Write-Output; pause', baseDir: true, wait: false}" + ` + $customYml[($actionsIndex + 1)..($customYml.Count)] + + Set-Content -Path $tempCustomYmlPath -Value $newCustomYml + } else { + Write-Error "Can't find "$customYmlPath", not adding live log." + } + } + + $startYmlPath = "Configuration\atlas\start.yml" + $tempStartYmlPath = "$playbookTemp\$startYmlPath" + if ($removeDependencies) { + if (Test-Path $startYmlPath -PathType Leaf) { + New-Item (Split-Path $tempStartYmlPath -Parent) -ItemType Directory -Force | Out-Null + Copy-Item -Path $startYmlPath -Destination $tempStartYmlPath -Force + $startYml = Get-Content -Path $tempStartYmlPath + + $noLocalBuildStart = $startYml.IndexOf(' ################ NO LOCAL BUILD ################') + $noLocalBuildEnd = $startYml.IndexOf(' ################ END NO LOCAL BUILD ################') + $newStartYml = $startYml[0..($noLocalBuildStart - 1)] + ` + $startYml[($noLocalBuildEnd + 1)..($startYml.Count)] + + Set-Content -Path $tempStartYmlPath -Value $newStartYml + } else { + Write-Error "Can't find "$startYmlPath", not removing dependencies." + } + } + + # exclude files + $excludeFiles = @( + "local-build.cmd", + "*.apbx" + ) + if (Test-Path $tempCustomYmlPath) { $excludeFiles += "custom.yml" } + if (Test-Path $tempStartYmlPath) { $excludeFiles += "start.yml" } + if (Test-Path $tempPbConfPath) { $excludeFiles += "playbook.conf" } + $files = "$rootTemp\7zFiles.txt" + (Get-ChildItem -File -Exclude $excludeFiles -Recurse).FullName | Resolve-Path -Relative | ForEach-Object {$_.Substring(2)} | Out-File $files -Encoding utf8 + + & $7zPath a -spf -y -mx1 -tzip "$apbxPath" `@"$files" | Out-Null + # add edited files + if (Test-Path "$playbookTemp\*.*") { + Push-Location "$playbookTemp" + & $7zPath u "$apbxPath" * | Out-Null + Pop-Location + } + + Write-Host "Built successfully! Path: `"$apbxPath`"" -ForegroundColor Green + if (!$IsLinux -and !$IsMacOS -and !$DontOpenPbLocation) { + explorer /select,"$apbxPath" + } +} finally { + Remove-Item $rootTemp -Force -EA 0 -Recurse | Out-Null + if ($currentDir) { Set-Location $currentDir } +} \ No newline at end of file diff --git a/src/playbook/Configuration/custom.yml b/src/playbook/Configuration/custom.yml index ccd3b6d213..a5c944ce11 100644 --- a/src/playbook/Configuration/custom.yml +++ b/src/playbook/Configuration/custom.yml @@ -2,10 +2,6 @@ title: Root Playbook File description: Runs all of the playbook files actions: - # AME Wizard Live Log for development playbooks - # Do not change the line position of this, otherwise things will break when using local-build - # - !run: {exe: 'cmd.exe', args: '/c start "AME Wizard Live Log" PowerShell -NoP -C "gc -Wait Logs\TIOutput.txt -EA SilentlyContinue | Write-Output; pause"', baseDir: true, wait: false} - # Check various conditions to see if the user should run Atlas or not - !powerShell: command: '.\UPGRADECHECK.ps1' diff --git a/src/playbook/local-build.cmd b/src/playbook/local-build.cmd index b41c6b168f..1084ba308e 100644 --- a/src/playbook/local-build.cmd +++ b/src/playbook/local-build.cmd @@ -1,253 +1,3 @@ -<# : batch portion -@echo off & PowerShell -NoP Get-Content """%~f0""" -Raw ^| iex & exit /b -: end batch / begin PowerShell #> - -# Do not change anything here, this is simply for reference -$defaultConfig = @{ - # Name of resulting APBX - fileName = "Atlas Test" - - # Should the script delete any playbook that already exists with the same name or not - # If not, it will make something like "Atlas Test (1).apbx" - replaceOldPlaybook = $true - - # Add AME Wizard Live Log window - liveLog = $true - - # Choose to get Atlas dependencies or not to speed up installation - removeDependencies = $true - - # Choose not to modify certain aspects from playbook.conf - removeRequirements = $false - removeWinverRequirement = $true - - # Not recommended to disable as it will show malicious - removeProductCode = $true -} - -$configPath = "$([Environment]::GetFolderPath('ApplicationData'))\local-build\config.json" - -# ------------- # -# config system # -# ------------- # - -$shortcut = "$([Environment]::GetFolderPath('LocalApplicationData'))\Microsoft\WindowsApps\ame-lb-conf.lnk" - -function New-ConfigPathShortcut { - $WshShell = New-Object -comObject WScript.Shell - $Shortcut = $WshShell.CreateShortcut($shortcut) - $Shortcut.TargetPath = $configPath - $Shortcut.Save() -} - -function CreateConfig($conf) { - New-Item -Type Directory -Force -Path $(Split-Path $configPath) -ErrorAction SilentlyContinue | Out-Null - $conf | ConvertTo-Json -Depth 100 | Out-File $configPath -} - -function Write-BulletPoint($message) { - $message | Foreach-Object { - Write-Host " - " -ForegroundColor Green -NoNewline - Write-Host $_ - } - Write-Host "" -} - - -if (Get-Command '7z.exe' -EA SilentlyContinue) { - $7zPath = '7z.exe' -} elseif (Test-Path "$([Environment]::GetFolderPath('ProgramFiles'))\7-Zip\7z.exe") { - $7zPath = "$([Environment]::GetFolderPath('ProgramFiles'))\7-Zip\7z.exe" -} -if (!$7zPath) { - Write-Host "This script requires 7-Zip to be installed to continue." - Pause - exit 1 -} - -if (!(Test-Path $configPath)) { - Remove-Item -Force -Path $shortcut -EA SilentlyContinue - - Write-Host "It seems like this is your first time using AME Local Build.`n" -ForegroundColor Cyan - - Write-BulletPoint "Adding config to %PATH% would allow you to type 'ame-lb-conf' into Run or any other shell and open the config." - Write-BulletPoint "The configuration is in JSON, and explanations of those arguments are contained in the script." - Write-BulletPoint "You can change the config path by modifying the script." - - - Write-Host "`n---------------------------------------------------------------------------------------------------------`n" -ForegroundColor Magenta - choice /c:yn /n /m "Would you like to add a shortcut to %PATH% for the configuration file? [Y/N]" - if ($LASTEXITCODE -eq 1) { New-ConfigPathShortcut } - - choice /c:yn /n /m "Would you like to open the config file now? [Y/N]" - CreateConfig $defaultConfig - if ($LASTEXITCODE -eq 1) { - Start-Process -FilePath "notepad.exe" -ArgumentList $configPath -Wait - } - Write-Host "" - - 3..1 | ForEach-Object { - Write-Host "`rCompleted, building playbook in $_... " -NoNewLine -ForegroundColor Yellow - Start-Sleep 1 - } -} - -# check if path shortcut matches config path -if (Test-Path $shortcut) { - if ($configPath -ne $(New-Object -ComObject WScript.Shell).CreateShortcut($shortcut).TargetPath) { New-ConfigPathShortcut } -} - -try { - $configNotHashtable = Get-Content $configPath | ConvertFrom-Json - # convert JSON config to hashtable - $config = @{}; foreach ($property in $configNotHashtable.PSObject.Properties) { $config[$property.Name] = $property.Value } -} catch { - Write-Host "Your configuration is corrupted." -ForegroundColor Yellow - choice /c:yn /n /m "Would you like to reset it? [Y/N]" - if ($LASTEXITCODE -eq 1) { - CreateConfig $defaultConfig - } else {exit 1} -} - -# update config -$defaultConfig.Keys | ForEach-Object { - if ($config.Keys -notcontains $_) { - $config = $config + @{ - $_ = $defaultConfig.$_ - } - $updateConfig = $true - } -} -if ($updateConfig) {CreateConfig $config} - -foreach ($a in $config.Keys) { - New-Variable -Name $a -Value $config.$a -} - -# ----------- # -# main script # -# ----------- # - -$apbxFileName = "$fileName.apbx" -$apbxPath = "$PWD\$fileName.apbx" - -if (!(Test-Path -Path "playbook.conf")) { - Write-Host "playbook.conf file not found in the current directory." -ForegroundColor Red - Start-Sleep 2 - exit 1 -} - -# check if old files are in use -$num = 1 -if (($replaceOldPlaybook) -and (Test-Path -Path $apbxFileName)) { - try { - $stream = [System.IO.File]::Open($apbxFileName, 'Open', 'Read', 'Write') - $stream.Close() - } catch { - while(Test-Path -Path "$fileName ($num).apbx") {$num++} - $apbxFileName = "$PWD\$fileName ($num).apbx" - } - Remove-Item -Path $apbxFileName -Force -EA 0 -} else { - if (Test-Path -Path $apbxFileName) { - while(Test-Path -Path "$fileName ($num).apbx") {$num++} - $apbxFileName = "$PWD\$fileName ($num).apbx" - } -} - -$zipFileName = Join-Path -Path $PWD -ChildPath $([System.IO.Path]::ChangeExtension($apbxFileName, "zip")) - -# remove old temp files -Remove-Item -Path $zipFileName -Force -EA 0 -if (!($?) -and (Test-Path -Path "$zipFileName")) { - Write-Host "Failed to delete temporary '$zipFileName' file!" -ForegroundColor Red - Start-Sleep 2 - exit 1 -} - -# make temp directories -$rootTemp = Join-Path -Path $env:TEMP -ChildPath $([System.IO.Path]::GetRandomFileName()) -New-Item $rootTemp -ItemType Directory -Force | Out-Null -if (!(Test-Path -Path "$rootTemp")) { - Write-Host "Failed to create temporary directory!" -ForegroundColor Red - Start-Sleep 2 - exit 1 -} -$configDir = "$rootTemp\playbook\Configuration\atlas" -New-Item $configDir -ItemType Directory -Force | Out-Null - -try { - $tempPlaybookConf = "$rootTemp\playbook\playbook.conf" - $ymlPath = "Configuration\custom.yml" - $tempStartYML = "$rootTemp\playbook\$ymlPath" - - # remove entries in playbook config that make it awkward for testing - $patterns = @() - # 0.6.5 has a bug where it will crash without the 'Requirements' field, but all of the requirements are removed - # "" and # "" - if ($removeRequirements) {$patterns += ""} - if ($removeWinverRequirement) {$patterns += "", "", ""} - if ($removeProductCode) {$patterns += ""} - - if ($patterns.Count -gt 0) { - $newContent = Get-Content "playbook.conf"| Where-Object { $_ -notmatch ($patterns -join '|') } - $newContent | Set-Content "$tempPlaybookConf" -Force - } - - if ($removeDependencies -or $liveLog) { - $startYML = "$PWD\$ymlPath" - if (Test-Path $startYML -PathType Leaf) { - Copy-Item -Path $startYML -Destination $tempStartYML -Force - - $content = Get-Content -Path $tempStartYML - - if ($liveLog) { - # uncomment the 8th line (6 in PowerShell because arrays are zero-based) - if ($content.Count -gt 6) { - $content[6] = $content[6] -replace ' #', '' - } - } - - if ($removeDependencies) { - # has to be raw for removing dependencies - $content = $content -join "`n" - - $startMarker = " ################ NO LOCAL BUILD ################" - $endMarker = " ################ END NO LOCAL BUILD ################" - - $startIndex = $content.IndexOf($startMarker) - $endIndex = $content.IndexOf($endMarker) - - if ($startIndex -ge 0 -and $endIndex -ge 0) { - $content = $content.Substring(0, $startIndex) + $content.Substring($endIndex + $endMarker.Length) - } - } - - Set-Content -Path $tempStartYML -Value $content - } - } - - $excludeFiles = @( - "local-build.cmd", - "*.apbx" - ) - if (Test-Path $tempStartYML) { $excludeFiles += "custom.yml" } - if (Test-Path $tempPlaybookConf) { $excludeFiles += "playbook.conf" } - - # make playbook, 7z is faster - if (Test-Path $apbxPath) { Remove-Item $apbxFileName -Force } - - (Get-ChildItem -File -Exclude $excludeFiles -Recurse).FullName ` - | Resolve-Path -Relative | ForEach-Object {$_.Substring(2)} | Out-File "$rootTemp\7zFiles.txt" -Encoding utf8 - - & $7zPath a -spf -y -mx1 -tzip "$apbxPath" `@"$rootTemp\7zFiles.txt" | Out-Null - # add edited files - Push-Location "$rootTemp\playbook" - & $7zPath u "$apbxPath" * | Out-Null - Pop-Location - - Write-Host "Build successfully! Path: `"$apbxPath`"" -ForegroundColor Green - Start-Sleep 1 -} finally { - Remove-Item $rootTemp -Force -EA 0 -Recurse | Out-Null -} \ No newline at end of file +@echo off +echo Building Playbook... +powershell -nop -ep bypass ^& "%cd%\..\local-build.ps1" -AddLiveLog -ReplaceOldPlaybook -Removals WinverRequirement, Verification -DontOpenPbLocation \ No newline at end of file