Skip to content

testing some rpcserver calls #682

testing some rpcserver calls

testing some rpcserver calls #682

Workflow file for this run

name: .NET Core Test and Publish
on:
push:
branches: [master-n3]
pull_request:
env:
DOTNET_VERSION: 10.0.x
jobs:
Test:
strategy:
matrix:
os: [ubuntu-latest, windows-latest]
runs-on: ${{ matrix.os }}
steps:
- name: Checkout
uses: actions/checkout@v5
- name: Setup .NET Core
uses: actions/setup-dotnet@v5
with:
dotnet-version: ${{ env.DOTNET_VERSION }}
- name: Check format
if: runner.os == 'Linux'
run: dotnet format --no-restore --verify-no-changes --verbosity diagnostic
- name: Build CLI
if: runner.os == 'Linux'
run: |
dotnet publish -o ./out -c Release src/Neo.CLI
find ./out -name 'config.json' | xargs perl -pi -e 's|LevelDBStore|MemoryStore|g'
- name: Install dependencies
if: runner.os == 'Linux'
run: sudo apt-get install libleveldb-dev expect
- name: Run tests with expect
if: runner.os == 'Linux'
run: expect ./.github/workflows/test-neo-cli.expect
- name: Run Unit Tests
if: runner.os == 'Windows'
run: |
forfiles /p tests /m *.csproj /s /c "cmd /c dotnet add @PATH package coverlet.msbuild"
dotnet test /p:CollectCoverage=true /p:CoverletOutput='${{ github.workspace }}/TestResults/coverage/' /p:MergeWith='${{ github.workspace }}/TestResults/coverage/coverage.json' /p:CoverletOutputFormat=lcov%2cjson -m:1
- name: Codecov
if: runner.os == 'Windows'
uses: codecov/codecov-action@v5
with:
token: ${{ secrets.CODECOV_TOKEN }}
files: ${{ github.workspace }}/TestResults/coverage/coverage.info
fail_ci_if_error: false
Test-with-plugins:
strategy:
matrix:
os: [ubuntu-latest]
runs-on: ${{ matrix.os }}
steps:
- name: Checkout
uses: actions/checkout@v5
- name: Setup .NET Core
uses: actions/setup-dotnet@v5
with:
dotnet-version: ${{ env.DOTNET_VERSION }}
- name: Build CLI
run: |
dotnet build -c Release
dotnet publish -o ./out -c Release src/Neo.CLI
- name: Create Plugins folder and copy plugin DLLs
run: |
mkdir -p ./out/Plugins
for plugin_dir in plugins/*/; do
plugin_name=$(basename "$plugin_dir")
build_output="$plugin_dir/bin/Release/net10.0"
if [ -d "$build_output" ]; then
mkdir -p "./out/Plugins/$plugin_name"
cp -r "$build_output"/* "./out/Plugins/$plugin_name/"
fi
done
# Remove duplicated RpcServer.dll from TokensTracker and StorageDumper (they can't load twice)
rm -f ./out/Plugins/TokensTracker/RpcServer.dll
rm -f ./out/Plugins/StateService/RpcServer.dll
- name: Install dependencies
run: sudo apt-get install -y libleveldb-dev expect jq
- name: Run tests with expect
run: expect ./.github/workflows/test-neo-cli-plugins.expect
- name: Start neo-cli with plugins
run: |
dotnet out/neo-cli.dll &
NEO_PID=$!
echo "NEO_PID=$NEO_PID" >> $GITHUB_ENV
sleep 10
- name: Test RPC calls
run: |
chmod +x ./.github/workflows/test-rpc-calls.sh
./.github/workflows/test-rpc-calls.sh
- name: Stop neo-cli
run: |
if [ -n "$NEO_PID" ]; then
kill $NEO_PID || true
fi
Release:
if: github.ref == 'refs/heads/master-n3' && github.repository == 'neo-project/neo-node'
needs: Test
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v5
- name: Get version
id: get_version
run: |
sudo apt install xmlstarlet -qq
# Only release when <Version> is explicitly set (dev builds keep <VersionPrefix> and should not release).
VERSION=$(xmlstarlet sel -N i=http://schemas.microsoft.com/developer/msbuild/2003 -t -v "//i:Version/text()" src/Directory.Build.props 2>/dev/null || echo "")
[ -z "$VERSION" ] && VERSION=$(find plugins -name Directory.Build.props | xargs xmlstarlet sel -N i=http://schemas.microsoft.com/developer/msbuild/2003 -t -v "//i:Version/text()" 2>/dev/null || echo "")
[ -n "$VERSION" ] && echo "version=v$VERSION" >> $GITHUB_OUTPUT || echo "version=" >> $GITHUB_OUTPUT
- name: Check tag
if: steps.get_version.outputs.version != '' && startsWith(steps.get_version.outputs.version, 'v')
id: check_tag
run: curl -s -I ${{ format('https://github.com/{0}/releases/tag/{1}', github.repository, steps.get_version.outputs.version) }} | head -n 1 | cut -d$' ' -f2 | xargs printf "statusCode=%s" | xargs echo >> $GITHUB_OUTPUT
- name: Create release
if: steps.check_tag.outputs.statusCode == '404'
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
if ! gh release view ${{ steps.get_version.outputs.version }} >/dev/null 2>&1; then
if [[ "${{ steps.get_version.outputs.version }}" == *"-"* ]]; then
gh release create ${{ steps.get_version.outputs.version }} \
--title "${{ steps.get_version.outputs.version }}" \
--notes "Release ${{ steps.get_version.outputs.version }}" \
--draft \
--prerelease
else
gh release create ${{ steps.get_version.outputs.version }} \
--title "${{ steps.get_version.outputs.version }}" \
--notes "Release ${{ steps.get_version.outputs.version }}" \
--draft
fi
fi
- name: Setup .NET Core
if: steps.check_tag.outputs.statusCode == '404'
uses: actions/setup-dotnet@v5
with:
dotnet-version: ${{ env.DOTNET_VERSION }}
- name: Install zip tool
if: steps.check_tag.outputs.statusCode == '404'
run: sudo apt-get update && sudo apt-get install -y zip
- name: Build LevelDBStore plugin for all platforms
if: steps.check_tag.outputs.statusCode == '404'
run: |
dotnet build plugins/LevelDBStore/LevelDBStore.csproj -c Release
- name: Build and package neo-cli for all platforms
if: steps.check_tag.outputs.statusCode == '404'
run: |
# Define platforms
platforms=("portable" "linux-x64" "linux-arm64" "win-x64" "osx-x64" "osx-arm64")
# LevelDBStore output directory (where native libs are copied after build)
LEVELDB_OUTPUT="plugins/LevelDBStore/bin/Release/net10.0"
# LevelDBStore intermediate directory (where native libs are downloaded)
LEVELDB_OBJ="plugins/LevelDBStore/bin/Release/net10.0/obj/LevelDBStore"
copy_native_lib() {
local rid=$1
local lib_name=$2
local target_dir=$3
local output_path="$LEVELDB_OUTPUT/runtimes/$rid/native/$lib_name"
local obj_path="$LEVELDB_OBJ/libleveldb-$rid/runtimes/$rid/native/$lib_name"
local zip_dir="$LEVELDB_OBJ/libleveldb-$rid"
if [ -f "$output_path" ]; then
cp "$output_path" "$target_dir/"
elif [ -f "$obj_path" ]; then
cp "$obj_path" "$target_dir/"
else
return
fi
# For macOS, also copy any extra .dylib files from the LevelDB package (best-effort)
if [[ "$rid" == osx-* ]] && [ -d "$zip_dir" ]; then
find "$zip_dir" -name "*.dylib" -type f -exec cp {} "$target_dir/" \; 2>/dev/null || true
fi
}
for platform in "${platforms[@]}"; do
if [ "$platform" == "portable" ]; then
dotnet publish src/Neo.CLI/Neo.CLI.csproj -c Release -o "./publish/$platform" --self-contained false
else
dotnet publish src/Neo.CLI/Neo.CLI.csproj -c Release -o "./publish/$platform" -r "$platform" --self-contained true
fi
mkdir -p "./publish/$platform/Plugins/LevelDBStore"
cp "$LEVELDB_OUTPUT/LevelDBStore.dll" "./publish/$platform/Plugins/LevelDBStore/" 2>/dev/null || true
if [ "$platform" == "portable" ]; then
copy_native_lib "linux-x64" "libleveldb.so" "./publish/$platform"
copy_native_lib "win-x64" "libleveldb.dll" "./publish/$platform"
copy_native_lib "osx-x64" "libleveldb.dylib" "./publish/$platform"
else
case "$platform" in
"linux-x64"|"linux-arm64") copy_native_lib "$platform" "libleveldb.so" "./publish/$platform" ;;
"win-x64") copy_native_lib "$platform" "libleveldb.dll" "./publish/$platform" ;;
"osx-x64"|"osx-arm64") copy_native_lib "$platform" "libleveldb.dylib" "./publish/$platform" ;;
esac
fi
cd "./publish/$platform" && zip -r "../../neo-cli-$platform.zip" . && cd ../..
done
- name: Build and package plugins (zip per plugin)
if: steps.check_tag.outputs.statusCode == '404'
run: |
set -euo pipefail
# Use neo-cli portable publish output as the baseline set of assemblies
if [ ! -d "./publish/portable" ]; then
echo "Error: ./publish/portable not found. neo-cli portable must be published first."
exit 1
fi
mkdir -p "./plugin-publish" "./plugin-zip"
# Collect baseline DLL filenames shipped with neo-cli portable
mapfile -t cli_dlls < <(find "./publish/portable" -maxdepth 1 -type f -name "*.dll" -printf "%f\n" | sort -u)
declare -A cli_dll_set
for f in "${cli_dlls[@]}"; do cli_dll_set["$f"]=1; done
# Package every plugin project under plugins/*/*.csproj (stage only, zip after all are staged)
for csproj in plugins/*/*.csproj; do
plugin_dir="$(dirname "$csproj")"
plugin_name="$(basename "$plugin_dir")"
# Publish plugin (framework-dependent) to get a clean dependency set
plugin_out="./plugin-publish/$plugin_name"
rm -rf "$plugin_out"
dotnet publish "$csproj" -c Release -o "$plugin_out" --self-contained false
# MPTTrie is only used as a dependency (by StateService). We publish it so that MPTTrie.dll
# exists under plugin-publish/, but we don't stage or zip it as a standalone plugin.
if [ "$plugin_name" == "MPTTrie" ]; then
continue
fi
plugin_json="$plugin_dir/$plugin_name.json"
# Staging layout required by release consumers:
# Plugins/<PluginName>/{PluginName}.dll (+ optional {PluginName}.json) + only required extra dependency dlls
stage_root="./plugin-zip/$plugin_name"
stage_dir="$stage_root/Plugins/$plugin_name"
rm -rf "$stage_root"
mkdir -p "$stage_dir"
# Always include the plugin's own assembly
if [ ! -f "$plugin_out/$plugin_name.dll" ]; then
echo "Error: Missing published plugin dll: $plugin_out/$plugin_name.dll"
exit 1
fi
cp "$plugin_out/$plugin_name.dll" "$stage_dir/"
# Include plugin json if present
if [ -f "$plugin_json" ]; then
cp "$plugin_json" "$stage_dir/"
fi
# Only include extra dependency DLLs for plugins that explicitly reference NuGet packages.
# This keeps "pure" project-reference plugins (e.g. DBFTPlugin) minimal: {Plugin}.dll (+ optional json).
if grep -q "<PackageReference" "$csproj"; then
# Include only dlls that neo-cli portable does NOT already ship
shopt -s nullglob
for dep in "$plugin_out"/*.dll; do
dep_name="$(basename "$dep")"
if [ "$dep_name" == "$plugin_name.dll" ]; then
continue
fi
if [ -z "${cli_dll_set["$dep_name"]+x}" ]; then
cp "$dep" "$stage_dir/"
fi
done
shopt -u nullglob
fi
done
# After all plugins are published, ensure StateService staging includes its MPTTrie dependency.
mpt_trie_dll="./plugin-publish/MPTTrie/MPTTrie.dll"
state_stage="./plugin-zip/StateService/Plugins/StateService"
if [ -f "$mpt_trie_dll" ] && [ -d "$state_stage" ]; then
cp "$mpt_trie_dll" "$state_stage/"
fi
# Finally, create zip per plugin from staged directories (excluding MPTTrie by design)
for csproj in plugins/*/*.csproj; do
plugin_dir="$(dirname "$csproj")"
plugin_name="$(basename "$plugin_dir")"
[ "$plugin_name" == "MPTTrie" ] && continue
stage_root="./plugin-zip/$plugin_name"
if [ -d "$stage_root" ]; then
(cd "$stage_root" && zip -r "../../$plugin_name.zip" "Plugins")
fi
done
- name: Upload CLI packages to release
if: steps.check_tag.outputs.statusCode == '404'
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
RELEASE_TAG="${{ steps.get_version.outputs.version }}"
# Verify release exists
if ! gh release view "$RELEASE_TAG" >/dev/null 2>&1; then
echo "Error: Release $RELEASE_TAG does not exist"
exit 1
fi
# Verify all required zip files exist
missing_files=()
for file in neo-cli-portable.zip neo-cli-linux-x64.zip neo-cli-linux-arm64.zip neo-cli-win-x64.zip neo-cli-osx-x64.zip neo-cli-osx-arm64.zip; do
[ ! -f "$file" ] && missing_files+=("$file")
done
# Verify plugin zip files exist (one per plugins/*/*.csproj, except MPTTrie which is only a dependency)
for csproj in plugins/*/*.csproj; do
plugin_dir="$(dirname "$csproj")"
plugin_name="$(basename "$plugin_dir")"
[ "$plugin_name" == "MPTTrie" ] && continue
[ ! -f "$plugin_name.zip" ] && missing_files+=("$plugin_name.zip")
done
if [ ${#missing_files[@]} -gt 0 ]; then
echo "Error: Missing zip files: ${missing_files[*]}"
exit 1
fi
# Upload all zip files to release
failed_files=()
for file in neo-cli-portable.zip neo-cli-linux-x64.zip neo-cli-linux-arm64.zip neo-cli-win-x64.zip neo-cli-osx-x64.zip neo-cli-osx-arm64.zip; do
if ! gh release upload "$RELEASE_TAG" "$file" --clobber; then
failed_files+=("$file")
fi
done
# Upload plugin zip files to release (excluding MPTTrie)
for csproj in plugins/*/*.csproj; do
plugin_dir="$(dirname "$csproj")"
plugin_name="$(basename "$plugin_dir")"
[ "$plugin_name" == "MPTTrie" ] && continue
if ! gh release upload "$RELEASE_TAG" "$plugin_name.zip" --clobber; then
failed_files+=("$plugin_name.zip")
fi
done
if [ ${#failed_files[@]} -gt 0 ]; then
echo "Error: Failed to upload: ${failed_files[*]}"
exit 1
fi
- name: Publish core packages to NuGet
if: steps.check_tag.outputs.statusCode == '404'
run: |
dotnet pack -o out -c Release
# Push only non-plugin packages here (plugins handled in a separate step)
for pkg in out/*.nupkg; do
name="$(basename "$pkg")"
case "$name" in
Neo.Plugins.*) continue ;;
esac
dotnet nuget push "$pkg" -s https://api.nuget.org/v3/index.json -k "${NUGET_TOKEN}" --skip-duplicate
done
env:
NUGET_TOKEN: ${{ secrets.NUGET_TOKEN }}
- name: Publish plugin packages to NuGet
if: steps.check_tag.outputs.statusCode == '404'
run: |
# Ensure plugin packages are packed (reuse existing 'out' folder to avoid rebuilding everything)
for csproj in plugins/*/*.csproj; do
dotnet pack "$csproj" -c Release -o out
done
# Push all Neo.Plugins.* packages to NuGet.org
for pkg in out/Neo.Plugins.*.nupkg; do
[ -f "$pkg" ] || continue
dotnet nuget push "$pkg" -s https://api.nuget.org/v3/index.json -k "${NUGET_TOKEN}" --skip-duplicate
done
env:
NUGET_TOKEN: ${{ secrets.NUGET_TOKEN }}