Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
c84d8f9
Add downstream build workflow
jamie-osec May 19, 2026
f722605
Isolate downstream build checkout
jamie-osec May 19, 2026
c1c98f2
Use anchor community downstream matrix
jamie-osec May 19, 2026
04f857e
Temporarily run downstream builds on PRs
jamie-osec May 19, 2026
3a2d15e
Install downstream CLI with AVM
jamie-osec May 19, 2026
1ed1b9f
Install downstream Anchor versions with AVM
jamie-osec May 19, 2026
51e9ca4
Refresh downstream AVM checkout
jamie-osec May 19, 2026
76dbf88
Isolate Solana caches for downstream builds
jamie-osec May 19, 2026
98f30e5
Temporarily test marginfi community branch
jamie-osec May 20, 2026
9bfa549
Temporarily test community PR 4
jamie-osec May 20, 2026
0f2a7cd
Use vendored downstream sources
jamie-osec May 20, 2026
f46823e
Allow vendored builds from subdirectories
jamie-osec May 20, 2026
f3f9861
Rerun downstream builds
jamie-osec May 21, 2026
bac8a46
Harden downstream build workflow
jamie-osec May 21, 2026
f8faf1d
Preinstall downstream Anchor CLIs
jamie-osec May 21, 2026
c0d8be7
Resolve downstream Anchor versions noninteractively
jamie-osec May 21, 2026
901b615
Isolate downstream Solana caches
jamie-osec May 21, 2026
3876d82
Improve downstream failure diagnostics
jamie-osec May 21, 2026
2e1cd89
Rerun downstream builds with updated pins
jamie-osec May 21, 2026
23eccb2
Rerun downstream builds with installer config fix
jamie-osec May 21, 2026
8d2ad8d
Temporarily skip non-downstream suites
jamie-osec May 21, 2026
e01fb92
Use fork branch for downstream AVM checkout
jamie-osec May 21, 2026
8ecba4a
Rerun downstream builds with Anchor commands
jamie-osec May 21, 2026
b69fbff
Resolve nested downstream Anchor versions
jamie-osec May 21, 2026
fda8713
Rerun downstream builds with NTT no-idl
jamie-osec May 21, 2026
c87a920
Rerun downstream builds with NTT lib target
jamie-osec May 21, 2026
002b3b5
Rerun downstream builds with restored NTT SDK
jamie-osec May 21, 2026
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
26 changes: 24 additions & 2 deletions .github/actions/setup-solana/action.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ runs:
path: |
~/.cache/solana/
~/.local/share/solana/
key: solana-${{ runner.os }}-v0000-${{ env.SOLANA_VERSION }}
key: solana-${{ runner.os }}-v0001-${{ env.SOLANA_VERSION }}
- uses: nick-fields/retry@v2
if: steps.cache-solana.outputs.cache-hit != 'true'
with:
Expand All @@ -20,7 +20,29 @@ runs:
retry_on: error
shell: bash
command: sh -c "$(curl -sSfL https://release.anza.xyz/v${{ env.SOLANA_VERSION }}/install)"
- run: echo "/home/runner/.local/share/solana/install/active_release/bin" >> $GITHUB_PATH
- name: Activate requested Solana release
run: |
set -euo pipefail

install_dir="$HOME/.local/share/solana/install"
release_dir="$install_dir/releases/$SOLANA_VERSION/solana-release"

if [[ ! -x "$release_dir/bin/solana" ]]; then
sh -c "$(curl -sSfL "https://release.anza.xyz/v$SOLANA_VERSION/install")"
else
ln -sfn "$release_dir" "$install_dir/active_release"
fi

echo "$install_dir/active_release/bin" >> "$GITHUB_PATH"
actual="$("$install_dir/active_release/bin/solana" --version)"
echo "$actual"
case "$actual" in
"solana-cli $SOLANA_VERSION"*) ;;
*)
echo "Expected Solana $SOLANA_VERSION, got: $actual" >&2
exit 1
;;
esac
shell: bash
- run: solana-keygen new --no-bip39-passphrase
shell: bash
Expand Down
292 changes: 292 additions & 0 deletions .github/workflows/downstream-builds.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,292 @@
name: Downstream Builds

on:
push:
branches:
- anchor-next
paths-ignore:
- "docs/**"
# FIXME: Remove this before final merge; downstream builds should only run
# on pushes to anchor-next once the workflow has been validated.
pull_request:
paths-ignore:
- "docs/**"

env:
SOLANA_VERSION: "3.1.10"

jobs:
downstream-matrix:
name: Build downstream matrix
runs-on: ubuntu-latest
timeout-minutes: 5
permissions:
contents: read
outputs:
matrix: ${{ steps.repos.outputs.matrix }}
steps:
- name: Checkout anchor-community
uses: actions/checkout@v3
with:
# Continue testing local downstream-suite changes from the fork branch.
repository: jamie-osec/anchor-community
ref: set-correct-solana-versions
path: anchor-community

- name: Build matrix from repos.json
id: repos
run: |
matrix="$(jq -c '{include: [.[] | {
name,
source,
repository: (.source | sub("^https://github.com/"; "") | sub("\\.git$"; "")),
commit,
directory,
build_path: ("anchor-community/programs/" + .directory),
build_command
}]}' anchor-community/repos.json)"

{
echo "matrix<<EOF"
echo "$matrix"
echo "EOF"
} >> "$GITHUB_OUTPUT"

anchor-build:
needs: downstream-matrix
name: ${{ matrix.name }}
runs-on: ubuntu-latest
timeout-minutes: 60
permissions:
contents: read
strategy:
fail-fast: false
max-parallel: 4
matrix: ${{ fromJson(needs.downstream-matrix.outputs.matrix) }}

steps:
- name: Checkout anchor-community
uses: actions/checkout@v3
with:
# Continue testing local downstream-suite changes from the fork branch.
repository: jamie-osec/anchor-community
ref: set-correct-solana-versions
path: anchor-community

- name: Verify vendored source
run: test -d "${{ matrix.build_path }}"

- name: Checkout AVM branch
uses: actions/checkout@v3
with:
repository: jamie-osec/anchor
ref: avm-improvements
path: avm-source

- name: Show AVM checkout
run: git -C avm-source rev-parse HEAD

- name: Install dependencies
run: |
set -euo pipefail

for attempt in 1 2 3; do
if sudo apt-get update && sudo apt-get install -y pkg-config build-essential libudev-dev; then
exit 0
fi

if [[ "$attempt" == 3 ]]; then
exit 1
fi

sleep $((attempt * 20))
done

- uses: actions/cache@v4
name: Cache Solana Tool Suite
id: cache-solana
with:
path: |
~/.cache/solana/
~/.local/share/solana/
key: downstream-solana-${{ runner.os }}-v0001-${{ matrix.directory }}-${{ env.SOLANA_VERSION }}
restore-keys: |
downstream-solana-${{ runner.os }}-v0001-${{ matrix.directory }}-

- uses: nick-fields/retry@v2
if: steps.cache-solana.outputs.cache-hit != 'true'
with:
retry_wait_seconds: 300
timeout_minutes: 2
max_attempts: 10
retry_on: error
shell: bash
command: sh -c "$(curl -sSfL https://release.anza.xyz/v${{ env.SOLANA_VERSION }}/install)"

- name: Activate requested Solana release
run: |
set -euo pipefail

install_dir="$HOME/.local/share/solana/install"
release_dir="$install_dir/releases/$SOLANA_VERSION/solana-release"

if [[ ! -x "$release_dir/bin/solana" ]]; then
sh -c "$(curl -sSfL "https://release.anza.xyz/v$SOLANA_VERSION/install")"
else
ln -sfn "$release_dir" "$install_dir/active_release"
fi

echo "$install_dir/active_release/bin" >> "$GITHUB_PATH"
actual="$("$install_dir/active_release/bin/solana" --version)"
echo "$actual"
case "$actual" in
"solana-cli $SOLANA_VERSION"*) ;;
*)
echo "Expected Solana $SOLANA_VERSION, got: $actual" >&2
exit 1
;;
esac
shell: bash

- run: solana-keygen new --no-bip39-passphrase
- run: solana config set --url localhost

- uses: actions/cache@v4
name: Cache AVM target
with:
path: avm-target/
key: cargo-target-${{ runner.os }}-downstream-avm-4534-${{ hashFiles('avm-source/Cargo.lock', 'avm-source/avm/src/**') }}
restore-keys: |
cargo-target-${{ runner.os }}-downstream-avm-4534-

- uses: actions/cache@v4
name: Cache ${{ matrix.name }} Cargo home
with:
path: |
~/.cargo/registry/index/
~/.cargo/registry/cache/
~/.cargo/git/db/
key: cargo-home-${{ runner.os }}-downstream-${{ matrix.directory }}-${{ hashFiles(format('{0}/Cargo.lock', matrix.build_path)) }}
restore-keys: |
cargo-home-${{ runner.os }}-downstream-${{ matrix.directory }}-

- name: Install AVM
env:
CARGO_TARGET_DIR: ${{ github.workspace }}/avm-target
run: |
cargo install --path avm-source/avm --locked --force
avm --version
echo "$HOME/.avm/bin" >> "$GITHUB_PATH"

- uses: actions/cache@v4
name: Cache ${{ matrix.name }} target
with:
path: ${{ matrix.build_path }}/target/
key: cargo-target-${{ runner.os }}-downstream-${{ matrix.directory }}-${{ hashFiles(format('{0}/Cargo.lock', matrix.build_path)) }}-${{ github.run_id }}
restore-keys: |
cargo-target-${{ runner.os }}-downstream-${{ matrix.directory }}-${{ hashFiles(format('{0}/Cargo.lock', matrix.build_path)) }}-
cargo-target-${{ runner.os }}-downstream-${{ matrix.directory }}-

- name: Build ${{ matrix.repository }}
working-directory: ${{ matrix.build_path }}
env:
BUILD_COMMAND: ${{ matrix.build_command }}
NO_COLOR: "1"
TERM: dumb
run: |
# Preinstall the downstream-pinned Anchor CLI without relying on an
# interactive prompt. The spawned `anchor` still exercises PR #4534's
# project-aware Solana/platform-tools selection during the build.
anchor_version="$(
python3 <<'PY'
import pathlib
import re
import tomllib

def clean_version(req):
match = re.search(r"\d+\.\d+\.\d+(?:[-+][0-9A-Za-z.-]+)?", req or "")
return match.group(0) if match else ""

anchor_tomls = [pathlib.Path("Anchor.toml")]
anchor_tomls.extend(
path for path in pathlib.Path(".").glob("**/Anchor.toml")
if "target" not in path.parts
)
seen = set()
for anchor_toml in anchor_tomls:
if anchor_toml in seen or not anchor_toml.exists():
continue
seen.add(anchor_toml)
version = tomllib.loads(anchor_toml.read_text()).get("toolchain", {}).get("anchor_version")
if version:
print(clean_version(version))
raise SystemExit

manifests = [pathlib.Path("Cargo.toml")]
manifests.extend(path for path in pathlib.Path(".").glob("**/Cargo.toml") if "target" not in path.parts)
seen = set()
for manifest in manifests:
if manifest in seen or not manifest.exists():
continue
seen.add(manifest)
data = tomllib.loads(manifest.read_text())
workspace_dep = data.get("workspace", {}).get("dependencies", {}).get("anchor-lang")
if isinstance(workspace_dep, str):
version = clean_version(workspace_dep)
elif isinstance(workspace_dep, dict):
version = clean_version(workspace_dep.get("version", ""))
else:
version = ""
if version:
print(version)
break

deps = data.get("dependencies", {})
dep = deps.get("anchor-lang")
if isinstance(dep, str):
version = clean_version(dep)
elif isinstance(dep, dict):
version = clean_version(dep.get("version", ""))
else:
version = ""
if version:
print(version)
break
PY
)"
if [[ -n "$anchor_version" ]]; then
avm install "$anchor_version"
avm use "$anchor_version"
fi

log="$RUNNER_TEMP/downstream-build.log"
set +e
script -qec "$BUILD_COMMAND" "$log"
status=$?
set -e

if [[ "$status" -ne 0 ]]; then
clean_log="$RUNNER_TEMP/downstream-build-clean.log"
python3 - "$log" "$clean_log" <<'PY'
import re
import sys

src, dst = sys.argv[1:3]
text = open(src, "rb").read().decode("utf-8", "replace")
text = text.replace("\r", "\n")
text = re.sub(r"\x1b\[[0-?]*[ -/]*[@-~]", "", text)
text = re.sub(r"[\x00-\x08\x0b\x0c\x0e-\x1f\x7f]", "", text)

lines = [line.rstrip() for line in text.splitlines()]
lines = [line for line in lines if line.strip()]
open(dst, "w", encoding="utf-8").write("\n".join(lines[-200:]))
PY

echo "::group::last 200 build log lines"
tail -n 200 "$clean_log" || true
echo "::endgroup::"

summary="$(tail -n 80 "$clean_log" | sed -e 's/%/%25/g' -e ':a;N;$!ba;s/\n/%0A/g')"
echo "::error title=${{ matrix.name }} build failed::$summary"
exit "$status"
fi
2 changes: 2 additions & 0 deletions .github/workflows/template-tests.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ jobs:
# Build CLI once to share across test jobs
build-cli:
name: Build CLI
# Temporarily skip while validating downstream-builds in #4561.
if: ${{ false }}
runs-on: ubuntu-latest
timeout-minutes: 30
steps:
Expand Down
2 changes: 2 additions & 0 deletions .github/workflows/tests.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ env:
jobs:
test-v2:
name: v2 Tests
# Temporarily skip while validating downstream-builds in #4561.
if: ${{ false }}
runs-on: ubuntu-latest
timeout-minutes: 60
steps:
Expand Down
Loading