diff --git a/.github/actions/codecov/action.yml b/.github/actions/codecov/action.yml new file mode 100644 index 00000000000..6cb78bb44d4 --- /dev/null +++ b/.github/actions/codecov/action.yml @@ -0,0 +1,41 @@ +name: codecov +inputs: + file: + required: false +runs: + using: composite + steps: + - name: restore_cache + uses: actions/cache@v3.3.2 + with: + key: v1-codecov + path: UPDATE_ME + restore-keys: v1-codecov + - name: Upload a code coverage report file to Codecov.io + run: |- + set -evx + case "$OSTYPE" in + darwin*) plat=macos;; + msys*) plat=windows; suffix=.exe;; + cygwin*) plat=windows; suffix=.exe;; + *) plat=linux;; + esac + mkdir -p _codecov_uploader/$plat/ + pushd _codecov_uploader/$plat/ + if [[ ! -f "codecov$suffix" ]]; then + curl -OL "https://uploader.codecov.io/latest/$plat/codecov$suffix" + fi + chmod +x "codecov$suffix" + popd + "_codecov_uploader/$plat/codecov$suffix" \ + -K \ + -f '${{ inputs.file }}' \ + -n "$CIRCLE_BUILD_NUM" + shell: bash + if: always() + - name: save_cache + uses: actions/cache@v3.3.2 + if: always() + with: + path: _codecov_uploader/ + key: v1-codecov diff --git a/.github/actions/concat_files/action.yml b/.github/actions/concat_files/action.yml new file mode 100644 index 00000000000..7423eeebc08 --- /dev/null +++ b/.github/actions/concat_files/action.yml @@ -0,0 +1,12 @@ +name: concat_files +inputs: + glob: + required: false + to: + required: false +runs: + using: composite + steps: + - name: Concatenate file contents + run: cat -s ${{ inputs.glob }} > ${{ inputs.to }} + shell: bash diff --git a/.github/actions/linux_netcore_test_base/action.yml b/.github/actions/linux_netcore_test_base/action.yml new file mode 100644 index 00000000000..9334b782c75 --- /dev/null +++ b/.github/actions/linux_netcore_test_base/action.yml @@ -0,0 +1,22 @@ +name: linux_netcore_test_base +inputs: + collect_tests_from: + required: false + default: ".tests.txt" + locale: + required: false + default: en_US.UTF-8 + code_coverage: + required: false + default: true +runs: + using: composite + steps: + - name: Install lib6c-dev (for RocksDBSharp) + run: apt update -y && apt install -y libc6-dev + shell: bash + - uses: "./.github/actions/netcore_test_base" + with: + collect_tests_from: "${{ inputs.collect_tests_from }}" + locale: "${{ inputs.locale }}" + code_coverage: "${{ inputs.code_coverage }}" diff --git a/.github/actions/macos_netcore_test_base/action.yml b/.github/actions/macos_netcore_test_base/action.yml new file mode 100644 index 00000000000..ff0213e5e49 --- /dev/null +++ b/.github/actions/macos_netcore_test_base/action.yml @@ -0,0 +1,56 @@ +name: macos_netcore_test_base +inputs: + collect_tests_from: + required: false + default: ".tests.txt" + locale: + required: false + default: en_US.UTF-8 + code_coverage: + required: false + default: true +runs: + using: composite + steps: + - uses: "./.github/actions/ulimit" + with: + "n": 10240 + - name: restore_cache + uses: actions/cache@v3.3.2 + with: + key: v1-macos-dotnet-sdk-6.0 + path: UPDATE_ME + restore-keys: v1-macos-dotnet-sdk-6.0 + - name: Export PATH & DOTNET_ROOT + run: |- + { + echo export PATH="$HOME/.dotnet:$PATH" + echo export DOTNET_ROOT="$HOME/.dotnet" + } >> $BASH_ENV + shell: bash + - name: Install .NET 6.0 SDK + run: |- + set -evx + echo $PATH > /dev/stderr + if ! command -v dotnet && [[ ! -f "$HOME/.dotnet/dotnet" ]]; then + curl \ + -L \ + -o /tmp/dotnet-install.sh \ + https://dot.net/v1/dotnet-install.sh + chmod +x /tmp/dotnet-install.sh + /tmp/dotnet-install.sh \ + --verbose \ + --channel 6.0 + fi + command -v dotnet + shell: bash + - name: save_cache + uses: actions/cache@v3.3.2 + with: + path: "~/.dotnet/" + key: v1-macos-dotnet-sdk-6.0 + - uses: "./.github/actions/netcore_test_base" + with: + collect_tests_from: "${{ inputs.collect_tests_from }}" + locale: "${{ inputs.locale }}" + code_coverage: "${{ inputs.code_coverage }}" diff --git a/.github/actions/netcore_build_base/action.yml b/.github/actions/netcore_build_base/action.yml new file mode 100644 index 00000000000..416def87538 --- /dev/null +++ b/.github/actions/netcore_build_base/action.yml @@ -0,0 +1,49 @@ +name: netcore_build_base +inputs: + collect_tests_to: + required: false + default: ".tests.txt" +runs: + using: composite + steps: + - uses: actions/checkout@v4.1.0 + - uses: "./.github/actions/concat_files" + with: + glob: "*/*.csproj" + to: ".combined-package-files.txt" + - name: restore_cache + uses: actions/cache@v3.3.2 + with: + key: v1-deps-{{ arch }}-{{ checksum ".combined-package-files.txt" }} + path: "~/.nuget/packages" + restore-keys: |- + v1-deps-{{ arch }}-{{ checksum ".combined-package-files.txt" }} + v1-deps-{{ arch }} + - run: dotnet restore + shell: bash + - run: dotnet build --no-restore -c Release -p:SkipSonar=true + shell: bash + - name: Collect tests + run: |- + set -evx + if ! command -v dotnet > /dev/null && \ + [[ -d /usr/local/share/dotnet ]]; then + export PATH="/usr/local/share/dotnet:$PATH" + fi + dotnet test --no-restore --no-build -c Release --list-tests \ + > .dotnet-list-tests.txt + grep ' ' .dotnet-list-tests.txt \ + | sed 's/ /\n /g' \ + | sed '/^$/d' \ + | grep '^ ' \ + | sed -E 's/^ |\(.*?\)$//g' \ + | uniq \ + | /usr/bin/sort -R --random-source=CHANGES.md \ + > "${{ inputs.collect_tests_to }}" + shell: bash + - uses: actions/upload-artifact@v3.1.3 + with: + path: |- + ./${{ inputs.collect_tests_to }} + ./*/bin/ + ./*/obj/ diff --git a/.github/actions/netcore_test_base/action.yml b/.github/actions/netcore_test_base/action.yml new file mode 100644 index 00000000000..f96419ee892 --- /dev/null +++ b/.github/actions/netcore_test_base/action.yml @@ -0,0 +1,126 @@ +name: netcore_test_base +inputs: + collect_tests_from: + required: false + default: ".tests.txt" + locale: + required: false + default: en_US.UTF-8 + code_coverage: + required: false + default: true + matrix_node_total: + required: false + default: 1 + matrix_node_index: + required: false + default: 0 +runs: + using: composite + steps: + - name: restore_cache + uses: actions/cache@v3.3.2 + with: + key: v1-dotcover-{{ arch }} + path: "~/.nuget/packages" + restore-keys: v1-dotcover-{{ arch }} + if: "${{ inputs.code_coverage }}" + - name: Install JetBrains dotCover + run: dotnet tool install --global JetBrains.dotCover.GlobalTool --version 2021.2.2 + if: "${{ inputs.code_coverage }}" + shell: bash + - uses: actions/checkout@v4.1.0 + - uses: actions/download-artifact@v3.0.2 + with: + path: "." + - name: Distribute tests + run: |- + set -evx + tests_collection="${{ inputs.collect_tests_from }}" + total="$(wc -l "$tests_collection" | awk '{ print $1 }')" + node_total="${{ inputs.matrix_node_total }}" + node_index="${{ inputs.matrix_node_index }}" + part="$(( (total + "$node_total" - 1) / "$node_total" ))" + tail -n +$(("$node_index" * part + 1)) "$tests_collection" \ + > .head_tests.txt + if [[ "$part" = "0" ]]; then + cp .head_tests.txt .current_tests.txt + else + head -n $part .head_tests.txt > .current_tests.txt + fi + excluded_tests=( + Libplanet.Net.Tests.Protocols.ProtocolTest.KademliaTest + Libplanet.Net.Tests.Protocols.ProtocolTest.Start + Libplanet.Net.Tests.Protocols.ProtocolTest.Ping + Libplanet.Net.Tests.Protocols.ProtocolTest.PingTwice + Libplanet.Net.Tests.Protocols.ProtocolTest.PingToClosedPeer + Libplanet.Net.Tests.Protocols.ProtocolTest.BootstrapException + Libplanet.Net.Tests.Protocols.ProtocolTest.BootstrapAsyncTest + Libplanet.Net.Tests.Protocols.ProtocolTest.RemoveStalePeers + Libplanet.Net.Tests.Protocols.ProtocolTest.RoutingTableFull + Libplanet.Net.Tests.Protocols.ProtocolTest.ReplacementCache + Libplanet.Net.Tests.Protocols.ProtocolTest.RemoveDeadReplacementCache + Libplanet.Net.Tests.Protocols.ProtocolTest.BroadcastMessage + Libplanet.Net.Tests.Protocols.ProtocolTest.BroadcastGuarantee + Libplanet.Net.Tests.Protocols.ProtocolTest.DoNotBroadcastToSourcePeer + Libplanet.Net.Tests.Protocols.ProtocolTest.RefreshTable + Libplanet.Extensions.Cocona.Tests.Commands.StatsCommandTest.SummaryInvalidArguments + Libplanet.Extensions.Cocona.Tests.Commands.StoreCommandTest.TestInvalidArguments + Libplanet.Extensions.Cocona.Tests.Commands.StoreCommandTest.TestBlockByTxIdNotExist + Libplanet.Extensions.Cocona.Tests.Commands.StoreCommandTest.TestBlockByTxIdTwo + Libplanet.Extensions.Cocona.Tests.Commands.StoreCommandTest.TestBlockHashesByTxId + Libplanet.Extensions.Cocona.Tests.Commands.StoreCommandTest.TestBuildIndexTxBlockBlockByTxId + Libplanet.Extensions.Cocona.Tests.Commands.StoreCommandTest.TestBlockByHashNotExists + Libplanet.Extensions.Cocona.Tests.Commands.StoreCommandTest.TestBlockByHash + Libplanet.Extensions.Cocona.Tests.Commands.StoreCommandTest.TestBlockByIndexNotExists + Libplanet.Extensions.Cocona.Tests.Commands.StoreCommandTest.TestBlockByIndex + Libplanet.Extensions.Cocona.Tests.Commands.StoreCommandTest.TestTxByIdNotExists + Libplanet.Extensions.Cocona.Tests.Commands.StoreCommandTest.TestTxById + ) + cat .current_tests.txt + first=1 + while read test; do + to_write=1 + for excl in "${excluded_tests[@]}"; do + if [[ "$test" == "$excl"* ]]; then + to_write=0 + fi + done + if [[ "$to_write" == "1" ]]; then + if [[ "$first" = "1" ]]; then + echo "FullyQualifiedName=$test" + first=0 + else + echo "| FullyQualifiedName=$test" + fi + fi + done < .current_tests.txt > .test-filter.txt + shell: bash + - name: Run tests (using dotCover) + run: ~/.dotnet/tools/dotnet-dotcover test --no-restore --no-build -c Release -l "junit;FailureBodyFormat=Verbose;LogFilePath=/tmp/junit/{assembly}.xml" --filter "$(cat .test-filter.txt)" --dcDisableDefaultFilters --dcReportType=DetailedXML --dcFilters="+:Libplanet;+:Libplanet.*;-:Libplanet.Tests;-:Libplanet.*.Tests;-:Libplanet.*.UnitTests;-:Libplanet.Benchmarks;-:Libplanet.Explorer" + env: + LC_ALL: "${{ inputs.locale }}" + LANG: "${{ inputs.locale }}" + LANGUAGE: "${{ inputs.locale }}" + if: "${{ inputs.code_coverage }}" + shell: bash + - uses: actions/upload-artifact@v3.1.3 + with: + path: "/tmp/junit" + if: "${{ inputs.code_coverage }}" + - uses: "./.github/actions/codecov" + if: "${{ inputs.code_coverage }}" + with: + file: dotCover.Output.xml + - name: Run tests + run: dotnet test --no-restore --no-build -c Release -l "junit;FailureBodyFormat=Verbose;LogFilePath=/tmp/junit/{assembly}.xml" --filter "$(cat .test-filter.txt)" + env: + LC_ALL: "${{ inputs.locale }}" + LANG: "${{ inputs.locale }}" + LANGUAGE: "${{ inputs.locale }}" + if: "${{ !(${{ inputs.code_coverage }}) }}" + shell: bash + - uses: actions/upload-artifact@v3.1.3 + with: + path: "/tmp/junit" + if: "${{ !(${{ inputs.code_coverage }}) }}" diff --git a/.github/actions/ulimit/action.yml b/.github/actions/ulimit/action.yml new file mode 100644 index 00000000000..03504771f1b --- /dev/null +++ b/.github/actions/ulimit/action.yml @@ -0,0 +1,9 @@ +name: ulimit +inputs: + "n": + required: false +runs: + using: composite + steps: + - run: echo 'ulimit -n ${{ inputs.n }}' >> $BASH_ENV + shell: bash diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml new file mode 100644 index 00000000000..6e7e372b40f --- /dev/null +++ b/.github/workflows/docs.yml @@ -0,0 +1,51 @@ +# yaml-language-server: $schema=https://json.schemastore.org/github-workflow.json +on: + push: + branches-ignore: + - gh-pages + tags: + - "*" + schedule: + - cron: 59 14 * * * + pull_request: null +name: update docs + +jobs: + docs: + if: github.event_name != 'schedule' || github.repository == 'planetarium/libplanet' + name: docs + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@main + if: github.event_name != 'pull_request' + - uses: actions/checkout@main + if: github.event_name == 'pull_request' + with: + ref: ${{ github.pull_request.head.sha }} + - run: git fetch --depth=1 origin +refs/tags/*:refs/tags/* + - uses: actions/setup-dotnet@v3 + with: + dotnet-version: 6.0.x + - run: dotnet build -p:SkipSonar=true + - run: mkdir -p Docs/obj/ + - run: Docs/build.ps1 + shell: pwsh + - uses: actions/upload-artifact@main + with: + name: docs + path: Docs/_site/ + - run: Docs/publish.sh + env: + GHPAGES_SSH_KEY: ${{ secrets.GHPAGES_SSH_KEY }} + if: github.event_name != 'pull_request' + - id: docs-url + run: 'echo ::set-output name=url::"$(cat Docs/obj/url.txt)"' + if: github.event_name != 'pull_request' + - uses: Sibz/github-status-action@v1.1.6 + with: + authToken: ${{ secrets.GITHUB_TOKEN }} + context: docs + description: Libplanet docs generated by DocFX + state: 'success' + target_url: ${{ steps.docs-url.outputs.url }} + if: github.event_name != 'pull_request' \ No newline at end of file diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index ada684e1308..7abf2379285 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -1,51 +1,83 @@ -# yaml-language-server: $schema=https://json.schemastore.org/github-workflow.json +name: planetarium/libplanet/main on: push: - branches-ignore: - - gh-pages - tags: - - "*" - schedule: - - cron: 59 14 * * * - pull_request: null -name: main - + branches: + - main +env: + CODECOV_TOKEN: ${{ secrets.CODECOV_API_ACCESS_TOKEN }} jobs: - docs: - if: github.event_name != 'schedule' || github.repository == 'planetarium/libplanet' - name: docs + linux-netcore-build: + defaults: + run: + working-directory: "/mnt/ramdisk" runs-on: ubuntu-latest + container: + image: mcr.microsoft.com/dotnet/sdk:6.0 steps: - - uses: actions/checkout@main - if: github.event_name != 'pull_request' - - uses: actions/checkout@main - if: github.event_name == 'pull_request' + - uses: actions/checkout@v4.1.0 + - uses: "./.github/actions/netcore_build_base" + linux-netcore-test-netmq: + defaults: + run: + working-directory: "/mnt/ramdisk" + runs-on: ubuntu-latest + container: + image: mcr.microsoft.com/dotnet/sdk:6.0 + needs: + - linux-netcore-build + env: + TRANSPORT_TYPE: netmq + steps: + - uses: actions/checkout@v4.1.0 + - uses: "./.github/actions/linux_netcore_test_base" + with: + code_coverage: false + linux-netcore-test-ar-SA: + defaults: + run: + working-directory: "/mnt/ramdisk" + runs-on: ubuntu-latest + container: + image: mcr.microsoft.com/dotnet/sdk:6.0 + needs: + - linux-netcore-build + steps: + - uses: actions/checkout@v4.1.0 + - uses: "./.github/actions/linux_netcore_test_base" with: - ref: ${{ github.pull_request.head.sha }} - - run: git fetch --depth=1 origin +refs/tags/*:refs/tags/* - - uses: actions/setup-dotnet@v3 + locale: ar_SA.UTF-8 + code_coverage: false + linux-netcore-test-fr-FR: + defaults: + run: + working-directory: "/mnt/ramdisk" + runs-on: ubuntu-latest + container: + image: mcr.microsoft.com/dotnet/sdk:6.0 + needs: + - linux-netcore-build + steps: + - uses: actions/checkout@v4.1.0 + - uses: "./.github/actions/linux_netcore_test_base" with: - dotnet-version: 6.0.x - - run: dotnet build -p:SkipSonar=true - - run: mkdir -p Docs/obj/ - - run: Docs/build.ps1 - shell: pwsh - - uses: actions/upload-artifact@main + locale: fr_FR.UTF-8 + code_coverage: false + macos-netcore-test: + runs-on: macos-latest + needs: + - linux-netcore-build + steps: + - uses: actions/checkout@v4.1.0 + - uses: maxim-lobanov/setup-xcode@v1.6.0 with: - name: docs - path: Docs/_site/ - - run: Docs/publish.sh - env: - GHPAGES_SSH_KEY: ${{ secrets.GHPAGES_SSH_KEY }} - if: github.event_name != 'pull_request' - - id: docs-url - run: 'echo ::set-output name=url::"$(cat Docs/obj/url.txt)"' - if: github.event_name != 'pull_request' - - uses: Sibz/github-status-action@v1.1.6 + xcode-version: 14.3.1 + - uses: "./.github/actions/macos_netcore_test_base" with: - authToken: ${{ secrets.GITHUB_TOKEN }} - context: docs - description: Libplanet docs generated by DocFX - state: 'success' - target_url: ${{ steps.docs-url.outputs.url }} - if: github.event_name != 'pull_request' + code_coverage: false + windows-netcore-test: + runs-on: ubuntu-latest + needs: + - linux-netcore-build + steps: + - uses: actions/checkout@v4.1.0 + - uses: "./.github/actions/netcore_test_base"