Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 56 additions & 0 deletions .github/workflows/EdFi.Api.Minimal.Template.MsSql.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
# SPDX-License-Identifier: Apache-2.0
# Licensed to the Ed-Fi Alliance under one or more agreements.
# The Ed-Fi Alliance licenses this file to you under the Apache License, Version 2.0.
# See the LICENSE and NOTICES files in the project root for more information.

name: Pkg EdFi.Api.Minimal.Template.MsSql
on:
release:
types:
- released
push:
tags:
- "v*.*.*"
workflow_dispatch:
inputs:
publish_package:
description: "Publish the built template package to the Azure Artifacts feed"
type: boolean
default: false

permissions:
contents: write
actions: read
id-token: write

jobs:
build-minimal-template:
name: Build Minimal Template ${{ matrix.standard_version }}
# One leg per supported Ed-Fi Data Standard version. Each leg invokes the whole reusable
# build/SBOM/provenance pipeline, so per-version outputs stay correlated. To add or drop a
# version, add or remove an `include` entry below (and its matching schema artifacts /
# template env file); see docs/DATA-STANDARD-VERSIONS.md. DS 5.2 is the default.
strategy:
fail-fast: false
matrix:
include:
- standard_version: "5.2.0"
package_name: "EdFi.Api.Minimal.Template.MsSql.5.2.0"
provenance_file: "minimal.template.intoto.jsonl"
environment_file: "./.env.template"
- standard_version: "6.1.0"
package_name: "EdFi.Api.Minimal.Template.MsSql.6.1.0"
provenance_file: "minimal.template.6.1.0.intoto.jsonl"
environment_file: "./.env.template.ds61"
uses: ./.github/workflows/build-minimal-template.yml
with:
standard_version: ${{ matrix.standard_version }}
package_name: ${{ matrix.package_name }}
manifest_file: "_manifest/spdx_2.2/manifest.spdx.json"
provenance_file: ${{ matrix.provenance_file }}
publish_package: ${{ github.event_name != 'workflow_dispatch' || inputs.publish_package == true }}
environment_file: ${{ matrix.environment_file }}
database_engine: mssql
secrets:
AZURE_ARTIFACTS_PERSONAL_ACCESS_TOKEN: ${{ secrets.AZURE_ARTIFACTS_PERSONAL_ACCESS_TOKEN }}
AZURE_ARTIFACTS_USER_NAME: ${{ secrets.AZURE_ARTIFACTS_USER_NAME }}
87 changes: 87 additions & 0 deletions .github/workflows/EdFi.Api.Populated.Template.MsSql.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
# SPDX-License-Identifier: Apache-2.0
# Licensed to the Ed-Fi Alliance under one or more agreements.
# The Ed-Fi Alliance licenses this file to you under the Apache License, Version 2.0.
# See the LICENSE and NOTICES files in the project root for more information.

name: Pkg EdFi.Api.Populated.Template.MsSql
on:
release:
types:
- released
push:
tags:
- "v*.*.*"
workflow_dispatch:
inputs:
publish_package:
description: "Publish the built template package to the Azure Artifacts feed"
type: boolean
default: false
standard_version:
description: "Build only this Data Standard version (e.g. 5.2.0 or 6.1.0). Leave blank to build every version in the matrix."
type: string
default: ""

permissions:
contents: write
actions: read
id-token: write

jobs:
# Builds the version matrix once so a manual dispatch can narrow the run to a single Data
# Standard version (standard_version input) without spending compute on the other legs.
# Release/tag runs carry no inputs and build every leg. To add or drop a version, edit the
# `legs` array below (and its matching schema artifacts / template env file); see
# docs/DATA-STANDARD-VERSIONS.md. DS 5.2 is the default.
configure-matrix:
name: Configure matrix
runs-on: ubuntu-latest
outputs:
include: ${{ steps.build-matrix.outputs.include }}
steps:
- name: Select Data Standard legs
id: build-matrix
shell: bash
env:
REQUESTED_VERSION: ${{ github.event_name == 'workflow_dispatch' && inputs.standard_version || '' }}
run: |
legs='[
{"standard_version":"5.2.0","package_name":"EdFi.Api.Populated.Template.MsSql.5.2.0","provenance_file":"populated.template.intoto.jsonl","environment_file":"./.env.template"},
{"standard_version":"6.1.0","package_name":"EdFi.Api.Populated.Template.MsSql.6.1.0","provenance_file":"populated.template.6.1.0.intoto.jsonl","environment_file":"./.env.template.ds61"}
]'
if [ -n "$REQUESTED_VERSION" ]; then
include=$(jq -c --arg v "$REQUESTED_VERSION" '[.[] | select(.standard_version == $v)]' <<< "$legs")
if [ "$(jq 'length' <<< "$include")" -eq 0 ]; then
echo "::error::standard_version '$REQUESTED_VERSION' is not a known leg." >&2
exit 1
fi
else
include=$(jq -c '.' <<< "$legs")
fi
echo "Selected legs: $include"
echo "include=$include" >> "$GITHUB_OUTPUT"

build-populated-template:
name: Build Populated Template ${{ matrix.standard_version }}
needs: configure-matrix
# Each leg invokes the whole reusable build/SBOM/provenance pipeline, so per-version outputs
# stay correlated. The matrix is computed by configure-matrix (filterable on dispatch).
strategy:
fail-fast: false
matrix:
include: ${{ fromJSON(needs.configure-matrix.outputs.include) }}
uses: ./.github/workflows/build-populated-template.yml
with:
standard_version: ${{ matrix.standard_version }}
package_name: ${{ matrix.package_name }}
manifest_file: "_manifest/spdx_2.2/manifest.spdx.json"
provenance_file: ${{ matrix.provenance_file }}
publish_package: ${{ github.event_name != 'workflow_dispatch' || inputs.publish_package == true }}
environment_file: ${{ matrix.environment_file }}
verify_restore: true
require_populated_data: true
database_engine: mssql
secrets:
AZURE_ARTIFACTS_PERSONAL_ACCESS_TOKEN: ${{ secrets.AZURE_ARTIFACTS_PERSONAL_ACCESS_TOKEN }}
AZURE_ARTIFACTS_USER_NAME: ${{ secrets.AZURE_ARTIFACTS_USER_NAME }}
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}
87 changes: 82 additions & 5 deletions .github/workflows/build-minimal-template.yml
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,15 @@ on:
required: false
type: string
default: "./.env.template"
# The built package's data dump is coupled to a specific engine image: the mssql .bak
# backup is coupled to the pinned mcr.microsoft.com/mssql/server:2022-latest image used to
# create and restore it, the same way the postgresql .sql dump is coupled to the
# PostgreSQL major version it was built and restored against.
database_engine:
description: "Database engine for the relational template datastore (postgresql or mssql)"
required: false
type: string
default: "postgresql"
secrets:
AZURE_ARTIFACTS_PERSONAL_ACCESS_TOKEN:
required: true
Expand Down Expand Up @@ -82,6 +91,26 @@ jobs:
hash-code: ${{ steps.hash-code.outputs.hash-code }}
dms-version: ${{ steps.versions.outputs.dms-v }}
steps:
- name: Validate workflow inputs
env:
DATABASE_ENGINE: ${{ inputs.database_engine }}
PACKAGE_NAME: ${{ inputs.package_name }}
run: |
$databaseEngine = $env:DATABASE_ENGINE
$packageName = $env:PACKAGE_NAME

$databaseEngines = @('postgresql', 'mssql')
if ($databaseEngine -notin $databaseEngines) {
throw "database_engine must be one of: $($databaseEngines -join ', '); got '$databaseEngine'."
}

# Minimal template package names are engine-dependent so a build cannot silently
# publish an MSSQL dump under the PostgreSQL product name, or vice versa.
$expectedPackagePrefix = if ($databaseEngine -eq 'mssql') { 'EdFi.Api.Minimal.Template.MsSql' } else { 'EdFi.Api.Minimal.Template.PostgreSql' }
if ($packageName -notlike "$expectedPackagePrefix*") {
throw "database_engine '$databaseEngine' requires a package_name with prefix '$expectedPackagePrefix'; got '$packageName'."
}

- name: Checkout the repo
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
with:
Expand Down Expand Up @@ -143,12 +172,12 @@ jobs:
- name: Start DMS Docker
run: |
$env:LOG_LEVEL="Warning"
./start-local-dms.ps1 -EnvironmentFile "${{ inputs.environment_file }}" -EnableConfig
./start-local-dms.ps1 -EnvironmentFile "${{ inputs.environment_file }}" -EnableConfig -DatabaseEngine "${{ inputs.database_engine }}"
working-directory: eng/docker-compose/

- name: Provision relational database
run: |
./provision-e2e-database.ps1 -EnvironmentFile "${{ inputs.environment_file }}" -Configuration Release
./provision-e2e-database.ps1 -EnvironmentFile "${{ inputs.environment_file }}" -Configuration Release -DatabaseEngine "${{ inputs.database_engine }}"
working-directory: eng/docker-compose/

# DMS fails fatally at startup when the Configuration Service has no data stores.
Expand All @@ -163,9 +192,20 @@ jobs:
$envValues = ReadValuesFromEnvFile "${{ inputs.environment_file }}"
$postgresUser = Get-EnvValue -EnvValues $envValues -Name "POSTGRES_USER" -DefaultValue "postgres"
$postgresCredential = ConvertTo-PostgresCredential -UserName $postgresUser -Secret $envValues.POSTGRES_PASSWORD

# Add-DataStore always requires a PostgresCredential; for mssql it goes unused because
# -ConnectionString is supplied verbatim below. The Configuration Service backing store
# is always PostgreSQL regardless of database_engine, so $postgresCredential above is
# unaffected.
$dataStoreConnectionString = ""
if ("${{ inputs.database_engine }}" -eq "mssql") {
$mssqlPassword = Get-EnvValue -EnvValues $envValues -Name "MSSQL_SA_PASSWORD" -DefaultValue "abcdefgh1!"
$dataStoreConnectionString = New-DataStoreConnectionString -DatabaseEngine "mssql" -DbHost "dms-mssql" -Port 1433 -Username "sa" -Password $mssqlPassword -DatabaseName $env:RELATIONAL_DB_NAME
}

Add-CmsClient -CmsUrl "http://localhost:8081" -ClientId "data-store-admin" -ClientSecret "ValidClientSecret1234567890!Abcd" -DisplayName "Data Store Setup Administrator"
$configToken = Get-CmsToken -CmsUrl "http://localhost:8081" -ClientId "data-store-admin" -ClientSecret "ValidClientSecret1234567890!Abcd"
$dataStoreId = Add-DataStore -CmsUrl "http://localhost:8081" -AccessToken $configToken -PostgresCredential $postgresCredential -PostgresDbName $env:RELATIONAL_DB_NAME -Name "Relational Template Data Store" -DataStoreType "Template"
$dataStoreId = Add-DataStore -CmsUrl "http://localhost:8081" -AccessToken $configToken -PostgresCredential $postgresCredential -PostgresDbName $env:RELATIONAL_DB_NAME -ConnectionString $dataStoreConnectionString -Name "Relational Template Data Store" -DataStoreType "Template"
if (-not $dataStoreId) {
throw "Failed to register the relational data store."
}
Expand Down Expand Up @@ -223,12 +263,49 @@ jobs:
-ApplicationName $uniqueAppName `
-DataStoreDatabaseName $env:RELATIONAL_DB_NAME `
-DataStoreId $env:RELATIONAL_DATA_STORE_ID `
-DumpAllUserSchemas
-DumpAllUserSchemas `
-DatabaseEngine '${{ inputs.database_engine }}'
working-directory: eng/DatabaseTemplates/

# A loader that exits 0 does not guarantee it wrote anything: gate on descriptor content
# here, before the package is uploaded or published, so an empty bulk load cannot slip
# through as a "minimal" template. Minimal templates load only descriptor sample data
# (no sample entities), so dms.Descriptor is the content this template type owns.
- name: Gate on descriptor content before packaging
env:
DATABASE_ENGINE: ${{ inputs.database_engine }}
ENVIRONMENT_FILE: ${{ inputs.environment_file }}
run: |
Import-Module ./env-utility.psm1 -Force
$envValues = ReadValuesFromEnvFile $env:ENVIRONMENT_FILE

if ($env:DATABASE_ENGINE -eq "mssql") {
$mssqlPassword = Get-EnvValue -EnvValues $envValues -Name "MSSQL_SA_PASSWORD" -DefaultValue "abcdefgh1!"
$query = "SET NOCOUNT ON; SELECT COUNT(*) FROM [dms].[Descriptor];"
$rawOutput = & docker exec dms-mssql /opt/mssql-tools18/bin/sqlcmd -S localhost -U sa -P $mssqlPassword -d $env:RELATIONAL_DB_NAME -C -b -h -1 -W -Q $query
if ($LASTEXITCODE -ne 0) {
throw "Failed to query dms.Descriptor row count from database '$($env:RELATIONAL_DB_NAME)'."
}
$descriptorCount = [long](@($rawOutput) | Where-Object { -not [string]::IsNullOrWhiteSpace($_) } | Select-Object -First 1)
}
else {
$rawOutput = & docker exec dms-postgresql psql -U postgres -d $env:RELATIONAL_DB_NAME -tA -c 'SELECT COUNT(*) FROM dms."Descriptor";'
if ($LASTEXITCODE -ne 0) {
throw "Failed to query dms.Descriptor row count from database '$($env:RELATIONAL_DB_NAME)'."
}
$descriptorCount = [long](@($rawOutput) | Where-Object { -not [string]::IsNullOrWhiteSpace($_) } | Select-Object -First 1)
}

if ($descriptorCount -lt 1) {
throw "Descriptor content gate failed: dms.Descriptor has $descriptorCount row(s) in database '$($env:RELATIONAL_DB_NAME)'; the bulk load did not populate descriptor data."
}

Write-Host "Descriptor content gate passed: dms.Descriptor has $descriptorCount row(s)." -ForegroundColor Green
working-directory: eng/docker-compose/

- name: Verify template package restore
run: |
./verify-template-restore.ps1 -SourceDatabaseName $env:RELATIONAL_DB_NAME
./verify-template-restore.ps1 -SourceDatabaseName $env:RELATIONAL_DB_NAME -DatabaseEngine '${{ inputs.database_engine }}'
working-directory: eng/DatabaseTemplates/

- name: Upload Bulk Load Logs
Expand Down
Loading
Loading