diff --git a/.github/workflows/ContinuousIntegration.yaml b/.github/workflows/ContinuousIntegration.yaml index 133ce1e..904ac0b 100644 --- a/.github/workflows/ContinuousIntegration.yaml +++ b/.github/workflows/ContinuousIntegration.yaml @@ -15,6 +15,13 @@ jobs: uses: actions/setup-dotnet@v5 with: dotnet-version: 10 + - name: Set up PowerShell + shell: bash + run: | + wget --output-document=var/PowerShell.deb --quiet "https://github.com/PowerShell/PowerShell/releases/download/v7.5.4/powershell_7.5.4-1.deb_amd64.deb" + sudo apt-get --assume-yes --quiet install ./var/PowerShell.deb + - name: Install dependencies + run: ./Invoke.ps1 Install - name: Run tests run: ./Invoke.ps1 Test env: diff --git a/.gitignore b/.gitignore index 03555ec..88816da 100644 --- a/.gitignore +++ b/.gitignore @@ -2,5 +2,6 @@ /.idea/ /.vs/ /bin/ -/*/obj/ +/src/*/obj/ +/test/obj/ /var/ diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..93c907c --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,11 @@ +{ + "version": "0.2.0", + "configurations": [ + { + "name": "Script", + "request": "launch", + "type": "PowerShell", + "script": "${workspaceFolder}/Debug.ps1" + } + ] +} diff --git a/ChangeLog.md b/ChangeLog.md index 6aeaf41..8c63cbe 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -1,5 +1,8 @@ # Changelog +## Version [3.3.0](https://github.com/cedx/free-mobile.net/compare/v3.2.0...v3.3.0) +- Merged the [C#](https://learn.microsoft.com/en-us/dotnet/csharp) and [PowerShell](https://learn.microsoft.com/en-us/powershell) projects into one solution. + ## Version [3.2.0](https://github.com/cedx/free-mobile.net/compare/v3.1.0...v3.2.0) - Restored support for [.NET](https://dotnet.microsoft.com/en-us) 9. diff --git a/Debug.ps1 b/Debug.ps1 new file mode 100755 index 0000000..df967bd --- /dev/null +++ b/Debug.ps1 @@ -0,0 +1,7 @@ +#!/usr/bin/env pwsh +$ErrorActionPreference = "Stop" +$PSNativeCommandUseErrorActionPreference = $true +Set-StrictMode -Version Latest + +Import-Module "$PSScriptRoot/FreeMobile.psd1" +# Insert the command to be debugged here. diff --git a/FreeMobile.psd1 b/FreeMobile.psd1 index 1e83adf..eeb21ca 100644 --- a/FreeMobile.psd1 +++ b/FreeMobile.psd1 @@ -1,17 +1,34 @@ @{ - ModuleVersion = "3.2.0" + DefaultCommandPrefix = "FreeMobile" + ModuleVersion = "3.3.0" PowerShellVersion = "7.5" + RootModule = "bin/Belin.FreeMobile.Cmdlets.dll" Author = "Cédric Belin " CompanyName = "Cedric-Belin.fr" Copyright = "© Cédric Belin" Description = "Send SMS messages to your Free Mobile device." + GUID = "8a16d600-a064-4037-9147-d13059c6abf7" + + AliasesToExport = @() + FunctionsToExport = @() + VariablesToExport = @() + + CmdletsToExport = @( + "New-Client" + "Send-Message" + ) + + RequiredAssemblies = @( + "bin/Belin.FreeMobile.dll" + ) PrivateData = @{ PSData = @{ LicenseUri = "https://github.com/cedx/free-mobile.net/blob/main/License.md" ProjectUri = "https://github.com/cedx/free-mobile.net" ReleaseNotes = "https://github.com/cedx/free-mobile.net/releases" + Tags = "api", "client", "free", "mobile", "sms" } } } diff --git a/FreeMobile.slnx b/FreeMobile.slnx index 7519cd5..b0eee23 100644 --- a/FreeMobile.slnx +++ b/FreeMobile.slnx @@ -15,10 +15,14 @@ + + + + @@ -33,11 +37,13 @@ + - + + diff --git a/PSModules.psd1 b/PSModules.psd1 index 1591798..a198403 100644 --- a/PSModules.psd1 +++ b/PSModules.psd1 @@ -1,3 +1,4 @@ @{ + Pester = @{} PSScriptAnalyzer = @{} } diff --git a/ReadMe.md b/ReadMe.md index d639855..cb1ca4c 100644 --- a/ReadMe.md +++ b/ReadMe.md @@ -1,6 +1,6 @@ # Free Mobile for .NET Send SMS messages to your [Free Mobile](https://mobile.free.fr) device, -in [C#](https://learn.microsoft.com/en-us/dotnet/csharp). +in [C#](https://learn.microsoft.com/en-us/dotnet/csharp) and [PowerShell](https://learn.microsoft.com/en-us/powershell). ## Documentation - [User guide](https://github.com/cedx/free-mobile.net/wiki) diff --git a/example/Cmdlets/Send-Message.ps1 b/example/Cmdlets/Send-Message.ps1 new file mode 100644 index 0000000..c9405cd --- /dev/null +++ b/example/Cmdlets/Send-Message.ps1 @@ -0,0 +1,9 @@ +<# +.SYNOPSIS + Sends an SMS notification. +#> +Import-Module FreeMobile + +$credential = [pscredential]::new("Your account identifier", (ConvertTo-SecureString "Your API key" -AsPlainText)) +Send-FreeMobileMessage "Hello World from PowerShell!" -Credential $credential +Write-Output "The message was sent successfully." diff --git a/src/FreeMobile.Cmdlets/FreeMobile.Cmdlets.csproj b/src/FreeMobile.Cmdlets/FreeMobile.Cmdlets.csproj new file mode 100644 index 0000000..156af5e --- /dev/null +++ b/src/FreeMobile.Cmdlets/FreeMobile.Cmdlets.csproj @@ -0,0 +1,39 @@ + + + Cedric-Belin.fr + © Cédric Belin + Send SMS messages to your Free Mobile device. + Free Mobile for PowerShell + 2.0.0 + + + + CedX + true + MIT + ReadMe.md + api;client;free;mobile;sms + https://github.com/cedx/free-mobile.net.git + snupkg + + + + false + Belin.FreeMobile.Cmdlets + true + enable + enable + ../../bin + net9.0 + + + + + + + + + + + + diff --git a/src/FreeMobile.Cmdlets/New-Client.cs b/src/FreeMobile.Cmdlets/New-Client.cs new file mode 100644 index 0000000..2e22e6b --- /dev/null +++ b/src/FreeMobile.Cmdlets/New-Client.cs @@ -0,0 +1,29 @@ +namespace Belin.FreeMobile.Cmdlets; + +using System.Net; + +/// +/// Creates a new Free Mobile client. +/// +[Cmdlet(VerbsCommon.New, "Client")] +[OutputType(typeof(Client))] +public class NewClient: PSCmdlet { + + /// + /// The Free Mobile user name and password. + /// + [Parameter(Mandatory = true, Position = 0, ValueFromPipeline = true), Credential] + public required PSCredential Credential { get; set; } + + /// + /// The base URL of the remote API endpoint. + /// + [Parameter] + public Uri? Uri { get; set; } + + /// + /// Performs execution of this command. + /// + protected override void ProcessRecord() => + WriteObject(new Client((NetworkCredential) Credential, Uri)); +} diff --git a/src/FreeMobile.Cmdlets/Send-Message.cs b/src/FreeMobile.Cmdlets/Send-Message.cs new file mode 100644 index 0000000..1ba2518 --- /dev/null +++ b/src/FreeMobile.Cmdlets/Send-Message.cs @@ -0,0 +1,48 @@ +namespace Belin.FreeMobile.Cmdlets; + +using System.Net; + +/// +/// Sends an SMS message to the specified Free Mobile account. +/// +[Cmdlet(VerbsCommunications.Send, "Message", DefaultParameterSetName = "Credential")] +[OutputType(typeof(void))] +public class SendMessage: PSCmdlet { + + /// + /// The Free Mobile client to use. + /// + [Parameter(Mandatory = true, ParameterSetName = "Client")] + public required Client Client { get; set; } + + /// + /// The Free Mobile user name and password. + /// + [Parameter(Mandatory = true, ParameterSetName = "Credential"), Credential] + public required PSCredential Credential { get; set; } + + /// + /// The message text. + /// + [Parameter(Mandatory = true, Position = 0, ValueFromPipeline = true)] + public required string Message { get; set; } + + /// + /// The base URL of the remote API endpoint. + /// + [Parameter(ParameterSetName = "Credential")] + public Uri? Uri { get; set; } + + /// + /// Performs initialization of command execution. + /// + protected override void BeginProcessing() { + if (ParameterSetName == "Credential") Client = new Client((NetworkCredential) Credential, Uri); + } + + /// + /// Performs execution of this command. + /// + protected override void ProcessRecord() => + Client.SendMessage(Message).GetAwaiter().GetResult(); +} diff --git a/src/Client.cs b/src/FreeMobile/Client.cs similarity index 100% rename from src/Client.cs rename to src/FreeMobile/Client.cs diff --git a/src/FreeMobile.csproj b/src/FreeMobile/FreeMobile.csproj similarity index 91% rename from src/FreeMobile.csproj rename to src/FreeMobile/FreeMobile.csproj index ffb4cfd..c52654f 100644 --- a/src/FreeMobile.csproj +++ b/src/FreeMobile/FreeMobile.csproj @@ -22,11 +22,11 @@ Belin.FreeMobile enable enable - ../bin + ../../bin net9.0 - + diff --git a/test/Cmdlets/Send-Message.Tests.ps1 b/test/Cmdlets/Send-Message.Tests.ps1 new file mode 100644 index 0000000..938945b --- /dev/null +++ b/test/Cmdlets/Send-Message.Tests.ps1 @@ -0,0 +1,24 @@ +<# +.SYNOPSIS + Tests the features of the `Send-Message` cmdlet. +#> +Describe "Send-Message" { + BeforeAll { + Import-Module ./FreeMobile.psd1 + } + + It "should throw an exception if a network error occurred" { + $credential = [pscredential]::new("anonymous", (ConvertTo-SecureString "secret" -AsPlainText)) + { "Hello World!" | Send-FreeMobileMessage -Credential $credential -Uri "http://localhost:666" } | Should -Throw + } + + It "should throw an exception if the credentials are invalid" { + $credential = [pscredential]::new("anonymous", (ConvertTo-SecureString "secret" -AsPlainText)) + { "Hello World!" | Send-FreeMobileMessage -Credential $credential } | Should -Throw + } + + It "should send SMS messages if the credentials are valid" { + $credential = [pscredential]::new($Env:FREEMOBILE_ACCOUNT, (ConvertTo-SecureString $Env:FREEMOBILE_API_KEY -AsPlainText)) + { "Hello Cédric, from PowerShell!" | Send-FreeMobileMessage -Credential $credential } | Should -Not -Throw + } +} diff --git a/test/FreeMobile.Tests.csproj b/test/FreeMobile.Tests.csproj index 15a5b59..6d19969 100644 --- a/test/FreeMobile.Tests.csproj +++ b/test/FreeMobile.Tests.csproj @@ -3,7 +3,7 @@ Cedric-Belin.fr © Cédric Belin Free Mobile for .NET - 3.2.0 + 3.3.0 @@ -20,7 +20,8 @@ - + + diff --git a/tool/Clean.ps1 b/tool/Clean.ps1 index ffc27f0..0eea56f 100644 --- a/tool/Clean.ps1 +++ b/tool/Clean.ps1 @@ -1,4 +1,5 @@ "Deleting all generated files..." Remove-Item "bin" -ErrorAction Ignore -Force -Recurse -Remove-Item "*/obj" -Force -Recurse +Remove-Item "src/*/obj" -Force -Recurse +Remove-Item "test/obj" -ErrorAction Ignore -Force -Recurse Remove-Item "var/*" -Exclude ".gitkeep" -Force -Recurse diff --git a/tool/Lint.ps1 b/tool/Lint.ps1 index ba35e3d..79e3d45 100644 --- a/tool/Lint.ps1 +++ b/tool/Lint.ps1 @@ -1,4 +1,5 @@ "Performing the static analysis of source code..." Import-Module PSScriptAnalyzer Invoke-ScriptAnalyzer $PSScriptRoot -Recurse +Invoke-ScriptAnalyzer test -Recurse Test-ModuleManifest FreeMobile.psd1 | Out-Null diff --git a/tool/Publish.ps1 b/tool/Publish.ps1 index 84c4620..3e1a2ea 100644 --- a/tool/Publish.ps1 +++ b/tool/Publish.ps1 @@ -1,12 +1,34 @@ -& "$PSScriptRoot/Clean.ps1" -& "$PSScriptRoot/Version.ps1" +if ($Release) { + & "$PSScriptRoot/Clean.ps1" + & "$PSScriptRoot/Version.ps1" +} +else { + "The ""-Release"" switch must be set!" + exit 1 +} "Publishing the package..." -$version = (Import-PowerShellDataFile "FreeMobile.psd1").ModuleVersion +$module = Import-PowerShellDataFile "FreeMobile.psd1" +$version = $module.ModuleVersion git tag "v$version" git push origin "v$version" -dotnet pack --output var -foreach ($item in Get-Item "var/*.nupkg") { +$output = "var/NuGet" +dotnet pack --output $output +foreach ($item in Get-Item "$output/*.nupkg") { dotnet nuget push $item --api-key $Env:NUGET_API_KEY --source https://api.nuget.org/v3/index.json } + +$output = "var/PSModule" +New-Item $output/bin -ItemType Directory | Out-Null +Copy-Item "FreeMobile.psd1" $output +Copy-Item *.md $output +Copy-Item $module.RootModule $output/bin +if ("RequiredAssemblies" -in $module.Keys) { Copy-Item $module.RequiredAssemblies $output/bin } + +$output = "var/PSGallery" +New-Item $output -ItemType Directory | Out-Null +Compress-PSResource var/PSModule $output +foreach ($item in Get-Item "$output/*.nupkg") { + Publish-PSResource -ApiKey $Env:PSGALLERY_API_KEY -NupkgPath $item +} diff --git a/tool/Test.ps1 b/tool/Test.ps1 index 475427c..798feab 100644 --- a/tool/Test.ps1 +++ b/tool/Test.ps1 @@ -1,2 +1,7 @@ "Running the test suite..." dotnet test --results-directory var +pwsh -Command { + Import-Module Pester + Invoke-Pester test + exit $LASTEXITCODE +} diff --git a/tool/Version.ps1 b/tool/Version.ps1 index 8252912..b17b895 100644 --- a/tool/Version.ps1 +++ b/tool/Version.ps1 @@ -1,5 +1,5 @@ "Updating the version number in the sources..." $version = (Import-PowerShellDataFile "FreeMobile.psd1").ModuleVersion -foreach ($item in Get-Item "*/*.csproj") { +foreach ($item in Get-ChildItem "*/*.csproj" -Recurse) { (Get-Content $item) -replace "\d+(\.\d+){2}", "$version" | Out-File $item } diff --git a/tool/Watch.ps1 b/tool/Watch.ps1 new file mode 100644 index 0000000..7582a8b --- /dev/null +++ b/tool/Watch.ps1 @@ -0,0 +1,3 @@ +"Watching for file changes..." +$configuration = $Release ? "Release" : "Debug" +Start-Process dotnet "watch build --configuration $configuration" -NoNewWindow -Wait -WorkingDirectory src