mirror of
https://github.com/coreybutler/nvm-windows.git
synced 2025-09-02 19:04:19 +00:00
455 lines
15 KiB
YAML
455 lines
15 KiB
YAML
name: Release
|
|
|
|
on:
|
|
workflow_run:
|
|
workflows: ["Autotag"]
|
|
types:
|
|
- completed
|
|
|
|
jobs:
|
|
build:
|
|
runs-on: windows-latest
|
|
|
|
if: ${{ github.event.workflow_run.conclusion == 'success' }}
|
|
|
|
permissions:
|
|
id-token: write
|
|
contents: write
|
|
attestations: write
|
|
|
|
env:
|
|
GO_VERSION: 1.23
|
|
QUIKGO_VERSION: 1.2.6
|
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
AUTHOR_BRIDGE_TOKEN: ${{ secrets.AUTHOR_BRIDGE_TOKEN }}
|
|
|
|
steps:
|
|
- name: Checkout code
|
|
uses: actions/checkout@v4
|
|
|
|
- name: Extract Tag from Event
|
|
id: extract_tag
|
|
shell: pwsh
|
|
run: |
|
|
Write-Host "Event payload:"
|
|
Get-Content $env:GITHUB_EVENT_PATH
|
|
|
|
# Extract the commit SHA from the event payload
|
|
$COMMIT_SHA = (Get-Content -Raw $env:GITHUB_EVENT_PATH | ConvertFrom-Json).workflow_run.head_commit.id
|
|
|
|
if (-not $COMMIT_SHA) {
|
|
Write-Host "Error: No commit SHA found in the event payload."
|
|
exit 1
|
|
}
|
|
|
|
Write-Host "Commit SHA: $COMMIT_SHA"
|
|
|
|
# Fetch tags and find the tag associated with the commit
|
|
git fetch --tags
|
|
$TAG_REF = git tag --contains $COMMIT_SHA | ForEach-Object { $_.Trim() } | Select-Object -First 1
|
|
|
|
if (-not $TAG_REF) {
|
|
Write-Host "Error: No tag found for this commit."
|
|
exit 1
|
|
}
|
|
|
|
Write-Host "Extracted tag reference: $TAG_REF"
|
|
echo "TAG=$TAG_REF" | Out-File -Append -FilePath $env:GITHUB_ENV
|
|
|
|
- name: Display Tag
|
|
shell: pwsh
|
|
run: |
|
|
Write-Host "Identified Tag: $env:TAG"
|
|
|
|
- name: Set up Go
|
|
uses: actions/setup-go@v5
|
|
with:
|
|
go-version: '${{ env.GO_VERSION }}'
|
|
|
|
- name: Cache Go Modules
|
|
uses: actions/cache@v4
|
|
with:
|
|
path: |
|
|
~/.cache/go-build
|
|
~/go/pkg/mod
|
|
key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}
|
|
restore-keys: |
|
|
${{ runner.os }}-go-
|
|
|
|
- name: Cache QuikGo
|
|
uses: actions/cache@v4
|
|
with:
|
|
path: |
|
|
~/go/bin
|
|
key: ${{ runner.os }}-qgo-v${{ env.QUIKGO_VERSION }}
|
|
restore-keys: |
|
|
${{ runner.os }}-qgo-
|
|
|
|
- name: Install QuikGo
|
|
run: |
|
|
if (-not (go list -m github.com/quikdev/go/cmd/qgo@v${{ env.QUIKGO_VERSION }})) {
|
|
if (-not (go list -m github.com/quikdev/go/cmd/qgo@v${{ env.QUIKGO_VERSION }})) {
|
|
go install github.com/quikdev/go/cmd/qgo@v${{ env.QUIKGO_VERSION }}
|
|
} else {
|
|
echo "QuikGo version ${{ env.QUIKGO_VERSION }} already installed."
|
|
}
|
|
} else {
|
|
echo "QuikGo version ${{ env.QUIKGO_VERSION }} already installed."
|
|
}
|
|
|
|
- name: Confirm QuikGo Installation
|
|
run: qgo --version
|
|
|
|
- name: Build NVM for Windows
|
|
run: |
|
|
cd src
|
|
qgo build --profile=release
|
|
echo ${{ github.workspace }}\bin
|
|
dir ${{ github.workspace }}\bin
|
|
cd ..\
|
|
|
|
# - name: Compress Executables
|
|
# uses: crazy-max/ghaction-upx@v3
|
|
# with:
|
|
# version: latest
|
|
# files: |
|
|
# ${{ github.workspace }}/bin/*.exe
|
|
# args: --brute
|
|
|
|
- name: Download Resource Hacker
|
|
run: |
|
|
Invoke-WebRequest -Uri "https://www.angusj.com/resourcehacker/resource_hacker.zip" -OutFile "resource_hacker.zip"
|
|
Expand-Archive -Path "resource_hacker.zip" -DestinationPath "$env:USERPROFILE\resource_hacker"
|
|
|
|
- name: Apply icon to executable
|
|
run: |
|
|
$resourceHackerPath = "$env:USERPROFILE\resource_hacker\ResourceHacker.exe"
|
|
$exe = "${{ github.workspace }}\bin\nvm.exe"
|
|
$iconFile = "${{ github.workspace }}\assets\nvm.ico"
|
|
& $resourceHackerPath -open $exe -save $exe -action add -res $iconFile -mask ICONGROUP,MAINICON
|
|
|
|
- name: Sign Executables
|
|
uses: azure/trusted-signing-action@v0.5.0
|
|
with:
|
|
azure-tenant-id: ${{ secrets.AZURE_TENANT_ID }}
|
|
azure-client-id: ${{ secrets.AZURE_CLIENT_ID }}
|
|
azure-client-secret: ${{ secrets.AZURE_CLIENT_SECRET }}
|
|
endpoint: ${{ secrets.AZURE_ENDPOINT }}
|
|
trusted-signing-account-name: ${{ secrets.AZURE_CODE_SIGNING_NAME }}
|
|
certificate-profile-name: ${{ secrets.AZURE_CERT_PROFILE_NAME }}
|
|
files-folder: ${{ github.workspace }}\bin
|
|
files-folder-filter: exe,dll
|
|
file-digest: SHA256
|
|
timestamp-rfc3161: http://timestamp.acs.microsoft.com
|
|
timestamp-digest: SHA256
|
|
|
|
- name: Identify & Download Latest Author-NVM Bridge App (Using GitHub API)
|
|
id: get_release
|
|
run: |
|
|
$repoOwner = "author"
|
|
$repoName = "author-nvm"
|
|
$token = $env:AUTHOR_BRIDGE_TOKEN # Ensure the token is provided as a secret
|
|
|
|
# Fetch the latest release information
|
|
Write-Host "GET https://api.github.com/repos/$repoOwner/$repoName/releases"
|
|
$response = Invoke-RestMethod -Uri "https://api.github.com/repos/$repoOwner/$repoName/releases" `
|
|
-Headers @{ Authorization = "token $token"; Accept = "application/vnd.github.v3+json"; }
|
|
|
|
if ($response -and $response[0].tag_name) {
|
|
$releaseTag = $response[0].tag_name
|
|
Write-Host "Latest release tag identified: $releaseTag"
|
|
|
|
# Fetch the release details for the identified tag
|
|
Write-Host "GET https://api.github.com/repos/$repoOwner/$repoName/releases/tags/$releaseTag"
|
|
$releaseDetails = Invoke-RestMethod -Uri "https://api.github.com/repos/$repoOwner/$repoName/releases/tags/$releaseTag" `
|
|
-Headers @{ Authorization = "token $token"; Accept = "application/vnd.github.v3+json"; }
|
|
|
|
# Extract asset ID for author-nvm.exe
|
|
$asset = $releaseDetails.assets | Where-Object { $_.name -eq 'author-nvm.exe' } | Select-Object -First 1
|
|
|
|
if ($asset -and $asset.id) {
|
|
$assetId = $asset.id
|
|
Write-Host "Asset ID for author-nvm.exe: $assetId"
|
|
"ASSET_ID=$assetId" | Out-File -Append -FilePath $env:GITHUB_ENV
|
|
|
|
# Download asset
|
|
$assetDownloadUrl = "https://api.github.com/repos/$repoOwner/$repoName/releases/assets/$assetId"
|
|
Write-Host "GET $assetDownloadUrl"
|
|
Invoke-WebRequest -Uri $assetDownloadUrl `
|
|
-Headers @{ Authorization = "token $token"; Accept = "application/octet-stream"; } `
|
|
-OutFile "$env:GITHUB_WORKSPACE\bin\author-nvm.exe"
|
|
} else {
|
|
Write-Error "author-nvm.exe not found in the latest release."
|
|
exit 1
|
|
}
|
|
} else {
|
|
Write-Error "No release tags found in the repository."
|
|
exit 1
|
|
}
|
|
|
|
- name: Generate Core Assets
|
|
run: |
|
|
$bin = "${{ github.workspace }}\bin"
|
|
$license = "${{ github.workspace }}\LICENSE"
|
|
$source = "${{ github.workspace }}\assets"
|
|
$target = "${{ github.workspace }}\.tmp"
|
|
$distros = "${{ github.workspace }}\.dist"
|
|
|
|
if (!(Test-Path -Path $target)) {
|
|
New-Item -ItemType Directory -Path $target
|
|
}
|
|
|
|
# Copy binaries to distribution
|
|
Get-ChildItem -Path $bin -File | ForEach-Object {
|
|
Copy-Item -Path $_.FullName -Destination $target
|
|
}
|
|
|
|
# Copy assets to distribution
|
|
Get-ChildItem -Path $source -File | ForEach-Object {
|
|
Copy-Item -Path $_.FullName -Destination $target
|
|
}
|
|
|
|
# Copy license to distribution
|
|
Copy-Item -Path $license -Destination $target
|
|
shell: pwsh
|
|
|
|
- name: Generate Asset Distribution
|
|
run: |
|
|
$source = "${{ github.workspace }}\.tmp"
|
|
$manual = "${{ github.workspace }}\.dist\nvm-noinstall.zip"
|
|
$checksum = "${{ github.workspace }}\.dist\nvm-noinstall.zip.checksum.txt"
|
|
|
|
if (Test-Path -Path $manual) {
|
|
Remove-Item -Path $manual -Force
|
|
}
|
|
|
|
& "C:\Program Files\7-Zip\7z.exe" a -tzip $manual "$source\*" -mx=9
|
|
|
|
$hash = Get-FileHash -Path $manual -Algorithm MD5
|
|
$hash.Hash | Out-File -FilePath $checksum -Encoding utf8
|
|
shell: pwsh
|
|
|
|
# - name: Install Inno Setup
|
|
# run: |
|
|
# choco install innosetup -y
|
|
|
|
# # Verify installation
|
|
# if (!(Test-Path "C:\Program Files (x86)\Inno Setup 6\ISCC.exe")) {
|
|
# Write-Error "Inno Setup installation failed."
|
|
# exit 1
|
|
# }
|
|
|
|
- name: Generate Installer
|
|
run: |
|
|
$iss = "${{ github.workspace }}\nvm.iss"
|
|
$distros = "${{ github.workspace }}\.dist"
|
|
|
|
if (!(Test-Path -Path $iss)) {
|
|
Write-Error "Inno Setup Script file not found: $iss"
|
|
exit 1
|
|
}
|
|
|
|
# Replace version placeholder in the .iss file
|
|
$version = $env:TAG -replace "^v", ""
|
|
(Get-Content -Path $iss) -replace "{{VERSION}}", $version | Set-Content -Path $iss
|
|
|
|
# Output the file to assure replacements worked
|
|
Get-Content $iss
|
|
|
|
# Get the files and directories in the source directory
|
|
$items = Get-ChildItem -Path $source -Recurse
|
|
$source = "${{ github.workspace }}\.tmp"
|
|
$destination = "${{ github.workspace }}\bin"
|
|
|
|
foreach ($item in $items) {
|
|
# Construct the target path
|
|
$target = $item.FullName -replace [regex]::Escape($source), [regex]::Escape($destination)
|
|
|
|
if ($item.PSIsContainer) {
|
|
# Create directories if they don't exist
|
|
if (-not (Test-Path -Path $target)) {
|
|
New-Item -ItemType Directory -Path $target
|
|
}
|
|
} else {
|
|
# Copy files if they don't already exist
|
|
if (-not (Test-Path -Path $target)) {
|
|
Copy-Item -Path $item.FullName -Destination $target
|
|
}
|
|
}
|
|
}
|
|
|
|
Write-Host "Available assets in bin directory:"
|
|
dir ${{ github.workspace }}\bin
|
|
|
|
Write-Host "Available assets in .tmp directory:"
|
|
dir ${{ github.workspace }}\.tmp
|
|
|
|
Write-Host "Available build tools:"
|
|
dir ${{ github.workspace }}\assets\buildtools
|
|
|
|
${{ github.workspace }}\assets\buildtools\iscc.exe "$iss" "/o$distros"
|
|
# iscc "$iss" "/o$distros"
|
|
shell: pwsh
|
|
|
|
- name: Sign Installer
|
|
uses: azure/trusted-signing-action@v0.5.0
|
|
with:
|
|
azure-tenant-id: ${{ secrets.AZURE_TENANT_ID }}
|
|
azure-client-id: ${{ secrets.INSTALLER_AZURE_CLIENT_ID }}
|
|
azure-client-secret: ${{ secrets.INSTALLER_AZURE_CLIENT_SECRET }}
|
|
endpoint: ${{ secrets.AZURE_ENDPOINT }}
|
|
trusted-signing-account-name: ${{ secrets.AZURE_CODE_SIGNING_NAME }}
|
|
certificate-profile-name: ${{ secrets.AZURE_CERT_PROFILE_NAME }}
|
|
files-folder: ${{ github.workspace }}\.dist
|
|
files-folder-filter: exe,dll
|
|
file-digest: SHA256
|
|
timestamp-rfc3161: http://timestamp.acs.microsoft.com
|
|
timestamp-digest: SHA256
|
|
|
|
- name: Generate Official Distribution
|
|
run: |
|
|
$source = "${{ github.workspace }}\.dist\nvm-setup.exe"
|
|
$distro = "${{ github.workspace }}\.dist\nvm-setup.zip"
|
|
$checksum = "${{ github.workspace }}\.dist\nvm-setup.zip.checksum.txt"
|
|
|
|
if (!(Test-Path -Path $source)) {
|
|
Write-Error "Source file for ZIP not found: $source"
|
|
exit 1
|
|
}
|
|
|
|
& "C:\Program Files\7-Zip\7z.exe" a -tzip $distro "$source" -mx=9
|
|
|
|
if (!(Test-Path -Path $distro)) {
|
|
Write-Error "ZIP file generation failed."
|
|
exit 1
|
|
}
|
|
|
|
$hash = Get-FileHash -Path $distro -Algorithm MD5
|
|
$hash.Hash | Out-File -FilePath $checksum -Encoding utf8
|
|
shell: pwsh
|
|
|
|
- name: Attestation
|
|
uses: actions/attest-build-provenance@v2
|
|
id: attest
|
|
with:
|
|
subject-path: |
|
|
${{ github.workspace }}/bin/*.exe
|
|
${{ github.workspace }}/.dist/*.exe
|
|
${{ github.workspace }}/.dist/*.zip
|
|
${{ github.workspace }}/.dist/*.checksum.txt
|
|
github-token: ${{ secrets.GITHUB_TOKEN }}
|
|
|
|
- name: Release
|
|
uses: softprops/action-gh-release@v2
|
|
if: success()
|
|
with:
|
|
tag_name: ${{ env.TAG }}
|
|
files: |
|
|
${{ github.workspace }}/.dist/*
|
|
fail_on_unmatched_files: true
|
|
generate_release_notes: true
|
|
prerelease: false
|
|
draft: false
|
|
make_latest: true
|
|
|
|
- name: Add Attestation Report to Release Notes
|
|
if: success()
|
|
uses: softprops/action-gh-release@v2
|
|
with:
|
|
tag_name: ${{ env.TAG }}
|
|
body: |
|
|
<br/>:office: **[Attestation Report](${{ steps.attest.outputs.attestation-url }})**
|
|
append_body: true
|
|
env:
|
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
|
|
rollback:
|
|
runs-on: ubuntu-latest
|
|
needs: build
|
|
if: failure()
|
|
|
|
steps:
|
|
- name: Checkout code
|
|
uses: actions/checkout@v4
|
|
with:
|
|
fetch-depth: 0 # Ensures that all references, including tags, are fetched
|
|
ref: ${{ github.event.workflow_run.head_sha }}
|
|
|
|
- name: Show current commit
|
|
run: |
|
|
git log -1 --decorate
|
|
git tag --contains HEAD
|
|
|
|
- name: Get the commit associated with the trigger
|
|
id: get_commit
|
|
run: |
|
|
if [ -f "$GITHUB_EVENT_PATH" ]; then
|
|
# Try to get the head SHA from workflow_run
|
|
COMMIT_SHA=$(jq -r '.head_commit.id' < "$GITHUB_EVENT_PATH")
|
|
if [ "$COMMIT_SHA" = "null" ]; then
|
|
COMMIT_SHA=$(jq -r '.workflow_run.head_commit.id' < "$GITHUB_EVENT_PATH")
|
|
fi
|
|
if [ -z "$COMMIT_SHA" ] || [ "$COMMIT_SHA" = "null" ]; then
|
|
echo "Error: Unable to retrieve commit SHA from GITHUB_EVENT_PATH"
|
|
cat "$GITHUB_EVENT_PATH"
|
|
echo "HEAD: $(git rev-parse HEAD)"
|
|
exit 1
|
|
fi
|
|
echo "Commit SHA: $COMMIT_SHA"
|
|
echo "COMMIT_SHA=$COMMIT_SHA" >> $GITHUB_ENV
|
|
else
|
|
echo "Error: GITHUB_EVENT_PATH not found"
|
|
exit 1
|
|
fi
|
|
|
|
- name: Fetch the tag associated with the commit using git
|
|
id: fetch_tag
|
|
run: |
|
|
# Debugging: print all tags in the repository
|
|
git tag
|
|
|
|
# Get the tag associated with the commit
|
|
echo "Finding tag associated with the commit..."
|
|
TAG=$(git tag --contains "$COMMIT_SHA" | head -n 1)
|
|
echo "Tag associated with the commit is: $TAG"
|
|
|
|
# Debugging: Check if the tag is found
|
|
if [ -z "$TAG" ]; then
|
|
echo "No tag found for this commit."
|
|
else
|
|
echo "Found tag: $TAG"
|
|
fi
|
|
|
|
echo "TAG=$TAG" >> $GITHUB_ENV
|
|
|
|
- name: Delete release
|
|
env:
|
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
run: |
|
|
# Use the TAG from the environment variable
|
|
if [ -z "$TAG" ]; then
|
|
echo "No tag to delete."
|
|
exit 1
|
|
fi
|
|
|
|
RELEASE_ID=$(gh release view "$TAG" --json id --jq '.id' || echo "")
|
|
if [ -n "$RELEASE_ID" ]; then
|
|
gh release delete "$TAG" --yes
|
|
echo "Release $TAG deleted successfully."
|
|
else
|
|
echo "Release $TAG not found."
|
|
fi
|
|
|
|
- name: Delete tag associated with release
|
|
run: |
|
|
# Use the TAG from the environment variable
|
|
if [ -z "$TAG" ]; then
|
|
echo "No tag to delete."
|
|
exit 1
|
|
fi
|
|
|
|
git tag -d "$TAG"
|
|
git push --delete origin "$TAG"
|
|
|
|
- name: Notify Rollback
|
|
run: echo "Rollback completed for release $TAG" |