Skip to content
Merged
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
3 changes: 1 addition & 2 deletions .github/workflows/aarch64-linux.yml
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
name: DevX closures for aarch64-linux

on:
# Disabled until we have a new aarch64-linux hydra builder
# push:
push:

jobs:
build:
Expand Down
12 changes: 4 additions & 8 deletions .github/workflows/hello.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ name: Test that we can build the hello world example form hackage

on:
push:
branches: [main]
workflow_dispatch:

jobs:
Expand All @@ -11,13 +12,11 @@ jobs:
fail-fast: false
matrix:
platform:
- x86_64-darwin
- x86_64-linux
# Skipping because we do not have runners for these set up.
#- aarch64-darwin
#- aarch64-linux
- x86_64-darwin
- aarch64-darwin
- aarch64-linux
compiler-nix-name:
- ghc810
- ghc96
- ghc98
- ghc910
Expand All @@ -34,9 +33,6 @@ jobs:
- false
- true
exclude:
# Just cross compiling javascript with ghc 9.6 and above
- compiler-nix-name: ghc810
target-platform: "-js"
# Windows cross compilation only works on x86_64 right now.
- platform: aarch64-darwin
target-platform: "-windows"
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/lints.yml
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ jobs:
nix_path: nixpkgs=channel:nixos-unstable
- run: |
nix profile install github:Kha/nixprof
nixprof record nix develop .#ghc8107 --accept-flake-config
nixprof record nix develop .#ghc96 --accept-flake-config
nixprof report -p
nixprof report -a
nixprof report -s
Expand Down
3 changes: 3 additions & 0 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,10 @@ jobs:
echo "matrix=$MATRIX" >> $GITHUB_OUTPUT

# We need this process step in here, because we have in excess of 256 jobs.
# Only upload to GHCR from the main branch to prevent PR pushes from
# overwriting production container images.
process:
if: github.ref == 'refs/heads/main'
needs: discover
runs-on: ubuntu-latest
strategy:
Expand Down
121 changes: 121 additions & 0 deletions .github/workflows/pr-validate.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
name: Validate DevX containers (PR)

# Validate devcontainer closures on pull requests by fetching
# Hydra-cached build outputs and smoke-testing them. This replaces
# the GHCR upload pipeline for PRs — actual uploads only happen
# from the main branch (gated in main.yml).
on:
pull_request:

env:
GH_TOKEN: ${{ github.token }}

jobs:
wait-for-hydra:
name: Wait for Hydra status
runs-on: ubuntu-latest
steps:
- uses: input-output-hk/actions/wait-for-hydra@latest
with:
check: required

discover:
needs: wait-for-hydra
name: Discover -env closures
runs-on: ubuntu-latest
outputs:
matrix: ${{ steps.set-matrix.outputs.matrix }}
steps:
- name: Discover Hydra -env check-runs
id: set-matrix
run: |
# Fetch all check-runs for this commit from Hydra.
# --paginate returns multiple JSON objects (one per page),
# so we pipe through jq --slurp to merge them before filtering.
RUNS=$(gh api "repos/$GITHUB_REPOSITORY/commits/${{ github.event.pull_request.head.sha }}/check-runs" --paginate)

# Pick a representative subset: one -env per platform to keep
# the matrix small (avoids 80+ jobs on every PR push).
# Only include successfully completed builds — Hydra posts
# check-runs at eval time before builds finish, so in-progress
# or failed builds would have store paths not yet in caches.
FILTERED=$(echo "$RUNS" | jq -s -c '
[.[].check_runs[]
| select(.name | endswith("-env"))
| select(.conclusion == "success")
| select(.output.summary | . != null and startswith("/nix/store/"))
| { "config": .name,
"build_path": .output.summary,
"short_name": (.name | sub("^[^.]+\\."; "")) }]
| group_by(.short_name)
| map(.[0])
| sort_by(.config)
| .[0:8]
')

echo "Selected closures for validation:"
echo "$FILTERED" | jq .
echo "matrix=$FILTERED" >> $GITHUB_OUTPUT

validate:
needs: discover
if: needs.discover.outputs.matrix != '[]' && needs.discover.outputs.matrix != ''
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
job: ${{ fromJson(needs.discover.outputs.matrix) }}
name: Validate ${{ matrix.job.short_name }}
steps:
- name: Install Nix
uses: cachix/install-nix-action@v31
with:
extra_nix_config: |
trusted-public-keys = cache.nixos.org-1:6NCHdD59X431o0gWypbMrAURkbJ16ZPMQFGspcDShjY= hydra.iohk.io:f/Ea+s+dFdN+3Y/G+FDgSq+a5NEWhJGzdjvKNGv0/EQ= loony-tools:pr9m4BkM/5/eSTZlkQyRt57Jz7OMBxNSUiMC4FkcNfk=
substituters = https://cache.iog.io/ https://cache.zw3rk.com/ https://cache.nixos.org/

- name: Validate closure
env:
SHELL_NIX_PATH: ${{ matrix.job.build_path }}
run: |
set -euo pipefail

echo "::group::Realize closure from Hydra cache"
nix-store -r "$SHELL_NIX_PATH"
echo "::endgroup::"

CLOSURE_PATHS=$(nix-store -qR "$SHELL_NIX_PATH")

# Verify the "devx" wrapper script is in the closure
if ! echo "$CLOSURE_PATHS" | grep -q "devx$"; then
echo "::error::No 'devx' wrapper found in closure"
exit 1
fi

DEVX_PATH=$(echo "$CLOSURE_PATHS" | grep "devx$" | head -1)
echo "Found devx wrapper: $DEVX_PATH"

echo "::group::Smoke test"
# Write smoke test commands to a temporary file — the devx
# wrapper sources $1 as a script, it doesn't support -c.
SMOKE_TEST=$(mktemp)
cat > "$SMOKE_TEST" << 'TESTEOF'
echo "GHC: $(ghc --version 2>/dev/null || echo N/A)"
echo "Cabal: $(cabal --version 2>/dev/null | head -1 || echo N/A)"
TESTEOF

# stdenv's setup.sh expects Nix builder runtime variables
# (NIX_BUILD_TOP, out, etc.) that only exist inside nix build.
# Provide them so the devx wrapper can source setup.sh.
export NIX_BUILD_TOP="$(mktemp -d)"
export TMPDIR="$NIX_BUILD_TOP"
export TMP="$NIX_BUILD_TOP"
export TEMP="$NIX_BUILD_TOP"
export TEMPDIR="$NIX_BUILD_TOP"
export NIX_STORE="/nix/store"
export out="$NIX_BUILD_TOP/out"
mkdir -p "$out"
"$DEVX_PATH" "$SMOKE_TEST"
echo "::endgroup::"

echo "Validation passed for ${{ matrix.job.short_name }}"
2 changes: 1 addition & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ if [ -n "\$VSCODE_IPC_HOOK_CLI" ]; then
mkdir -p "\$(dirname "\$VSCODE_IPC_HOOK_CLI")"
fi
# This line is the one that actually brings DevX devshell ...
source $(grep -m 1 -e '-env.sh$' store-paths.txt)
source $(grep -m 1 -e 'devx$' store-paths.txt)
EOF

# This enforce those settings in DevContainer whatever "Settings Sync" user preferences ...
Expand Down
13 changes: 10 additions & 3 deletions extra/ghcr-upload.sh
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,14 @@ set -euox pipefail

# retry three times in case of intermittent network errors.
nix-store -r "$SHELL_NIX_PATH" || nix-store -r "$SHELL_NIX_PATH" || nix-store -r "$SHELL_NIX_PATH"
#nix build ".#hydraJobs.${DEV_SHELL}" --show-trace --accept-flake-config
nix-store --export $(nix-store -qR "$SHELL_NIX_PATH") | tee store-paths.txt | zstd -z8T8 >${DEV_SHELL}
if [[ ! $(tail -n 1 store-paths.txt) =~ "devx" ]]; then exit 1; fi
# Collect closure paths and export them as a zstd-compressed NAR archive.
# Save the path list separately for verification — nix-store --export
# produces binary output (contains null bytes) which can't be inspected
# with text tools like tail/grep.
CLOSURE_PATHS=$(nix-store -qR "$SHELL_NIX_PATH")
nix-store --export $CLOSURE_PATHS | zstd -z8T8 >${DEV_SHELL}
# Verify the environment script is included in the closure.
# The wrapper script is always named "devx" for compatibility with
# input-output-hk/actions/devx/action.yml which matches on that name.
if ! echo "$CLOSURE_PATHS" | grep -q "devx$"; then exit 1; fi
oras push ghcr.io/input-output-hk/devx:${DEV_SHELL} ${DEV_SHELL}
Loading
Loading