From 84f3925e4ee1ed4580d60989e1e9875bb2c86d4f Mon Sep 17 00:00:00 2001 From: James Brundage <+@noreply.github.com> Date: Mon, 31 Mar 2025 16:28:24 -0700 Subject: [PATCH 01/30] feat: Neocities module scaffolding and workflow ( Fixes #1, Fixes #6, Fixes #7 ) --- .github/workflows/Build.yml | 512 +++++++++++++++++++++ Build/GitHub/Jobs/BuildNeocities.psd1 | 39 ++ Build/GitHub/Steps/PublishTestResults.psd1 | 10 + Build/Neocities.ezout.ps1 | 39 ++ Neocities.ps.psm1 | 26 ++ 5 files changed, 626 insertions(+) create mode 100644 .github/workflows/Build.yml create mode 100644 Build/GitHub/Jobs/BuildNeocities.psd1 create mode 100644 Build/GitHub/Steps/PublishTestResults.psd1 create mode 100644 Build/Neocities.ezout.ps1 create mode 100644 Neocities.ps.psm1 diff --git a/.github/workflows/Build.yml b/.github/workflows/Build.yml new file mode 100644 index 0000000..1444e3f --- /dev/null +++ b/.github/workflows/Build.yml @@ -0,0 +1,512 @@ + +name: Build Module +on: + push: + pull_request: + workflow_dispatch: +jobs: + TestPowerShellOnLinux: + runs-on: ubuntu-latest + steps: + - name: InstallPester + id: InstallPester + shell: pwsh + run: | + $Parameters = @{} + $Parameters.PesterMaxVersion = ${env:PesterMaxVersion} + foreach ($k in @($parameters.Keys)) { + if ([String]::IsNullOrEmpty($parameters[$k])) { + $parameters.Remove($k) + } + } + Write-Host "::debug:: InstallPester $(@(foreach ($p in $Parameters.GetEnumerator()) {'-' + $p.Key + ' ' + $p.Value}) -join ' ')" + & {<# + .Synopsis + Installs Pester + .Description + Installs Pester + #> + param( + # The maximum pester version. Defaults to 4.99.99. + [string] + $PesterMaxVersion = '4.99.99' + ) + [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 + Install-Module -Name Pester -Repository PSGallery -Force -Scope CurrentUser -MaximumVersion $PesterMaxVersion -SkipPublisherCheck -AllowClobber + Import-Module Pester -Force -PassThru -MaximumVersion $PesterMaxVersion} @Parameters + - name: Check out repository + uses: actions/checkout@v4 + - name: RunPester + id: RunPester + shell: pwsh + run: | + $Parameters = @{} + $Parameters.ModulePath = ${env:ModulePath} + $Parameters.PesterMaxVersion = ${env:PesterMaxVersion} + $Parameters.NoCoverage = ${env:NoCoverage} + $Parameters.NoCoverage = $parameters.NoCoverage -match 'true'; + foreach ($k in @($parameters.Keys)) { + if ([String]::IsNullOrEmpty($parameters[$k])) { + $parameters.Remove($k) + } + } + Write-Host "::debug:: RunPester $(@(foreach ($p in $Parameters.GetEnumerator()) {'-' + $p.Key + ' ' + $p.Value}) -join ' ')" + & {<# + .Synopsis + Runs Pester + .Description + Runs Pester tests after importing a PowerShell module + #> + param( + # The module path. If not provided, will default to the second half of the repository ID. + [string] + $ModulePath, + # The Pester max version. By default, this is pinned to 4.99.99. + [string] + $PesterMaxVersion = '4.99.99', + + # If set, will not collect code coverage. + [switch] + $NoCoverage + ) + + $global:ErrorActionPreference = 'continue' + $global:ProgressPreference = 'silentlycontinue' + + $orgName, $moduleName = $env:GITHUB_REPOSITORY -split "/" + if (-not $ModulePath) { $ModulePath = ".\$moduleName.psd1" } + $importedPester = Import-Module Pester -Force -PassThru -MaximumVersion $PesterMaxVersion + $importedModule = Import-Module $ModulePath -Force -PassThru + $importedPester, $importedModule | Out-Host + + $codeCoverageParameters = @{ + CodeCoverage = "$($importedModule | Split-Path)\*-*.ps1" + CodeCoverageOutputFile = ".\$moduleName.Coverage.xml" + } + + if ($NoCoverage) { + $codeCoverageParameters = @{} + } + + + $result = + Invoke-Pester -PassThru -Verbose -OutputFile ".\$moduleName.TestResults.xml" -OutputFormat NUnitXml @codeCoverageParameters + + if ($result.FailedCount -gt 0) { + "::debug:: $($result.FailedCount) tests failed" + foreach ($r in $result.TestResult) { + if (-not $r.Passed) { + "::error::$($r.describe, $r.context, $r.name -join ' ') $($r.FailureMessage)" + } + } + throw "::error:: $($result.FailedCount) tests failed" + } + } @Parameters + - name: PublishTestResults + uses: actions/upload-artifact@v3 + with: + name: PesterResults + path: '**.TestResults.xml' + if: ${{always()}} + TagReleaseAndPublish: + runs-on: ubuntu-latest + if: ${{ success() }} + steps: + - name: Check out repository + uses: actions/checkout@v2 + - name: TagModuleVersion + id: TagModuleVersion + shell: pwsh + run: | + $Parameters = @{} + $Parameters.ModulePath = ${env:ModulePath} + $Parameters.UserEmail = ${env:UserEmail} + $Parameters.UserName = ${env:UserName} + $Parameters.TagVersionFormat = ${env:TagVersionFormat} + $Parameters.TagAnnotationFormat = ${env:TagAnnotationFormat} + foreach ($k in @($parameters.Keys)) { + if ([String]::IsNullOrEmpty($parameters[$k])) { + $parameters.Remove($k) + } + } + Write-Host "::debug:: TagModuleVersion $(@(foreach ($p in $Parameters.GetEnumerator()) {'-' + $p.Key + ' ' + $p.Value}) -join ' ')" + & {param( + [string] + $ModulePath, + + # The user email associated with a git commit. + [string] + $UserEmail, + + # The user name associated with a git commit. + [string] + $UserName, + + # The tag version format (default value: 'v$(imported.Version)') + # This can expand variables. $imported will contain the imported module. + [string] + $TagVersionFormat = 'v$($imported.Version)', + + # The tag version format (default value: '$($imported.Name) $(imported.Version)') + # This can expand variables. $imported will contain the imported module. + [string] + $TagAnnotationFormat = '$($imported.Name) $($imported.Version)' + ) + + + $gitHubEvent = if ($env:GITHUB_EVENT_PATH) { + [IO.File]::ReadAllText($env:GITHUB_EVENT_PATH) | ConvertFrom-Json + } else { $null } + + + @" + ::group::GitHubEvent + $($gitHubEvent | ConvertTo-Json -Depth 100) + ::endgroup:: + "@ | Out-Host + + if (-not ($gitHubEvent.head_commit.message -match "Merge Pull Request #(?\d+)") -and + (-not $gitHubEvent.psobject.properties['inputs'])) { + "::warning::Pull Request has not merged, skipping Tagging" | Out-Host + return + } + + + + $imported = + if (-not $ModulePath) { + $orgName, $moduleName = $env:GITHUB_REPOSITORY -split "/" + Import-Module ".\$moduleName.psd1" -Force -PassThru -Global + } else { + Import-Module $modulePath -Force -PassThru -Global + } + + if (-not $imported) { return } + + $targetVersion =$ExecutionContext.InvokeCommand.ExpandString($TagVersionFormat) + $existingTags = git tag --list + + @" + Target Version: $targetVersion + + Existing Tags: + $($existingTags -join [Environment]::NewLine) + "@ | Out-Host + + $versionTagExists = $existingTags | Where-Object { $_ -match $targetVersion } + + if ($versionTagExists) { + "::warning::Version $($versionTagExists)" + return + } + + if (-not $UserName) { $UserName = $env:GITHUB_ACTOR } + if (-not $UserEmail) { $UserEmail = "$UserName@github.com" } + git config --global user.email $UserEmail + git config --global user.name $UserName + + git tag -a $targetVersion -m $ExecutionContext.InvokeCommand.ExpandString($TagAnnotationFormat) + git push origin --tags + + if ($env:GITHUB_ACTOR) { + exit 0 + }} @Parameters + - name: ReleaseModule + id: ReleaseModule + shell: pwsh + run: | + $Parameters = @{} + $Parameters.ModulePath = ${env:ModulePath} + $Parameters.UserEmail = ${env:UserEmail} + $Parameters.UserName = ${env:UserName} + $Parameters.TagVersionFormat = ${env:TagVersionFormat} + $Parameters.ReleaseNameFormat = ${env:ReleaseNameFormat} + $Parameters.ReleaseAsset = ${env:ReleaseAsset} + $Parameters.ReleaseAsset = $parameters.ReleaseAsset -split ';' -replace '^[''"]' -replace '[''"]$' + foreach ($k in @($parameters.Keys)) { + if ([String]::IsNullOrEmpty($parameters[$k])) { + $parameters.Remove($k) + } + } + Write-Host "::debug:: ReleaseModule $(@(foreach ($p in $Parameters.GetEnumerator()) {'-' + $p.Key + ' ' + $p.Value}) -join ' ')" + & {param( + [string] + $ModulePath, + + # The user email associated with a git commit. + [string] + $UserEmail, + + # The user name associated with a git commit. + [string] + $UserName, + + # The tag version format (default value: 'v$(imported.Version)') + # This can expand variables. $imported will contain the imported module. + [string] + $TagVersionFormat = 'v$($imported.Version)', + + # The release name format (default value: '$($imported.Name) $($imported.Version)') + [string] + $ReleaseNameFormat = '$($imported.Name) $($imported.Version)', + + # Any assets to attach to the release. Can be a wildcard or file name. + [string[]] + $ReleaseAsset + ) + + + $gitHubEvent = if ($env:GITHUB_EVENT_PATH) { + [IO.File]::ReadAllText($env:GITHUB_EVENT_PATH) | ConvertFrom-Json + } else { $null } + + + @" + ::group::GitHubEvent + $($gitHubEvent | ConvertTo-Json -Depth 100) + ::endgroup:: + "@ | Out-Host + + if (-not ($gitHubEvent.head_commit.message -match "Merge Pull Request #(?\d+)") -and + (-not $gitHubEvent.psobject.properties['inputs'])) { + "::warning::Pull Request has not merged, skipping GitHub release" | Out-Host + return + } + + + + $imported = + if (-not $ModulePath) { + $orgName, $moduleName = $env:GITHUB_REPOSITORY -split "/" + Import-Module ".\$moduleName.psd1" -Force -PassThru -Global + } else { + Import-Module $modulePath -Force -PassThru -Global + } + + if (-not $imported) { return } + + $targetVersion =$ExecutionContext.InvokeCommand.ExpandString($TagVersionFormat) + $targetReleaseName = $targetVersion + $releasesURL = 'https://api.github.com/repos/${{github.repository}}/releases' + "Release URL: $releasesURL" | Out-Host + $listOfReleases = Invoke-RestMethod -Uri $releasesURL -Method Get -Headers @{ + "Accept" = "application/vnd.github.v3+json" + "Authorization" = 'Bearer ${{ secrets.GITHUB_TOKEN }}' + } + + $releaseExists = $listOfReleases | Where-Object tag_name -eq $targetVersion + + if ($releaseExists) { + "::warning::Release '$($releaseExists.Name )' Already Exists" | Out-Host + $releasedIt = $releaseExists + } else { + $releasedIt = Invoke-RestMethod -Uri $releasesURL -Method Post -Body ( + [Ordered]@{ + owner = '${{github.owner}}' + repo = '${{github.repository}}' + tag_name = $targetVersion + name = $ExecutionContext.InvokeCommand.ExpandString($ReleaseNameFormat) + body = + if ($env:RELEASENOTES) { + $env:RELEASENOTES + } elseif ($imported.PrivateData.PSData.ReleaseNotes) { + $imported.PrivateData.PSData.ReleaseNotes + } else { + "$($imported.Name) $targetVersion" + } + draft = if ($env:RELEASEISDRAFT) { [bool]::Parse($env:RELEASEISDRAFT) } else { $false } + prerelease = if ($env:PRERELEASE) { [bool]::Parse($env:PRERELEASE) } else { $false } + } | ConvertTo-Json + ) -Headers @{ + "Accept" = "application/vnd.github.v3+json" + "Content-type" = "application/json" + "Authorization" = 'Bearer ${{ secrets.GITHUB_TOKEN }}' + } + } + + + + + + if (-not $releasedIt) { + throw "Release failed" + } else { + $releasedIt | Out-Host + } + + $releaseUploadUrl = $releasedIt.upload_url -replace '\{.+$' + + if ($ReleaseAsset) { + $fileList = Get-ChildItem -Recurse + $filesToRelease = + @(:nextFile foreach ($file in $fileList) { + foreach ($relAsset in $ReleaseAsset) { + if ($relAsset -match '[\*\?]') { + if ($file.Name -like $relAsset) { + $file; continue nextFile + } + } elseif ($file.Name -eq $relAsset -or $file.FullName -eq $relAsset) { + $file; continue nextFile + } + } + }) + + $releasedFiles = @{} + foreach ($file in $filesToRelease) { + if ($releasedFiles[$file.Name]) { + Write-Warning "Already attached file $($file.Name)" + continue + } else { + $fileBytes = [IO.File]::ReadAllBytes($file.FullName) + $releasedFiles[$file.Name] = + Invoke-RestMethod -Uri "${releaseUploadUrl}?name=$($file.Name)" -Headers @{ + "Accept" = "application/vnd.github+json" + "Authorization" = 'Bearer ${{ secrets.GITHUB_TOKEN }}' + } -Body $fileBytes -ContentType Application/octet-stream + $releasedFiles[$file.Name] + } + } + + "Attached $($releasedFiles.Count) file(s) to release" | Out-Host + } + + + + } @Parameters + - name: PublishPowerShellGallery + id: PublishPowerShellGallery + shell: pwsh + run: | + $Parameters = @{} + $Parameters.ModulePath = ${env:ModulePath} + $Parameters.Exclude = ${env:Exclude} + $Parameters.Exclude = $parameters.Exclude -split ';' -replace '^[''"]' -replace '[''"]$' + foreach ($k in @($parameters.Keys)) { + if ([String]::IsNullOrEmpty($parameters[$k])) { + $parameters.Remove($k) + } + } + Write-Host "::debug:: PublishPowerShellGallery $(@(foreach ($p in $Parameters.GetEnumerator()) {'-' + $p.Key + ' ' + $p.Value}) -join ' ')" + & {param( + [string] + $ModulePath, + + [string[]] + $Exclude = @('*.png', '*.mp4', '*.jpg','*.jpeg', '*.gif', 'docs[/\]*') + ) + + $gitHubEvent = if ($env:GITHUB_EVENT_PATH) { + [IO.File]::ReadAllText($env:GITHUB_EVENT_PATH) | ConvertFrom-Json + } else { $null } + + if (-not $Exclude) { + $Exclude = @('*.png', '*.mp4', '*.jpg','*.jpeg', '*.gif','docs[/\]*') + } + + + @" + ::group::GitHubEvent + $($gitHubEvent | ConvertTo-Json -Depth 100) + ::endgroup:: + "@ | Out-Host + + @" + ::group::PSBoundParameters + $($PSBoundParameters | ConvertTo-Json -Depth 100) + ::endgroup:: + "@ | Out-Host + + if (-not ($gitHubEvent.head_commit.message -match "Merge Pull Request #(?\d+)") -and + (-not $gitHubEvent.psobject.properties['inputs'])) { + "::warning::Pull Request has not merged, skipping Gallery Publish" | Out-Host + return + } + + + $imported = + if (-not $ModulePath) { + $orgName, $moduleName = $env:GITHUB_REPOSITORY -split "/" + Import-Module ".\$moduleName.psd1" -Force -PassThru -Global + } else { + Import-Module $modulePath -Force -PassThru -Global + } + + if (-not $imported) { return } + + $foundModule = try { Find-Module -Name $imported.Name -ErrorAction SilentlyContinue} catch {} + + if ($foundModule -and (([Version]$foundModule.Version) -ge ([Version]$imported.Version))) { + "::warning::Gallery Version of $moduleName is more recent ($($foundModule.Version) >= $($imported.Version))" | Out-Host + } else { + + $gk = '${{secrets.GALLERYKEY}}' + + $rn = Get-Random + $moduleTempFolder = Join-Path $pwd "$rn" + $moduleTempPath = Join-Path $moduleTempFolder $moduleName + New-Item -ItemType Directory -Path $moduleTempPath -Force | Out-Host + + Write-Host "Staging Directory: $ModuleTempPath" + + $imported | Split-Path | + Get-ChildItem -Force | + Where-Object Name -NE $rn | + Copy-Item -Destination $moduleTempPath -Recurse + + $moduleGitPath = Join-Path $moduleTempPath '.git' + Write-Host "Removing .git directory" + if (Test-Path $moduleGitPath) { + Remove-Item -Recurse -Force $moduleGitPath + } + + if ($Exclude) { + "::notice::Attempting to Exlcude $exclude" | Out-Host + Get-ChildItem $moduleTempPath -Recurse | + Where-Object { + foreach ($ex in $exclude) { + if ($_.FullName -like $ex) { + "::notice::Excluding $($_.FullName)" | Out-Host + return $true + } + } + } | + Remove-Item + } + + Write-Host "Module Files:" + Get-ChildItem $moduleTempPath -Recurse + Write-Host "Publishing $moduleName [$($imported.Version)] to Gallery" + Publish-Module -Path $moduleTempPath -NuGetApiKey $gk + if ($?) { + Write-Host "Published to Gallery" + } else { + Write-Host "Gallery Publish Failed" + exit 1 + } + } + } @Parameters + BuildNeocities: + runs-on: ubuntu-latest + if: ${{ success() }} + steps: + - name: Check out repository + uses: actions/checkout@v2 + - name: GitLogger + uses: GitLogging/GitLoggerAction@main + id: GitLogger + - name: Use PSSVG Action + uses: StartAutomating/PSSVG@main + id: PSSVG + - name: Use PipeScript Action + uses: StartAutomating/PipeScript@main + id: PipeScript + - name: UseEZOut + uses: StartAutomating/EZOut@master + - name: UseHelpOut + uses: StartAutomating/HelpOut@master + - name: Use PSJekyll Action + uses: PowerShellWeb/PSJekyll@main + id: PSJekyll +env: + REGISTRY: ghcr.io + IMAGE_NAME: ${{ github.repository }} diff --git a/Build/GitHub/Jobs/BuildNeocities.psd1 b/Build/GitHub/Jobs/BuildNeocities.psd1 new file mode 100644 index 0000000..8eaba5a --- /dev/null +++ b/Build/GitHub/Jobs/BuildNeocities.psd1 @@ -0,0 +1,39 @@ +@{ + "runs-on" = "ubuntu-latest" + if = '${{ success() }}' + steps = @( + @{ + name = 'Check out repository' + uses = 'actions/checkout@v2' + }, + @{ + name = 'GitLogger' + uses = 'GitLogging/GitLoggerAction@main' + id = 'GitLogger' + }, + @{ + name = 'Use PSSVG Action' + uses = 'StartAutomating/PSSVG@main' + id = 'PSSVG' + }, + @{ + name = 'Use PipeScript Action' + uses = 'StartAutomating/PipeScript@main' + id = 'PipeScript' + }, + 'RunEZOut', + 'RunHelpOut', + @{ + name = 'Use PSJekyll Action' + uses = 'PowerShellWeb/PSJekyll@main' + id = 'PSJekyll' + } + <#@{ + name = 'Run WebSocket (on branch)' + if = '${{github.ref_name != ''main''}}' + uses = './' + id = 'WebSocketAction' + },#> + # 'BuildAndPublishContainer' + ) +} \ No newline at end of file diff --git a/Build/GitHub/Steps/PublishTestResults.psd1 b/Build/GitHub/Steps/PublishTestResults.psd1 new file mode 100644 index 0000000..5b169ed --- /dev/null +++ b/Build/GitHub/Steps/PublishTestResults.psd1 @@ -0,0 +1,10 @@ +@{ + name = 'PublishTestResults' + uses = 'actions/upload-artifact@v3' + with = @{ + name = 'PesterResults' + path = '**.TestResults.xml' + } + if = '${{always()}}' +} + diff --git a/Build/Neocities.ezout.ps1 b/Build/Neocities.ezout.ps1 new file mode 100644 index 0000000..480ccb0 --- /dev/null +++ b/Build/Neocities.ezout.ps1 @@ -0,0 +1,39 @@ +#requires -Module EZOut +# Install-Module EZOut or https://github.com/StartAutomating/EZOut +$myFile = $MyInvocation.MyCommand.ScriptBlock.File +$myRoot = $myFile | Split-Path | Split-Path +$myModuleName = $myFile | Split-Path | Split-Path | Split-Path -Leaf +Push-Location $myRoot +$formatting = @( + # Add your own Write-FormatView here, + # or put them in a Formatting or Views directory + foreach ($potentialDirectory in 'Formatting','Views','Types') { + Join-Path $myRoot $potentialDirectory | + Get-ChildItem -ea ignore | + Import-FormatView -FilePath {$_.Fullname} + } +) + +$destinationRoot = $myRoot + +if ($formatting) { + $myFormatFilePath = Join-Path $destinationRoot "$myModuleName.format.ps1xml" + # You can also output to multiple paths by passing a hashtable to -OutputPath. + $formatting | Out-FormatData -Module $MyModuleName -OutputPath $myFormatFilePath +} + +$types = @( + # Add your own Write-TypeView statements here + # or declare them in the 'Types' directory + Join-Path $myRoot Types | + Get-Item -ea ignore | + Import-TypeView + +) + +if ($types) { + $myTypesFilePath = Join-Path $destinationRoot "$myModuleName.types.ps1xml" + # You can also output to multiple paths by passing a hashtable to -OutputPath. + $types | Out-TypeData -OutputPath $myTypesFilePath +} +Pop-Location diff --git a/Neocities.ps.psm1 b/Neocities.ps.psm1 new file mode 100644 index 0000000..562e155 --- /dev/null +++ b/Neocities.ps.psm1 @@ -0,0 +1,26 @@ +$commandsPath = Join-Path $PSScriptRoot Commands +[include('*-*')]$commandsPath + +$myModule = $MyInvocation.MyCommand.ScriptBlock.Module +$ExecutionContext.SessionState.PSVariable.Set($myModule.Name, $myModule) +$myModule.pstypenames.insert(0, $myModule.Name) + +New-PSDrive -Name $MyModule.Name -PSProvider FileSystem -Scope Global -Root $PSScriptRoot -ErrorAction Ignore + +if ($home) { + $MyModuleProfileDirectory = Join-Path ([Environment]::GetFolderPath("LocalApplicationData")) $MyModule.Name + if (-not (Test-Path $MyModuleProfileDirectory)) { + $null = New-Item -ItemType Directory -Path $MyModuleProfileDirectory -Force + } + New-PSDrive -Name "My$($MyModule.Name)" -PSProvider FileSystem -Scope Global -Root $MyModuleProfileDirectory -ErrorAction Ignore +} + +# Set a script variable of this, set to the module +# (so all scripts in this scope default to the correct `$this`) +$script:this = $myModule + +#region Custom +#endregion Custom + +Export-ModuleMember -Alias * -Function * -Variable $myModule.Name + From 1a087d0f0d608d0221f4537f8446bd619c5b8c2d Mon Sep 17 00:00:00 2001 From: StartAutomating Date: Mon, 31 Mar 2025 23:29:25 +0000 Subject: [PATCH 02/30] feat: Neocities module scaffolding and workflow ( Fixes #1, Fixes #6, Fixes #7 ) --- Neocities.psm1 | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 Neocities.psm1 diff --git a/Neocities.psm1 b/Neocities.psm1 new file mode 100644 index 0000000..41a1efb --- /dev/null +++ b/Neocities.psm1 @@ -0,0 +1,36 @@ +$commandsPath = Join-Path $PSScriptRoot Commands +:ToIncludeFiles foreach ($file in (Get-ChildItem -Path "$commandsPath" -Filter "*-*" -Recurse)) { + if ($file.Extension -ne '.ps1') { continue } # Skip if the extension is not .ps1 + foreach ($exclusion in '\.[^\.]+\.ps1$') { + if (-not $exclusion) { continue } + if ($file.Name -match $exclusion) { + continue ToIncludeFiles # Skip excluded files + } + } + . $file.FullName +} + +$myModule = $MyInvocation.MyCommand.ScriptBlock.Module +$ExecutionContext.SessionState.PSVariable.Set($myModule.Name, $myModule) +$myModule.pstypenames.insert(0, $myModule.Name) + +New-PSDrive -Name $MyModule.Name -PSProvider FileSystem -Scope Global -Root $PSScriptRoot -ErrorAction Ignore + +if ($home) { + $MyModuleProfileDirectory = Join-Path ([Environment]::GetFolderPath("LocalApplicationData")) $MyModule.Name + if (-not (Test-Path $MyModuleProfileDirectory)) { + $null = New-Item -ItemType Directory -Path $MyModuleProfileDirectory -Force + } + New-PSDrive -Name "My$($MyModule.Name)" -PSProvider FileSystem -Scope Global -Root $MyModuleProfileDirectory -ErrorAction Ignore +} + +# Set a script variable of this, set to the module +# (so all scripts in this scope default to the correct `$this`) +$script:this = $myModule + +#region Custom +#endregion Custom + +Export-ModuleMember -Alias * -Function * -Variable $myModule.Name + + From bd51585797dc835d01c9f8ff8d9d99722b9c20bc Mon Sep 17 00:00:00 2001 From: James Brundage <+@noreply.github.com> Date: Mon, 31 Mar 2025 16:30:51 -0700 Subject: [PATCH 03/30] feat: Neocities types and formatting ( Fixes #7 ) --- Types/neocities.file/get_CreatedAt.ps1 | 7 +++++++ Types/neocities.file/get_UpdatedAt.ps1 | 7 +++++++ Types/neocities.file/neocities.file.format.ps1 | 1 + Types/neocities.info/get_CreatedAt.ps1 | 7 +++++++ Types/neocities.info/get_UpdatedAt.ps1 | 7 +++++++ Types/neocities.info/get_Url.ps1 | 7 +++++++ Types/neocities.info/neocities.info.format.ps1 | 9 +++++++++ 7 files changed, 45 insertions(+) create mode 100644 Types/neocities.file/get_CreatedAt.ps1 create mode 100644 Types/neocities.file/get_UpdatedAt.ps1 create mode 100644 Types/neocities.file/neocities.file.format.ps1 create mode 100644 Types/neocities.info/get_CreatedAt.ps1 create mode 100644 Types/neocities.info/get_UpdatedAt.ps1 create mode 100644 Types/neocities.info/get_Url.ps1 create mode 100644 Types/neocities.info/neocities.info.format.ps1 diff --git a/Types/neocities.file/get_CreatedAt.ps1 b/Types/neocities.file/get_CreatedAt.ps1 new file mode 100644 index 0000000..26dd3b7 --- /dev/null +++ b/Types/neocities.file/get_CreatedAt.ps1 @@ -0,0 +1,7 @@ +<# +.SYNOPSIS + Gets the creation time +.DESCRIPTION + Gets the creation time, as a `[DateTime]` object. +#> +$this.created_at -as [DateTime] diff --git a/Types/neocities.file/get_UpdatedAt.ps1 b/Types/neocities.file/get_UpdatedAt.ps1 new file mode 100644 index 0000000..5e85a62 --- /dev/null +++ b/Types/neocities.file/get_UpdatedAt.ps1 @@ -0,0 +1,7 @@ +<# +.SYNOPSIS + Gets the last update time +.DESCRIPTION + Gets the last update time, as a `[DateTime]` object. +#> +$this.updated_at -as [DateTime] diff --git a/Types/neocities.file/neocities.file.format.ps1 b/Types/neocities.file/neocities.file.format.ps1 new file mode 100644 index 0000000..08dbbc7 --- /dev/null +++ b/Types/neocities.file/neocities.file.format.ps1 @@ -0,0 +1 @@ +Write-FormatView -TypeName 'neocities.file' -Property Path, Size, CreatedAt, UpdatedAt -AutoSize diff --git a/Types/neocities.info/get_CreatedAt.ps1 b/Types/neocities.info/get_CreatedAt.ps1 new file mode 100644 index 0000000..26dd3b7 --- /dev/null +++ b/Types/neocities.info/get_CreatedAt.ps1 @@ -0,0 +1,7 @@ +<# +.SYNOPSIS + Gets the creation time +.DESCRIPTION + Gets the creation time, as a `[DateTime]` object. +#> +$this.created_at -as [DateTime] diff --git a/Types/neocities.info/get_UpdatedAt.ps1 b/Types/neocities.info/get_UpdatedAt.ps1 new file mode 100644 index 0000000..dfd7077 --- /dev/null +++ b/Types/neocities.info/get_UpdatedAt.ps1 @@ -0,0 +1,7 @@ +<# +.SYNOPSIS + Gets the last update time +.DESCRIPTION + Gets the last update time, as a `[DateTime]` object. +#> +$this.last_updated -as [DateTime] diff --git a/Types/neocities.info/get_Url.ps1 b/Types/neocities.info/get_Url.ps1 new file mode 100644 index 0000000..12e08fc --- /dev/null +++ b/Types/neocities.info/get_Url.ps1 @@ -0,0 +1,7 @@ +param() +if ($this.Domain) { + "https://$($this.Domain)/" +} +elseif ($this.sitename) { + "https://$($this.sitename).neocities.org/" +} diff --git a/Types/neocities.info/neocities.info.format.ps1 b/Types/neocities.info/neocities.info.format.ps1 new file mode 100644 index 0000000..bc2337b --- /dev/null +++ b/Types/neocities.info/neocities.info.format.ps1 @@ -0,0 +1,9 @@ +Write-FormatView -TypeName 'neocities.info' -Property SiteName, Views, Hits, CreatedAt, UpdatedAt, Url -AutoSize -VirtualProperty @{ + SiteName = { + if ($psStyle) { + $PSStyle.FormatHyperlink($_.SiteName, $_.Url) + } else { + $_.SiteName + } + } +} From 83f7e16ca5833e3e779f6bf5f381dfc898989305 Mon Sep 17 00:00:00 2001 From: StartAutomating Date: Mon, 31 Mar 2025 23:31:40 +0000 Subject: [PATCH 04/30] feat: Neocities types and formatting ( Fixes #7 ) --- Neocities.format.ps1xml | 96 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 96 insertions(+) create mode 100644 Neocities.format.ps1xml diff --git a/Neocities.format.ps1xml b/Neocities.format.ps1xml new file mode 100644 index 0000000..4e6a12f --- /dev/null +++ b/Neocities.format.ps1xml @@ -0,0 +1,96 @@ + + + + + neocities.file + + neocities.file + + + + + + + + + + + + + + + + + + Path + + + Size + + + CreatedAt + + + UpdatedAt + + + + + + + + neocities.info + + neocities.info + + + + + + + + + + + + + + + + + + + + + + + + if ($psStyle) { + $PSStyle.FormatHyperlink($_.SiteName, $_.Url) + } else { + $_.SiteName + } + + + + Views + + + Hits + + + CreatedAt + + + UpdatedAt + + + Url + + + + + + + + \ No newline at end of file From c424ad761a03a0f61f3761489f4af15a8b4a9088 Mon Sep 17 00:00:00 2001 From: StartAutomating Date: Mon, 31 Mar 2025 23:31:40 +0000 Subject: [PATCH 05/30] feat: Neocities types and formatting ( Fixes #7 ) --- Neocities.types.ps1xml | 78 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 78 insertions(+) create mode 100644 Neocities.types.ps1xml diff --git a/Neocities.types.ps1xml b/Neocities.types.ps1xml new file mode 100644 index 0000000..b59f50e --- /dev/null +++ b/Neocities.types.ps1xml @@ -0,0 +1,78 @@ + + + + neocities.file + + + CreatedAt + + <# +.SYNOPSIS + Gets the creation time +.DESCRIPTION + Gets the creation time, as a `[DateTime]` object. +#> +$this.created_at -as [DateTime] + + + + + UpdatedAt + + <# +.SYNOPSIS + Gets the last update time +.DESCRIPTION + Gets the last update time, as a `[DateTime]` object. +#> +$this.updated_at -as [DateTime] + + + + + + + neocities.info + + + CreatedAt + + <# +.SYNOPSIS + Gets the creation time +.DESCRIPTION + Gets the creation time, as a `[DateTime]` object. +#> +$this.created_at -as [DateTime] + + + + + UpdatedAt + + <# +.SYNOPSIS + Gets the last update time +.DESCRIPTION + Gets the last update time, as a `[DateTime]` object. +#> +$this.last_updated -as [DateTime] + + + + + Url + + param() +if ($this.Domain) { + "https://$($this.Domain)/" +} +elseif ($this.sitename) { + "https://$($this.sitename).neocities.org/" +} + + + + + + \ No newline at end of file From 5caeab617f1fea6e483906bb4392c769f28de8c8 Mon Sep 17 00:00:00 2001 From: James Brundage <+@noreply.github.com> Date: Mon, 31 Mar 2025 16:33:23 -0700 Subject: [PATCH 06/30] fix: PublishTestResults step - using upload-artifact@main ( Fixes #6 ) --- .github/workflows/Build.yml | 2 +- Build/GitHub/Steps/PublishTestResults.psd1 | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/Build.yml b/.github/workflows/Build.yml index 1444e3f..5809b2a 100644 --- a/.github/workflows/Build.yml +++ b/.github/workflows/Build.yml @@ -103,7 +103,7 @@ jobs: } } @Parameters - name: PublishTestResults - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@main with: name: PesterResults path: '**.TestResults.xml' diff --git a/Build/GitHub/Steps/PublishTestResults.psd1 b/Build/GitHub/Steps/PublishTestResults.psd1 index 5b169ed..e8111e8 100644 --- a/Build/GitHub/Steps/PublishTestResults.psd1 +++ b/Build/GitHub/Steps/PublishTestResults.psd1 @@ -1,6 +1,6 @@ @{ name = 'PublishTestResults' - uses = 'actions/upload-artifact@v3' + uses = 'actions/upload-artifact@main' with = @{ name = 'PesterResults' path = '**.TestResults.xml' From 07b407e2d9ff7156576b317d1224b895b6fef8c0 Mon Sep 17 00:00:00 2001 From: James Brundage <+@noreply.github.com> Date: Mon, 31 Mar 2025 16:35:10 -0700 Subject: [PATCH 07/30] feat: Get-Neocities ( Fixes #2 ) --- Commands/Get-Neocities.ps1 | 122 +++++++++++++++++++++++++++++++++++++ 1 file changed, 122 insertions(+) create mode 100644 Commands/Get-Neocities.ps1 diff --git a/Commands/Get-Neocities.ps1 b/Commands/Get-Neocities.ps1 new file mode 100644 index 0000000..1c43cb9 --- /dev/null +++ b/Commands/Get-Neocities.ps1 @@ -0,0 +1,122 @@ +function Get-Neocities +{ + <# + .SYNOPSIS + Gets neocities information + .DESCRIPTION + Gets neocities information from the neocities API, or lists the files in your neocities site. + .EXAMPLE + Get-Neocities + .EXAMPLE + Get-Neocities -Credential $neocitiesCredential + .EXAMPLE + Get-Neocities -List + #> + [Alias('neocities')] + [CmdletBinding(DefaultParameterSetName='info')] + param( + # If set, will list the files in your neocities site + [Parameter(Mandatory,ValueFromPipelineByPropertyName,ParameterSetName='list')] + [switch] + $List, + + # The credential used to connect. + # This only needs to be provided once per module session + # (every time the module is imported) + [Parameter(ValueFromPipelineByPropertyName)] + [Alias( + 'Credentials', # Plural aliases are nice + 'PSCredential', # so are parameters that match the type name. + 'NeocitiesCredential', # A contextual alias is a good idea, too. + 'NeocitiesCredentials' # And you may need to pluralize that contextual alias. + )] + [PSCredential] + $Credential, + + # The access token used to connect. + # This only needs to be provided once per module session + # (every time the module is imported) + [Parameter(ValueFromPipelineByPropertyName)] + [string] + $AccessToken + ) + + begin { + $NeocitiesApi = "https://neocities.org/api" + } + + process { + # The parameter set name contains the route + $parameterSet = $PSCmdlet.ParameterSetName + # and we want to use this to decorate all returned values with a type name + $psuedoNamespace = "neocities" + $pseudoType = "$parameterSet" + # Start by constructing the parameters for Invoke-RestMethod + $InvokeSplat = [Ordered]@{ + Uri = "$NeocitiesApi", $PSCmdlet.ParameterSetName -join '/' + } + + # If an access token was provided + if ($AccessToken) + { + # use it + $InvokeSplat.Headers = @{Authorization = "Bearer $AccessToken"} + # and cache it for later use + $script:NeocitiesAccessToken = $AccessToken + } + elseif ($Credential) + { + # If a credential was provided, use it + $InvokeSplat.Credential = $Credential + # and cache it for later use + $script:NeoCitiesCredential = $Credential + # (don't forget to set authentication to basic) + $InvokeSplat.Authentication = 'Basic' + } + elseif ($script:NeocitiesAccessToken) { + # If we had a cached access token, use it + $InvokeSplat.Headers = @{Authorization = "Bearer $($script:NeocitiesAccessToken)"} + } + elseif ($script:NeoCitiesCredential) { + # If we had a cached credential, use it + $InvokeSplat.Credential = $script:NeoCitiesCredential + # and don't forget to set authentication to basic. + $InvokeSplat.Authentication = 'Basic' + } + + # If neither an access token nor a credential was provided, we can't do anything. + if (-not $InvokeSplat.Credential -and -not $InvokeSplat.Headers) + { + # so error out. + Write-Error "No -Credential provided" + return + } + + + # Write a little verbose message to let the user know what we're doing + Write-Verbose "Requesting $($InvokeSplat.Uri)" + # and get a response from neocities. + $neocitiesResponse = Invoke-RestMethod @InvokeSplat + switch ($parameterSet) { + info { + # If we're getting info, we want to return the info object + $neocitiesResponse = $neocitiesResponse.info + } + list { + # If we're listing files, we want to return the files object + $neocitiesResponse = @($neocitiesResponse.files) + # and we want to return each as a 'file', not a 'list' + $pseudoType = 'file' + } + } + + # Go over each response + foreach ($neoResponse in $neocitiesResponse) { + # and decorate them with the type name + $neoResponse.pstypenames.clear() + $neoResponse.pstypenames.insert(0, ($psuedoNamespace, $pseudoType -join '.')) + # and output the response. + $neoResponse + } + } +} From d0a3ee81d5ace82c40788e9bff382e40df22e835 Mon Sep 17 00:00:00 2001 From: James Brundage <+@noreply.github.com> Date: Mon, 31 Mar 2025 16:37:20 -0700 Subject: [PATCH 08/30] feat: Connect-Neocities ( Fixes #4 ) --- Commands/Connect-Neocities.ps1 | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 Commands/Connect-Neocities.ps1 diff --git a/Commands/Connect-Neocities.ps1 b/Commands/Connect-Neocities.ps1 new file mode 100644 index 0000000..4b3d528 --- /dev/null +++ b/Commands/Connect-Neocities.ps1 @@ -0,0 +1,33 @@ +function Connect-Neocities +{ + <# + .SYNOPSIS + Connect to Neocities + .DESCRIPTION + Connect to Neocities using a credential object. + + This will create a session that can be used to authenticate to the Neocities API. + .LINK + Get-Neocities + #> + param( + # The Neocities credential + [Parameter(ValueFromPipelineByPropertyName)] + [Alias( + 'Credentials', # Plural aliases are nice + 'PSCredential', # so are parameters that match the type name. + 'NeocitiesCredential', # A contextual alias is a good idea, too. + 'NeocitiesCredentials' # And you may need to pluralize that contextual alias. + )] + [PSCredential] + $Credential + ) + + begin { + $NeocitiesApi = "https://neocities.org/api" + } + + process { + Invoke-RestMethod -Uri ($NeocitiesApi,'key' -join '/') -Credential $Credential -Authentication Basic + } +} From b70c3f552cb9b7217fa6c2d36e9c29ac83923f47 Mon Sep 17 00:00:00 2001 From: James Brundage <+@noreply.github.com> Date: Mon, 31 Mar 2025 16:45:58 -0700 Subject: [PATCH 09/30] feat: Set-Neocities ( Fixes #3 ) --- Commands/Set-Neocities.ps1 | 166 +++++++++++++++++++++++++++++++++++++ 1 file changed, 166 insertions(+) create mode 100644 Commands/Set-Neocities.ps1 diff --git a/Commands/Set-Neocities.ps1 b/Commands/Set-Neocities.ps1 new file mode 100644 index 0000000..1aa8885 --- /dev/null +++ b/Commands/Set-Neocities.ps1 @@ -0,0 +1,166 @@ +function Set-Neocities +{ + <# + .SYNOPSIS + Sets Neocities files + .DESCRIPTION + Sets files on Neocities website using the neocities API. + #> + [CmdletBinding(DefaultParameterSetName='upload')] + param( + # The path to the file to upload, or a dictionary of files and their contents. + [Parameter(ValueFromPipelineByPropertyName)] + [Alias('Fullname','FilePath','Path')] + [PSObject] + $File, + + # The neocities credential + [Parameter(ValueFromPipelineByPropertyName)] + [Alias( + 'Credentials', # Plural aliases are nice + 'PSCredential', # so are parameters that match the type name. + 'NeocitiesCredential', # A contextual alias is a good idea, too. + 'NeocitiesCredentials' # And you may need to pluralize that contextual alias. + )] + [PSCredential] + $Credential, + + # The access token + [Parameter(ValueFromPipelineByPropertyName)] + [string] + $AccessToken + ) + + begin { + $NeocitiesApi = "https://neocities.org/api" + $multiparts = [Ordered]@{} + $boundary = "boundary" + $contentType = "multipart/form-data; boundary=`"$boundary`"" + + } + process { + $parameterSet = $PSCmdlet.ParameterSetName + $psuedoNamespace = "neocities" + $pseudoType = "$parameterSet" + $InvokeSplat = [Ordered]@{ + Uri = "$NeocitiesApi", $PSCmdlet.ParameterSetName -join '/' + } + + # If an access token was provided + if ($AccessToken) + { + # use it + $InvokeSplat.Headers = @{Authorization = "Bearer $AccessToken"} + # and cache it for later use + $script:NeocitiesAccessToken = $AccessToken + } + elseif ($Credential) + { + # If a credential was provided, use it + $InvokeSplat.Credential = $Credential + # and cache it for later use + $script:NeoCitiesCredential = $Credential + # (don't forget to set authentication to basic) + $InvokeSplat.Authentication = 'Basic' + } + elseif ($script:NeocitiesAccessToken) { + # If we had a cached access token, use it + $InvokeSplat.Headers = @{Authorization = "Bearer $($script:NeocitiesAccessToken)"} + } + elseif ($script:NeoCitiesCredential) { + # If we had a cached credential, use it + $InvokeSplat.Credential = $script:NeoCitiesCredential + # and don't forget to set authentication to basic. + $InvokeSplat.Authentication = 'Basic' + } + + # If neither an access token nor a credential was provided, we can't do anything. + if (-not $InvokeSplat.Credential -and -not $InvokeSplat.Headers) + { + # so error out. + Write-Error "No -Credential provided" + return + } + + $InvokeSplat.ContentType = $contentType + + # If we were piped in a file + if ($_ -is [IO.FileInfo]) { + $file = $_ # set the parameter directly + } + + # For every file passed in, we need to make a unique request. + foreach ($fileInfo in $file) { + # If this is a file, this is easy + if ($fileInfo -is [IO.FileInfo]) { + # just get the string representation of the file's bytes and add them to the multipart collection + $multiparts[$file.Name] = $OutputEncoding.GetString([IO.File]::ReadAllBytes($file)) + } + # If the file was a path, we need to get the file's contents + elseif ($fileInfo -is [string] -and (Test-Path $fileInfo)) { + $multiparts[$fileInfo] = Get-Content -Raw $fileInfo + } + # If the file was a dictionary, treat each key as a file name and each value as the file's contents + elseif ($fileInfo -is [Collections.IDictionary]) { + foreach ($keyValuePair in $fileInfo.GetEnumerator()) { + # If the value is a byte array, convert it to a string + if ($keyValuePair.Value -is [byte[]]) { + $multiparts[$keyValuePair.Key] = $OutputEncoding.GetString($keyValuePair.Value) + } + # If the value is a file, read the file's bytes and convert them to a string + elseif ($keyValuePair.Value -is [IO.FileInfo]) { + $multiparts[$keyValuePair.Key] = $OutputEncoding.GetString([IO.File]::ReadAllBytes($keyValuePair.Value)) + } + # If the value is a pth to file, read the file's bytes and convert them to a string + elseif ($keyValuePair.Value -is [string] -and (Test-Path $keyValuePair.Value)) { + $multiparts[$keyValuePair.Key] = Get-Content -Raw $keyValuePair.Value + } + # last but not least, stringify the value and add it to the collection + else + { + $multiparts[$keyValuePair.Key] = "$($keyValuePair.Value)" + } + } + } + } + + } + + end { + # Despite the content type being multipart, we can actually only send one part at a time: + + # Any way we slice it, we'll need to POST the data to the API. + $InvokeSplat.Method = 'POST' + + + # For each part we've found + foreach ($filePart in $multiparts.GetEnumerator()) { + $InvokeSplat.Body = @( + # Create a bounary + "--$boundary" + # Add the file name and content type to the header + "Content-Disposition: form-data; name=`"$($filePart.Key)`"; filename=`"$($filePart.Key)`"" + # We're always uploading this a text/plain with neocities, and we need to set the encoding to whatever we passed. + "Content-Type: text/plain; charset=$($OutputEncoding.WebName)" + # The bounary MIME data must be followed by a newline + "`r`n" + # followed by the file contents + $filePart.Value + # followed by an additional boundary + "--$boundary--" + ) -join "`r`n" # (all of these pieces are joined by a newline) + + # If -WhatIf was passed, don't actually upload the file, just show the splatted parameters. + if ($WhatIfPreference) { + # (Remove the headers and credential from the splatted parameters, so we don't leak any sensitive information) + $InvokeSplat.Remove('Headers') + $InvokeSplat.Remove('Credential') + $InvokeSplat + continue + } + + # Invoke-RestMethod with our splatted parameters, and we'll upload the file. + Invoke-RestMethod @InvokeSplat + } + } +} \ No newline at end of file From 132abc7a84b9211ec2c03a3a7af2e6f067a245fa Mon Sep 17 00:00:00 2001 From: James Brundage <+@noreply.github.com> Date: Mon, 31 Mar 2025 16:53:26 -0700 Subject: [PATCH 10/30] feat: Remove-Neocities ( Fixes #5 ) --- Commands/Remove-Neocities.ps1 | 115 ++++++++++++++++++++++++++++++++++ 1 file changed, 115 insertions(+) create mode 100644 Commands/Remove-Neocities.ps1 diff --git a/Commands/Remove-Neocities.ps1 b/Commands/Remove-Neocities.ps1 new file mode 100644 index 0000000..cc59be6 --- /dev/null +++ b/Commands/Remove-Neocities.ps1 @@ -0,0 +1,115 @@ +function Remove-Neocities +{ + <# + .SYNOPSIS + Removes files from neocities + .DESCRIPTION + Removes files from a neocities site using the neocities API. + #> + [CmdletBinding(DefaultParameterSetName='delete',SupportsShouldProcess,ConfirmImpact='High')] + param( + # The name of the file to remove. + [Parameter(Mandatory,ValueFromPipelineByPropertyName)] + [Alias('FullName','Path')] + [string[]] + $FileName, + + + # The neocities credential + [Parameter(ValueFromPipelineByPropertyName)] + [Alias( + 'Credentials', # Plural aliases are nice + 'PSCredential', # so are parameters that match the type name. + 'NeocitiesCredential', # A contextual alias is a good idea, too. + 'NeocitiesCredentials' # And you may need to pluralize that contextual alias. + )] + [PSCredential] + $Credential, + + # The neocities access token. + [Parameter(ValueFromPipelineByPropertyName)] + [string] + $AccessToken + ) + + begin { + $NeocitiesApi = "https://neocities.org/api" + } + + process { + $parameterSet = $PSCmdlet.ParameterSetName + $psuedoNamespace = "neocities" + $pseudoType = "$parameterSet" + $InvokeSplat = [Ordered]@{ + Uri = "$NeocitiesApi", $PSCmdlet.ParameterSetName -join '/' + Method = 'POST' + } + + # If an access token was provided + if ($AccessToken) + { + # use it + $InvokeSplat.Headers = @{Authorization = "Bearer $AccessToken"} + # and cache it for later use + $script:NeocitiesAccessToken = $AccessToken + } + elseif ($Credential) + { + # If a credential was provided, use it + $InvokeSplat.Credential = $Credential + # and cache it for later use + $script:NeoCitiesCredential = $Credential + # (don't forget to set authentication to basic) + $InvokeSplat.Authentication = 'Basic' + } + elseif ($script:NeocitiesAccessToken) { + # If we had a cached access token, use it + $InvokeSplat.Headers = @{Authorization = "Bearer $($script:NeocitiesAccessToken)"} + } + elseif ($script:NeoCitiesCredential) { + # If we had a cached credential, use it + $InvokeSplat.Credential = $script:NeoCitiesCredential + # and don't forget to set authentication to basic. + $InvokeSplat.Authentication = 'Basic' + } + + # If neither an access token nor a credential was provided, we can't do anything. + if (-not $InvokeSplat.Credential -and -not $InvokeSplat.Headers) + { + # so error out. + Write-Error "No -Credential provided" + return + } + + # For every file name provided, we need to remove it from the neocities site. + foreach ($file in $fileName) { + # Despite the name taking an array, we need to remove one file at a time. + $InvokeSplat.Body = + [web.httputility]::UrlEncode("filenames[]"),'=',[web.httputility]::UrlEncode($file) -join '' + Write-Verbose "Requesting $($InvokeSplat.Uri)" + # If -WhatIf was specified, we need to remove the credential and headers from the splat + if ($WhatIfPreference) { + $splatCopy = [Ordered]@{} + $InvokeSplat + $splatCopy.Remove('Credential') + $splatCopy.Remove('Headers') + # and then output the splat to the pipeline + $splatCopy + continue + } + # If we did not confirm the deletion + if (-not $PSCmdlet.ShouldProcess("Delete $file")) { + # skip it. + continue + } + + # Get the response from neocities. + $neocitiesResponse = Invoke-RestMethod @InvokeSplat + # and decorate any response so that we know it was a deletion. + foreach ($neoResponse in $neocitiesResponse) { + $neoResponse.pstypenames.clear() + $neoResponse.pstypenames.insert(0, ($psuedoNamespace, $pseudoType -join '.')) + $neoResponse + } + } + } +} From 3145ad6f3709af22fb18f5a0a154d0847ae594e3 Mon Sep 17 00:00:00 2001 From: James Brundage <+@noreply.github.com> Date: Mon, 31 Mar 2025 16:54:36 -0700 Subject: [PATCH 11/30] feat: Neocities HelpOut ( Fixes #8 ) --- Build/Neocities.HelpOut.ps1 | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 Build/Neocities.HelpOut.ps1 diff --git a/Build/Neocities.HelpOut.ps1 b/Build/Neocities.HelpOut.ps1 new file mode 100644 index 0000000..ae37d2e --- /dev/null +++ b/Build/Neocities.HelpOut.ps1 @@ -0,0 +1,14 @@ +#requires -Module HelpOut + +#region Load the Module +$ModuleName = 'Neocities' +Push-Location ($PSScriptRoot | Split-Path) +if (-not (Get-Module $ModuleName)) { + Import-Module .\ -Global -PassThru | Out-Host +} +#endregion Load the Module + +# This will save the MarkdownHelp to the docs folder, and output all of the files created. +Save-MarkdownHelp -PassThru -Module $ModuleName -ExcludeCommandType Alias + +Pop-Location \ No newline at end of file From 5c513e2b6ad57ffcc3ef737512eb0d1d905f7379 Mon Sep 17 00:00:00 2001 From: StartAutomating Date: Mon, 31 Mar 2025 23:55:46 +0000 Subject: [PATCH 12/30] feat: Neocities HelpOut ( Fixes #8 ) --- docs/Connect-Neocities.md | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) create mode 100644 docs/Connect-Neocities.md diff --git a/docs/Connect-Neocities.md b/docs/Connect-Neocities.md new file mode 100644 index 0000000..62b4020 --- /dev/null +++ b/docs/Connect-Neocities.md @@ -0,0 +1,39 @@ +Connect-Neocities +----------------- + +### Synopsis +Connect to Neocities + +--- + +### Description + +Connect to Neocities using a credential object. + +This will create a session that can be used to authenticate to the Neocities API. + +--- + +### Related Links +* [Get-Neocities](Get-Neocities.md) + +--- + +### Parameters +#### **Credential** +The Neocities credential +Plural aliases are nice +so are parameters that match the type name. +A contextual alias is a good idea, too. +And you may need to pluralize that contextual alias. + +|Type |Required|Position|PipelineInput |Aliases | +|----------------|--------|--------|---------------------|-----------------------------------------------------------------------------| +|`[PSCredential]`|false |1 |true (ByPropertyName)|Credentials
PSCredential
NeocitiesCredential
NeocitiesCredentials| + +--- + +### Syntax +```PowerShell +Connect-Neocities [[-Credential] ] [] +``` From fd1150f730e7964783faf7f006139eecf09a4a50 Mon Sep 17 00:00:00 2001 From: StartAutomating Date: Mon, 31 Mar 2025 23:55:46 +0000 Subject: [PATCH 13/30] feat: Neocities HelpOut ( Fixes #8 ) --- docs/_data/Help/Connect-Neocities.json | 35 ++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 docs/_data/Help/Connect-Neocities.json diff --git a/docs/_data/Help/Connect-Neocities.json b/docs/_data/Help/Connect-Neocities.json new file mode 100644 index 0000000..fd56cbc --- /dev/null +++ b/docs/_data/Help/Connect-Neocities.json @@ -0,0 +1,35 @@ +{ + "Synopsis": "Connect to Neocities", + "Description": "Connect to Neocities using a credential object. \n\nThis will create a session that can be used to authenticate to the Neocities API.", + "Parameters": [ + { + "Name": null, + "Type": null, + "Description": "", + "Required": false, + "Position": 0, + "Aliases": null, + "DefaultValue": null, + "Globbing": false, + "PipelineInput": null, + "variableLength": false + } + ], + "Notes": [ + null + ], + "CommandType": "Function", + "Component": [ + null + ], + "Inputs": [ + null + ], + "Outputs": [ + null + ], + "Links": [ + null + ], + "Examples": [] +} \ No newline at end of file From a977bd91b539d3af903ca760c3812662f503c7fd Mon Sep 17 00:00:00 2001 From: StartAutomating Date: Mon, 31 Mar 2025 23:55:47 +0000 Subject: [PATCH 14/30] feat: Neocities HelpOut ( Fixes #8 ) --- docs/Get-Neocities.md | 72 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 72 insertions(+) create mode 100644 docs/Get-Neocities.md diff --git a/docs/Get-Neocities.md b/docs/Get-Neocities.md new file mode 100644 index 0000000..39cc348 --- /dev/null +++ b/docs/Get-Neocities.md @@ -0,0 +1,72 @@ +Get-Neocities +------------- + +### Synopsis +Gets neocities information + +--- + +### Description + +Gets neocities information from the neocities API, or lists the files in your neocities site. + +--- + +### Examples +> EXAMPLE 1 + +```PowerShell +Get-Neocities +``` +> EXAMPLE 2 + +```PowerShell +Get-Neocities -Credential $neocitiesCredential +``` +> EXAMPLE 3 + +```PowerShell +Get-Neocities -List +``` + +--- + +### Parameters +#### **List** +If set, will list the files in your neocities site + +|Type |Required|Position|PipelineInput | +|----------|--------|--------|---------------------| +|`[Switch]`|true |named |true (ByPropertyName)| + +#### **Credential** +The credential used to connect. +This only needs to be provided once per module session +(every time the module is imported) +Plural aliases are nice +so are parameters that match the type name. +A contextual alias is a good idea, too. +And you may need to pluralize that contextual alias. + +|Type |Required|Position|PipelineInput |Aliases | +|----------------|--------|--------|---------------------|-----------------------------------------------------------------------------| +|`[PSCredential]`|false |named |true (ByPropertyName)|Credentials
PSCredential
NeocitiesCredential
NeocitiesCredentials| + +#### **AccessToken** +The access token used to connect. +This only needs to be provided once per module session +(every time the module is imported) + +|Type |Required|Position|PipelineInput | +|----------|--------|--------|---------------------| +|`[String]`|false |named |true (ByPropertyName)| + +--- + +### Syntax +```PowerShell +Get-Neocities [-Credential ] [-AccessToken ] [] +``` +```PowerShell +Get-Neocities -List [-Credential ] [-AccessToken ] [] +``` From 489d244a55afa525c9a565a636b3766154999a8e Mon Sep 17 00:00:00 2001 From: StartAutomating Date: Mon, 31 Mar 2025 23:55:47 +0000 Subject: [PATCH 15/30] feat: Neocities HelpOut ( Fixes #8 ) --- docs/_data/Help/Get-Neocities.json | 49 ++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) create mode 100644 docs/_data/Help/Get-Neocities.json diff --git a/docs/_data/Help/Get-Neocities.json b/docs/_data/Help/Get-Neocities.json new file mode 100644 index 0000000..8a113e1 --- /dev/null +++ b/docs/_data/Help/Get-Neocities.json @@ -0,0 +1,49 @@ +{ + "Synopsis": "Gets neocities information", + "Description": "Gets neocities information from the neocities API, or lists the files in your neocities site.", + "Parameters": [ + { + "Name": null, + "Type": null, + "Description": "", + "Required": false, + "Position": 0, + "Aliases": null, + "DefaultValue": null, + "Globbing": false, + "PipelineInput": null, + "variableLength": false + } + ], + "Notes": [ + null + ], + "CommandType": "Function", + "Component": [ + null + ], + "Inputs": [ + null + ], + "Outputs": [ + null + ], + "Links": [], + "Examples": [ + { + "Title": "EXAMPLE 1", + "Markdown": "", + "Code": "Get-Neocities" + }, + { + "Title": "EXAMPLE 2", + "Markdown": "", + "Code": "Get-Neocities -Credential $neocitiesCredential" + }, + { + "Title": "EXAMPLE 3", + "Markdown": "", + "Code": "Get-Neocities -List" + } + ] +} \ No newline at end of file From 7ebf0230e85c2006ea62266812b909efea38f6d1 Mon Sep 17 00:00:00 2001 From: StartAutomating Date: Mon, 31 Mar 2025 23:55:47 +0000 Subject: [PATCH 16/30] feat: Neocities HelpOut ( Fixes #8 ) --- docs/Remove-Neocities.md | 57 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) create mode 100644 docs/Remove-Neocities.md diff --git a/docs/Remove-Neocities.md b/docs/Remove-Neocities.md new file mode 100644 index 0000000..f29b305 --- /dev/null +++ b/docs/Remove-Neocities.md @@ -0,0 +1,57 @@ +Remove-Neocities +---------------- + +### Synopsis +Removes files from neocities + +--- + +### Description + +Removes files from a neocities site using the neocities API. + +--- + +### Parameters +#### **FileName** +The name of the file to remove. + +|Type |Required|Position|PipelineInput |Aliases | +|------------|--------|--------|---------------------|-----------------| +|`[String[]]`|true |1 |true (ByPropertyName)|FullName
Path| + +#### **Credential** +The neocities credential +Plural aliases are nice +so are parameters that match the type name. +A contextual alias is a good idea, too. +And you may need to pluralize that contextual alias. + +|Type |Required|Position|PipelineInput |Aliases | +|----------------|--------|--------|---------------------|-----------------------------------------------------------------------------| +|`[PSCredential]`|false |2 |true (ByPropertyName)|Credentials
PSCredential
NeocitiesCredential
NeocitiesCredentials| + +#### **AccessToken** +The neocities access token. + +|Type |Required|Position|PipelineInput | +|----------|--------|--------|---------------------| +|`[String]`|false |3 |true (ByPropertyName)| + +#### **WhatIf** +-WhatIf is an automatic variable that is created when a command has ```[CmdletBinding(SupportsShouldProcess)]```. +-WhatIf is used to see what would happen, or return operations without executing them +#### **Confirm** +-Confirm is an automatic variable that is created when a command has ```[CmdletBinding(SupportsShouldProcess)]```. +-Confirm is used to -Confirm each operation. + +If you pass ```-Confirm:$false``` you will not be prompted. + +If the command sets a ```[ConfirmImpact("Medium")]``` which is lower than ```$confirmImpactPreference```, you will not be prompted unless -Confirm is passed. + +--- + +### Syntax +```PowerShell +Remove-Neocities [-FileName] [[-Credential] ] [[-AccessToken] ] [-WhatIf] [-Confirm] [] +``` From 98004e1d89852f542589a01115ec0bd89f06a6c9 Mon Sep 17 00:00:00 2001 From: StartAutomating Date: Mon, 31 Mar 2025 23:55:47 +0000 Subject: [PATCH 17/30] feat: Neocities HelpOut ( Fixes #8 ) --- docs/_data/Help/Remove-Neocities.json | 33 +++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 docs/_data/Help/Remove-Neocities.json diff --git a/docs/_data/Help/Remove-Neocities.json b/docs/_data/Help/Remove-Neocities.json new file mode 100644 index 0000000..292a64c --- /dev/null +++ b/docs/_data/Help/Remove-Neocities.json @@ -0,0 +1,33 @@ +{ + "Synopsis": "Removes files from neocities", + "Description": "Removes files from a neocities site using the neocities API.", + "Parameters": [ + { + "Name": null, + "Type": null, + "Description": "", + "Required": false, + "Position": 0, + "Aliases": null, + "DefaultValue": null, + "Globbing": false, + "PipelineInput": null, + "variableLength": false + } + ], + "Notes": [ + null + ], + "CommandType": "Function", + "Component": [ + null + ], + "Inputs": [ + null + ], + "Outputs": [ + null + ], + "Links": [], + "Examples": [] +} \ No newline at end of file From 35ebb376b230d5b7467de73a194f5fb3fad5a9ff Mon Sep 17 00:00:00 2001 From: StartAutomating Date: Mon, 31 Mar 2025 23:55:48 +0000 Subject: [PATCH 18/30] feat: Neocities HelpOut ( Fixes #8 ) --- docs/Set-Neocities.md | 46 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) create mode 100644 docs/Set-Neocities.md diff --git a/docs/Set-Neocities.md b/docs/Set-Neocities.md new file mode 100644 index 0000000..b8a5f2d --- /dev/null +++ b/docs/Set-Neocities.md @@ -0,0 +1,46 @@ +Set-Neocities +------------- + +### Synopsis +Sets Neocities files + +--- + +### Description + +Sets files on Neocities website using the neocities API. + +--- + +### Parameters +#### **File** +The path to the file to upload, or a dictionary of files and their contents. + +|Type |Required|Position|PipelineInput |Aliases | +|------------|--------|--------|---------------------|------------------------------| +|`[PSObject]`|false |1 |true (ByPropertyName)|Fullname
FilePath
Path| + +#### **Credential** +The neocities credential +Plural aliases are nice +so are parameters that match the type name. +A contextual alias is a good idea, too. +And you may need to pluralize that contextual alias. + +|Type |Required|Position|PipelineInput |Aliases | +|----------------|--------|--------|---------------------|-----------------------------------------------------------------------------| +|`[PSCredential]`|false |2 |true (ByPropertyName)|Credentials
PSCredential
NeocitiesCredential
NeocitiesCredentials| + +#### **AccessToken** +The access token + +|Type |Required|Position|PipelineInput | +|----------|--------|--------|---------------------| +|`[String]`|false |3 |true (ByPropertyName)| + +--- + +### Syntax +```PowerShell +Set-Neocities [[-File] ] [[-Credential] ] [[-AccessToken] ] [] +``` From 7a1e3100313ac5039aa182ba09eadad5cebe5964 Mon Sep 17 00:00:00 2001 From: StartAutomating Date: Mon, 31 Mar 2025 23:55:48 +0000 Subject: [PATCH 19/30] feat: Neocities HelpOut ( Fixes #8 ) --- docs/_data/Help/Set-Neocities.json | 33 ++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 docs/_data/Help/Set-Neocities.json diff --git a/docs/_data/Help/Set-Neocities.json b/docs/_data/Help/Set-Neocities.json new file mode 100644 index 0000000..dc80558 --- /dev/null +++ b/docs/_data/Help/Set-Neocities.json @@ -0,0 +1,33 @@ +{ + "Synopsis": "Sets Neocities files", + "Description": "Sets files on Neocities website using the neocities API.", + "Parameters": [ + { + "Name": null, + "Type": null, + "Description": "", + "Required": false, + "Position": 0, + "Aliases": null, + "DefaultValue": null, + "Globbing": false, + "PipelineInput": null, + "variableLength": false + } + ], + "Notes": [ + null + ], + "CommandType": "Function", + "Component": [ + null + ], + "Inputs": [ + null + ], + "Outputs": [ + null + ], + "Links": [], + "Examples": [] +} \ No newline at end of file From 112a72bf4990c3c91e9f8bdbb6c9348021d9b294 Mon Sep 17 00:00:00 2001 From: StartAutomating Date: Mon, 31 Mar 2025 23:55:49 +0000 Subject: [PATCH 20/30] feat: Neocities HelpOut ( Fixes #8 ) --- docs/README.md | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 docs/README.md diff --git a/docs/README.md b/docs/README.md new file mode 100644 index 0000000..28fe077 --- /dev/null +++ b/docs/README.md @@ -0,0 +1,2 @@ +# Neocities +Manage Neocities with PowerShell From e32ff0aacf60a2aee9c70fba2121b4bdefed2558 Mon Sep 17 00:00:00 2001 From: James Brundage <+@noreply.github.com> Date: Mon, 31 Mar 2025 17:10:14 -0700 Subject: [PATCH 21/30] release: Neocities 0.1 ( Fixes #1 ) --- Neocities.psd1 | 35 +++++++++++++++++++++++++++++++++++ README.md | 34 +++++++++++++++++++++++++++++++++- 2 files changed, 68 insertions(+), 1 deletion(-) create mode 100644 Neocities.psd1 diff --git a/Neocities.psd1 b/Neocities.psd1 new file mode 100644 index 0000000..9e078bc --- /dev/null +++ b/Neocities.psd1 @@ -0,0 +1,35 @@ +@{ + ModuleVersion = '0.1' + RootModule = 'Neocities.psm1' + Guid = 'd62958e7-1cc7-470b-bde3-da29e96579fd' + Author = 'James Brundage' + CompanyName = 'Start-Automating' + Copyright = '2025 Start-Automating' + Description = 'Neocities PowerShell - Personal Webpages in PowerShell' + FunctionsToExport = @('Connect-Neocities','Get-Neocities','Set-Neocities','Remove-Neocities') + AliasesToExport = @('Neocities') + FormatsToProcess = @('Neocities.format.ps1xml') + TypesToProcess = @('Neocities.types.ps1xml') + PrivateData = @{ + PSData = @{ + Tags = @('neocities', 'PowerShell', 'Web', 'PowerShellWeb') + ProjectURI = 'https://github.com/PowerShellWeb/NeoPS' + LicenseURI = 'https://github.com/PowerShellWeb/NeoPS/blob/main/LICENSE' + ReleaseNotes = @' +> Like It? [Star It](https://github.com/PowerShellWeb/NeoPS) +> Love It? [Support It](https://github.com/sponsors/StartAutomating) + +## Neocities 0.1 + +Initial Neocities module (#1): + +* Get-Neocities (#2) +* Set-Neocities (#3) +* Remove-Neocities (#5) +* Connect-Neocities (#4) + +--- +'@ + } + } +} \ No newline at end of file diff --git a/README.md b/README.md index 28fe077..a476851 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,34 @@ -# Neocities +## Neocities + Manage Neocities with PowerShell + +[https://neocities.org](Neocities) is a wonderful site for free personal webpages. + +It's bringing back the ethos of old internet: one of the most popular free hosting services of the 90s was [geocities](https://en.wikipedia.org/wiki/GeoCities). + +## The Neocities Module + +Neocities is also the name a PowerShell module to manage Neocities (no official relation). + +The Neocities module PowerShell is built atop the [neocities api](https://neocities.org/api). + +### Installing and Importing + +You can install the Neocities module by using the [PowerShell Gallery](https://powershellgallery.com) + +~~~PowerShell +Install-Module Neocities +~~~ + +Once installed, you can import it with: + +~~~PowerShell +Import-Module Neocities -PassThru +~~~ + +### Neocities Commands + +* [Get-Neocities](docs/Get-Neocities.md) gets neocities content +* [Set-Neocities](docs/Set-Neocities.md) sets neocities content +* [Remove-Neocities](docs/Remove-Neocities.md) removes neocities content +* [Connect-Neocities](docs/Connect-Neocities.md) connects with a credential and gives you an access token \ No newline at end of file From 9224f3c2f6c7842390c09b896fcd98e424f8a8e1 Mon Sep 17 00:00:00 2001 From: James Brundage <+@noreply.github.com> Date: Mon, 31 Mar 2025 17:13:03 -0700 Subject: [PATCH 22/30] release: Neocities 0.1 ( Fixes #1 ) Updating inner links --- Neocities.psd1 | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Neocities.psd1 b/Neocities.psd1 index 9e078bc..88a90cc 100644 --- a/Neocities.psd1 +++ b/Neocities.psd1 @@ -13,10 +13,10 @@ PrivateData = @{ PSData = @{ Tags = @('neocities', 'PowerShell', 'Web', 'PowerShellWeb') - ProjectURI = 'https://github.com/PowerShellWeb/NeoPS' - LicenseURI = 'https://github.com/PowerShellWeb/NeoPS/blob/main/LICENSE' + ProjectURI = 'https://github.com/PowerShellWeb/Neocities' + LicenseURI = 'https://github.com/PowerShellWeb/Neocities/blob/main/LICENSE' ReleaseNotes = @' -> Like It? [Star It](https://github.com/PowerShellWeb/NeoPS) +> Like It? [Star It](https://github.com/PowerShellWeb/Neocities) > Love It? [Support It](https://github.com/sponsors/StartAutomating) ## Neocities 0.1 From 21b7b8060815a6c3f0ed9935b34dd40b75d71420 Mon Sep 17 00:00:00 2001 From: StartAutomating Date: Tue, 1 Apr 2025 00:13:07 +0000 Subject: [PATCH 23/30] release: Neocities 0.1 ( Fixes #1 ) --- docs/README.md | 34 +++++++++++++++++++++++++++++++++- 1 file changed, 33 insertions(+), 1 deletion(-) diff --git a/docs/README.md b/docs/README.md index 28fe077..26b278b 100644 --- a/docs/README.md +++ b/docs/README.md @@ -1,2 +1,34 @@ -# Neocities +## Neocities + Manage Neocities with PowerShell + +[https://neocities.org](Neocities) is a wonderful site for free personal webpages. + +It's bringing back the ethos of old internet: one of the most popular free hosting services of the 90s was [geocities](https://en.wikipedia.org/wiki/GeoCities). + +## The Neocities Module + +Neocities is also the name a PowerShell module to manage Neocities (no official relation). + +The Neocities module PowerShell is built atop the [neocities api](https://neocities.org/api). + +### Installing and Importing + +You can install the Neocities module by using the [PowerShell Gallery](https://powershellgallery.com) + +~~~PowerShell +Install-Module Neocities +~~~ + +Once installed, you can import it with: + +~~~PowerShell +Import-Module Neocities -PassThru +~~~ + +### Neocities Commands + +* [Get-Neocities](Get-Neocities.md) gets neocities content +* [Set-Neocities](Set-Neocities.md) sets neocities content +* [Remove-Neocities](Remove-Neocities.md) removes neocities content +* [Connect-Neocities](Connect-Neocities.md) connects with a credential and gives you an access token From 2a2f87a5abdcf441ce03e3648a825d1c3d1a8bd2 Mon Sep 17 00:00:00 2001 From: StartAutomating Date: Tue, 1 Apr 2025 00:13:07 +0000 Subject: [PATCH 24/30] release: Neocities 0.1 ( Fixes #1 ) --- docs/neocities/file/README.md | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 docs/neocities/file/README.md diff --git a/docs/neocities/file/README.md b/docs/neocities/file/README.md new file mode 100644 index 0000000..be859e2 --- /dev/null +++ b/docs/neocities/file/README.md @@ -0,0 +1,8 @@ +## neocities.file + + +### Script Properties + + +* [get_CreatedAt](get_CreatedAt.md) +* [get_UpdatedAt](get_UpdatedAt.md) From 73336991da4a75dd7c96cd98ed96031307217c57 Mon Sep 17 00:00:00 2001 From: StartAutomating Date: Tue, 1 Apr 2025 00:13:07 +0000 Subject: [PATCH 25/30] release: Neocities 0.1 ( Fixes #1 ) --- docs/neocities/file/get_CreatedAt.md | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 docs/neocities/file/get_CreatedAt.md diff --git a/docs/neocities/file/get_CreatedAt.md b/docs/neocities/file/get_CreatedAt.md new file mode 100644 index 0000000..eab9266 --- /dev/null +++ b/docs/neocities/file/get_CreatedAt.md @@ -0,0 +1,13 @@ +get_CreatedAt +------------- + +### Synopsis +Gets the creation time + +--- + +### Description + +Gets the creation time, as a `[DateTime]` object. + +--- From f4aaeb1a058542ea9ff5ca946a8dd0c317044c64 Mon Sep 17 00:00:00 2001 From: StartAutomating Date: Tue, 1 Apr 2025 00:13:07 +0000 Subject: [PATCH 26/30] release: Neocities 0.1 ( Fixes #1 ) --- docs/neocities/file/get_UpdatedAt.md | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 docs/neocities/file/get_UpdatedAt.md diff --git a/docs/neocities/file/get_UpdatedAt.md b/docs/neocities/file/get_UpdatedAt.md new file mode 100644 index 0000000..d3841b5 --- /dev/null +++ b/docs/neocities/file/get_UpdatedAt.md @@ -0,0 +1,13 @@ +get_UpdatedAt +------------- + +### Synopsis +Gets the last update time + +--- + +### Description + +Gets the last update time, as a `[DateTime]` object. + +--- From 86b735c4234954017947b5a5975b16f0476d3d0c Mon Sep 17 00:00:00 2001 From: StartAutomating Date: Tue, 1 Apr 2025 00:13:08 +0000 Subject: [PATCH 27/30] release: Neocities 0.1 ( Fixes #1 ) --- docs/neocities/info/README.md | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 docs/neocities/info/README.md diff --git a/docs/neocities/info/README.md b/docs/neocities/info/README.md new file mode 100644 index 0000000..c644323 --- /dev/null +++ b/docs/neocities/info/README.md @@ -0,0 +1,8 @@ +## neocities.info + + +### Script Properties + + +* [get_CreatedAt](get_CreatedAt.md) +* [get_UpdatedAt](get_UpdatedAt.md) From ef9ba0461fbbf014d6d2bbc602ec0bd94055aae7 Mon Sep 17 00:00:00 2001 From: StartAutomating Date: Tue, 1 Apr 2025 00:13:08 +0000 Subject: [PATCH 28/30] release: Neocities 0.1 ( Fixes #1 ) --- docs/neocities/info/get_CreatedAt.md | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 docs/neocities/info/get_CreatedAt.md diff --git a/docs/neocities/info/get_CreatedAt.md b/docs/neocities/info/get_CreatedAt.md new file mode 100644 index 0000000..eab9266 --- /dev/null +++ b/docs/neocities/info/get_CreatedAt.md @@ -0,0 +1,13 @@ +get_CreatedAt +------------- + +### Synopsis +Gets the creation time + +--- + +### Description + +Gets the creation time, as a `[DateTime]` object. + +--- From a0f001689c9d440bdf55b65bd2631d90db71bcf9 Mon Sep 17 00:00:00 2001 From: StartAutomating Date: Tue, 1 Apr 2025 00:13:08 +0000 Subject: [PATCH 29/30] release: Neocities 0.1 ( Fixes #1 ) --- docs/neocities/info/get_UpdatedAt.md | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 docs/neocities/info/get_UpdatedAt.md diff --git a/docs/neocities/info/get_UpdatedAt.md b/docs/neocities/info/get_UpdatedAt.md new file mode 100644 index 0000000..d3841b5 --- /dev/null +++ b/docs/neocities/info/get_UpdatedAt.md @@ -0,0 +1,13 @@ +get_UpdatedAt +------------- + +### Synopsis +Gets the last update time + +--- + +### Description + +Gets the last update time, as a `[DateTime]` object. + +--- From 41d71c7caf9828ce784d81d7e49f93a869d53446 Mon Sep 17 00:00:00 2001 From: James Brundage <+@noreply.github.com> Date: Mon, 31 Mar 2025 17:25:24 -0700 Subject: [PATCH 30/30] release: Neocities 0.1 ( Fixes #1, Fixes #6, Fixes #10 ) Adding workflow definition and FUNDING.yml --- .github/FUNDING.yml | 1 + Build/Neocities.GitHubWorkflow.PSDevOps.ps1 | 15 +++++++++++++++ 2 files changed, 16 insertions(+) create mode 100644 .github/FUNDING.yml create mode 100644 Build/Neocities.GitHubWorkflow.PSDevOps.ps1 diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml new file mode 100644 index 0000000..36bd853 --- /dev/null +++ b/.github/FUNDING.yml @@ -0,0 +1 @@ +github: [StartAutomating] diff --git a/Build/Neocities.GitHubWorkflow.PSDevOps.ps1 b/Build/Neocities.GitHubWorkflow.PSDevOps.ps1 new file mode 100644 index 0000000..8e4c551 --- /dev/null +++ b/Build/Neocities.GitHubWorkflow.PSDevOps.ps1 @@ -0,0 +1,15 @@ +#requires -Module PSDevOps +Import-BuildStep -SourcePath ( + Join-Path $PSScriptRoot 'GitHub' +) -BuildSystem GitHubWorkflow + +Push-Location ($PSScriptRoot | Split-Path) + +New-GitHubWorkflow -Name "Build Module" -On Push, + PullRequest, Demand -Job TestPowerShellOnLinux, + TagReleaseAndPublish, BuildNeocities -Environment ([Ordered]@{ + REGISTRY = 'ghcr.io' + IMAGE_NAME = '${{ github.repository }}' + }) -OutputPath .\.github\workflows\Build.yml + +Pop-Location \ No newline at end of file