Skip to content

[new release] modelkit (4 packages) (0.4.1) #11526

[new release] modelkit (4 packages) (0.4.1)

[new release] modelkit (4 packages) (0.4.1) #11526

Workflow file for this run

name: Windows CI
on:
pull_request:
permissions: read-all
jobs:
analyse:
runs-on: ubuntu-latest
outputs:
matrix: ${{ steps.matrix.outputs.result }}
steps:
- name: Checkout tree
uses: actions/checkout@v7
with:
fetch-depth: 2
- name: Get changed files
id: changed-files
uses: tj-actions/changed-files@v47
- name: Compute build matrix
id: matrix
uses: actions/github-script@v9
with:
script: |
let changed_files = '${{ steps.changed-files.outputs.all_changed_files }}';
let modified_files = '${{ steps.changed-files.outputs.modified_files }}';
const pkg_re = /^packages\/[^/]+\/([^/]+)/;
// Versioned packages whose opam file has been edited (rather than added).
const edited_set = new Set();
for (file of modified_files.split(' ')) {
const package = file.match(pkg_re);
if (package)
edited_set.add(package[1]);
}
// All changed packages, edited ones first so that the switch is restored
// between each before any new package accumulates in it.
const edited = [];
const added = [];
const seen = new Set();
for (file of changed_files.split(' ')) {
console.log("Changed: " + file);
const package = file.match(pkg_re);
if (package && !seen.has(package[1])) {
seen.add(package[1]);
if (edited_set.has(package[1])) {
console.log(" => upgrade " + package[1]);
edited.push(package[1]);
} else {
console.log(" => install " + package[1]);
added.push(package[1]);
}
}
}
// Edited packages come first, so each 75-package chunk is split back into
// its edited and added halves; the build job tests the edited ones first
// (restoring the switch between each) then installs the added ones.
const ordered = edited.concat(added);
const splits =
Array.from({ length: Math.ceil(ordered.length / 75) },
(_, i) => {
const slice = ordered.slice(i * 75, i * 75 + 75);
return {
edited: slice.filter(p => edited_set.has(p)).join(' '),
added: slice.filter(p => !edited_set.has(p)).join(' '),
};
});
return {windows_environment: ['cygwin', 'msys2'], packages: splits};
build:
name: "target/host: x86_64-w64-mingw32, build: ${{ matrix.windows_environment }}"
strategy:
fail-fast: false
matrix: ${{ fromJSON(needs.analyse.outputs.matrix) }}
if: ${{ fromJSON(needs.analyse.outputs.matrix).packages[0] != null }}
runs-on: windows-latest
needs: analyse
steps:
- name: Checkout tree
uses: actions/checkout@v7
- name: Fetch base
run: |
git remote add upstream https://github.com/ocaml/opam-repository.git
git fetch --depth=1 upstream ${{ github.event.pull_request.base.sha }}
git branch repo-${{ github.event.pull_request.base.sha }} ${{ github.event.pull_request.base.sha }}
- name: Prune PATH
# The runner ships a lot of optional software whose bin directories would
# otherwise shadow the conf-* packages under test - most importantly
# Strawberry Perl (a complete gcc/mingw toolchain) and chocolatey's
# pkgconfiglite. Drop those directories before setup-ocaml runs, so opam
# only ever sees the toolchain it installs itself.
run: |
# New optional software in the runner image should be added here
# explicitly, rather than relying on a whitelist - that way a newly
# added directory shows up as Kept and is noticed, rather than being
# silently dropped.
$exclude = @(
# Toolchains and tools that would shadow the packages under test
'Strawberry' # bundles gcc/mingw, perl and pkg-config
'chocolatey' # pkgconfiglite, openssl, ...
'OpenSSL'
'vcpkg'
'mingw64' # standalone gcc/mingw, plus Git's bundled copy
'LLVM' # clang
'Git\bin' # Git's MSYS bash/sh (git itself stays via Git\cmd)
'Git\usr' # Git's MSYS unix tools (perl, sed, awk, ...)
'CMake'
'NSIS'
'WiX'
# Optional development software, unused by opam
'MongoDB'
'mongosh'
'PostgreSQL'
'mysql'
'Microsoft SQL Server'
'\R\R-'
'SeleniumWebDrivers'
'Microsoft SDKs\Azure'
'Amazon'
'Cloud SDK'
'Mercurial'
'ghcup'
'cabal'
'\stack\'
'sbt'
'pipx'
'php'
'aliyun'
'kind'
'dotnet'
'GitHub CLI'
'npm'
'nodejs'
'windows\go\'
'Ruby'
'Python'
'Java'
'kotlinc'
'cargo'
'ImageMagick'
'Web Platform Installer'
'Performance Toolkit'
'Service Fabric'
)
$kept = @()
foreach ($dir in $env:PATH -split ';' | Where-Object { $_ }) {
if ($exclude | Where-Object { $dir -like "*$_*" }) {
Write-Host "Dropping $dir"
} else {
Write-Host "Keeping $dir"
$kept += $dir
}
}
"PATH=$($kept -join ';')" | Out-File -FilePath $env:GITHUB_ENV -Append -Encoding utf8
- name: Set-up OCaml
uses: ocaml/setup-ocaml@v3
with:
ocaml-compiler: "5"
opam-repositories: |
default: git+file://${{ github.workspace }}#repo-${{ github.event.pull_request.base.sha }}
opam-pin: false
windows-environment: ${{ matrix.windows_environment }}
- name: Initial state
run: |
# commands
Write-Host "# Switch invariant: `e[34m$(opam switch invariant)`e[0m"
opam list
opam repo
- name: Install packages
env:
CI_CASE: ${{ matrix.windows_environment }}-mingw
run: |
# package installations
$failed = $false
function Skip-Until {
param(
[Parameter(Mandatory, Position=0)][string]$Pattern,
[Parameter(ValueFromPipeline)]$Line
)
begin { $found = $false }
process {
if ($found) { $Line }
elseif ($Line -match $Pattern) { $found = $true }
}
}
function Get-Status {
param([int]$Code)
switch ($Code) {
0 { 'ok' }
5 { 'skip' } # TODO: Remove when https://github.com/ocaml/opam/issues/6017 is fixed
20 { 'skip' }
31 { 'fail' }
default { throw "Unexpected error $Code" }
}
}
$switch = "${{ github.workspace }}\_opam"
$backup = "${{ github.workspace }}\_opam.bak"
$repoBranch = "repo-${{ github.event.pull_request.base.sha }}"
$baseRef = "${{ github.event.pull_request.base.sha }}"
$prRef = "${{ github.sha }}"
# Re-point the repository's git branch at $Ref and update (opam repo
# set-url re-initialises the repository, which is much slower)
function Set-Repo {
param([Parameter(Mandatory, Position=0)][string]$Ref)
git branch -f $repoBranch $Ref
opam update -q > $null
}
$edited = @('${{ matrix.packages.edited }}' -split ' ' | Where-Object { $_ })
# Edited packages are tested both ways: as an upgrade (the loop below)
# and, like added packages, as a fresh install under the PR.
$install = @('${{ matrix.packages.added }}' -split ' ' | Where-Object { $_ }) + $edited
if ($edited) {
# If packages have been edited, take a backup copy of the switch, as
# each installation needs a fresh copy of the switch.
robocopy $switch $backup /MIR /NFL /NDL /NJH /NJS /NP > $null
# robocopy's exit status is a bit mask: bits 0-2 are informational.
if ($LASTEXITCODE -ge 8) { throw "robocopy backup failed ($LASTEXITCODE)" }
}
# Edited packages: the switch begins at the base commit on master. For
# each edited package, first install the existing package using the
# package description from master. If this succeeds, lock the versions
# of all packages in the switch using opam switch set-invariant. Then
# update the repository to the PR and run opam upgrade (or repeat
# opam install, if it failed the first time).
Foreach ($pkg in $edited) {
$pkg_dir = $pkg.Split('.')[0]
# opam doesn't support reducing Error 46 to a Warning
opam lint --warnings=-46 -v "packages/$pkg_dir/$pkg" > $null
if ($LASTEXITCODE -ne 0) {
# Allow Error 46 to display here, though
opam lint -v "packages/$pkg_dir/$pkg"
Write-Host "$pkg failed linting."; $failed = $true
}
Write-Host "::group::Testing edited package `e[1;34m$pkg`e[0m"
opam install --color=always --confirm-level=unsafe-yes "$pkg"
$base = Get-Status $LASTEXITCODE
if ($base -eq 'ok') {
# Lock the switch to exactly the installed packages and versions
# via the invariant (the invariant requires the package to be
# installed, where pinning only requires that if it's installed,
# then it's installed using the pin).
$invariant = opam list --color=never --installed --short --columns=package
opam switch set-invariant -n @($invariant)
Set-Repo $prRef
opam upgrade --color=always --confirm-level=unsafe-yes
$upgrade_exit_code = $LASTEXITCODE
$still = opam list --installed --short "$pkg"
# 31 implies build failure; any other failure implies no solution.
$pr = if ($upgrade_exit_code -eq 31) { 'fail' }
elseif ($upgrade_exit_code -ne 0) { 'skip' }
elseif (-not $still) { 'skip' }
else { 'ok' }
} else {
# Not installed on the base: apply the PR and retry the install.
Set-Repo $prRef
opam install --color=always --confirm-level=unsafe-yes "$pkg"
$pr = Get-Status $LASTEXITCODE
}
opam config list $pkg_dir | Skip-Until ':opamfile'
Write-Host "::endgroup::"
$regress = ($base -ne 'fail' -and $pr -eq 'fail') -or ($base -eq 'ok' -and $pr -eq 'skip')
$color = if ($regress) { '31' } elseif ($pr -eq 'ok') { '32' } else { '33' }
Write-Host "`e[1;${color}m${pkg}: base = $base -> PR = $pr`e[0m"
if ($regress) { $failed = $true }
# Restore the base switch (including its invariant) and repo for the
# next package.
robocopy $backup $switch /MIR /NFL /NDL /NJH /NJS /NP > $null
if ($LASTEXITCODE -ge 8) { throw "robocopy restore failed ($LASTEXITCODE)" }
Set-Repo $baseRef
Write-Host
}
# Install each added (and edited) package as normal, using the PR.
if ($install) {
Set-Repo $prRef
}
Foreach ($pkg in $install) {
$pkg_dir = $pkg.Split('.')[0]
opam lint --warnings=-46 -v "packages/$pkg_dir/$pkg" > $null
if ($LASTEXITCODE -ne 0) {
opam lint -v "packages/$pkg_dir/$pkg"
Write-Host "$pkg failed linting."; $failed = $true
}
Write-Host "::group::Testing `e[1;34m$pkg`e[0m"
opam install --color=always --confirm-level=unsafe-yes "$pkg"
$install_exit_code = $LASTEXITCODE
opam config list $pkg_dir | Skip-Until ':opamfile'
Write-Host "::endgroup::"
switch ($install_exit_code) {
0 { Write-Host "`e[1;32m$pkg installed successfully`e[0m."; Break }
5 { Write-Host "$pkg is not installable. `e[1;33mSkip`e[0m."; Break } # TODO: Remove when https://github.com/ocaml/opam/issues/6017 is fixed
20 { Write-Host "$pkg is not installable. `e[1;33mSkip`e[0m."; Break }
31 {
$this_failed = $true
Foreach ($failpkg in Get-ChildItem -Path "${{ github.workspace }}\_opam\.opam-switch\build" -Name) {
if (opam show -f x-ci-accept-failures: "$failpkg" | Select-String -Pattern """$env:CI_CASE""" -SimpleMatch) {
$this_failed = $false
Write-Host "$failpkg failed to build but that was expected:"
Write-Host "its 'x-ci-accept-failures' field contains ""$env:CI_CASE"". `e[1;33mSkip`e[0m."
} else {
Write-Host "`e[1;31m$failpkg failed to build`e[0m."
}
}
$failed = $failed -or $this_failed
Remove-Item -Path "${{ github.workspace }}\_opam\.opam-switch\build" -Recurse -Force
Break
}
default { throw "Unexpected error $_" }
}
Write-Host
}
if ($failed) {
throw "One or more packages failed to lint or build"
}