Skip to content

Commit b3f0408

Browse files
authored
Merge branch 'main' into bugfix/readme
2 parents 7abe2d7 + fe4fb7f commit b3f0408

27 files changed

Lines changed: 1100 additions & 223 deletions

.github/workflows/pester-tests.yml

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,6 @@ name: Pester Tests
33
on:
44
pull_request:
55
branches: [ main ]
6-
push:
7-
branches: [ main ]
86

97
jobs:
108
pester-tests:

.github/workflows/publish.yml

Lines changed: 21 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,18 @@ jobs:
186186
if ($testResults.FailedCount -gt 0) {
187187
throw "Tests failed. Cannot publish to PowerShell Gallery."
188188
}
189+
190+
- name: Inject Values into Module
191+
shell: pwsh
192+
env:
193+
CLIENT_ID: ${{ secrets.GOOGLE_CLIENT_ID }}
194+
CLIENT_SECRET: ${{ secrets.GOOGLE_CLIENT_SECRET }}
195+
run: |
196+
$file = "./src/public/Initialize-Blogger.ps1"
197+
$content = Get-Content $file -Raw
198+
$content = $content -replace "<<CLIENT_ID>>", $env:CLIENT_ID
199+
$content = $content -replace "<<CLIENT_SECRET>>", $env:CLIENT_SECRET
200+
$content | Set-Content -Path $file -Force
189201
190202
- name: Publish to PowerShell Gallery
191203
shell: pwsh
@@ -274,45 +286,19 @@ jobs:
274286
Write-Host "Created and pushed tag v${{ steps.version.outputs.version }}"
275287
}
276288
277-
- name: Get Commit Messages for Release Notes
278-
if: steps.run-mode.outputs.is-dry-run == 'false'
279-
id: release-notes
280-
shell: pwsh
281-
run: |
282-
# Get the previous tag
283-
$previousTag = git describe --tags --abbrev=0 "v${{ steps.version.outputs.version }}~1" 2>$null
284-
if ($LASTEXITCODE -ne 0) {
285-
# If no previous tag, get last 10 commits
286-
$commits = git log --oneline --pretty=format:"- %s (%h)" -n 10
287-
} else {
288-
# Get commits since the previous tag
289-
$commits = git log --oneline --pretty=format:"- %s (%h)" "$previousTag..v${{ steps.version.outputs.version }}"
290-
}
291-
292-
$releaseNotes = @"
293-
## Changes in version ${{ steps.version.outputs.version }}
294-
295-
$($commits -join "`n")
296-
297-
## Installation
298-
``````powershell
299-
Install-Module -Name PSBlogger -RequiredVersion ${{ steps.version.outputs.version }}
300-
``````
301-
"@
302-
303-
# Escape for GitHub Actions
304-
$releaseNotes = $releaseNotes -replace "`r`n", "`n" -replace "`n", "%0A"
305-
echo "release-notes=$releaseNotes" >> $env:GITHUB_OUTPUT
306-
307289
- name: Create GitHub Release
308290
if: steps.run-mode.outputs.is-dry-run == 'false'
309-
uses: actions/create-release@v1
310-
env:
311-
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
291+
uses: softprops/action-gh-release@v2
312292
with:
313293
tag_name: v${{ steps.version.outputs.version }}
314-
release_name: Release v${{ steps.version.outputs.version }}
315-
body: ${{ steps.release-notes.outputs.release-notes }}
294+
name: Release v${{ steps.version.outputs.version }}
295+
generate_release_notes: true
296+
append_body: true
297+
body: |
298+
## Installation
299+
```powershell
300+
Install-Module -Name PSBlogger -RequiredVersion ${{ steps.version.outputs.version }}
301+
```
316302
draft: false
317303
prerelease: false
318304

CONTRIBUTING.md

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
# Contribution Guide
2+
3+
## Environment Setup
4+
5+
### Tools
6+
7+
Local development requires the following:
8+
9+
- PowerShell 7.x
10+
- Pester 5.7.1
11+
- [Pandoc](https://pandoc.org)
12+
- Visual Studio Code, with the following extensions:
13+
- Test Adapter Converter
14+
- Test Explorer UI
15+
- Pester Tests
16+
17+
Development is presently done on Windows 11, though conceptually it should work on Linux
18+
19+
### Codespace
20+
21+
As an alternative to local development environments, a GitHub Codespace can be used to build and test. Codespace usage has an [associated cost](https://docs.github.com/en/billing/concepts/product-billing/github-codespaces). The free option should be sufficient for most developers.
22+
23+
Codespaces are Linux based and require the above tools to be installed.
24+
25+
TODO: DevContainer configuration with tools installed is pending.
26+
27+
### Google Application
28+
29+
The environment uses a Google Application with the following setup. The published module has credentials defined, but if you may want to create an application for local testing purposes.
30+
31+
While this is not a fully documented walk-through on how to create a Google Application in the [Developer Console](https://console.cloud.google.com), the application has the following details.
32+
33+
- Branding:
34+
- An app name + support email
35+
- Audience: Testing
36+
- Clients:
37+
- Web Application
38+
- Authorized redirect URIs:
39+
- <http://localhost/oauth2callback>
40+
- <https://localhost:8040/oauth2callback>
41+
- Data Access: uses the following scopes:
42+
43+
- <https://www.googleapis.com/auth/blogger>: manage blogger account and posts
44+
- <https://www.googleapis.com/auth.drive.file>: upload and manage files into Google Drive that are scoped to the application.
45+
46+
For local testing, you'll need the Client ID and Client Secret
47+
48+
## Running Locally
49+
50+
Within Visual Studio Code, you should be able to run the tests with no additional configuration.
51+
52+
To test the module manually, you will need to provide your client-id and client-secret as environment variables.
53+
54+
```shell
55+
cd ./src
56+
./reload.ps1 # to load the source into memory
57+
58+
$env:PSBLOGGER_CLIENT_ID = "<your-id>"
59+
$env:PSBLOGGER_CLIENT_SECRET = "<your-secret>"
60+
61+
Initialize-Blogger
62+
```

README.md

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@ A PowerShell library for publishing markdown files authored in markdown to Blogg
1414
choco install pandoc
1515
```
1616

17-
(Future: still need to publish to PowerShell nuget library)
1817
```
1918
Install-Module PSBlogger
2019
```

src/PSBlogger.psd1

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
RootModule = 'PSBlogger.psm1'
66

77
# Version number of this module.
8-
ModuleVersion = '0.2.0'
8+
ModuleVersion = '0.9.0'
99

1010
# Supported PSEditions
1111
# CompatiblePSEditions = @()
@@ -20,7 +20,7 @@ Author = 'Bryan Cook'
2020
CompanyName = 'Bryan Cook'
2121

2222
# Copyright statement for this module
23-
Copyright = '#169; me'
23+
# Copyright = '#169; me'
2424

2525
# Description of the functionality provided by this module
2626
Description = 'Module to publish markdown files to Blogger'
@@ -97,16 +97,16 @@ PrivateData = @{
9797
Tags = 'blogger','markdown','pandoc'
9898

9999
# A URL to the license for this module.
100-
#LicenseUri = ''
100+
LicenseUri = 'https://github.com/bryanbcook/PSBlogger?tab=MIT-1-ov-file#readme'
101101

102102
# A URL to the main website for this project.
103-
ProjectUri = 'http://www.bryancook.net/'
103+
ProjectUri = 'https://github.com/bryanbcook/PSBlogger'
104104

105105
# A URL to an icon representing this module.
106106
#IconUri = ''
107107

108108
# ReleaseNotes of this module
109-
#ReleaseNotes = ''
109+
ReleaseNotes = 'https://github.com/bryanbcook/PSBlogger/releases'
110110
# Prerelease string of this module
111111
# Prerelease = ''
112112

src/private/AuthWebServer.ps1

Lines changed: 43 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -13,36 +13,60 @@ Function Wait-GoogleAuthApiToken
1313
$HttpListener.Start()
1414

1515
$authCodeReceived = $False
16-
16+
1717
while ($HttpListener.IsListening -and -not $authCodeReceived) {
18-
$HttpContext = $HttpListener.GetContext()
19-
$HttpRequest = $HttpContext.Request
20-
$Query = $HttpRequest.QueryString
18+
# Use async method with timeout to allow for cancellation
19+
$contextTask = $HttpListener.GetContextAsync()
20+
21+
# Wait for either a request or cancellation (check every 500ms)
22+
while (-not $contextTask.IsCompleted) {
23+
Start-Sleep -Milliseconds 500
24+
25+
# Check if user pressed Ctrl+C by testing if we can write to console
26+
try {
27+
[Console]::TreatControlCAsInput = $false
28+
if ([Console]::KeyAvailable) {
29+
$key = [Console]::ReadKey($true)
30+
if ($key.Key -eq 'C' -and $key.Modifiers -eq 'Control') {
31+
Write-Information "`nCancellation requested. Stopping auth server..."
32+
return $null
33+
}
34+
}
35+
}
36+
catch {
37+
# Ignore console access errors
38+
}
39+
}
40+
41+
if ($contextTask.IsCompleted) {
42+
$HttpContext = $contextTask.Result
43+
$HttpRequest = $HttpContext.Request
44+
$Query = $HttpRequest.QueryString
2145

22-
if ($null -ne $Query["code"]) {
23-
$authCode = $Query["code"]
24-
Write-Output $authCode
25-
Write-Verbose "Received auth-code: $authCode"
26-
$authCodeReceived = $true
46+
if ($null -ne $Query["code"]) {
47+
$authCode = $Query["code"]
48+
Write-Output $authCode
49+
Write-Verbose "Received auth-code: $authCode"
50+
$authCodeReceived = $true
2751

28-
# Send "Thanks!"
29-
$buffer = [System.Text.Encoding]::UTF8.GetBytes("<html><body>Good Job! Successfully authorized PSBlogger. You can close this browser window now.</body></html>")
30-
$response = $HttpContext.Response
31-
$response.ContentLength64 = $buffer.Length
32-
$output = $response.OutputStream;
33-
$output.Write($buffer,0,$buffer.Length)
34-
$output.Close() | Write-Verbose
35-
}
52+
# Send "Thanks!"
53+
$buffer = [System.Text.Encoding]::UTF8.GetBytes("<html><body>Good Job! Successfully authorized PSBlogger. You can close this browser window now.</body></html>")
54+
$response = $HttpContext.Response
55+
$response.ContentLength64 = $buffer.Length
56+
$output = $response.OutputStream;
57+
$output.Write($buffer,0,$buffer.Length)
58+
$output.Close() | Write-Verbose
59+
}
60+
}
3661
}
37-
3862
Write-Verbose "Stopping HttpListener."
3963
$HttpListener.Stop()
4064
Write-Verbose "Stopped HttpListener."
4165
}
4266
catch {
4367
# TODO: Catch Permission denied error and warn about running from an elevated prompt
4468
# or add Requires -Administrator
45-
Write-Error $_.ToString()
69+
Write-Error $_.ToString() -ErrorAction Stop
4670
}
4771
finally {
4872
if ($null -ne $HttpListener) {

src/private/Get-AuthHeader.ps1

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,13 @@ function Get-AuthHeader()
44

55
if (!(Test-GoogleAccessToken $BloggerSession.AccessToken))
66
{
7-
$token = Update-GoogleAccessToken -refreshToken $BloggerSession.RefreshToken
7+
$credentialCache = Get-CredentialCache
8+
$updateArgs = @{
9+
clientId = $credentialCache.client_id
10+
clientSecret = $credentialCache.client_secret
11+
refreshToken = $BloggerSession.RefreshToken
12+
}
13+
$token = Update-GoogleAccessToken @updateArgs
814
Update-CredentialCache -token $token
915
}
1016

src/private/GoogleAccessToken.ps1

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,11 @@ function Get-GoogleAccessToken
44
[Parameter(Mandatory=$true)]
55
[string]$code,
66

7-
[Parameter()]
8-
[string]$clientId = "284606892422-ribvo7oodlbtd70e8onn8rg4hm58mluj.apps.googleusercontent.com",
7+
[Parameter(Mandatory=$true)]
8+
[string]$clientId,
99

10-
[Parameter()]
11-
[string]$clientSecret = "PUK0j9ig-GHcSByQao2i1aIa",
10+
[Parameter(Mandatory=$true)]
11+
[string]$clientSecret,
1212

1313
[Parameter()]
1414
[string]$redirectUri = "http://localhost/oauth2callback"
@@ -39,10 +39,10 @@ function Update-GoogleAccessToken
3939
{
4040
param(
4141
[Parameter()]
42-
[string]$clientId = "284606892422-ribvo7oodlbtd70e8onn8rg4hm58mluj.apps.googleusercontent.com",
42+
[string]$clientId,
4343

4444
[Parameter()]
45-
[string]$clientSecret = "PUK0j9ig-GHcSByQao2i1aIa",
45+
[string]$clientSecret,
4646

4747
[Parameter()]
4848
[string]$refreshToken

src/private/ModuleInitHelpers.ps1

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
function Test-IsAdmin
2+
{
3+
$currentIdentity = [System.Security.Principal.WindowsIdentity]::GetCurrent()
4+
$principal = New-Object System.Security.Principal.WindowsPrincipal($currentIdentity)
5+
return $principal.IsInRole([System.Security.Principal.WindowsBuiltInRole]::Administrator)
6+
}
7+
8+
function Test-PandocInstalled {
9+
[CmdletBinding()]
10+
[OutputType([bool])]
11+
param()
12+
13+
try {
14+
$null = Get-Command pandoc -ErrorAction Stop
15+
Write-Verbose "Pandoc is installed and available in PATH"
16+
return $true
17+
}
18+
catch {
19+
Write-Verbose "Pandoc is not installed or not available in PATH"
20+
return $false
21+
}
22+
}
23+
24+
function Test-ChocolateyInstalled {
25+
[CmdletBinding()]
26+
[OutputType([bool])]
27+
param()
28+
29+
try {
30+
$null = Get-Command choco -ErrorAction Stop
31+
Write-Verbose "Chocolatey is installed and available in PATH"
32+
return $true
33+
}
34+
catch {
35+
Write-Verbose "Chocolatey is not installed or not available in PATH"
36+
return $false
37+
}
38+
}
39+
40+
function Install-PandocWithChocolatey {
41+
[CmdletBinding()]
42+
param()
43+
44+
Write-Information "Installing Pandoc using Chocolatey..."
45+
46+
try {
47+
$process = Start-Process choco -ArgumentList "install", "pandoc", "-y" -NoNewWindow -Wait -PassThru
48+
49+
if ($process.ExitCode -eq 0) {
50+
Write-Information "Pandoc installation completed successfully."
51+
Write-Information "You may need to restart your PowerShell session for Pandoc to be available in PATH."
52+
}
53+
else {
54+
Write-Error "Pandoc installation failed with exit code: $($process.ExitCode)"
55+
}
56+
}
57+
catch {
58+
Write-Error "Failed to install Pandoc: $($_.Exception.Message)"
59+
}
60+
}

0 commit comments

Comments
 (0)