From 953ecd084b5281a9bb4d0bb57f33aeed39493e5f Mon Sep 17 00:00:00 2001 From: kormic911 Date: Mon, 1 Sep 2025 00:51:38 -0500 Subject: [PATCH 1/7] Create LICENSE --- LICENSE | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 LICENSE diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..d2d0337 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2025 PwshDevs + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. From cf8bf47e446be96460e29e43b37dda4f1a65468d Mon Sep 17 00:00:00 2001 From: kormic911 <2898792+kormic911@users.noreply.github.com> Date: Mon, 1 Sep 2025 05:51:50 +0000 Subject: [PATCH 2/7] Automated Release Tagging for 1.0.8 in DevSetup.psd1 --- DevSetup/DevSetup.psd1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DevSetup/DevSetup.psd1 b/DevSetup/DevSetup.psd1 index e671fe2..5b547d5 100644 --- a/DevSetup/DevSetup.psd1 +++ b/DevSetup/DevSetup.psd1 @@ -12,7 +12,7 @@ RootModule = 'DevSetup.psm1' # Version number of this module. -ModuleVersion = '1.0.7' +ModuleVersion = '1.0.8' # Supported PSEditions # CompatiblePSEditions = @() From a9b0762a892224f592100a2e9019e7f1ab646ebc Mon Sep 17 00:00:00 2001 From: kormic911 Date: Mon, 1 Sep 2025 00:54:39 -0500 Subject: [PATCH 3/7] Updating README to show how to install devsetup. --- .../Providers/Chocolatey/Install-Chocolatey.ps1 | 2 +- .../Providers/Scoop/Install-ScoopComponents.ps1 | 2 +- README.md | 13 ++++++++++++- 3 files changed, 14 insertions(+), 3 deletions(-) diff --git a/DevSetup/Private/Providers/Chocolatey/Install-Chocolatey.ps1 b/DevSetup/Private/Providers/Chocolatey/Install-Chocolatey.ps1 index 66a6744..fe42a23 100644 --- a/DevSetup/Private/Providers/Chocolatey/Install-Chocolatey.ps1 +++ b/DevSetup/Private/Providers/Chocolatey/Install-Chocolatey.ps1 @@ -97,7 +97,7 @@ Function Install-Chocolatey { # Verify installation $chocoInstalled = Get-Command choco -ErrorAction SilentlyContinue if ($chocoInstalled) { - $chocoVersion = Invoke-Expression "& choco --version" 2>$null + $chocoVersion = Invoke-Expression "& choco --version" 2>$null 3>$null 4>$null 5>$null 6>$null #Write-Host "Chocolatey successfully installed (version: $chocoVersion)!" -ForegroundColor Green Write-StatusMessage "[OK]" -ForegroundColor Green } else { diff --git a/DevSetup/Private/Providers/Scoop/Install-ScoopComponents.ps1 b/DevSetup/Private/Providers/Scoop/Install-ScoopComponents.ps1 index 699d8da..cf5aa56 100644 --- a/DevSetup/Private/Providers/Scoop/Install-ScoopComponents.ps1 +++ b/DevSetup/Private/Providers/Scoop/Install-ScoopComponents.ps1 @@ -230,7 +230,7 @@ Function Install-ScoopComponents { } Write-StatusMessage "- Installing Scoop package: $displayName" -ForegroundColor Gray -Indent 2 -Width 112 -NoNewLine - ($result = Install-ScoopPackage @installParams) | Out-Null + $result = Install-ScoopPackage @installParams 2>$null 3>$null 4>$null 5>$null 6>$null if (-not $result) { Write-StatusMessage "[FAILED]" -ForegroundColor Red diff --git a/README.md b/README.md index c5bc5ba..c2ff4de 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,13 @@ # devsetup -A tool used to setup dev environments +## Installation + +To install `devsetup` run the command below, ensure you are running it from an elevated shell (Administrator) when running on Windows as some of the commands need Administrator privileges (for instance, installing NuGet). +```bash +Set-ExecutionPolicy -ExecutionPolicy Bypass -Scope CurrentUser -Force +iwr https://install.pwshdevs.com/devsetup | iex +``` + +Once `devsetup` is installed run the command below to initialize your environment. +```bash +devsetup -init +``` \ No newline at end of file From 9e3df61524ea0fc8dda5e6c3e5cb836819051e74 Mon Sep 17 00:00:00 2001 From: kormic911 Date: Thu, 4 Sep 2025 16:51:44 -0500 Subject: [PATCH 4/7] Fixing a weird bug that has to do with currentuser scope paths for powershell modules --- .gitignore | 485 ++++++++++++++++++ .../Commands/Export-DevSetupEnv.Tests.ps1 | 22 +- .../Private/Commands/Export-DevSetupEnv.ps1 | 54 +- .../Commands/Initialize-DevSetup.Tests.ps1 | 3 + .../Commands/Show-DevSetupEnvList.Tests.ps1 | 102 +++- .../Private/Commands/Show-DevSetupEnvList.ps1 | 38 +- .../Commands/Uninstall-DevSetupEnv.Tests.ps1 | 2 + .../Commands/Uninstall-DevSetupEnv.ps1 | 41 +- DevSetup/Private/Commands/Update-DevSetup.ps1 | 22 +- .../Chocolatey/Install-Chocolatey.ps1 | 4 +- .../Core/Install-CoreDependencies.ps1 | 13 +- .../Test-PowershellModuleInstalled.ps1 | 35 +- DevSetup/Private/Utils/Get-DevSetupPath.ps1 | 15 +- .../Private/Utils/Get-DevSetupVersion.ps1 | 3 +- .../Utils/Initialize-DevSetupEnvs.Tests.ps1 | 2 + DevSetup/Public/Use-DevSetup.ps1 | 89 ++-- 16 files changed, 813 insertions(+), 117 deletions(-) create mode 100644 .gitignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..d2fbd84 --- /dev/null +++ b/.gitignore @@ -0,0 +1,485 @@ +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. +## +## Get latest from `dotnet new gitignore` + +# dotenv files +.env + +# User-specific files +*.rsuser +*.suo +*.user +*.userosscache +*.sln.docstates + +# User-specific files (MonoDevelop/Xamarin Studio) +*.userprefs + +# Mono auto generated files +mono_crash.* + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +[Rr]eleases/ +x64/ +x86/ +[Ww][Ii][Nn]32/ +[Aa][Rr][Mm]/ +[Aa][Rr][Mm]64/ +bld/ +[Bb]in/ +[Oo]bj/ +[Ll]og/ +[Ll]ogs/ + +# Visual Studio 2015/2017 cache/options directory +.vs/ +# Uncomment if you have tasks that create the project's static files in wwwroot +#wwwroot/ + +# Visual Studio 2017 auto generated files +Generated\ Files/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +# NUnit +*.VisualState.xml +TestResult.xml +testResults.xml +nunit-*.xml + +# Build Results of an ATL Project +[Dd]ebugPS/ +[Rr]eleasePS/ +dlldata.c + +# Benchmark Results +BenchmarkDotNet.Artifacts/ + +# .NET +project.lock.json +project.fragment.lock.json +artifacts/ + +# Tye +.tye/ + +# ASP.NET Scaffolding +ScaffoldingReadMe.txt + +# StyleCop +StyleCopReport.xml + +# Files built by Visual Studio +*_i.c +*_p.c +*_h.h +*.ilk +*.meta +*.obj +*.iobj +*.pch +*.pdb +*.ipdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*_wpftmp.csproj +*.log +*.tlog +*.vspscc +*.vssscc +.builds +*.pidb +*.svclog +*.scc + +# Chutzpah Test files +_Chutzpah* + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opendb +*.opensdf +*.sdf +*.cachefile +*.VC.db +*.VC.VC.opendb + +# Visual Studio profiler +*.psess +*.vsp +*.vspx +*.sap + +# Visual Studio Trace Files +*.e2e + +# TFS 2012 Local Workspace +$tf/ + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper +*.DotSettings.user + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# AxoCover is a Code Coverage Tool +.axoCover/* +!.axoCover/settings.json + +# Coverlet is a free, cross platform Code Coverage Tool +coverage*.json +coverage*.xml +coverage*.info + +# Visual Studio code coverage results +*.coverage +*.coveragexml + +# NCrunch +_NCrunch_* +.*crunch*.local.xml +nCrunchTemp_* + +# MightyMoose +*.mm.* +AutoTest.Net/ + +# Web workbench (sass) +.sass-cache/ + +# Installshield output folder +[Ee]xpress/ + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish/ + +# Publish Web Output +*.[Pp]ublish.xml +*.azurePubxml +# Note: Comment the next line if you want to checkin your web deploy settings, +# but database connection strings (with potential passwords) will be unencrypted +*.pubxml +*.publishproj + +# Microsoft Azure Web App publish settings. Comment the next line if you want to +# checkin your Azure Web App publish settings, but sensitive information contained +# in these scripts will be unencrypted +PublishScripts/ + +# NuGet Packages +*.nupkg +# NuGet Symbol Packages +*.snupkg +# The packages folder can be ignored because of Package Restore +**/[Pp]ackages/* +# except build/, which is used as an MSBuild target. +!**/[Pp]ackages/build/ +# Uncomment if necessary however generally it will be regenerated when needed +#!**/[Pp]ackages/repositories.config +# NuGet v3's project.json files produces more ignorable files +*.nuget.props +*.nuget.targets + +# Microsoft Azure Build Output +csx/ +*.build.csdef + +# Microsoft Azure Emulator +ecf/ +rcf/ + +# Windows Store app package directories and files +AppPackages/ +BundleArtifacts/ +Package.StoreAssociation.xml +_pkginfo.txt +*.appx +*.appxbundle +*.appxupload + +# Visual Studio cache files +# files ending in .cache can be ignored +*.[Cc]ache +# but keep track of directories ending in .cache +!?*.[Cc]ache/ + +# Others +ClientBin/ +~$* +*~ +*.dbmdl +*.dbproj.schemaview +*.jfm +*.pfx +*.publishsettings +orleans.codegen.cs + +# Including strong name files can present a security risk +# (https://github.com/github/gitignore/pull/2483#issue-259490424) +#*.snk + +# Since there are multiple workflows, uncomment next line to ignore bower_components +# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) +#bower_components/ + +# RIA/Silverlight projects +Generated_Code/ + +# Backup & report files from converting an old project file +# to a newer Visual Studio version. Backup files are not needed, +# because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm +ServiceFabricBackup/ +*.rptproj.bak + +# SQL Server files +*.mdf +*.ldf +*.ndf + +# Business Intelligence projects +*.rdl.data +*.bim.layout +*.bim_*.settings +*.rptproj.rsuser +*- [Bb]ackup.rdl +*- [Bb]ackup ([0-9]).rdl +*- [Bb]ackup ([0-9][0-9]).rdl + +# Microsoft Fakes +FakesAssemblies/ + +# GhostDoc plugin setting file +*.GhostDoc.xml + +# Node.js Tools for Visual Studio +.ntvs_analysis.dat +node_modules/ + +# Visual Studio 6 build log +*.plg + +# Visual Studio 6 workspace options file +*.opt + +# Visual Studio 6 auto-generated workspace file (contains which files were open etc.) +*.vbw + +# Visual Studio 6 auto-generated project file (contains which files were open etc.) +*.vbp + +# Visual Studio 6 workspace and project file (working project files containing files to include in project) +*.dsw +*.dsp + +# Visual Studio 6 technical files +*.ncb +*.aps + +# Visual Studio LightSwitch build output +**/*.HTMLClient/GeneratedArtifacts +**/*.DesktopClient/GeneratedArtifacts +**/*.DesktopClient/ModelManifest.xml +**/*.Server/GeneratedArtifacts +**/*.Server/ModelManifest.xml +_Pvt_Extensions + +# Paket dependency manager +.paket/paket.exe +paket-files/ + +# FAKE - F# Make +.fake/ + +# CodeRush personal settings +.cr/personal + +# Python Tools for Visual Studio (PTVS) +__pycache__/ +*.pyc + +# Cake - Uncomment if you are using it +# tools/** +# !tools/packages.config + +# Tabs Studio +*.tss + +# Telerik's JustMock configuration file +*.jmconfig + +# BizTalk build output +*.btp.cs +*.btm.cs +*.odx.cs +*.xsd.cs + +# OpenCover UI analysis results +OpenCover/ + +# Azure Stream Analytics local run output +ASALocalRun/ + +# MSBuild Binary and Structured Log +*.binlog + +# NVidia Nsight GPU debugger configuration file +*.nvuser + +# MFractors (Xamarin productivity tool) working folder +.mfractor/ + +# Local History for Visual Studio +.localhistory/ + +# Visual Studio History (VSHistory) files +.vshistory/ + +# BeatPulse healthcheck temp database +healthchecksdb + +# Backup folder for Package Reference Convert tool in Visual Studio 2017 +MigrationBackup/ + +# Ionide (cross platform F# VS Code tools) working folder +.ionide/ + +# Fody - auto-generated XML schema +FodyWeavers.xsd + +# VS Code files for those working on multiple tools +.vscode/* +!.vscode/settings.json +!.vscode/tasks.json +!.vscode/launch.json +!.vscode/extensions.json +*.code-workspace + +# Local History for Visual Studio Code +.history/ + +# Windows Installer files from build outputs +*.cab +*.msi +*.msix +*.msm +*.msp + +# JetBrains Rider +*.sln.iml +.idea/ + +## +## Visual studio for Mac +## + + +# globs +Makefile.in +*.userprefs +*.usertasks +config.make +config.status +aclocal.m4 +install-sh +autom4te.cache/ +*.tar.gz +tarballs/ +test-results/ + +# Mac bundle stuff +*.dmg +*.app + +# content below from: https://github.com/github/gitignore/blob/main/Global/macOS.gitignore +# General +.DS_Store +.AppleDouble +.LSOverride + +# Icon must end with two \r +Icon + + +# Thumbnails +._* + +# Files that might appear in the root of a volume +.DocumentRevisions-V100 +.fseventsd +.Spotlight-V100 +.TemporaryItems +.Trashes +.VolumeIcon.icns +.com.apple.timemachine.donotpresent + +# Directories potentially created on remote AFP share +.AppleDB +.AppleDesktop +Network Trash Folder +Temporary Items +.apdisk + +# content below from: https://github.com/github/gitignore/blob/main/Global/Windows.gitignore +# Windows thumbnail cache files +Thumbs.db +ehthumbs.db +ehthumbs_vista.db + +# Dump file +*.stackdump + +# Folder config file +[Dd]esktop.ini + +# Recycle Bin used on file shares +$RECYCLE.BIN/ + +# Windows Installer files +*.cab +*.msi +*.msix +*.msm +*.msp + +# Windows shortcuts +*.lnk + +# Vim temporary swap files +*.swp diff --git a/DevSetup/Private/Commands/Export-DevSetupEnv.Tests.ps1 b/DevSetup/Private/Commands/Export-DevSetupEnv.Tests.ps1 index d4e4e23..a494767 100644 --- a/DevSetup/Private/Commands/Export-DevSetupEnv.Tests.ps1 +++ b/DevSetup/Private/Commands/Export-DevSetupEnv.Tests.ps1 @@ -1,9 +1,12 @@ BeforeAll { . $PSScriptRoot\Export-DevSetupEnv.ps1 . $PSScriptRoot\..\..\..\DevSetup\Private\Utils\Get-DevSetupEnvPath.ps1 + . $PSScriptRoot\..\..\..\DevSetup\Private\Utils\Get-DevSetupLocalEnvPath.ps1 + . $PSScriptRoot\..\..\..\DevSetup\Private\Utils\Get-DevSetupCommunityEnvPath.ps1 . $PSScriptRoot\..\..\..\DevSetup\Private\Utils\Write-NewConfig.ps1 Mock Get-DevSetupEnvPath { "TestDrive:\DevSetupEnvs" } Mock Get-DevSetupLocalEnvPath { "TestDrive:\DevSetupEnvs\local"} + Mock Get-DevSetupCommunityEnvPath { "TestDrive:\DevSetupEnvs\community"} Mock Write-NewConfig { param($OutFile) $OutFile } Mock Write-Host { } Mock Write-Error { } @@ -20,6 +23,15 @@ Describe "Export-DevSetupEnv" { } } + Context "When called with a valid path" { + It "Should create the config file and return its path" { + $result = Export-DevSetupEnv -Path "TestDrive:\MyCustomPath\MyEnv.devsetup" + $result | Should -Be "TestDrive:\MyCustomPath\MyEnv.devsetup" + Assert-MockCalled Write-NewConfig -Exactly 1 -Scope It -ParameterFilter { $OutFile -eq "TestDrive:\MyCustomPath\MyEnv.devsetup" } + Assert-MockCalled Write-Host -Scope It -ParameterFilter { $Object -match "exported to" -and $ForegroundColor -eq "Green" } + } + } + Context "When called with a name that needs sanitization" { It "Should sanitize the name and warn" { $result = Export-DevSetupEnv -Name "Data Science Environment!" @@ -28,6 +40,14 @@ Describe "Export-DevSetupEnv" { } } + Context "When called with a path that needs sanitization" { + It "Should sanitize the path and warn" { + $result = Export-DevSetupEnv -Path "TestDrive:\MyCustomPath\MyEnv!.devsetup" + $result | Should -Be "TestDrive:\MyCustomPath\MyEnv.devsetup" + Assert-MockCalled Write-Host -Scope It -ParameterFilter { $Object -match "sanitized" -and $ForegroundColor -eq "Yellow" } + } + } + Context "When Write-NewConfig fails" { It "Should write error and return null" { Mock Write-NewConfig { param($OutFile) $null } @@ -36,4 +56,4 @@ Describe "Export-DevSetupEnv" { Assert-MockCalled Write-Error -Exactly 1 -Scope It -ParameterFilter { $Message -match "Failed to create configuration file" } } } -} \ No newline at end of file +} diff --git a/DevSetup/Private/Commands/Export-DevSetupEnv.ps1 b/DevSetup/Private/Commands/Export-DevSetupEnv.ps1 index 8efc008..b30fa3b 100644 --- a/DevSetup/Private/Commands/Export-DevSetupEnv.ps1 +++ b/DevSetup/Private/Commands/Export-DevSetupEnv.ps1 @@ -60,16 +60,56 @@ #> Function Export-DevSetupEnv { + [CmdletBinding()] Param( - [string]$Name + [Parameter(Mandatory=$true, ParameterSetName="Export")] + [string]$Name, + [Parameter(Mandatory=$true, ParameterSetName="ExportPath")] + [string]$Path ) - # Sanitize EnvName to only contain alphanumeric characters, hyphens, and periods - $sanitizedEnvName = $Name -replace '[^a-zA-Z0-9\-\.]', '' - if ($sanitizedEnvName -ne $Name) { - Write-Host "EnvName sanitized from '$Name' to '$sanitizedEnvName' (removed non-alphanumeric characters)" -ForegroundColor Yellow + $OutFile = $null + if($PSBoundParameters.ContainsKey('Name')) { + $Provider = "local" + + if($Name -like "*:*") { + $Parts = $Name.Split(":") + $Name = $Parts[1]; + $Provider = $Parts[0] + } + $SanitizedEnvName = $Name -replace '[^a-zA-Z0-9\-\.]', '' + if ($SanitizedEnvName -ne $Name) { + Write-Host "EnvName sanitized from '$Name' to '$SanitizedEnvName' (removed non-alphanumeric characters)" -ForegroundColor Yellow + } + + $BasePath = Join-Path -Path (Get-DevSetupEnvPath) -ChildPath $Provider + if(-not (Test-Path -Path $BasePath)) { + New-Item -Path $BasePath -ItemType Directory -Force | Out-Null + } + + $OutFile = Join-Path -Path $BasePath -ChildPath "$SanitizedEnvName.devsetup" + } elseif($PSBoundParameters.ContainsKey('Path')) { + $BasePath = Split-Path -Path $Path -Parent + if(-not (Test-Path -Path $BasePath)) { + New-Item -Path $BasePath -ItemType Directory -Force | Out-Null + } + $Name = Split-Path -Path $Path -Leaf + if($Name -notlike "*.devsetup") { + $Name = "$Name.devsetup" + } + + $SanitizedEnvName = $Name -replace '[^a-zA-Z0-9\-\.]', '' + + if ($SanitizedEnvName -ne $Name) { + Write-Host "EnvName sanitized from '$Name' to '$SanitizedEnvName' (removed non-alphanumeric characters)" -ForegroundColor Yellow + } + $OutFile = Join-Path -Path $BasePath -ChildPath $SanitizedEnvName } - $Name = $sanitizedEnvName - $OutFile = Join-Path -Path (Get-DevSetupLocalEnvPath) -ChildPath "$Name.devsetup" + + if(-not $OutFile) { + Write-Error "Failed to determine output file path" + return $null + } + $config = Write-NewConfig -OutFile $OutFile if (-not $config) { Write-Error "Failed to create configuration file" diff --git a/DevSetup/Private/Commands/Initialize-DevSetup.Tests.ps1 b/DevSetup/Private/Commands/Initialize-DevSetup.Tests.ps1 index 1f2d442..2906d50 100644 --- a/DevSetup/Private/Commands/Initialize-DevSetup.Tests.ps1 +++ b/DevSetup/Private/Commands/Initialize-DevSetup.Tests.ps1 @@ -1,6 +1,9 @@ BeforeAll { . $PSScriptRoot\Initialize-DevSetup.ps1 . $PSScriptRoot\..\..\..\DevSetup\Private\Utils\Get-DevSetupPath.ps1 + . $PSScriptRoot\..\..\..\DevSetup\Private\Utils\Get-DevSetupEnvPath.ps1 + . $PSScriptRoot\..\..\..\DevSetup\Private\Utils\Get-DevSetupLocalEnvPath.ps1 + . $PSScriptRoot\..\..\..\DevSetup\Private\Utils\Get-DevSetupCommunityEnvPath.ps1 . $PSScriptRoot\..\..\..\DevSetup\Private\Providers\Core\Install-CoreDependencies.ps1 . $PSScriptRoot\..\..\..\DevSetup\Private\Utils\Initialize-DevSetupEnvs.ps1 Mock Write-Host { } diff --git a/DevSetup/Private/Commands/Show-DevSetupEnvList.Tests.ps1 b/DevSetup/Private/Commands/Show-DevSetupEnvList.Tests.ps1 index 422e8cd..2880232 100644 --- a/DevSetup/Private/Commands/Show-DevSetupEnvList.Tests.ps1 +++ b/DevSetup/Private/Commands/Show-DevSetupEnvList.Tests.ps1 @@ -6,6 +6,7 @@ BeforeAll { . $PSScriptRoot\..\..\..\DevSetup\Private\Utils\Get-DevSetupPath.ps1 . $PSScriptRoot\..\..\..\DevSetup\Private\Utils\Test-OperatingSystem.ps1 . $PSScriptRoot\..\..\..\DevSetup\Private\Utils\Format-PrettyTable.ps1 + . $PSScriptRoot\..\..\..\DevSetup\Private\Utils\Write-StatusMessage.ps1 Mock Get-DevSetupPath { "C:\DevSetup" } Mock Optimize-DevSetupEnvs { } Mock Write-Host { } @@ -15,13 +16,14 @@ BeforeAll { Mock Get-Content { '[{"name":"EnvWin","version":"1.0","platform":"windows","file":"envwin.yaml"},{"name":"EnvLinux","version":"2.0","platform":"linux","file":"envlinux.yaml"},{"name":"EnvMac","version":"3.0","platform":"macos","file":"envmac.yaml"},{"name":"EnvCross","version":"4.0","platform":"cross-platform","file":"envcross.yaml"},{"name":"EnvUnspec","version":"5.0","file":"envunspec.yaml"}]' } Mock ConvertFrom-Json { @( - @{ name = "EnvWin"; version = "1.0"; platform = "windows"; file = "envwin.yaml" }, - @{ name = "EnvLinux"; version = "2.0"; platform = "linux"; file = "envlinux.yaml" }, - @{ name = "EnvMac"; version = "3.0"; platform = "macos"; file = "envmac.yaml" }, - @{ name = "EnvCross"; version = "4.0"; platform = "cross-platform"; file = "envcross.yaml" }, - @{ name = "EnvUnspec"; version = "5.0"; file = "envunspec.yaml" } + @{ name = "EnvWin"; version = "1.0"; platform = "windows"; provider = "local"; file = "envwin.yaml" }, + @{ name = "EnvLinux"; version = "2.0"; platform = "linux"; provider = "community"; file = "envlinux.yaml" }, + @{ name = "EnvMac"; version = "3.0"; platform = "macos"; provider = "other"; file = "envmac.yaml" }, + @{ name = "EnvCross"; version = "4.0"; platform = "cross-platform"; provider = "local"; file = "envcross.yaml" }, + @{ name = "EnvUnspec"; version = "5.0"; provider = "other2"; file = "envunspec.yaml" } ) } + Mock Write-StatusMessage { Param($Message) } } Describe "Show-DevSetupEnvList" { @@ -49,8 +51,8 @@ Describe "Show-DevSetupEnvList" { Mock Format-PrettyTable { } Mock Test-OperatingSystem { param($Windows, $Linux, $MacOS) if ($Windows) { $true } else { $false } } Show-DevSetupEnvList -Platform "current" - Assert-MockCalled Write-Host -Scope It -ParameterFilter { $Object -match "Filtering for current platform: windows" } - Assert-MockCalled Format-PrettyTable -Exactly 1 -Scope It + Assert-MockCalled Write-StatusMessage -Scope It -ParameterFilter { $Message -match "Filtering for platform: windows" } + Assert-MockCalled Format-PrettyTable -Exactly 1 -Scope It -ParameterFilter { $Rows.Count -eq 1 } } } @@ -59,8 +61,8 @@ Describe "Show-DevSetupEnvList" { Mock Format-PrettyTable { } Mock Test-OperatingSystem { param($Windows, $Linux, $MacOS) if ($Linux) { $true } else { $false } } Show-DevSetupEnvList -Platform "current" - Assert-MockCalled Write-Host -Scope It -ParameterFilter { $Object -match "Filtering for current platform: linux" } - Assert-MockCalled Format-PrettyTable -Exactly 1 -Scope It + Assert-MockCalled Write-StatusMessage -Scope It -ParameterFilter { $Message -match "Filtering for platform: linux" } + Assert-MockCalled Format-PrettyTable -Exactly 1 -Scope It -ParameterFilter { $Rows.Count -eq 1 } } } @@ -69,8 +71,8 @@ Describe "Show-DevSetupEnvList" { Mock Format-PrettyTable { } Mock Test-OperatingSystem { param($Windows, $Linux, $MacOS) if ($MacOS) { $true } else { $false } } Show-DevSetupEnvList -Platform "current" - Assert-MockCalled Write-Host -Scope It -ParameterFilter { $Object -match "Filtering for current platform: macos" } - Assert-MockCalled Format-PrettyTable -Exactly 1 -Scope It + Assert-MockCalled Write-StatusMessage -Scope It -ParameterFilter { $Message -match "Filtering for platform: macos" } + Assert-MockCalled Format-PrettyTable -Exactly 1 -Scope It -ParameterFilter { $Rows.Count -eq 1 } } } @@ -78,8 +80,8 @@ Describe "Show-DevSetupEnvList" { It "Should show all environments without filtering" { Mock Format-PrettyTable { } Show-DevSetupEnvList -Platform "all" - Assert-MockCalled Write-Host -Scope It -ParameterFilter { $Object -match "Showing all environments regardless of platform" } - Assert-MockCalled Format-PrettyTable -Exactly 1 -Scope It + Assert-MockCalled Write-StatusMessage -Scope It -ParameterFilter { $Message -match "Filtering for platform: all" } + Assert-MockCalled Format-PrettyTable -Exactly 1 -Scope It -ParameterFilter { $Rows.Count -eq 5 } } } @@ -87,10 +89,80 @@ Describe "Show-DevSetupEnvList" { It "Should filter and display only windows-compatible environments" { Mock Format-PrettyTable { } Show-DevSetupEnvList -Platform "windows" - Assert-MockCalled Write-Host -Scope It -ParameterFilter { $Object -match "Filtering for platform: windows" } - Assert-MockCalled Format-PrettyTable -Exactly 1 -Scope It + Assert-MockCalled Write-StatusMessage -Scope It -ParameterFilter { $Message -match "Filtering for platform: windows" } + Assert-MockCalled Format-PrettyTable -Exactly 1 -Scope It -ParameterFilter { $Rows.Count -eq 1 } + } + } + + Context "When filtering for specific platform (windows) and provider (local)" { + It "Should filter and display only windows-compatible environments from local provider" { + Mock Format-PrettyTable { } + Show-DevSetupEnvList -Platform "windows" -Provider "local" + $script:count = 0; + Assert-MockCalled Write-StatusMessage -Scope It -ParameterFilter { + if($script:count -eq 0) { $Message -match "Filtering for platform: windows" } + if($script:count -eq 1) { $Message -match ", provider: local" } + $script:count++; + } -Times 2 + Assert-MockCalled Format-PrettyTable -Exactly 1 -Scope It -ParameterFilter { $Rows.Count -eq 1 } } } + + Context "When filtering for specific platform (windows) and provider (community)" { + It "Should filter and display only windows-compatible environments from community provider" { + Mock Format-PrettyTable { } + Show-DevSetupEnvList -Platform "windows" -Provider "community" + $script:count = 0; + Assert-MockCalled Write-StatusMessage -Scope It -ParameterFilter { + if($script:count -eq 0) { $Message -match "Filtering for platform: windows" } + if($script:count -eq 1) { $Message -match ", provider: community" } + $script:count++; + } -Times 2 + Assert-MockCalled Format-PrettyTable -Exactly 0 -Scope It -ParameterFilter { $Rows.Count -eq 0 } + } + } + + Context "When filtering for specific platform (linux) and provider (community)" { + It "Should filter and display only linux-compatible environments from community provider" { + Mock Format-PrettyTable { } + Show-DevSetupEnvList -Platform "linux" -Provider "community" + $script:count = 0; + Assert-MockCalled Write-StatusMessage -Scope It -ParameterFilter { + if($script:count -eq 0) { $Message -match "Filtering for platform: linux" } + if($script:count -eq 1) { $Message -match ", provider: community" } + $script:count++; + } -Times 2 + Assert-MockCalled Format-PrettyTable -Exactly 1 -Scope It -ParameterFilter { $Rows.Count -eq 1 } + } + } + + Context "When filtering for specific platform (macos) and provider (other)" { + It "Should filter and display only macos-compatible environments from other provider" { + Mock Format-PrettyTable { } + Show-DevSetupEnvList -Platform "macos" -Provider "other" + $script:count = 0; + Assert-MockCalled Write-StatusMessage -Scope It -ParameterFilter { + if($script:count -eq 0) { $Message -match "Filtering for platform: macos" } + if($script:count -eq 1) { $Message -match ", provider: other" } + $script:count++; + } -Times 2 + Assert-MockCalled Format-PrettyTable -Exactly 1 -Scope It -ParameterFilter { $Rows.Count -eq 1 } + } + } + + Context "When filtering for specific platform (all) and provider (local)" { + It "Should filter and display all environment from local provider" { + Mock Format-PrettyTable { } + Show-DevSetupEnvList -Platform "all" -Provider "local" + $script:count = 0; + Assert-MockCalled Write-StatusMessage -Scope It -ParameterFilter { + if($script:count -eq 0) { $Message -match "Filtering for platform: all" } + if($script:count -eq 1) { $Message -match ", provider: local" } + $script:count++; + } -Times 2 + Assert-MockCalled Format-PrettyTable -Exactly 1 -Scope It -ParameterFilter { $Rows.Count -eq 2 } + } + } Context "When no environments are found for a platform" { It "Should display guidance message" { diff --git a/DevSetup/Private/Commands/Show-DevSetupEnvList.ps1 b/DevSetup/Private/Commands/Show-DevSetupEnvList.ps1 index 70d60d7..df7c7a9 100644 --- a/DevSetup/Private/Commands/Show-DevSetupEnvList.ps1 +++ b/DevSetup/Private/Commands/Show-DevSetupEnvList.ps1 @@ -69,7 +69,11 @@ Function Show-DevSetupEnvList { Param ( [Parameter(Mandatory=$false, Position=0)] [ValidateSet("current", "all", "windows", "linux", "macos")] - [string]$Platform = "current" # Default to current platform + [string]$Platform = "current", # Default to current platform + [Parameter(Mandatory=$false)] + [string]$Provider, + [Parameter(Mandatory=$false)] + [switch]$Installed ) @@ -88,13 +92,18 @@ Function Show-DevSetupEnvList { } else { $platformFilter = "windows" } - Write-Host "Filtering for current platform: $platformFilter" -ForegroundColor Gray - } elseif ($platformFilter -eq "all") { - Write-Host "Showing all environments regardless of platform" -ForegroundColor Gray - } else { - Write-Host "Filtering for platform: $platformFilter" -ForegroundColor Gray + } + Write-StatusMessage "Filtering for platform: $platformFilter" -ForegroundColor Gray -NoNewLine + + if($Provider) { + Write-StatusMessage ", provider: $Provider" -ForegroundColor Gray -NoNewLine } + if($Installed) { + Write-StatusMessage ", installed only" -ForegroundColor Gray -NoNewLine + } + Write-Host "" + # Get the environments.json file path $devSetupPath = Get-DevSetupPath $environmentsJsonPath = Join-Path -Path $devSetupPath -ChildPath "environments.json" @@ -114,17 +123,16 @@ Function Show-DevSetupEnvList { } } + if ($Provider) { + $environments = $environments | Where-Object { $_.provider -and ($_.provider.ToLower() -eq $Provider.ToLower()) } + } + #if ($Installed) { + # $environments = $environments | Where-Object { Test-DevSetupEnvInstalled -Name $_.name -Provider $_.provider } + #} + # Filter environments by platform if ($platformFilter -ne "all") { - $filteredEnvironments = @() - foreach ($env in $environments) { - $envPlatform = if ($env.platform) { $env.platform.ToLower() } else { "" } - # Match exact platform or cross-platform environments - if ($envPlatform -eq $platformFilter) { - $filteredEnvironments += $env - } - } - $environments = $filteredEnvironments + $environments = $environments | Where-Object { ($_.platform -and ($_.platform.ToLower() -eq $platformFilter)) } } if ($environments.Count -eq 0) { diff --git a/DevSetup/Private/Commands/Uninstall-DevSetupEnv.Tests.ps1 b/DevSetup/Private/Commands/Uninstall-DevSetupEnv.Tests.ps1 index 24bb3ed..3dbcbbf 100644 --- a/DevSetup/Private/Commands/Uninstall-DevSetupEnv.Tests.ps1 +++ b/DevSetup/Private/Commands/Uninstall-DevSetupEnv.Tests.ps1 @@ -2,6 +2,7 @@ BeforeAll { . $PSScriptRoot\Uninstall-DevSetupEnv.ps1 . $PSScriptRoot\..\..\..\DevSetup\Private\Utils\Read-ConfigurationFile.ps1 . $PSScriptRoot\..\..\..\DevSetup\Private\Utils\Get-DevSetupEnvPath.ps1 + . $PSScriptRoot\..\..\..\DevSetup\Private\Utils\Test-OperatingSystem.ps1 . $PSScriptRoot\..\..\..\DevSetup\Private\Providers\Scoop\Uninstall-ScoopComponents.ps1 . $PSScriptRoot\..\..\..\DevSetup\Private\Providers\Chocolatey\Uninstall-ChocolateyPackages.ps1 . $PSScriptRoot\..\..\..\DevSetup\Private\Providers\PowerShell\Uninstall-PowershellModules.ps1 @@ -11,6 +12,7 @@ BeforeAll { Mock Uninstall-PowershellModules { $true } Mock Uninstall-ChocolateyPackages { $true } Mock Uninstall-ScoopComponents { $true } + Mock Test-OperatingSystem { $true } Mock Write-Host { } Mock Write-Error { } } diff --git a/DevSetup/Private/Commands/Uninstall-DevSetupEnv.ps1 b/DevSetup/Private/Commands/Uninstall-DevSetupEnv.ps1 index a2b4190..b2b596d 100644 --- a/DevSetup/Private/Commands/Uninstall-DevSetupEnv.ps1 +++ b/DevSetup/Private/Commands/Uninstall-DevSetupEnv.ps1 @@ -59,20 +59,33 @@ Function Uninstall-DevSetupEnv { [CmdletBinding()] Param( - [Parameter(Mandatory=$true, Position=0)] - [string]$Name + [Parameter(Mandatory=$true, Position=0, ParameterSetName = "Uninstall")] + [string]$Name, + [Parameter(Mandatory=$true, Position=0, ParameterSetName = "UninstallPath")] + [string]$Path ) try { - $Provider = "local" - - if($Name -like "*:*") { - $parts = $Name.Split(":") - $Name = $parts[1]; - $Provider = $parts[0] + $YamlFile = $null + + if($PSBoundParameters.ContainsKey('Name')) { + $Provider = "local" + + if($Name -like "*:*") { + $parts = $Name.Split(":") + $Name = $parts[1]; + $Provider = $parts[0] + } + + $YamlFile = Join-Path -Path (Join-Path -Path (Get-DevSetupEnvPath) -ChildPath $Provider) -ChildPath "$Name.devsetup" + } elseif($PSBoundParameters.ContainsKey('Path')) { + if(-not (Test-Path -Path $Path)) { + Write-Error "Invalid Path provided" + return + } + $YamlFile = $Path } - $YamlFile = Join-Path -Path (Join-Path -Path (Get-DevSetupEnvPath) -ChildPath $Provider) -ChildPath "$Name.devsetup" #$YamlFile = Join-Path -Path (Get-DevSetupEnvPath) -ChildPath "$Name.yaml" if (-not (Test-Path $YamlFile)) { Write-Error "Environment file not found: $YamlFile" @@ -93,11 +106,13 @@ Function Uninstall-DevSetupEnv { # Install PowerShell module dependencies $status = Uninstall-PowershellModules -YamlData $YamlData - # Install Chocolatey package dependencies - $status = Uninstall-ChocolateyPackages -YamlData $YamlData + if ((Test-OperatingSystem -Windows)) { + # Install Chocolatey package dependencies + $status = Uninstall-ChocolateyPackages -YamlData $YamlData - # Install Scoop package dependencies - $status = Uninstall-ScoopComponents -YamlData $YamlData + # Install Scoop package dependencies + $status = Uninstall-ScoopComponents -YamlData $YamlData + } } catch { Write-Error "An error occurred during uninstallation: $_" return diff --git a/DevSetup/Private/Commands/Update-DevSetup.ps1 b/DevSetup/Private/Commands/Update-DevSetup.ps1 index 8ecf2b4..d52ae68 100644 --- a/DevSetup/Private/Commands/Update-DevSetup.ps1 +++ b/DevSetup/Private/Commands/Update-DevSetup.ps1 @@ -1,7 +1,27 @@ Function Update-DevSetup { [CmdletBinding()] - Param() + Param( + [Parameter(Mandatory=$true, ParameterSetName="Main")] + [switch]$Main, + [Parameter(Mandatory=$true, ParameterSetName="Develop")] + [switch]$Develop, + [Parameter(Mandatory=$true, ParameterSetName="Version")] + [string]$Version, + [Parameter(Mandatory=$true, ParameterSetName="Latest")] + [switch]$Latest + ) + $RemoteVersion = Get-DevSetupVersion -Remote + $LocalVersion = Get-DevSetupVersion -Local + if($RemoteVersion -gt $LocalVersion) { + Write-Host "A new version of DevSetup is available: $RemoteVersion (current version: $LocalVersion)" -ForegroundColor Yellow + } elseif ($RemoteVersion -eq $LocalVersion) { + Write-Host "You are already running the latest version of DevSetup: $LocalVersion" -ForegroundColor Green + return + } else { + Write-Host "You are running a newer version of DevSetup ($LocalVersion) than the latest release ($RemoteVersion)" -ForegroundColor Yellow + return + } Write-Host "" Write-Host "- Updating list of available environments..." -ForegroundColor Cyan Optimize-DevSetupEnvs | Out-Null diff --git a/DevSetup/Private/Providers/Chocolatey/Install-Chocolatey.ps1 b/DevSetup/Private/Providers/Chocolatey/Install-Chocolatey.ps1 index fe42a23..30d386f 100644 --- a/DevSetup/Private/Providers/Chocolatey/Install-Chocolatey.ps1 +++ b/DevSetup/Private/Providers/Chocolatey/Install-Chocolatey.ps1 @@ -81,7 +81,7 @@ Function Install-Chocolatey { $chocoInstalled = Get-Command choco -ErrorAction SilentlyContinue if ($chocoInstalled) { - $chocoVersion = Invoke-Expression "& choco --version" 2>$null + Invoke-Expression "& choco --version" *>$null #Write-Host "Chocolatey is already installed (version: $chocoVersion)" -ForegroundColor Green Write-StatusMessage "[OK]" -ForegroundColor Green } else { @@ -97,7 +97,7 @@ Function Install-Chocolatey { # Verify installation $chocoInstalled = Get-Command choco -ErrorAction SilentlyContinue if ($chocoInstalled) { - $chocoVersion = Invoke-Expression "& choco --version" 2>$null 3>$null 4>$null 5>$null 6>$null + Invoke-Expression "& choco --version" *>$null #Write-Host "Chocolatey successfully installed (version: $chocoVersion)!" -ForegroundColor Green Write-StatusMessage "[OK]" -ForegroundColor Green } else { diff --git a/DevSetup/Private/Providers/Core/Install-CoreDependencies.ps1 b/DevSetup/Private/Providers/Core/Install-CoreDependencies.ps1 index e03f285..008c6bc 100644 --- a/DevSetup/Private/Providers/Core/Install-CoreDependencies.ps1 +++ b/DevSetup/Private/Providers/Core/Install-CoreDependencies.ps1 @@ -72,9 +72,11 @@ Function Install-CoreDependencies { Param() # Install NuGet PackageProvider - if (-not (Install-NuGet)) { - Write-Error "Failed to install NuGet PackageProvider" - return $false + if ((Test-OperatingSystem -Windows)) { + if (-not (Install-NuGet)) { + Write-Error "Failed to install NuGet PackageProvider" + return $false + } } # Get required modules from DevSetup manifest @@ -125,7 +127,10 @@ Function Install-CoreDependencies { return $false } } else { - Write-Warning "Skipping Windows-only installations on non-Windows platform" + if (-not (Install-Homebrew)) { + Write-Error "Failed to install Homebrew" + return $false + } } return $true diff --git a/DevSetup/Private/Providers/Powershell/Test-PowershellModuleInstalled.ps1 b/DevSetup/Private/Providers/Powershell/Test-PowershellModuleInstalled.ps1 index cc5e943..9e41077 100644 --- a/DevSetup/Private/Providers/Powershell/Test-PowershellModuleInstalled.ps1 +++ b/DevSetup/Private/Providers/Powershell/Test-PowershellModuleInstalled.ps1 @@ -91,30 +91,25 @@ Function Test-PowershellModuleInstalled { ) # CurrentUser ps5.1 - # $HOME\Documents\WindowsPowerShell\Modules + # $env:USERPROFILE\Documents\WindowsPowerShell\Modules # CurrentUser ps7 - # $HOME\Documents\PowerShell\Modules + # $env:USERPROFILE\Documents\PowerShell\Modules + # CurrentUser ps7 (linux/macos) + # $env:HOME/.local/share/powershell/Modules # AllUsers ps5.1 - # $Env:ProgramFiles\WindowsPowerShell\Modules + # $env:ProgramFiles\WindowsPowerShell\Modules # AllUsers ps7 - # $Env:ProgramFiles\PowerShell\Modules + # $env:ProgramFiles\PowerShell\Modules + # AllUsers ps7 (linux/macos) + # $env:HOME/.local/share/powershell/Modules $InstallPaths = @( - @{ - Path = "$env:USERPROFILE\Documents\WindowsPowerShell\Modules"; - Scope = "CurrentUser" - }, - @{ - Path = "$env:USERPROFILE\Documents\PowerShell\Modules"; - Scope = "CurrentUser" - } - @{ - Path = "$env:ProgramFiles\PowerShell\Modules"; - Scope = "AllUsers" - }, - @{ - Path = "$env:ProgramFiles\WindowsPowerShell\Modules"; - Scope = "AllUsers" + $env:PSModulePath -split ([System.IO.Path]::PathSeparator) | ForEach-Object { + if($_ -match [regex]::Escape("$HOME")) { + @{ Path = $_; Scope = "CurrentUser" } + } else { + @{ Path = $_; Scope = "AllUsers" } + } } ) @@ -130,7 +125,7 @@ Function Test-PowershellModuleInstalled { if($PSBoundParameters.ContainsKey('Scope')) { $InstallPaths | ForEach-Object { - if ($module.Path -like "$($_.Path)\*") { + if ($module.Path -like "$($_.Path)*") { if ($_.Scope -eq $Scope) { $installedState += [InstalledState]::GlobalVersionMet } diff --git a/DevSetup/Private/Utils/Get-DevSetupPath.ps1 b/DevSetup/Private/Utils/Get-DevSetupPath.ps1 index b7d2393..c16f15b 100644 --- a/DevSetup/Private/Utils/Get-DevSetupPath.ps1 +++ b/DevSetup/Private/Utils/Get-DevSetupPath.ps1 @@ -1,9 +1,14 @@ Function Get-DevSetupPath { - # Get user's home directory + # Get user's home directory + if(Test-OperatingSystem -Windows) { $homeDirectory = Get-EnvironmentVariable USERPROFILE - - # Define .devsetup folder path - $devSetupPath = Join-Path -Path $homeDirectory -ChildPath "devsetup" + } elseif (Test-OperatingSystem -Linux) { + $homeDirectory = Get-EnvironmentVariable HOME + } elseif (Test-OperatingSystem -MacOS) { + $homeDirectory = Get-EnvironmentVariable HOME + } - return $devSetupPath + # Define .devsetup folder path + $devSetupPath = Join-Path -Path $homeDirectory -ChildPath "devsetup" + return $devSetupPath } \ No newline at end of file diff --git a/DevSetup/Private/Utils/Get-DevSetupVersion.ps1 b/DevSetup/Private/Utils/Get-DevSetupVersion.ps1 index 9c71bf2..90d4a48 100644 --- a/DevSetup/Private/Utils/Get-DevSetupVersion.ps1 +++ b/DevSetup/Private/Utils/Get-DevSetupVersion.ps1 @@ -85,13 +85,14 @@ Function Get-DevSetupVersion { return $null } - $release = Get-GitHubRelease -Uri $projectUri + $release = (Get-GitHubRelease -Uri $projectUri | Select-Object -First 1) if (-not $release -or -not $release.tag_name) { Write-Error "Failed to retrieve latest release information from GitHub." return $null } # Remove 'v' prefix if present in tag name + Write-Host $release.tag_name $versionString = $release.tag_name -replace '^v', '' $versionObject = [Version]::new($versionString) return $versionObject diff --git a/DevSetup/Private/Utils/Initialize-DevSetupEnvs.Tests.ps1 b/DevSetup/Private/Utils/Initialize-DevSetupEnvs.Tests.ps1 index 643628f..0b5b19b 100644 --- a/DevSetup/Private/Utils/Initialize-DevSetupEnvs.Tests.ps1 +++ b/DevSetup/Private/Utils/Initialize-DevSetupEnvs.Tests.ps1 @@ -6,6 +6,8 @@ BeforeAll { . $PSScriptRoot\Write-StatusMessage.ps1 . $PSScriptRoot\Optimize-DevSetupEnvs.ps1 . $PSScriptRoot\Get-DevSetupEnvPath.ps1 + . $PSScriptRoot\Get-DevSetupLocalEnvPath.ps1 + . $PSScriptRoot\Get-DevSetupCommunityEnvPath.ps1 . $PSScriptRoot\Get-DevSetupManifest.ps1 Mock Get-DevSetupEnvPath { "TestDrive:\DevSetupEnvs" } Mock Get-DevSetupManifest { diff --git a/DevSetup/Public/Use-DevSetup.ps1 b/DevSetup/Public/Use-DevSetup.ps1 index 71f6379..df02c7e 100644 --- a/DevSetup/Public/Use-DevSetup.ps1 +++ b/DevSetup/Public/Use-DevSetup.ps1 @@ -121,16 +121,36 @@ Function Use-DevSetup { [switch]$Install, [Parameter(Mandatory = $true, ParameterSetName = "Update")] + [Parameter(Mandatory = $true, ParameterSetName = "UpdateMain")] + [Parameter(Mandatory = $true, ParameterSetName = "UpdateDevelop")] + [Parameter(Mandatory = $true, ParameterSetName = "UpdateVersion")] [switch]$Update, + [Parameter(Mandatory = $true, ParameterSetName = "UpdateMain")] + [switch]$Main, + [Parameter(Mandatory = $true, ParameterSetName = "UpdateDevelop")] + [switch]$Develop, + [Parameter(Mandatory = $true, ParameterSetName = "UpdateVersion")] + [string]$Version, [Parameter(Mandatory = $true, ParameterSetName = "Init")] [switch]$Init, [Parameter(Mandatory = $true, ParameterSetName = "Export")] + [Parameter(Mandatory = $true, ParameterSetName = "ExportPath")] [switch]$Export, [Parameter(Mandatory = $true, ParameterSetName = "List")] + [Parameter(Mandatory = $true, ParameterSetName = "ListPlatform")] + [Parameter(Mandatory = $true, ParameterSetName = "ListProvider")] + [Parameter(Mandatory = $true, ParameterSetName = "ListProviderPlatform")] [switch]$List, + [Parameter(Mandatory = $true, ParameterSetName = "ListPlatform")] + [Parameter(Mandatory = $true, ParameterSetName = "ListProviderPlatform")] + [ValidateSet("current", "all", "Windows", "Linux", "macOS")] + [string]$Platform, + [Parameter(Mandatory = $true, ParameterSetName = "ListProvider")] + [Parameter(Mandatory = $true, ParameterSetName = "ListProviderPlatform")] + [string]$Provider, [Parameter(Mandatory = $true, ParameterSetName = "Uninstall")] [switch]$Uninstall, @@ -144,10 +164,8 @@ Function Use-DevSetup { [string]$Url, [Parameter(Mandatory = $true, ParameterSetName = "InstallPath")] - [string]$Path, - - [Parameter(Mandatory = $false, ParameterSetName = "List")] - [string]$Platform = "current" + [Parameter(Mandatory = $true, ParameterSetName = "ExportPath")] + [string]$Path ) try { @@ -158,16 +176,7 @@ Function Use-DevSetup { function Repeat-Char($char, $count) { -join (1..$count | ForEach-Object { $char }) } # Display fancy action header - #Write-Host "" - #Write-Host "+===============================================================================+" -ForegroundColor Cyan - #Write-Host "|" -ForegroundColor Cyan -NoNewline - #Write-Host " DEVSETUP " -ForegroundColor Yellow -NoNewline - #Write-Host "|" -ForegroundColor Cyan - #Write-Host "|" -ForegroundColor Cyan -NoNewline - #Write-Host " Development Environment Manager " -ForegroundColor White -NoNewline - #Write-Host "|" -ForegroundColor Cyan - #Write-Host "+===============================================================================+" -ForegroundColor Cyan -# Define box drawing characters using [char] codes + # Define box drawing characters using [char] codes $b = [char]0x2588 # █ (full block) $tl = [char]0x2554 # ╔ (top-left) $tr = [char]0x2557 # ╗ (top-right) @@ -208,7 +217,6 @@ Function Use-DevSetup { Write-Host "$b$b$b$b$b$b" -ForegroundColor White -NoNewLine Write-Host "$tr" (Repeat-Char " " 24) "$v" -ForegroundColor Cyan - #Write-Host "$v $b$b$tl$h$h$b$b$tr$b$b$tl$h$h$h$h$br$b$b$v $b$b$v$b$b$tl$h$h$h$h$br$b$b$tl$h$h$h$h$br$bl$h$h$b$b$tl$h$h$br$b$b$v $b$b$v$b$b$tl$h$h$b$b$tr $v" -ForegroundColor Cyan Write-Host "$v" (Repeat-Char " " 25) -ForegroundColor Cyan -NoNewLine Write-Host "$b$b" -ForegroundColor White -NoNewLine Write-Host "$tl$h$h" -ForegroundColor Cyan -NoNewLine @@ -235,7 +243,6 @@ Function Use-DevSetup { Write-Host "$b$b" -ForegroundColor White -NoNewLine Write-Host "$tr" (Repeat-Char " " 23) "$v" -ForegroundColor Cyan - #Write-Host "$v $b$b$v $b$b$v$b$b$b$b$b$tr $b$b$v $b$b$v$b$b$b$b$b$b$b$tr$b$b$b$b$b$tr $b$b$v $b$b$v $b$b$v$b$b$b$b$b$b$tl$br $v" -ForegroundColor Cyan Write-Host "$v" (Repeat-Char " " 25) -ForegroundColor Cyan -NoNewLine Write-Host "$b$b" -ForegroundColor White -NoNewLine Write-Host "$v " -ForegroundColor Cyan -NoNewLine @@ -260,7 +267,6 @@ Function Use-DevSetup { Write-Host "$b$b$b$b$b$b" -ForegroundColor White -NoNewLine Write-Host "$tl$br" (Repeat-Char " " 23) "$v" -ForegroundColor Cyan - #Write-Host "$v $b$b$v $b$b$v$b$b$tl$h$h$br $bl$b$b$tr $b$b$tl$br$bl$h$h$h$h$b$b$v$b$b$tl$h$h$br $b$b$v $b$b$v $b$b$v$b$b$tl$h$h$h$br $v" -ForegroundColor Cyan Write-Host "$v" (Repeat-Char " " 25) -ForegroundColor Cyan -NoNewLine Write-Host "$b$b" -ForegroundColor White -NoNewLine Write-Host "$v " -ForegroundColor Cyan -NoNewLine @@ -285,7 +291,6 @@ Function Use-DevSetup { Write-Host "$b$b" -ForegroundColor White -NoNewLine Write-Host "$tl$h$h$h$br" (Repeat-Char " " 24) "$v" -ForegroundColor Cyan - #Write-Host "$v $b$b$b$b$b$b$tl$br$b$b$b$b$b$b$b$tr $bl$b$b$b$b$tl$br $b$b$b$b$b$b$b$v$b$b$b$b$b$b$b$tr $b$b$v $bl$b$b$b$b$b$b$tl$br$b$b$v $v" -ForegroundColor Cyan Write-Host "$v" (Repeat-Char " " 25) -ForegroundColor Cyan -NoNewLine Write-Host "$b$b$b$b$b$b" -ForegroundColor White -NoNewLine Write-Host "$tl$br" -ForegroundColor Cyan -NoNewLine @@ -317,14 +322,21 @@ Function Use-DevSetup { $actionDisplay = switch ($selectedAction) { - 'install' { ">> INSTALLING Development Environment" } - 'installpath' { ">> INSTALLING Development Environment From Path" } - 'installurl' { ">> INSTALLING Development Environment From Url" } - 'update' { ">> UPDATING DevSetup System" } - 'init' { ">> INITIALIZING DevSetup System" } - 'export' { ">> EXPORTING Current Configuration" } - 'list' { ">> LISTING Available Environments" } - 'uninstall' { ">> UNINSTALLING Development Environment" } + 'install' { ">> INSTALLING Development Environment" } + 'installpath' { ">> INSTALLING Development Environment From Path" } + 'installurl' { ">> INSTALLING Development Environment From Url" } + 'update' { ">> UPDATING DevSetup System" } + 'updatemain' { ">> UPDATING DevSetup System to main" } + 'updatedevelop' { ">> UPDATING DevSetup System to develop" } + 'updateversion' { ">> UPDATING DevSetup System to version $Version" } + 'init' { ">> INITIALIZING DevSetup System" } + 'export' { ">> EXPORTING Current Configuration" } + 'exportpath' { ">> EXPORTING Current Configuration" } + 'list' { ">> LISTING Available Environments" } + 'listprovider' { ">> LISTING Available Environments From Provider" } + 'listplatform' { ">> LISTING Available Environments From Platform" } + 'listproviderplatform' { ">> LISTING Available Environments From Provider and Platform" } + 'uninstall' { ">> UNINSTALLING Development Environment" } } $paddedAction = $actionDisplay.PadLeft(($actionDisplay.Length + 118) / 2).PadRight(118) @@ -341,24 +353,35 @@ Function Use-DevSetup { $ParameterCopy.Remove('Install') Install-DevSetupEnv @ParameterCopy } - 'update' { + {$_ -eq 'update' -or $_ -eq 'updatemain' -or $_ -eq 'updatedevelop' -or $_ -eq 'updateversion'} { Write-Host "Updating devsetup system..." -ForegroundColor Yellow - Update-DevSetup | Out-Null + $ParameterCopy = [hashtable]$PSBoundParameters + $ParameterCopy.Remove('Update') + if($_ -eq 'update') { + $ParameterCopy['Latest'] = $true + } + Update-DevSetup @ParameterCopy | Out-Null } 'init' { Write-Host "Initializing DevSetup system..." -ForegroundColor Yellow Initialize-DevSetup | Out-Null } - 'export' { + { $_ -eq 'export' -or $_ -eq 'exportpath' } { Write-Host "Exporting current development environment..." -ForegroundColor Yellow - Export-DevSetupEnv -Name $Name + $ParameterCopy = [hashtable]$PSBoundParameters + $ParameterCopy.Remove('Export') + Export-DevSetupEnv @ParameterCopy } - 'list' { - Show-DevSetupEnvList -Platform $Platform + { $_ -eq 'list' -or $_ -eq 'listplatform' -or $_ -eq 'listprovider' -or $_ -eq 'listproviderplatform' } { + $ParameterCopy = [hashtable]$PSBoundParameters + $ParameterCopy.Remove('List') + Show-DevSetupEnvList @ParameterCopy } 'uninstall' { Write-Host "Uninstalling development environment..." -ForegroundColor Yellow - Uninstall-DevSetupEnv -Name $Name + $ParameterCopy = [hashtable]$PSBoundParameters + $ParameterCopy.Remove('Uninstall') + Uninstall-DevSetupEnv @ParameterCopy } } From a64a7c8aeceb0000dece963ab3ae054c7b0fd3d1 Mon Sep 17 00:00:00 2001 From: kormic911 Date: Thu, 4 Sep 2025 16:59:51 -0500 Subject: [PATCH 5/7] Validating test cases and fixing some copilot suggested corrections --- .../Core/Install-CoreDependencies.Tests.ps1 | 2 ++ .../Providers/Homebrew/Install-Homebrew.ps1 | 23 +++++++++++++++++++ .../Test-PowershellModuleInstalled.Tests.ps1 | 4 +++- .../Test-PowershellModuleInstalled.ps1 | 7 +++++- .../Private/Utils/Get-DevSetupPath.Tests.ps1 | 2 ++ .../Private/Utils/Get-DevSetupVersion.ps1 | 2 +- 6 files changed, 37 insertions(+), 3 deletions(-) create mode 100644 DevSetup/Private/Providers/Homebrew/Install-Homebrew.ps1 diff --git a/DevSetup/Private/Providers/Core/Install-CoreDependencies.Tests.ps1 b/DevSetup/Private/Providers/Core/Install-CoreDependencies.Tests.ps1 index f5b7300..8673921 100644 --- a/DevSetup/Private/Providers/Core/Install-CoreDependencies.Tests.ps1 +++ b/DevSetup/Private/Providers/Core/Install-CoreDependencies.Tests.ps1 @@ -6,6 +6,7 @@ BeforeAll { . $PSScriptRoot\..\..\..\..\DevSetup\Private\Providers\Chocolatey\Install-Chocolatey.ps1 . $PSScriptRoot\..\..\..\..\DevSetup\Private\Providers\Chocolatey\Install-ChocolateyPackage.ps1 . $PSScriptRoot\..\..\..\..\DevSetup\Private\Providers\Scoop\Install-Scoop.ps1 + . $PSScriptRoot\..\..\..\..\DevSetup\Private\Providers\Homebrew\Install-Homebrew.ps1 . $PSScriptRoot\..\..\..\..\DevSetup\Private\Utils\Test-RunningAsAdmin.ps1 . $PSScriptRoot\..\..\..\..\DevSetup\Private\Utils\Test-OperatingSystem.ps1 . $PSScriptRoot\..\..\..\..\DevSetup\Private\Utils\Write-StatusMessage.ps1 @@ -14,6 +15,7 @@ BeforeAll { Mock Write-Warning { } Mock Write-Error { } Mock Test-RunningAsAdmin { return $true } + Mock Install-Homebrew { return $true } } Describe "Install-CoreDependencies" { diff --git a/DevSetup/Private/Providers/Homebrew/Install-Homebrew.ps1 b/DevSetup/Private/Providers/Homebrew/Install-Homebrew.ps1 new file mode 100644 index 0000000..b11664a --- /dev/null +++ b/DevSetup/Private/Providers/Homebrew/Install-Homebrew.ps1 @@ -0,0 +1,23 @@ +Function Install-Homebrew { + [CmdletBinding()] + Param( + ) + + # Install Homebrew + Write-StatusMessage "- Installing Homebrew package manager" -ForegroundColor Gray -Indent 2 -Width 77 -NoNewline + if (-not (Get-Command "brew" -ErrorAction SilentlyContinue)) { + # Installation command for Homebrew (Linux/Mac) + $installCmd = 'NONINTERACTIVE=1 /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"' + (bash -c "$installCmd") *> $null + if (-not (Get-Command "brew" -ErrorAction SilentlyContinue)) { + Write-StatusMessage "[FAILED]" -ForegroundColor Red + return $false + } else { + Write-StatusMessage "[OK]" -ForegroundColor Green + return $true + } + } else { + Write-StatusMessage "[OK]" -ForegroundColor Green + return $true + } +} \ No newline at end of file diff --git a/DevSetup/Private/Providers/Powershell/Test-PowershellModuleInstalled.Tests.ps1 b/DevSetup/Private/Providers/Powershell/Test-PowershellModuleInstalled.Tests.ps1 index 4c18e17..9a2dab5 100644 --- a/DevSetup/Private/Providers/Powershell/Test-PowershellModuleInstalled.Tests.ps1 +++ b/DevSetup/Private/Providers/Powershell/Test-PowershellModuleInstalled.Tests.ps1 @@ -1,6 +1,8 @@ BeforeAll { . $PSScriptRoot\Test-PowershellModuleInstalled.ps1 - . $PSScriptRoot\..\..\..\..\DevSetup\Private\Enums\InstalledState.ps1 + . $PSScriptRoot\..\..\..\..\DevSetup\Private\Enums\InstalledState.ps1 + . $PSScriptRoot\..\..\..\..\DevSetup\Private\Utils\Test-OperatingSystem.ps1 + Mock Test-OperatingSystem { $true } } Describe "Test-PowershellModuleInstalled" { diff --git a/DevSetup/Private/Providers/Powershell/Test-PowershellModuleInstalled.ps1 b/DevSetup/Private/Providers/Powershell/Test-PowershellModuleInstalled.ps1 index 9e41077..5b14c5f 100644 --- a/DevSetup/Private/Providers/Powershell/Test-PowershellModuleInstalled.ps1 +++ b/DevSetup/Private/Providers/Powershell/Test-PowershellModuleInstalled.ps1 @@ -103,9 +103,14 @@ Function Test-PowershellModuleInstalled { # $env:ProgramFiles\PowerShell\Modules # AllUsers ps7 (linux/macos) # $env:HOME/.local/share/powershell/Modules + if((Test-OperatingSystem -Windows)) { + $SearchPath = $env:USERPROFILE + } else { + $SearchPath = $env:HOME + } $InstallPaths = @( $env:PSModulePath -split ([System.IO.Path]::PathSeparator) | ForEach-Object { - if($_ -match [regex]::Escape("$HOME")) { + if($_ -match [regex]::Escape("$SearchPath")) { @{ Path = $_; Scope = "CurrentUser" } } else { @{ Path = $_; Scope = "AllUsers" } diff --git a/DevSetup/Private/Utils/Get-DevSetupPath.Tests.ps1 b/DevSetup/Private/Utils/Get-DevSetupPath.Tests.ps1 index 913a919..f8a8fc0 100644 --- a/DevSetup/Private/Utils/Get-DevSetupPath.Tests.ps1 +++ b/DevSetup/Private/Utils/Get-DevSetupPath.Tests.ps1 @@ -1,6 +1,8 @@ BeforeAll { . $PSScriptRoot\Get-DevSetupPath.ps1 . $PSScriptRoot\Get-EnvironmentVariable.ps1 + . $PSScriptRoot\Test-OperatingSystem.ps1 + Mock Test-OperatingSystem { $true } } Describe "Get-DevSetupPath" { diff --git a/DevSetup/Private/Utils/Get-DevSetupVersion.ps1 b/DevSetup/Private/Utils/Get-DevSetupVersion.ps1 index 90d4a48..00411f6 100644 --- a/DevSetup/Private/Utils/Get-DevSetupVersion.ps1 +++ b/DevSetup/Private/Utils/Get-DevSetupVersion.ps1 @@ -92,7 +92,7 @@ Function Get-DevSetupVersion { } # Remove 'v' prefix if present in tag name - Write-Host $release.tag_name + #Write-Host $release.tag_name $versionString = $release.tag_name -replace '^v', '' $versionObject = [Version]::new($versionString) return $versionObject From 55783ab05c563587a3286815469f878693b3f9a0 Mon Sep 17 00:00:00 2001 From: kormic911 Date: Thu, 4 Sep 2025 17:04:16 -0500 Subject: [PATCH 6/7] Update DevSetup/Private/Utils/Get-DevSetupVersion.ps1 Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- DevSetup/Private/Utils/Get-DevSetupVersion.ps1 | 1 - 1 file changed, 1 deletion(-) diff --git a/DevSetup/Private/Utils/Get-DevSetupVersion.ps1 b/DevSetup/Private/Utils/Get-DevSetupVersion.ps1 index 00411f6..88caecc 100644 --- a/DevSetup/Private/Utils/Get-DevSetupVersion.ps1 +++ b/DevSetup/Private/Utils/Get-DevSetupVersion.ps1 @@ -92,7 +92,6 @@ Function Get-DevSetupVersion { } # Remove 'v' prefix if present in tag name - #Write-Host $release.tag_name $versionString = $release.tag_name -replace '^v', '' $versionObject = [Version]::new($versionString) return $versionObject From 49b3815bdaf1c14f728a9ccaaaeffb987d1d25ce Mon Sep 17 00:00:00 2001 From: kormic911 Date: Thu, 4 Sep 2025 17:05:34 -0500 Subject: [PATCH 7/7] Update DevSetup/Private/Providers/Powershell/Test-PowershellModuleInstalled.ps1 Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- .../Providers/Powershell/Test-PowershellModuleInstalled.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DevSetup/Private/Providers/Powershell/Test-PowershellModuleInstalled.ps1 b/DevSetup/Private/Providers/Powershell/Test-PowershellModuleInstalled.ps1 index 5b14c5f..f5e1614 100644 --- a/DevSetup/Private/Providers/Powershell/Test-PowershellModuleInstalled.ps1 +++ b/DevSetup/Private/Providers/Powershell/Test-PowershellModuleInstalled.ps1 @@ -130,7 +130,7 @@ Function Test-PowershellModuleInstalled { if($PSBoundParameters.ContainsKey('Scope')) { $InstallPaths | ForEach-Object { - if ($module.Path -like "$($_.Path)*") { + if ($module.Path -like "$($_.Path)$([System.IO.Path]::DirectorySeparatorChar)*") { if ($_.Scope -eq $Scope) { $installedState += [InstalledState]::GlobalVersionMet }