Skip to content

Add SQL Server installation steps to Copilot setup workflow #130

Add SQL Server installation steps to Copilot setup workflow

Add SQL Server installation steps to Copilot setup workflow #130

name: 'Copilot Setup Steps'
# This workflow sets up a complete development environment for the PowerShell module project
# when executed by GitHub Copilot Agent for development assistance.
on:
workflow_dispatch:
pull_request:
paths:
- '.github/workflows/copilot-setup-steps.yml'
push:
paths:
- '.github/workflows/copilot-setup-steps.yml'
# cSpell: ignore unshallow LASTEXITCODE PSDSC noreport dearmor distro keyrings endgroup libmi libc
jobs:
copilot-setup-steps:
name: Setup PowerShell Development Environment
runs-on: ubuntu-latest
permissions:
contents: read
steps:
- name: Set Environment Variables
shell: bash
run: |
echo "Setting MODULE_NAME=$MODULE_NAME to GitHub environment"
echo "MODULE_NAME=$MODULE_NAME" >> "$GITHUB_ENV"
env:
MODULE_NAME: 'SqlServerDsc'
- name: Checkout Repository
uses: actions/checkout@v5
with:
fetch-depth: 0 # Full history needed for GitVersion
# This step is needed for GitVersion because Copilot switches to its working branch
# after checkout and fetches only depth 2.
- name: Ensure full history for GitVersion
shell: pwsh
run: |
Write-Host 'Ensuring full history for GitVersion...'
$isShallow = (& git rev-parse --is-shallow-repository) -eq 'true'
if ($isShallow)
{
Write-Host 'Repository is shallow. Fetching full history and tags...'
git fetch --prune --unshallow --tags --no-recurse-submodules
if ($LASTEXITCODE -ne 0)
{
throw 'git fetch --unshallow failed'
}
}
else
{
Write-Host 'Repository is not shallow. Refreshing tags...'
git fetch --prune --tags --no-recurse-submodules
if ($LASTEXITCODE -ne 0)
{
throw 'git fetch --tags failed'
}
}
Write-Host 'History ready for GitVersion.'
- name: Install Linux Dependencies
shell: bash
run: |
echo "Installing Linux dependencies for PowerShell DSC..."
# Update package list
echo "::group::Update package list"
echo "Updating package list..."
sudo apt-get update
echo "Package list updated successfully"
echo "::endgroup::"
# Ensure gpg is available
sudo apt-get install -y gnupg
# Check if Microsoft repository is already added, if not add it
if ! grep -q "packages.microsoft.com" /etc/apt/sources.list /etc/apt/sources.list.d/* 2>/dev/null; then
echo "::group::Add Microsoft repository"
echo "Adding Microsoft repository..."
# Add Microsoft's GPG key and repository (keyring)
sudo install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://packages.microsoft.com/keys/microsoft.asc | gpg --dearmor | sudo tee /etc/apt/keyrings/microsoft.gpg >/dev/null
sudo chmod a+r /etc/apt/keyrings/microsoft.gpg
DISTRO_CODENAME="$(lsb_release -cs)"
echo "deb [arch=amd64 signed-by=/etc/apt/keyrings/microsoft.gpg] https://packages.microsoft.com/repos/microsoft-ubuntu-${DISTRO_CODENAME}-prod ${DISTRO_CODENAME} main" | sudo tee "/etc/apt/sources.list.d/microsoft-${DISTRO_CODENAME}-prod.list" >/dev/null
# Update package list again after adding the new repo
echo "Updating package list after adding Microsoft repository..."
if ! sudo apt-get update; then
echo "::warning::apt-get update failed after adding Microsoft repo (repo may be unavailable for this distro). Continuing..."
fi
echo "Microsoft repository added successfully"
echo "::endgroup::"
else
echo "Microsoft repository already configured, skipping..."
fi
# Install OMI (Open Management Infrastructure) which provides libmi
echo "::group::Install OMI and dependencies"
if apt-cache policy omi 2>/dev/null | grep -q 'Candidate:'; then
echo "Installing OMI package..."
# Set a shorter hostname to avoid SSL certificate generation errors
# OMI generates SSL certificates during installation and GitHub Actions runners
# often have very long hostnames that exceed the 64-character limit for CN fields
echo "Setting temporary hostname to avoid SSL certificate generation errors..."
ORIGINAL_HOSTNAME=$(hostname)
# Install trap to always restore hostname on EXIT or ERR
restore_hostname() {
echo "Restoring original hostname..."
sudo hostname "$ORIGINAL_HOSTNAME"
trap - EXIT ERR # Remove the trap after restore
}
trap 'restore_hostname' EXIT ERR
sudo hostname "dsc-runner"
if ! sudo apt-get install -y omi; then
echo "OMI package failed to install; continuing..."
echo "::warning::OMI package failed to install; continuing without OMI"
else
echo "OMI package installed successfully"
fi
# Restore original hostname and remove trap
restore_hostname
else
echo "Package 'omi' not found in repositories; skipping OMI install."
echo "::warning::OMI package not found in repositories, skipping installation"
fi
echo "::endgroup::"
echo "::group::Installing additional development dependencies..."
echo "Installing development dependencies..."
sudo apt-get install -y libc6-dev libssl-dev tree
echo "Development dependencies installed successfully"
echo "::endgroup::"
# Set LD_LIBRARY_PATH permanently for the runner session
echo "Setting LD_LIBRARY_PATH environment variable..."
echo "LD_LIBRARY_PATH=/opt/omi/lib:/usr/lib/x86_64-linux-gnu:${LD_LIBRARY_PATH}" >> "$GITHUB_ENV"
echo "Environment variable set successfully"
echo "Linux dependencies installed successfully"
- name: Configure PowerShell Environment
shell: pwsh
run: |
Write-Host "Configure PowerShell environment..."
# Install dependent PowerShell modules
Write-Host "Installing SqlServer module..."
Install-PSResource -Name 'SqlServer' -Version '21.1.18256' -Scope 'CurrentUser' -Repository 'PSGallery' -TrustRepository
Write-Host "SqlServer module installed successfully"
Write-Host "Installing PSDSC module..."
Install-PSResource -Name 'PSDSC' -Scope 'CurrentUser' -Repository 'PSGallery' -TrustRepository
Write-Host "PSDSC module installed successfully"
Write-Host "PowerShell environment configuration complete"
- name: Install DSCv3
shell: pwsh
run: |
Write-Host "Install DSCv3 in environment..."
# Install dependent PowerShell modules
Write-Host "Installing DSCv3 executable..."
Install-DscExe -IncludePrerelease -Force
Write-Host "DSCv3 installed successfully"
Write-Host "DSCv3 install complete"
- name: Verify DSCv3
shell: pwsh
run: |
Write-Host "Running DSCv3 to validate correct operation..."
dsc --version
- name: Install SQL Server on Ubuntu
shell: bash
run: |
echo "Installing SQL Server 2022 on Ubuntu..."
# Import the public repository GPG keys
echo "::group::Import Microsoft GPG keys"
curl -fsSL https://packages.microsoft.com/keys/microsoft.asc | sudo tee /etc/apt/trusted.gpg.d/microsoft.asc > /dev/null
echo "::endgroup::"
# Register the SQL Server Ubuntu repository
echo "::group::Register SQL Server repository"
sudo add-apt-repository "$(wget -qO- https://packages.microsoft.com/config/ubuntu/20.04/mssql-server-2022.list)" -y
echo "::endgroup::"
# Update package list and install SQL Server
echo "::group::Install SQL Server package"
sudo apt-get update
sudo apt-get install -y mssql-server
echo "::endgroup::"
# Configure SQL Server with mssql-conf (unattended setup)
echo "::group::Configure SQL Server"
sudo MSSQL_SA_PASSWORD='P@ssw0rd1' \
MSSQL_PID='Developer' \
MSSQL_TCP_PORT=1433 \
ACCEPT_EULA='Y' \
/opt/mssql/bin/mssql-conf -n setup
echo "::endgroup::"
# Verify SQL Server is running
echo "::group::Verify SQL Server status"
sudo systemctl status mssql-server --no-pager --lines=5
echo "::endgroup::"
echo "SQL Server 2022 installation completed successfully"
- name: Install SQL Server Command Line Tools
shell: bash
run: |
echo "Installing SQL Server command line tools..."
# Import Microsoft GPG keys (if not already done)
echo "::group::Import Microsoft GPG keys for tools"
curl -fsSL https://packages.microsoft.com/keys/microsoft.asc | sudo tee /etc/apt/trusted.gpg.d/microsoft.asc > /dev/null
echo "::endgroup::"
# Register Microsoft Ubuntu repository for tools
echo "::group::Register Microsoft tools repository"
curl -fsSL https://packages.microsoft.com/config/ubuntu/20.04/prod.list | sudo tee /etc/apt/sources.list.d/mssql-release.list
echo "::endgroup::"
# Install mssql-tools18 and unixODBC
echo "::group::Install mssql-tools18"
sudo apt-get update
sudo ACCEPT_EULA=Y apt-get install -y mssql-tools18 unixodbc-dev
echo "::endgroup::"
# Add tools to PATH
echo "::group::Configure PATH for SQL tools"
echo 'export PATH="$PATH:/opt/mssql-tools18/bin"' >> ~/.bashrc
echo 'export PATH="$PATH:/opt/mssql-tools18/bin"' >> ~/.bash_profile
echo "/opt/mssql-tools18/bin" >> $GITHUB_PATH
echo "::endgroup::"
# Test sqlcmd connectivity
echo "::group::Test SQL Server connectivity"
/opt/mssql-tools18/bin/sqlcmd -S localhost -U sa -P 'P@ssw0rd1' -Q "SELECT @@VERSION" -b
echo "::endgroup::"
echo "SQL Server command line tools installed successfully"
- name: Configure SQL Server Environment for Integration Tests
shell: pwsh
run: |
Write-Host "Configuring SQL Server environment for SqlServerDsc integration tests..."
# Set SqlServerDsc CI environment variable
Write-Host "Setting SqlServerDsc CI environment variable..."
$env:SqlServerDscCI = $true
echo "SqlServerDscCI=true" >> $env:GITHUB_ENV
# Configure SQL Server connection parameters for Linux
Write-Host "Setting SQL Server connection parameters for integration tests..."
# Set SA password for integration tests
$env:SQL_SA_PASSWORD = 'P@ssw0rd1'
echo "SQL_SA_PASSWORD=P@ssw0rd1" >> $env:GITHUB_ENV
Write-Host "SQL Server will use the default instance (MSSQLSERVER)"
Write-Host "This is because SQL Server on Linux does not support named instances"
# Test SQL Server connectivity using SqlServer module
Write-Host "Testing SQL Server connectivity using PowerShell SqlServer module..."
try {
# Connect to default instance on localhost
$connectionString = "Server=localhost;Database=master;User Id=sa;Password=P@ssw0rd1;TrustServerCertificate=true;Encrypt=false;"
$connection = New-Object System.Data.SqlClient.SqlConnection($connectionString)
$connection.Open()
$command = $connection.CreateCommand()
$command.CommandText = "SELECT @@VERSION, @@SERVERNAME, SERVERPROPERTY('Edition')"
$reader = $command.ExecuteReader()
if ($reader.Read()) {
Write-Host "SQL Server Version: $($reader[0])"
Write-Host "Server Name: $($reader[1])"
Write-Host "Edition: $($reader[2])"
}
$reader.Close()
$connection.Close()
Write-Host "SQL Server connectivity test successful!"
Write-Host "Integration tests will use the default instance (MSSQLSERVER)"
}
catch {
Write-Error "Failed to connect to SQL Server: $($_.Exception.Message)"
exit 1
}
Write-Host "SQL Server environment configuration complete"
- name: Install .NET Tools
shell: pwsh
run: |
Write-Host 'Installing/Updating .NET tools...'
# Install GitVersion for semantic versioning (idempotent)
dotnet tool update --global GitVersion.Tool --version 5.* `
|| dotnet tool install --global GitVersion.Tool --version 5.*
# Verify installation
dotnet-gitversion /version
Write-Host '.NET tools ready.'
- name: Verify GitVersion
shell: pwsh
run: |
Write-Host 'Running GitVersion to determine semantic version (parsing to PowerShell object)...'
dotnet-gitversion | ConvertFrom-Json
- name: Resolve Dependencies
shell: pwsh
run: |
Write-Host 'Resolving project dependencies...'
# Run dependency resolution
./build.ps1 -ResolveDependency -Tasks 'noop' -UseModuleFast -ErrorAction Stop
Write-Host 'Dependencies resolved successfully.'
- name: Build Module
shell: pwsh
run: |
Write-Host "Building $env:MODULE_NAME module..."
# Build the module
./build.ps1 -Tasks 'build' -ErrorAction Stop
# Verify build output
$builtPath = "output/builtModule/$env:MODULE_NAME"
if (Test-Path -Path $builtPath)
{
Write-Host "Module built successfully at: $builtPath"
# Show files with paths relative to the built module base path using `tree` (run directly in PowerShell)
$base = (Resolve-Path -Path $builtPath).ProviderPath
Write-Host "Files under $base (relative paths):"
# Run tree directly and strip leading './' from its output
tree --noreport $builtPath
}
else
{
Write-Error 'Module build failed - output directory not found'
exit 1
}
- name: Import Built Module
shell: pwsh
run: |
Write-Host "Importing built $env:MODULE_NAME module..."
./build.ps1 -Tasks 'noop'
Import-Module -Name $env:MODULE_NAME -Force
# Verify module is loaded
$module = Get-Module -Name $env:MODULE_NAME -ErrorAction SilentlyContinue
if ($module)
{
Write-Host 'Module imported successfully:'
Write-Host " Name: $($module.Name)"
Write-Host " Version: $($module.Version)"
Write-Host " Path: $($module.Path)"
# Show available commands
$commands = @(Get-Command -Module $env:MODULE_NAME)
if ($commands.Count -gt 0)
{
Write-Host " Exported Commands: $($commands.Count)"
Write-Host "`nAvailable Commands:"
$commands |
Select-Object Name, ModuleName | Format-Table -AutoSize
}
else
{
Write-Host 'No commands exported by the module.'
}
$dscResources = @(dsc resource list --adapter Microsoft.DSC/PowerShell --output-format json | ConvertFrom-Json)
Write-Host "`n Available class-based DSC Resources: $($dscResources.Count)`n"
$dscResources | Format-Table type, capabilities, implementedAs, requireAdapter -GroupBy kind -AutoSize
}
else
{
Write-Error 'Failed to import module'
exit 1
}