Skip to content

Update publish-all-nuget-packages.yml #51

Update publish-all-nuget-packages.yml

Update publish-all-nuget-packages.yml #51

name: Publish NuGet Packages
on:
push:
branches: [main]
release:
types: [published, prerelease]
permissions:
contents: write
packages: write
jobs:
publish-nuget:
runs-on: ubuntu-latest
strategy:
matrix:
package:
- { id: BlueTeam-Tools, folder: BlueTeam-Tools, nuspec: BlueTeam-Tools.nuspec, tags: "powershell security eventlog incidentresponse blueteam automation enterprise" }
- { id: Core-ScriptLibrary, folder: Core-ScriptLibrary, nuspec: Core-ScriptLibrary.nuspec, tags: "powershell scripting nuget modular automation dotnet" }
- { id: ITSM-Templates-SVR, folder: ITSM-Templates-SVR, nuspec: ITSM-Templates-SVR.nuspec, tags: "itsm server configuration documentation automation enterprise" }
- { id: ITSM-Templates-WKS, folder: ITSM-Templates-WKS, nuspec: ITSM-Templates-WKS.nuspec, tags: "itsm workstation configuration powershell registry automation windows" }
- { id: SysAdmin-Tools, folder: SysAdmin-Tools, nuspec: SysAdmin-Tools.nuspec, tags: "sysadmin activedirectory gpo powershell sso network wsus security automation enterprise" }
fail-fast: false
steps:
- name: 🧾 Checkout repository
uses: actions/checkout@v4
with:
fetch-depth: 0
submodules: recursive
- name: 🛠️ Debug workflow start
run: |
echo "Workflow started for package ${{ matrix.package.id }}"
echo "Event: ${{ github.event_name }}"
echo "Repository: ${{ github.repository }}"
echo "Commit: ${{ github.sha }}"
echo "Listing repository contents:"
ls -R
echo "Checking for .nuspec files in root:"
ls -l *.nuspec || echo "No .nuspec files found in root"
echo "Checking for LICENSE file:"
ls -l LICENSE || echo "LICENSE not found in root"
echo "Checking for CHANGELOG.md:"
ls -l CHANGELOG.md || echo "CHANGELOG.md not found in root"
echo "Checking for package directories:"
for pkg in BlueTeam-Tools Core-ScriptLibrary ITSM-Templates-SVR ITSM-Templates-WKS SysAdmin-Tools; do
ls -lR "$pkg" || echo "Directory $pkg not found"
done
echo "Checking .NET SDK version:"
dotnet --version
echo "Checking for mono and nuget availability:"
which mono || echo "mono not found"
which nuget || echo "nuget not found"
- name: 📦 Install dependencies
run: |
echo "Installing mono-complete and xmlstarlet"
sudo apt-get update
sudo apt-get install -y mono-complete xmlstarlet
echo "Checking mono version:"
mono --version
echo "Installing nuget.exe"
wget -O nuget.exe https://dist.nuget.org/win-x86-commandline/v6.11.0/nuget.exe
chmod +x nuget.exe
sudo mv nuget.exe /usr/local/bin/nuget
echo "Verifying nuget command:"
mono /usr/local/bin/nuget help | head -n 1
- name: 📁 Prepare and stage files
id: prepare
run: |
pkg="${{ matrix.package.id }}"
folder="${{ matrix.package.folder }}"
nuspec="${{ matrix.package.nuspec }}"
echo "Preparing package $pkg"
if [ ! -f "$nuspec" ]; then
echo "❌ Error: NuSpec file $nuspec missing in root, skipping package"
echo "skip=true" >> "$GITHUB_OUTPUT"
exit 0
fi
mkdir -p ReadmeCopies nupkg-out "tmp-$pkg"
if [ -d "$folder" ]; then
echo "Copying package directory $folder to tmp-$pkg"
cp -r "$folder/." "tmp-$pkg/"
else
echo "⚠️ Warning: Folder $folder missing, proceeding with .nuspec only"
fi
cp "$nuspec" "tmp-$pkg/$nuspec"
if [ -f "$folder/README.md" ]; then
cp "$folder/README.md" "ReadmeCopies/$pkg-README.md"
cp "ReadmeCopies/$pkg-README.md" "tmp-$pkg/$pkg-README.md"
echo "Copied README.md for $pkg"
else
echo "⚠️ Warning: README.md not found for $pkg"
fi
if [ -f "$folder/icon.png" ]; then
cp "$folder/icon.png" "tmp-$pkg/icon.png"
echo "Copied icon.png for $pkg"
else
echo "⚠️ Warning: icon.png not found for $pkg"
fi
if [ -f "LICENSE" ]; then
cp "LICENSE" "tmp-$pkg/LICENSE"
echo "Copied LICENSE to tmp-$pkg"
else
echo "❌ Error: LICENSE file not found in root, skipping package"
echo "skip=true" >> "$GITHUB_OUTPUT"
exit 0
fi
echo "Listing tmp-$pkg contents:"
ls -lR "tmp-$pkg"
echo "Checking .nuspec file contents:"
cat "$nuspec"
echo "Validating .nuspec metadata:"
xmlstarlet val "$nuspec" || { echo "❌ Error: Invalid XML in $nuspec"; echo "skip=true" >> "$GITHUB_OUTPUT"; exit 0; }
xmlstarlet sel -t -m "//metadata/id" -v . "$nuspec" > /dev/null || { echo "❌ Error: Missing id in $nuspec"; echo "skip=true" >> "$GITHUB_OUTPUT"; exit 0; }
xmlstarlet sel -t -m "//metadata/version" -v . "$nuspec" > /dev/null || { echo "❌ Error: Missing version in $nuspec"; echo "skip=true" >> "$GITHUB_OUTPUT"; exit 0; }
xmlstarlet sel -t -m "//metadata/authors" -v . "$nuspec" > /dev/null || { echo "❌ Error: Missing authors in $nuspec"; echo "skip=true" >> "$GITHUB_OUTPUT"; exit 0; }
xmlstarlet sel -t -m "//metadata/description" -v . "$nuspec" > /dev/null || { echo "❌ Error: Missing description in $nuspec"; echo "skip=true" >> "$GITHUB_OUTPUT"; exit 0; }
xmlstarlet sel -t -m "//metadata/license" -v . "$nuspec" > /dev/null || { echo "❌ Error: Missing license in $nuspec"; echo "skip=true" >> "$GITHUB_OUTPUT"; exit 0; }
xmlstarlet sel -t -m "//metadata/projectUrl" -v . "$nuspec" > /dev/null || { echo "❌ Error: Missing projectUrl in $nuspec"; echo "skip=true" >> "$GITHUB_OUTPUT"; exit 0; }
echo "Validating .nuspec file paths:"
invalid_paths=false
grep '<file src="' "$nuspec" | while read -r line ; do
src=$(echo "$line" | sed -E 's/.*src="([^"]+)".*/\1/')
src_expanded=$(echo "$src" | sed "s|\${{ matrix.package.folder }}|$folder|g")
if [[ "$src" == */*/* ]]; then
dir=$(echo "$src_expanded" | cut -d'/' -f1)
if [ -d "tmp-$pkg/$dir" ]; then
echo "Path $src_expanded exists in tmp-$pkg"
else
echo "❌ Error: Directory $dir for $src in $nuspec does not exist in tmp-$pkg"
invalid_paths=true
fi
elif [ -f "tmp-$pkg/$src_expanded" ]; then
echo "Path $src_expanded exists in tmp-$pkg"
else
echo "❌ Error: File $src_expanded in $nuspec does not exist in tmp-$pkg"
invalid_paths=true
fi
done
if [ "$invalid_paths" = "true" ]; then
echo "❌ Error: Invalid paths found in $nuspec, skipping package"
echo "skip=true" >> "$GITHUB_OUTPUT"
exit 0
fi
echo "skip=false" >> "$GITHUB_OUTPUT"
- name: 📖 Enhance .nuspec with rich metadata
if: steps.prepare.outputs.skip != 'true'
run: |
pkg="${{ matrix.package.id }}"
nuspec="${{ matrix.package.nuspec }}"
folder="${{ matrix.package.folder }}"
version=$(xmlstarlet sel -t -m "//metadata/version" -v . "$nuspec" || echo "0.0.0")
if [ -z "$version" ]; then
echo "⚠️ Warning: Version not found in $nuspec, using default"
version="0.0.0"
fi
echo "version=$version" >> "$GITHUB_OUTPUT"
changelog=$(awk "/^## \\[$version\\]/,/^## \\[/" CHANGELOG.md | sed '1d;/^## \\[/d' || echo "No changelog found for version $version")
changelog_sanitized=$(printf "%s" "$changelog" | sed ':a;N;$!ba;s/\n/\\n/g;s/"/\\"/g')
echo "notes=$changelog_sanitized" >> "$GITHUB_OUTPUT"
# Update .nuspec with rich metadata
cp "tmp-$pkg/$nuspec" "tmp-$pkg/$nuspec.bak"
xmlstarlet ed \
-u "//metadata/releaseNotes" -v "$changelog_sanitized" \
-s "//metadata[not(releaseNotes)]" -t elem -n "releaseNotes" -v "$changelog_sanitized" \
-u "//metadata/tags" -v "${{ matrix.package.tags }}" \
-s "//metadata[not(tags)]" -t elem -n "tags" -v "${{ matrix.package.tags }}" \
-s "//metadata[not(icon)]" -t elem -n "icon" -v "icon.png" \
-s "//metadata[not(repository)]" -t elem -n "repository" -v "" \
-s "//metadata/repository" -t attr -n "type" -v "git" \
-s "//metadata/repository" -t attr -n "url" -v "https://github.com/${{ github.repository }}" \
-s "//metadata/repository" -t attr -n "branch" -v "${{ github.ref_name }}" \
-s "//metadata/repository" -t attr -n "commit" -v "${{ github.sha }}" \
-s "//metadata[not(copyright)]" -t elem -n "copyright" -v "Copyright (c) 2025 Luiz Hamilton Roberto da Silva" \
-s "//metadata[not(owners)]" -t elem -n "owners" -v "Luiz Hamilton Roberto da Silva" \
-s "//metadata[not(requireLicenseAcceptance)]" -t elem -n "requireLicenseAcceptance" -v "false" \
"tmp-$pkg/$nuspec" > "tmp-$pkg/$nuspec.tmp"
mv "tmp-$pkg/$nuspec.tmp" "tmp-$pkg/$nuspec"
# Add README.md and icon.png to files if present
if [ -f "tmp-$pkg/$pkg-README.md" ]; then
xmlstarlet ed -s "//files" -t elem -n "file" -v "" \
-s "//files/file[last()]" -t attr -n "src" -v "$pkg-README.md" \
-s "//files/file[last()]" -t attr -n "target" -v "content" \
"tmp-$pkg/$nuspec" > "tmp-$pkg/$nuspec.tmp"
mv "tmp-$pkg/$nuspec.tmp" "tmp-$pkg/$nuspec"
fi
if [ -f "tmp-$pkg/icon.png" ]; then
xmlstarlet ed -s "//files" -t elem -n "file" -v "" \
-s "//files/file[last()]" -t attr -n "src" -v "icon.png" \
-s "//files/file[last()]" -t attr -n "target" -v "images" \
"tmp-$pkg/$nuspec" > "tmp-$pkg/$nuspec.tmp"
mv "tmp-$pkg/$nuspec.tmp" "tmp-$pkg/$nuspec"
fi
echo "Updated .nuspec with rich metadata:"
cat "tmp-$pkg/$nuspec"
- name: 📦 Pack NuGet package
if: steps.prepare.outputs.skip != 'true'
run: |
pkg="${{ matrix.package.id }}"
nuspec="${{ matrix.package.nuspec }}"
if [ ! -d "tmp-$pkg" ]; then
echo "❌ Error: Directory tmp-$pkg missing, skipping package"
exit 0
fi
cd "tmp-$pkg"
mono /usr/local/bin/nuget pack "$nuspec" \
-OutputDirectory ../nupkg-out \
-Symbols -SymbolPackageFormat snupkg \
-NonInteractive \
|| { echo "❌ Error: Failed to pack $nuspec"; exit 0; }
- name: 🚀 Push to GitHub Packages
if: steps.prepare.outputs.skip != 'true' && (github.event_name == 'push' || github.event_name == 'release')
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
for pkg_path in nupkg-out/*.nupkg nupkg-out/*.snupkg; do
if [ -f "$pkg_path" ]; then
echo "Pushing $pkg_path to GitHub Packages"
mono /usr/local/bin/nuget push "$pkg_path" \
-Source "https://nuget.pkg.github.com/${{ github.repository_owner }}/index.json" \
-ApiKey "$GITHUB_TOKEN" \
-NonInteractive -SkipDuplicate
fi
done
- name: 🚀 Push to NuGet.org
if: steps.prepare.outputs.skip != 'true' && (github.event_name == 'push' || github.event_name == 'release')
env:
NUGET_API_KEY: ${{ secrets.NUGET_API_KEY }}
run: |
for pkg_path in nupkg-out/*.nupkg nupkg-out/*.snupkg; do
if [ -f "$pkg_path" ]; then
echo "Pushing $pkg_path to NuGet.org"
mono /usr/local/bin/nuget push "$pkg_path" \
-Source "https://api.nuget.org/v3/index.json" \
-ApiKey "$NUGET_API_KEY" \
-NonInteractive -SkipDuplicate
fi
done
- name: 🏷️ Create Git tag
if: steps.prepare.outputs.skip != 'true' && (github.event_name == 'push' || github.event_name == 'release')
run: |
tag="${{ matrix.package.id }}-v${{ steps.prepare.outputs.version }}"
if git tag --list | grep -q "^$tag$"; then
echo "Tag $tag already exists, skipping creation"
else
git config user.name "github-actions"
git config user.email "github-actions@github.com"
git tag "$tag"
git push origin "$tag"
fi
- name: 🧹 Clean up
if: always()
run: |
rm -rf "tmp-${{ matrix.package.id }}" ReadmeCopies nupkg-out || true