Hi Fam!
So i jumped into the AI wagon. As Im currently creating the B4XDaisy UIKit, i had an idea last week about creating automated changelogs about this beautiful TailwindCSS based framework.
My Release folder is structured in such a way that each version has its own folder.
The purpose of my changelog is to compare 2 b4xlibs and give me whats new and what has changed. So I wrote a prompt so that the AI agent can do that and generate for me a report. It fires up a Powershell script (which I approve) before it runs.
This mermaid chart has been generated with AI from "create for me a mermaid chart based on my xxxx script". As I also wanted to get it as an image, I included that it should help me with a png to print it. So it generated an HTML file with a button to click and download the image.
Here is my powershell script generated by AI.
Usage.... "whatsnew 0.50 0.40"
The Generated Changelog...
I did not want a detailed "diff" per file...
#SharingTheGoodness
So i jumped into the AI wagon. As Im currently creating the B4XDaisy UIKit, i had an idea last week about creating automated changelogs about this beautiful TailwindCSS based framework.
My Release folder is structured in such a way that each version has its own folder.
The purpose of my changelog is to compare 2 b4xlibs and give me whats new and what has changed. So I wrote a prompt so that the AI agent can do that and generate for me a report. It fires up a Powershell script (which I approve) before it runs.
This mermaid chart has been generated with AI from "create for me a mermaid chart based on my xxxx script". As I also wanted to get it as an image, I included that it should help me with a png to print it. So it generated an HTML file with a button to click and download the image.
Here is my powershell script generated by AI.
Usage.... "whatsnew 0.50 0.40"
B4X:
Param(
[Parameter(Mandatory=$false, Position=0)]
[string]$OldVersion,
[Parameter(Mandatory=$false, Position=1)]
[string]$OutReleaseVersion,
[Parameter(Mandatory=$false, Position=2)]
[string]$NewLibPath
)
if (-not $OldVersion) {
Write-Host "Usage: .\whatsnew.ps1 <old-version> [out-release-version] [new-b4xlib-path] e.g. .\whatsnew.ps1 0.40 0.50 C:\dist\Libraries\B4XDaisyUIKit.b4xlib"
exit 1
}
$scriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path
$releasesLibDir = Join-Path $scriptDir "Releases\v$OldVersion\Libraries"
Add-Type -AssemblyName System.IO.Compression.FileSystem -ErrorAction SilentlyContinue
# locate old library (if present)
$oldLib = $null
if (Test-Path $releasesLibDir) {
$oldLib = Get-ChildItem -Path $releasesLibDir -Filter "*.b4xlib" -File | Where-Object { $_.Name -match 'Daisy' } | Select-Object -First 1
if (-not $oldLib) { $oldLib = Get-ChildItem -Path $releasesLibDir -Filter "*.b4xlib" -File | Select-Object -First 1 }
}
function Get-ZipBasMap([string]$zipPath) {
$map = @{}
try {
$z = [System.IO.Compression.ZipFile]::OpenRead($zipPath)
} catch {
Write-Error ("Failed to open {0}: {1}" -f $zipPath, $_)
return $map
}
foreach ($entry in $z.Entries) {
if ($entry.FullName -like '*.bas') {
$stream = $entry.Open()
$sha = [System.Security.Cryptography.SHA256]::Create()
try {
$hashBytes = $sha.ComputeHash($stream)
$hash = [System.BitConverter]::ToString($hashBytes) -replace '-', ''
$map[$entry.Name] = $hash
} finally {
$stream.Close()
$sha.Dispose()
}
}
}
$z.Dispose()
return $map
}
$oldMap = @{}
if ($oldLib) { $oldMap = Get-ZipBasMap $oldLib.FullName }
# resolve new lib path
$newLibPathResolved = $null
if ($NewLibPath) { $newLibPathResolved = $NewLibPath }
else {
$candidate1 = Join-Path $scriptDir 'dist\Libraries\B4XDaisyUIKit.b4xlib'
$candidate2 = 'C:\b4a\libraries\B4XDaisyUIKit.b4xlib'
if (Test-Path $candidate1) { $newLibPathResolved = $candidate1 }
elseif (Test-Path $candidate2) { $newLibPathResolved = $candidate2 }
}
$newMap = @{}
if ($newLibPathResolved) { $newMap = Get-ZipBasMap $newLibPathResolved }
# Compare libs if possible
$whatsnew = @()
$modified = @()
$removed = @()
if ($newMap.Count -gt 0) {
if ($oldMap.Count -eq 0) {
# everything in new is new
$whatsnew = $newMap.Keys | Sort-Object
} else {
$oldKeys = $oldMap.Keys
$newKeys = $newMap.Keys
foreach ($k in $newKeys) {
if (-not ($oldKeys -contains $k)) { $whatsnew += $k }
else { if ($oldMap[$k] -ne $newMap[$k]) { $modified += $k } }
}
foreach ($k in $oldKeys) { if (-not ($newKeys -contains $k)) { $removed += $k } }
}
# write basic whatsnewlist (new files only)
# Disabled: Only generating markdown changelog
if ($whatsnew.Count -eq 0) {
Write-Host "No new B4XDaisy*.bas files found comparing libs (old: v$OldVersion)."
} else {
Write-Host "Found $($whatsnew.Count) new file(s):"
$whatsnew | ForEach-Object { Write-Host " - $_" }
}
# write detailed whatsnew into release root if requested
# Disabled: Only generating markdown changelog
if (-not [string]::IsNullOrWhiteSpace($OutReleaseVersion)) {
# Skip whatsnew.txt generation - only create markdown changelog
}
# Generate diffs for new and modified files to aid release notes
# Diff generation disabled by user request. No per-file diffs will be produced.
# Generate a markdown CHANGELOG in the release root (no links to diffs)
if (-not [string]::IsNullOrWhiteSpace($OutReleaseVersion)) {
$releaseRoot = Join-Path $scriptDir "Releases\v$OutReleaseVersion"
$changelogPath = Join-Path $releaseRoot ("CHANGELOG v{0}.md" -f $OutReleaseVersion)
$repoUrl = 'https://github.com/Mashiane/Sithaso-B4XDaisy-UIKit---Native-Android-Components-inspired-by-DaisyUI'
$chLines = @()
$chLines += "# Changelog - v$OutReleaseVersion"
$chLines += ""
$chLines += ("Generated on: " + (Get-Date -Format 'yyyy-MM-dd'))
$chLines += ""
$chLines += ("Compare: v$OldVersion -> v$OutReleaseVersion")
$chLines += ""
$chLines += "Repository: $repoUrl"
$chLines += ""
$chLines += "## Summary"
$chLines += ""
# Sort new files alphabetically; sort modified files alphabetically
$newSorted = $whatsnew | Sort-Object
$modSorted = $modified | Sort-Object
$chLines += ("- New components: " + ($newSorted.Count))
$chLines += ("- Modified components: " + ($modSorted.Count))
$chLines += ("- Removed components: " + ($removed.Count))
$chLines += ""
$chLines += "## New Files"
$chLines += ""
if ($newSorted.Count -eq 0) { $chLines += "- (none)" } else { $newSorted | ForEach-Object { $chLines += ("- " + $_) } }
$chLines += ""
$chLines += "## Modified Files"
$chLines += ""
if ($modSorted.Count -eq 0) { $chLines += "- (none)" } else { $modSorted | ForEach-Object { $chLines += ("- " + $_) } }
$chLines += ""
$chLines += "## Removed Files"
$chLines += ""
if ($removed.Count -eq 0) { $chLines += "- (none)" } else { $removed | ForEach-Object { $chLines += ("- " + $_) } }
$chLines | Out-File -FilePath $changelogPath -Encoding UTF8
Write-Host "Wrote release changelog to $changelogPath"
}
exit 0
}
# Fallback: legacy behavior comparing local source files to old lib entries
$localDir = Join-Path $scriptDir 'B4A'
if (-not (Test-Path $localDir)) { Write-Error "Local B4A folder not found at $localDir"; exit 5 }
$localFiles = Get-ChildItem -Path $localDir -Recurse -Filter 'B4XDaisy*.bas' -File | ForEach-Object { $_.Name } | Sort-Object -Unique
$zipNames = $oldMap.Keys
$legacyNew = @()
foreach ($f in $localFiles) { if (-not ($zipNames -contains $f)) { $legacyNew += $f } }
# Disabled: Only generating markdown changelog
if ($legacyNew.Count -eq 0) {
Write-Host "No new B4XDaisy*.bas files found for version $OldVersion."
} else {
Write-Host "Found $($legacyNew.Count) new file(s):"
$legacyNew | ForEach-Object { Write-Host " - $_" }
}
# Skip whatsnewlist generation - only create markdown changelog
if (-not [string]::IsNullOrWhiteSpace($OutReleaseVersion)) {
# Skip whatsnew.txt generation - only create markdown changelog
}
exit 0
The Generated Changelog...
I did not want a detailed "diff" per file...
#SharingTheGoodness