Skip to content

Publish Release To NuGet #26

Publish Release To NuGet

Publish Release To NuGet #26

name: Publish Release To NuGet
on:
release:
types: [ published ] # Trigger on published pre-releases and releases
workflow_dispatch:
inputs:
tag:
description: 'Tag name'
required: true
default: 'v4.1.0'
jobs:
variables:
name: Set Variables
runs-on: ubuntu-latest
env:
TAG: ${{ github.event.release.tag_name || github.event.inputs.tag }}
steps:
- name: Extract semantic version from tag
id: set_version
run: |
# Remove the "v" prefix if it exists and extract the semantic version number
SEMANTIC_VERSION=$(echo "${TAG}" | grep -Po "(?<=^|[^0-9])([0-9]+\.[0-9]+\.[0-9]+(\.[0-9]+)?(-[a-zA-Z]+[0-9]*)?)")
SEMANTIC_VERSION=${SEMANTIC_VERSION#"v"}
if [ -z "${SEMANTIC_VERSION}" ]; then
echo "Error: Tag '${TAG}' does not start with a valid semantic version number (e.g., #.#.#; #.#.#.#; #.#.#.#-beta)"
exit 1
fi
echo "Extracted semantic version: ${SEMANTIC_VERSION}"
echo "semantic_version=${SEMANTIC_VERSION}" >> $GITHUB_OUTPUT
outputs:
tag: ${{ env.TAG }}
semanticVersion: ${{ steps.set_version.outputs.semantic_version }}
buildFrameworkVersions:
name: Build .NET Framework versions
needs: [ variables ]
runs-on: windows-2019 # required version for Framework 4.0
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
ref: ${{ needs.variables.outputs.tag }}
- name: Add msbuild to PATH
uses: microsoft/setup-msbuild@v2
- name: Setup NuGet
uses: nuget/setup-nuget@v2
- name: Restore NuGet packages
run: nuget restore ./OptimizelySDK.NETFramework.sln
- name: Build and strongly name assemblies
run: msbuild /p:SignAssembly=true /p:AssemblyOriginatorKeyFile=$(pwd)/keypair.snk /p:Configuration=Release ./OptimizelySDK.NETFramework.sln
- name: Upload Framework artifacts
uses: actions/upload-artifact@v4
with:
name: unsigned-dlls-framework
if-no-files-found: error
path: ./**/bin/Release/**/Optimizely*.dll
buildStandard16:
name: Build .NET 1.6 version
needs: [ variables ]
runs-on: windows-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
ref: ${{ needs.variables.outputs.tag }}
- name: Setup .NET
uses: actions/setup-dotnet@v4
- name: Restore dependencies
run: dotnet restore OptimizelySDK.NetStandard16/OptimizelySDK.NetStandard16.csproj
- name: Build and strongly name assemblies
run: dotnet build OptimizelySDK.NetStandard16/OptimizelySDK.NetStandard16.csproj /p:SignAssembly=true /p:AssemblyOriginatorKeyFile=$(pwd)/keypair.snk -c Release
- name: Upload Standard 1.6 artifact
uses: actions/upload-artifact@v4
with:
name: unsigned-dlls-standard16
if-no-files-found: error
path: ./**/bin/Release/**/Optimizely*.dll
buildStandard20:
name: Build .NET 2.0 version
needs: [ variables ]
runs-on: windows-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
ref: ${{ needs.variables.outputs.tag }}
- name: Setup .NET
uses: actions/setup-dotnet@v4
- name: Restore dependencies
run: dotnet restore OptimizelySDK.NetStandard20/OptimizelySDK.NetStandard20.csproj
- name: Build and strongly name Standard 2.0 project
run: dotnet build OptimizelySDK.NetStandard20/OptimizelySDK.NetStandard20.csproj /p:SignAssembly=true /p:AssemblyOriginatorKeyFile=$(pwd)/keypair.snk -c Release
- name: Build and strongly name assemblies
uses: actions/upload-artifact@v4
with:
name: unsigned-dlls-standard20
if-no-files-found: error
path: ./**/bin/Release/**/Optimizely*.dll
combineArtifacts:
name: Combine artifacts
needs: [ variables, buildFrameworkVersions, buildStandard16, buildStandard20 ]
runs-on: ubuntu-latest
steps:
- name: Download Framework artifacts
uses: actions/download-artifact@v4
with:
name: unsigned-dlls-framework
path: ./unsigned-dlls-framework
- name: Download Standard 1.6 artifacts
uses: actions/download-artifact@v4
with:
name: unsigned-dlls-standard16
path: ./unsigned-dlls-standard16
- name: Download Standard 2.0 artifacts
uses: actions/download-artifact@v4
with:
name: unsigned-dlls-standard20
path: ./unsigned-dlls-standard20
- name: List all downloaded artifacts
run: ls -R ./
- name: Combine artifacts
run: |
mkdir -p ./unsigned-dlls
find ./unsigned-dlls-framework -type f -name 'Optimizely*.dll' ! -path '*/OptimizelySDK.Tests/*' -exec mv {} ./unsigned-dlls/ \;
find ./unsigned-dlls-standard16 -type f -name 'Optimizely*.dll' -exec mv {} ./unsigned-dlls/ \;
find ./unsigned-dlls-standard20 -type f -name 'Optimizely*.dll' -exec mv {} ./unsigned-dlls/ \;
- name: Upload combined artifacts
uses: actions/upload-artifact@v4
with:
name: unsigned-dlls
if-no-files-found: error
path: ./unsigned-dlls
sign:
name: Send DLLs for signing
needs: [ combineArtifacts ]
runs-on: ubuntu-latest
env:
# TODO: Replace actual values
SIGNING_SERVER_PRIVATE_KEY: ${{ secrets.SIGNING_SERVER_PRIVATE_KEY }}
SIGNING_SERVER_HOST: ${{ secrets.SIGNING_SERVER_HOST }}
SIGNING_SERVER_UPLOAD_PATH: /path/to/UPLOAD/directory
SIGNING_SERVER_DOWNLOAD_PATH: /path/to/DOWNLOAD/directory
steps:
# TODO: Remove this when we're ready to automate
- name: Temporarily halt progress
run: exit 1
- name: Download the unsigned files
uses: actions/download-artifact@v4
with:
name: unsigned-dlls
path: ./unsigned-dlls
- name: Setup SSH
uses: shimataro/ssh-key-action@v2
with:
key: $SIGNING_SERVER_PRIVATE_KEY
- name: Send files to signing server
run: scp -r ./unsigned-dlls $SIGNING_SERVER_HOST:$SIGNING_SERVER_UPLOAD_PATH
- name: Wait for artifact to be published
run: |
for i in {1..60}; do
# Replace with actual path
if ssh $SIGNING_SERVER_HOST "ls $SIGNING_SERVER_DOWNLOAD_PATH"; then
exit 0
fi
sleep 10
done
exit 1
- name: Download signed files
run: |
mkdir ./signed-dlls
scp -r $SIGNING_SERVER_HOST:$SIGNING_SERVER_DOWNLOAD_PATH ./signed-dlls
- name: Delete signed files from server
run: ssh $SIGNING_SERVER_HOST "rm -rf $SIGNING_SERVER_DOWNLOAD_PATH/*"
- name: Upload signed files
uses: actions/upload-artifact@v4
with:
name: signed-dlls
if-no-files-found: error
path: ./signed-dlls
pack:
name: Pack NuGet package
needs: [ sign ]
runs-on: ubuntu-latest
env:
VERSION: ${{ needs.variables.outputs.semanticVersion }}
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
ref: ${{ needs.variables.outputs.tag }}
- name: Install mono
run: |
sudo apt update
sudo apt install -y mono-devel
- name: Download NuGet files
uses: actions/download-artifact@v4
with:
name: signed-dlls
path: ./signed-dlls
- name: Organize files
run: |
pushd ./signed-dlls
# Move all dlls to the root directory
find . -type f -name "*.dll" -exec mv {} .
popd
# Create directories
mkdir -p nuget/lib/net35/ nuget/lib/net40/ nuget/lib/net45/ nuget/lib/netstandard1.6/ nuget/lib/netstandard2.0/
pushd ./nuget
# Move files to directories
mv ../signed-dlls/OptimizelySDK.Net35.dll lib/net35/
mv ../signed-dlls/OptimizelySDK.Net40.dll lib/net40/
mv ../signed-dlls/OptimizelySDK.dll lib/net45/
mv ../signed-dlls/OptimizelySDK.NetStandard16.dll lib/netstandard1.6/
mv ../signed-dlls/OptimizelySDK.NetStandard20.dll lib/netstandard2.0/
popd
- name: Create nuspec
# Uses env.VERSION in OptimizelySDK.nuspec.template
run: |
chmod +x ./OptimizelySDK.nuspec.template
./OptimizelySDK.nuspec.template
- name: Pack NuGet package
run: |
pushd ./nuget
nuget pack OptimizelySDK.nuspec
popd
- name: Upload nupkg artifact
uses: actions/upload-artifact@v4
with:
name: nuget-package
if-no-files-found: error
path: ./nuget/Optimizely.SDK.${{ env.VERSION }}.nupkg
publish:
name: Publish package to NuGet after reviewing the artifact
needs: [ pack ]
runs-on: ubuntu-latest
# Review the `nuget-package` artifact ensuring the dlls are
# organized and signed before approving.
environment: 'i-reviewed-nuget-package-artifact'
env:
VERSION: ${{ needs.variables.outputs.semanticVersion }}
steps:
- name: Download NuGet files
uses: actions/download-artifact@v4
with:
name: nuget-package
path: ./nuget
- name: Setup .NET
uses: actions/setup-dotnet@v4
- name: Publish NuGet package
run: |
dotnet nuget push ./nuget/Optimizely.SDK.${{ env.VERSION }}.nupkg --source https://api.nuget.org/v3/index.json --api-key ${{ secrets.NUGET_API_KEY }}