diff --git a/.github/actions/get-dotnet-channel/action.yml b/.github/actions/get-dotnet-channel/action.yml new file mode 100644 index 000000000..84bab509d --- /dev/null +++ b/.github/actions/get-dotnet-channel/action.yml @@ -0,0 +1,43 @@ +name: Convert Target Framework to Channel +description: | + Convert Target Framework to Channel. A channel is either LTS/STS or a version number. + Use `target_framework` for a single conversion with `channel` as output. + Use `target_framework_array` for a single conversion with `channels_multiline` as output. + +inputs: + target_framework: + description: 'The target framework to use' + required: false + target_framework_array: + description: 'The target framework array to use' + required: false + +outputs: + channel: + description: 'The converted Channel variable' + value: ${{steps.set_output.outputs.channel}} + channels_multiline: + description: 'The converted Channels multiline variable' + value: ${{steps.set_output.outputs.channels_multiline}} + +runs: + using: "composite" + steps: + - name: Set Channels + id: set_output + run: | + $target_framework = "${{inputs.target_framework}}"; + if ($target_framework -ne '') { + $channel = $target_framework.Replace('coreapp', '').Replace('net', ''); + "channel=$channel" | Out-File -FilePath $env:GITHUB_OUTPUT -Append; + } + $target_frameworks = "${{inputs.target_framework_array}}"; + if ($target_frameworks -ne '') { + $EOF = -join (1..15 | ForEach {[char]((48..57)+(65..90)+(97..122) | Get-Random)}); + "channels_multiline<<$EOF" | Out-File -FilePath $env:GITHUB_OUTPUT -Append; + foreach ($target_framework in ConvertFrom-Json "${{inputs.target_framework_array}}") { + $target_framework.Replace('coreapp', '').Replace('net', '') | Out-File -FilePath $env:GITHUB_OUTPUT -Append; + } + "$EOF" | Out-File -FilePath $env:GITHUB_OUTPUT -Append; + } + shell: pwsh \ No newline at end of file diff --git a/.github/actions/get-dotnet-path/action.yml b/.github/actions/get-dotnet-path/action.yml new file mode 100644 index 000000000..1967f844f --- /dev/null +++ b/.github/actions/get-dotnet-path/action.yml @@ -0,0 +1,51 @@ +name: Get .NET Path +description: Get .NET path for the architecture + +inputs: + architecture: + description: 'The architecture to use' + required: true + +outputs: + path: + description: 'The .NET path for the architecture' + value: ${{ steps.set-path.outputs.path }} + +runs: + using: "composite" + steps: + - name: Get Program Files path for x86 + if: ${{runner.os == 'Windows' && inputs.architecture == 'x86'}} + uses: ./.github/actions/get-program-files + id: get-program-files-x86 + with: + architecture: x86 + + - name: Get Program Files path for x64 + if: ${{runner.os == 'Windows' && (inputs.architecture == 'x86' || inputs.architecture == 'x64')}} + uses: ./.github/actions/get-program-files + id: get-program-files-x64 + with: + architecture: x64 + + - name: Set .NET path for ${{inputs.architecture}} + id: set-path + run: | + if ('${{runner.os == 'Windows'}}' -eq 'true') { + if ('${{inputs.architecture == 'x86'}}' -eq 'true') { + $dotnet = "${{steps.get-program-files-x86.outputs.path}}/dotnet/dotnet.exe"; + } else { + $dotnet = "${{steps.get-program-files-x64.outputs.path}}/dotnet/dotnet.exe"; + } + } elseif ('${{inputs.image == 'macos-14'}}' -eq 'true') { + if ('${{inputs.architecture == 'x64'}}' -eq 'true') { + $dotnet = "/Users/runner/.dotnet/x64/dotnet"; + } else { + $dotnet = "/Users/runner/.dotnet/dotnet"; + } + } else { + # Ubuntu only has x64 + $dotnet = 'dotnet'; + } + "path=$dotnet" | Out-File -FilePath $env:GITHUB_OUTPUT -Append; + shell: pwsh diff --git a/.github/actions/get-mono-path/action.yml b/.github/actions/get-mono-path/action.yml new file mode 100644 index 000000000..30183462a --- /dev/null +++ b/.github/actions/get-mono-path/action.yml @@ -0,0 +1,44 @@ +name: Get Mono Path +description: Get Mono path for the architecture + +inputs: + architecture: + description: 'The architecture to use' + required: true + +outputs: + path: + description: 'The Mono path for the architecture' + value: ${{ steps.set-path.outputs.path }} + +runs: + using: "composite" + steps: + - name: Get Program Files path for x86 + if: ${{runner.os == 'Windows' && inputs.architecture == 'x86'}} + uses: ./.github/actions/get-program-files + id: get-program-files-x86 + with: + architecture: x86 + + - name: Get Program Files path for x64 + if: ${{runner.os == 'Windows' && (inputs.architecture == 'x86' || inputs.architecture == 'x64')}} + uses: ./.github/actions/get-program-files + id: get-program-files-x64 + with: + architecture: x64 + + - name: Set Mono path for ${{inputs.architecture}} + id: set-path + run: | + if ('${{runner.os == 'Windows'}}' -eq 'true') { + if ('${{inputs.architecture == 'x86'}}' -eq 'true') { + $mono = "${{steps.get-program-files-x86.outputs.path}}/Mono/bin/mono.exe"; + } else { + $mono = "${{steps.get-program-files-x64.outputs.path}}/Mono/bin/mono.exe"; + } + } else { + $mono = 'mono'; + } + "path=$mono" | Out-File -FilePath $env:GITHUB_OUTPUT -Append; + shell: pwsh diff --git a/.github/actions/get-program-files/action.yml b/.github/actions/get-program-files/action.yml new file mode 100644 index 000000000..95afca37d --- /dev/null +++ b/.github/actions/get-program-files/action.yml @@ -0,0 +1,28 @@ +name: Get ProgramFiles Path +description: Get ProgramFiles path for the architecture + +inputs: + architecture: + description: 'The architecture to use' + required: true + +outputs: + path: + description: 'The ProgramFiles path for the architecture' + value: ${{ steps.set-path.outputs.path }} + +runs: + using: "composite" + steps: + - name: Set Program Files path for ${{inputs.architecture}} + id: set-path + run: | + if ('${{ inputs.architecture == 'x86'}}' -eq 'true') { + $path = [System.Environment]::GetFolderPath([System.Environment+SpecialFolder]::ProgramFilesX86); + "path=$path" | Out-File -FilePath $env:GITHUB_OUTPUT -Append; + } + if ('${{ inputs.architecture == 'x64'}}' -eq 'true') { + $path = [System.Environment]::GetFolderPath([System.Environment+SpecialFolder]::ProgramFiles); + "path=$path" | Out-File -FilePath $env:GITHUB_OUTPUT -Append; + } + shell: pwsh diff --git a/.github/actions/setup-dotnet-macos-rosetta/action.yml b/.github/actions/setup-dotnet-macos-rosetta/action.yml new file mode 100644 index 000000000..9eff5f041 --- /dev/null +++ b/.github/actions/setup-dotnet-macos-rosetta/action.yml @@ -0,0 +1,37 @@ +name: Setup .NET +description: Setup .NET using the provided target framework and architecture + +inputs: + target_framework: + description: 'The .NET target framework to setup' + required: true + target_framework_array: + description: 'The .NET target frameworks to setup' + required: true + +runs: + using: "composite" + steps: + - name: Get .NET Channels + uses: ./.github/actions/get-dotnet-channel + id: get_channels + with: + target_framework: ${{inputs.target_framework}} + target_framework_array: ${{inputs.target_framework_array}} + + - name: Setup .NET x64 ${{steps.get_channels.outputs.channels_multiline}} + uses: dlemstra/setup-dotnet@add-architecture-option + with: + dotnet-architecture: x64 + dotnet-version: | + ${{steps.get_channels.outputs.channel}} + ${{steps.get_channels.outputs.channels_multiline}} + env: + DOTNET_INSTALL_DIR: /Users/runner/.dotnet/x64 + + - name: Setup .NET ${{steps.get_channels.outputs.channels_multiline}} + uses: actions/setup-dotnet@v4 + with: + dotnet-version: | + ${{steps.get_channels.outputs.channel}} + ${{steps.get_channels.outputs.channels_multiline}} diff --git a/.github/actions/setup-dotnet-unix/action.yml b/.github/actions/setup-dotnet-unix/action.yml new file mode 100644 index 000000000..5eb827076 --- /dev/null +++ b/.github/actions/setup-dotnet-unix/action.yml @@ -0,0 +1,30 @@ +name: Setup .NET +description: Setup .NET using the provided target framework and architecture + +inputs: + target_framework: + description: 'The .NET target framework to setup' + required: true + target_framework_array: + description: 'The .NET target frameworks to setup' + required: true + +runs: + using: "composite" + steps: + - name: Setup .NET Sdk + uses: actions/setup-dotnet@v4 + + - name: Get .NET Channels + uses: ./.github/actions/get-dotnet-channel + id: get_channels + with: + target_framework: ${{inputs.target_framework}} + target_framework_array: ${{inputs.target_framework_array}} + + - name: Setup .NET ${{steps.get_channels.outputs.channels_multiline}} + uses: actions/setup-dotnet@v4 + with: + dotnet-version: | + ${{steps.get_channels.outputs.channel}} + ${{steps.get_channels.outputs.channels_multiline}} diff --git a/.github/actions/setup-dotnet-windows/action.yml b/.github/actions/setup-dotnet-windows/action.yml new file mode 100644 index 000000000..e7fbc620a --- /dev/null +++ b/.github/actions/setup-dotnet-windows/action.yml @@ -0,0 +1,48 @@ +name: Setup .NET Windows +description: Setup .NET for Windows using the provided target framework and architecture + +inputs: + architecture: + description: 'The .NET architecture to setup' + required: true + target_framework: + description: 'The .NET target framework to setup' + required: true + target_framework_array: + description: 'The .NET target frameworks to setup' + required: true + +runs: + using: "composite" + steps: + - name: Get .NET Channel for ${{inputs.target_framework}} + uses: ./.github/actions/get-dotnet-channel + id: get_channels + with: + target_framework: ${{inputs.target_framework}} + target_framework_array: ${{inputs.target_framework_array}} + + - name: Get Program Files path for x86 + uses: ./.github/actions/get-program-files + if: ${{inputs.architecture == 'x86'}} + id: get-program-files-x86 + with: + architecture: x86 + + - name: Setup .NET x86 ${{steps.get_channels.outputs.channels_multiline}} + uses: dlemstra/setup-dotnet@add-architecture-option + if: ${{inputs.architecture == 'x86'}} + with: + dotnet-architecture: x86 + dotnet-version: | + ${{steps.get_channels.outputs.channel}} + ${{steps.get_channels.outputs.channels_multiline}} + env: + DOTNET_INSTALL_DIR: ${{steps.get-program-files-x86.outputs.path}}/dotnet + + - name: Setup .NET ${{inputs.architecture}} ${{steps.get_channels.outputs.channels_multiline}} + uses: actions/setup-dotnet@v4 + with: + dotnet-version: | + ${{steps.get_channels.outputs.channel}} + ${{steps.get_channels.outputs.channels_multiline}} diff --git a/.github/actions/setup-mono-windows/action.yml b/.github/actions/setup-mono-windows/action.yml new file mode 100644 index 000000000..342224f82 --- /dev/null +++ b/.github/actions/setup-mono-windows/action.yml @@ -0,0 +1,28 @@ +name: Setup Mono Windows +description: Setup Mono for Windows using the latest version + +inputs: + architecture: + description: 'The architecture to setup Mono for' + required: true + version: + description: 'The Mono version to install' + required: false + +outputs: + path: + description: 'The Mono path for the architecture' + value: '${{steps.get-program-files.outputs.path}}/Mono/bin/mono.exe' + +runs: + using: "composite" + steps: + - name: Setup Mono + run: choco install mono --yes --no-progress --${{inputs.architecture}} ${{(inputs.version != '' && '--version=') || ''}}${{inputs.version}} --ignore-checksums + shell: pwsh + + - name: Get Program Files path for ${{inputs.architecture}} + uses: ./.github/actions/get-program-files + id: get-program-files + with: + architecture: ${{inputs.architecture}} diff --git a/.github/actions/setup-wine-macos/action.yml b/.github/actions/setup-wine-macos/action.yml new file mode 100644 index 000000000..ecea2e128 --- /dev/null +++ b/.github/actions/setup-wine-macos/action.yml @@ -0,0 +1,24 @@ +name: Install Wine on OS X +description: Install Wine on OS X + +runs: + using: "composite" + steps: + # wine@staging v9.17 + - run: | + curl -L ${{env.WINE_CASK}} > wine@staging.rb; + brew install --cask wine@staging.rb; + rm wine@staging.rb; + shell: bash + env: + WINE_CASK: https://raw.githubusercontent.com/Homebrew/homebrew-cask/2f29727c9961e8159df6dc19db315bc7783a4b99/Casks/w/wine%40staging.rb + + # We can't use /usr/share/wine/mono because it's read-only + # We can't use /opt/wine/mono because it's read-only + - run: | + mkdir -p ~/.wine/share/wine/mono + curl -L -o mono.tar.xz ${{env.WINE_MONO}} + tar -xf mono.tar.xz -C ~/.wine/share/wine/mono + shell: bash + env: + WINE_MONO: https://github.com/madewokherd/wine-mono/releases/download/wine-mono-9.3.0/wine-mono-9.3.0-x86.tar.xz \ No newline at end of file diff --git a/.github/actions/setup-wine-ubuntu/action.yml b/.github/actions/setup-wine-ubuntu/action.yml new file mode 100644 index 000000000..8226b03f7 --- /dev/null +++ b/.github/actions/setup-wine-ubuntu/action.yml @@ -0,0 +1,35 @@ +name: Install Wine on Ubuntu +description: Install Wine on Ubuntu + +runs: + using: "composite" + steps: + - run: sudo dpkg --add-architecture i386 + shell: bash + + - run: | + sudo mkdir -pm755 /etc/apt/keyrings; + sudo wget -O /etc/apt/keyrings/winehq-archive.key https://dl.winehq.org/wine-builds/winehq.key; + sudo wget -NP /etc/apt/sources.list.d/ https://dl.winehq.org/wine-builds/ubuntu/dists/jammy/winehq-jammy.sources + shell: bash + + - run: sudo apt-get update + shell: bash + + - run: | + sudo apt install --install-recommends \ + winehq-staging=${{env.WINE_VERSION}} \ + wine-staging=${{env.WINE_VERSION}} \ + wine-staging-i386=${{env.WINE_VERSION}} \ + wine-staging-amd64=${{env.WINE_VERSION}} + shell: bash + env: + WINE_VERSION: 9.17~jammy-1 + + - run: | + mkdir -p /usr/share/wine/mono + curl -L -o mono.tar.xz ${{env.WINE_MONO}} + tar -xf mono.tar.xz -C /usr/share/wine/mono + shell: bash + env: + WINE_MONO: https://github.com/madewokherd/wine-mono/releases/download/wine-mono-9.3.0/wine-mono-9.3.0-x86.tar.xz diff --git a/.github/actions/test-build-artifacts-upload/action.yml b/.github/actions/test-build-artifacts-upload/action.yml new file mode 100644 index 000000000..2548ab4c6 --- /dev/null +++ b/.github/actions/test-build-artifacts-upload/action.yml @@ -0,0 +1,23 @@ +name: Upload Build Artifacts +description: Upload the build artifacts for the specified image and build configuration + +inputs: + image: + description: 'The image to use' + required: true + architecture: + description: 'The architecture to use' + required: true + build_configuration: + description: 'The build configuration to use' + required: true + +runs: + using: "composite" + steps: + - name: Upload Build Artifacts + uses: actions/upload-artifact@v4 + with: + name: artifacts-${{inputs.image}}-${{inputs.architecture}}-${{inputs.build_configuration}} + path: artifacts/ + retention-days: 7 \ No newline at end of file diff --git a/.github/actions/test-build-cache-download/action.yml b/.github/actions/test-build-cache-download/action.yml new file mode 100644 index 000000000..6aa92fbcf --- /dev/null +++ b/.github/actions/test-build-cache-download/action.yml @@ -0,0 +1,22 @@ +name: Download Test Build Cache +description: Download the build cache for the specified image and build configuration + +inputs: + image: + description: 'The image to use' + required: true + architecture: + description: 'The architecture to use' + required: true + build_configuration: + description: 'The build configuration to use' + required: true + +runs: + using: "composite" + steps: + - name: Download Build Cache + uses: actions/download-artifact@v4 + with: + name: build-cache-${{inputs.image}}-${{inputs.architecture}}-${{inputs.build_configuration}} + path: artifacts/ \ No newline at end of file diff --git a/.github/actions/test-build-cache-upload/action.yml b/.github/actions/test-build-cache-upload/action.yml new file mode 100644 index 000000000..f01065cf5 --- /dev/null +++ b/.github/actions/test-build-cache-upload/action.yml @@ -0,0 +1,23 @@ +name: Upload Test Build Cache +description: Upload the build cache for the specified image and build configuration + +inputs: + image: + description: 'The image to use' + required: true + architecture: + description: 'The architecture to use' + required: true + build_configuration: + description: 'The build configuration to use' + required: true + +runs: + using: "composite" + steps: + - name: Upload Artifacts + uses: actions/upload-artifact@v4 + with: + name: build-cache-${{inputs.image}}-${{inputs.architecture}}-${{inputs.build_configuration}} + path: artifacts/ + retention-days: 1 diff --git a/.github/actions/test-results-download-publish/action.yml b/.github/actions/test-results-download-publish/action.yml new file mode 100644 index 000000000..7f2d8b437 --- /dev/null +++ b/.github/actions/test-results-download-publish/action.yml @@ -0,0 +1,47 @@ +name: Download and Publish Test Results +description: Download the test results for the specified operating system and build configuration + +inputs: + workflow_run: + required: true + description: 'The workflow run Id to download the test results from' + experimental: + required: false + default: "false" + description: 'Whether the tests are mandatory for the build to pass' + +runs: + using: "composite" + steps: + - name: Download Event File + uses: actions/download-artifact@v4 + with: + run-id: ${{ fromJson(inputs.workflow_run).id }} + github-token: ${{ github.token }} + name: test-event-file + merge-multiple: false + + - name: Download Test Results + uses: actions/download-artifact@v4 + with: + run-id: ${{ fromJson(inputs.workflow_run).id }} + github-token: ${{ github.token }} + pattern: ${{(inputs.experimental == 'true' && 'experimental-') || ''}}test-results-* + path: test-results + merge-multiple: false + + - name: Publish Test Results + uses: nike4613/actions-test-results@v3 + with: + check_name: Test Results ${{(inputs.experimental == 'true' && '(Experimental)') || ''}} + files: test-results/**/*.trx + fail_on: ${{(inputs.experimental == 'true' && 'nothing') || 'test failures'}} + comment_mode: ${{(inputs.experimental == 'true' && 'off') || 'always'}} + use_emojis: true + + commit: ${{ fromJson(inputs.workflow_run).head_sha }} + event_file: event.json + event_name: ${{ fromJson(inputs.workflow_run).event }} + #gist_token: ${{ secrets.gist_token }} + + comment_on_commit: true diff --git a/.github/actions/test-results-upload/action.yml b/.github/actions/test-results-upload/action.yml new file mode 100644 index 000000000..477ea3332 --- /dev/null +++ b/.github/actions/test-results-upload/action.yml @@ -0,0 +1,28 @@ +name: Upload Test Results +description: Upload the test results for the specified image and build configuration + +inputs: + osimage: + description: 'The image to use' + required: true + architecture: + description: 'The architecture to use' + required: true + build_configuration: + description: 'The build configuration to use' + required: true + experimental: + description: 'Whether the tests are mandatory for the build to pass' + required: true + +runs: + using: "composite" + steps: + - name: Upload Test Results + uses: actions/upload-artifact@v4 + if: ${{success() || failure()}} + with: + name: ${{(inputs.experimental == 'true' && 'experimental-') || ''}}test-results-${{inputs.image}}-${{inputs.architecture}}-${{inputs.build_configuration}} + path: '**/*.trx' + if-no-files-found: ${{(inputs.experimental == 'true' && 'ignore') || 'warn'}} + retention-days: 1 diff --git a/.github/workflows/reusable-build.yml b/.github/workflows/reusable-build.yml new file mode 100644 index 000000000..280861f89 --- /dev/null +++ b/.github/workflows/reusable-build.yml @@ -0,0 +1,97 @@ +name: 🔒Reusable Workflow Build for Tests + +on: + workflow_call: + inputs: + image: + required: true + type: string + description: 'The image to use' + architecture: + required: true + type: string + description: 'The architecture to use' + build_configuration: + required: true + type: string + description: 'The build configuration to use' + +env: + # Disable the .NET logo in the console output. + DOTNET_NOLOGO: true + # Disable the .NET first time experience to skip caching NuGet packages and speed up the build. + DOTNET_SKIP_FIRST_TIME_EXPERIENCE: true + # Disable sending .NET CLI telemetry to Microsoft. + DOTNET_CLI_TELEMETRY_OPTOUT: true + +jobs: + get-version: + name: Calculating Version Suffix + runs-on: ubuntu-latest + outputs: + version_suffix: ${{ steps.set-vars.outputs.version_suffix }} + steps: + - uses: actions/checkout@v4 + + - id: git-vars + name: Get git branch information + shell: bash + run: | + echo "##[set-output name=git_branch;]$(echo $GITHUB_REF)" + echo "::set-output name=git_hash::$(git rev-parse --short HEAD)" + + - id: set-vars + uses: actions/github-script@v7 + with: + script: | + let runNumber = "${{ github.run_number }}"; + let gitHash = "${{ steps.git-vars.outputs.git_hash }}"; + let rawGitRef = "${{ steps.git-vars.outputs.git_branch }}"; + console.log("rawGitRef: " + rawGitRef); + let gitRef = rawGitRef.replace(/^refs\/heads\//, "").replace(/^refs\/heads\//, "").replace(/[_//!@#$%&]/g, "-"); + if(gitRef.indexOf("refs/pull/") === 0) { + gitRef = "pr-" + gitRef.substring(10, gitRef.lastIndexOf("/")); + } + var versSuffix = `${gitRef}.${runNumber}+${gitHash}`; + console.log(versSuffix); + core.setOutput("version_suffix", versSuffix); + + build: + name: Upload Test Build Output Cache + runs-on: ${{inputs.image}} + needs: [get-version] + timeout-minutes: 10 + steps: + - uses: actions/checkout@v4 + + - name: Add msbuild to PATH + uses: microsoft/setup-msbuild@v2 + + - name: Setup .NET + uses: actions/setup-dotnet@v4 + + - name: Build on master branch + if: ${{github.ref == 'refs/heads/master'}} + run: | + dotnet restore AsmResolver.sln; + msbuild AsmResolver.sln -property:Configuration=${{inputs.build_configuration}} -property:Platform=${{inputs.architecture}}; + + - name: Build on non-master branch + if: ${{github.ref != 'refs/heads/master'}} + run: | + dotnet restore AsmResolver.sln /p:VersionSuffix=${{needs.get-version.outputs.version_suffix}}; + msbuild AsmResolver.sln -property:Configuration=${{inputs.build_configuration}} -property:Platform=${{inputs.architecture}} -property:VersionSuffix=${{needs.get-version.outputs.version_suffix}}; + + - name: Upload Build Artifacts + uses: ./.github/actions/test-build-artifacts-upload + with: + image: ${{inputs.image}} + architecture: ${{inputs.architecture}} + build_configuration: ${{inputs.build_configuration}} + + - name: Upload Build Cache + uses: ./.github/actions/test-build-cache-upload + with: + image: ${{inputs.image}} + architecture: ${{inputs.architecture}} + build_configuration: ${{inputs.build_configuration}} diff --git a/.github/workflows/reusable-publish.yml b/.github/workflows/reusable-publish.yml new file mode 100644 index 000000000..607cbf157 --- /dev/null +++ b/.github/workflows/reusable-publish.yml @@ -0,0 +1,60 @@ +name: 🔒Reusable Workflow Publish + +on: + workflow_call: + inputs: + image: + required: true + type: string + description: 'The image to use' + architecture: + required: true + type: string + description: 'The architecture to use' + build_configuration: + required: true + type: string + description: 'The build configuration to use' + secrets: + NUGET_API_KEY: + required: true + NIGHTLY_NUGET_API_KEY: + required: true + NIGHTLY_NUGET_SOURCE: + required: true + +env: + # Disable the .NET logo in the console output. + DOTNET_NOLOGO: true + # Disable the .NET first time experience to skip caching NuGet packages and speed up the build. + DOTNET_SKIP_FIRST_TIME_EXPERIENCE: true + # Disable sending .NET CLI telemetry to Microsoft. + DOTNET_CLI_TELEMETRY_OPTOUT: true + +jobs: + publish: + name: Publish NuGet Packages from Build Output Cache + runs-on: ubuntu-latest + timeout-minutes: 10 + steps: + - uses: actions/checkout@v4 + + - name: Setup .NET + uses: actions/setup-dotnet@v4 + + - name: Download Build Cache + uses: ./.github/actions/test-build-cache-download + with: + image: ${{inputs.image}} + architecture: ${{inputs.architecture}} + build_configuration: ${{inputs.build_configuration}} + + - name: Push to NuGet + if: ${{github.ref == 'refs/heads/master'}} + run: dotnet nuget push "./artifacts/**/*.nupkg" -k ${{secrets.NUGET_API_KEY}} --skip-duplicate + shell: pwsh + + - name: Push to NuGet Nightly + if: ${{github.ref == 'refs/heads/development'}} + run: dotnet nuget push "./artifacts/**/*.nupkg" -k ${{secrets.NIGHTLY_NUGET_API_KEY}} -s ${{secrets.NIGHTLY_NUGET_SOURCE}} --skip-duplicate + shell: pwsh diff --git a/.github/workflows/reusable-test.yml b/.github/workflows/reusable-test.yml new file mode 100644 index 000000000..687372510 --- /dev/null +++ b/.github/workflows/reusable-test.yml @@ -0,0 +1,157 @@ +name: 🔒Reusable Workflow Test +# We build the binaries for all os and configurations +# So we don't have to do that on each test run + +on: + workflow_call: + inputs: + image: + required: true + type: string + description: 'The image to use' + architecture: + required: true + type: string + description: 'The architecture to use' + dotnet_target_frameworks: + required: true + type: string + description: 'The target frameworks to use' + build_configuration: + required: true + type: string + description: 'The build configuration to use' + is_experimental: + required: false + type: boolean + default: false + description: 'Whether the tests are mandatory for the build to pass' + skip_experimental: + required: false + type: boolean + default: false + description: 'Whether to skip the experimental tests' + +env: + # Disable the .NET logo in the console output. + DOTNET_NOLOGO: true + # Disable the .NET first time experience to skip caching NuGet packages and speed up the build. + DOTNET_SKIP_FIRST_TIME_EXPERIENCE: true + # Disable sending .NET CLI telemetry to Microsoft. + DOTNET_CLI_TELEMETRY_OPTOUT: true + +jobs: + test: + name: Execute Tests + runs-on: ${{inputs.image}} + continue-on-error: ${{inputs.is_experimental}} + timeout-minutes: 10 + if: ${{ !inputs.is_experimental || (inputs.is_experimental && !inputs.skip_experimental) }} + steps: + - uses: actions/checkout@v4 + + - name: Install Rosetta 2 on OS X + if: ${{inputs.image == 'macos-14' && inputs.architecture == 'x64'}} + run: /usr/sbin/softwareupdate --install-rosetta --agree-to-license + + # Wine + - name: Setup Wine on Ubuntu + if: ${{runner.os == 'Linux'}} + uses: ./.github/actions/setup-wine-ubuntu + + - name: Setup Wine on OS X + if: ${{runner.os == 'macOS'}} + uses: ./.github/actions/setup-wine-macos + + - name: Get Installed Wine Information + if: ${{runner.os == 'Linux' || runner.os == 'macOS'}} + run: wine --version + + - name: Get Installed Wine Programs Information + if: ${{runner.os == 'Linux' || runner.os == 'macOS'}} + run: wine uninstaller --list + # Wine + + # .NET + - name: Setup .NET on Ubuntu and OS X (Intel/Arm) + if: ${{runner.os == 'Linux' || (inputs.image == 'macos-13' || (inputs.image == 'macos-14' && inputs.architecture == 'arm64'))}} + uses: ./.github/actions/setup-dotnet-unix + with: + target_framework: '' + target_framework_array: ${{inputs.dotnet_target_frameworks}} + + - name: Setup .NET on OS X (Arm) Rosetta 2 + if: ${{inputs.image == 'macos-14' && inputs.architecture == 'x64'}} + uses: ./.github/actions/setup-dotnet-macos-rosetta + with: + target_framework: '' + target_framework_array: ${{inputs.dotnet_target_frameworks}} + + - name: Setup .NET on Windows + if: ${{runner.os == 'Windows'}} + uses: ./.github/actions/setup-dotnet-windows + with: + architecture: ${{inputs.architecture}} + target_framework: '' + target_framework_array: ${{inputs.dotnet_target_frameworks}} + + - name: Get .NET path for ${{inputs.architecture}} + uses: ./.github/actions/get-dotnet-path + id: get-dotnet-path + with: + architecture: ${{inputs.architecture}} + + - name: Get Installed .NET Information for ${{inputs.architecture}} + run: '& "${{steps.get-dotnet-path.outputs.path}}" --info' + shell: pwsh + # .NET + + # Mono + - name: Setup Mono on Windows + if: ${{runner.os == 'Windows'}} + uses: ./.github/actions/setup-mono-windows + with: + architecture: ${{inputs.architecture}} + + - name: Get Mono path for ${{inputs.architecture}} + uses: ./.github/actions/get-mono-path + id: get-mono-path + with: + architecture: ${{inputs.architecture}} + + - name: Get Installed Mono Information + run: '& "${{steps.get-mono-path.outputs.path}}" --version' + shell: pwsh + # Mono + + - name: Download Build Cache + uses: ./.github/actions/test-build-cache-download + with: + #image: ${{inputs.image}} + image: 'windows-latest' + architecture: ${{(inputs.architecture == 'arm64' && 'x64') || inputs.architecture}} + build_configuration: ${{inputs.build_configuration}} + + # TODO: Cover Mono on Windows + - name: Test + run: | + $files = Get-ChildItem -Path ./test -Recurse -Filter *.csproj | ? { $_.FullName -inotmatch 'TestBinaries' }; + $hasError = $false; + foreach ($file in $files) { + & "${{steps.get-dotnet-path.outputs.path}}" test $file.FullName -c ${{inputs.build_configuration}} -l trx -l 'console;verbosity=normal'; + Write-Host "Exit code for $($file.FullName): $exitCode" + $hasError = $hasError -or $LASTEXITCODE -ne 0; + } + if ($hasError) { + throw 'Tests failed'; + } + shell: pwsh + + - name: Upload Test Results + if: always() + uses: ./.github/actions/test-results-upload + with: + image: ${{inputs.image}} + architecture: ${{inputs.architecture}} + build_configuration: ${{inputs.build_configuration}} + experimental: ${{inputs.is_experimental}} diff --git a/.github/workflows/test-and-publish.yml b/.github/workflows/test-and-publish.yml new file mode 100644 index 000000000..7f23b7363 --- /dev/null +++ b/.github/workflows/test-and-publish.yml @@ -0,0 +1,124 @@ +name: Test and Publish NuGet + +on: + push: + branches: + - master + - development + - simple + - simple-test2 + paths-ignore: + - '.github/workflows/docs.yml' + - 'docs/**' + pull_request: + branches: + - master + - development + paths-ignore: + - '.github/workflows/docs.yml' + - 'docs/*' + workflow_dispatch: + +concurrency: + group: ${{github.workflow}}-${{github.event.pull_request.number || github.ref}} + cancel-in-progress: true + +env: + # Right now we can't run experimental tests that can fail, since it will affect the PR + # By default we only run it on master/development branches + # Unless the variable will be true + EXPERIMENTAL: false + + # You are interested in changing these values + BUILD_CONFIGURATIONS: "['Release']" + DOTNET_TARGET_FRAMEWORKS: "['netcoreapp3.1', 'net5.0', 'net6.0', 'net7.0', 'net8.0']" + DOTNET_TARGET_FRAMEWORKS_MACOS_ARM64: "['net6.0', 'net7.0', 'net8.0']" + FRAMEWORK_TARGET_FRAMEWORKS: "['net35', 'net48']" + +jobs: + + # This technique allows us to run `test-results-publish.yml` with the owner's secrets + # without comprimizing the security + upload-event-file: + name: Upload Event File + runs-on: ubuntu-latest + steps: + - name: Upload event file + uses: actions/upload-artifact@v4 + with: + name: test-event-file + path: ${{ github.event_path }} + retention-days: 1 + + # https://stackoverflow.com/a/77549656 + variables: + name: Variable Accessibility Workaround for Jobs + runs-on: ubuntu-latest + outputs: + EXPERIMENTAL: ${{ env.EXPERIMENTAL == 'true' || (github.event == 'push' && github.ref == 'refs/heads/master' || github.ref == 'refs/heads/development') }} + BUILD_CONFIGURATIONS: ${{env.BUILD_CONFIGURATIONS}} + DOTNET_TARGET_FRAMEWORKS: ${{env.DOTNET_TARGET_FRAMEWORKS}} + DOTNET_TARGET_FRAMEWORKS_MACOS_ARM64: ${{env.DOTNET_TARGET_FRAMEWORKS_MACOS_ARM64}} + FRAMEWORK_TARGET_FRAMEWORKS: ${{env.FRAMEWORK_TARGET_FRAMEWORKS}} + steps: + - name: Compute outputs + run: | + echo "EXPERIMENTAL=${{env.EXPERIMENTAL}}" >> $GITHUB_OUTPUT + echo "BUILD_CONFIGURATIONS=${{env.BUILD_CONFIGURATIONS}}" >> $GITHUB_OUTPUT + echo "DOTNET_TARGET_FRAMEWORKS=${{env.DOTNET_TARGET_FRAMEWORKS}}" >> $GITHUB_OUTPUT + echo "DOTNET_TARGET_FRAMEWORKS_MACOS_ARM64=${{env.DOTNET_TARGET_FRAMEWORKS_MACOS_ARM64}}" >> $GITHUB_OUTPUT + echo "FRAMEWORK_TARGET_FRAMEWORKS=${{env.FRAMEWORK_TARGET_FRAMEWORKS}}" >> $GITHUB_OUTPUT + + build: + name: Perform Build + needs: [variables] + strategy: + matrix: + runner: [ + { image: 'windows-latest', arch: 'x64' }, + { image: 'windows-latest', arch: 'x86' }, + ] + build_configuration: ${{fromJson(needs.variables.outputs.BUILD_CONFIGURATIONS)}} + uses: ./.github/workflows/reusable-build.yml + with: + image: ${{matrix.runner.image}} + architecture: ${{matrix.runner.arch}} + build_configuration: ${{matrix.build_configuration}} + + test: + name: Execute Tests + needs: [variables, build] + strategy: + fail-fast: false + matrix: + runner: [ + { image: 'windows-latest', arch: 'x64' }, + { image: 'windows-latest', arch: 'x86' }, + { image: 'ubuntu-latest', arch: 'x64' }, + { image: 'macos-13', arch: 'x64' }, + { image: 'macos-14', arch: 'arm64' }, + { image: 'macos-14', arch: 'x64' }, + ] + build_configuration: ${{fromJson(needs.variables.outputs.BUILD_CONFIGURATIONS)}} + uses: ./.github/workflows/reusable-test.yml + with: + image: ${{matrix.runner.image}} + architecture: ${{matrix.runner.arch}} + dotnet_target_frameworks: ${{needs.variables.outputs.DOTNET_TARGET_FRAMEWORKS}} + build_configuration: ${{matrix.build_configuration}} + #ignore non-windows tests since support is yet lacking + is_experimental: ${{matrix.runner.image != 'windows-latest' && matrix.runner.image != 'ubuntu-latest'}} + skip_experimental: ${{ needs.variables.outputs.EXPERIMENTAL != 'true' }} + + publish: + name: Publish NuGet Packages + needs: [variables, test] + uses: ./.github/workflows/reusable-publish.yml + with: + image: 'windows-latest' + architecture: 'x64' + build_configuration: 'Release' + secrets: + NUGET_API_KEY: ${{ secrets.NUGET_API_KEY }} + NIGHTLY_NUGET_API_KEY: ${{ secrets.NIGHTLY_NUGET_API_KEY }} + NIGHTLY_NUGET_SOURCE: ${{ secrets.NIGHTLY_NUGET_SOURCE }} diff --git a/.github/workflows/test-results-publish.yml b/.github/workflows/test-results-publish.yml new file mode 100644 index 000000000..ea19a5cf2 --- /dev/null +++ b/.github/workflows/test-results-publish.yml @@ -0,0 +1,37 @@ + +name: Publish Test Results + +on: + workflow_run: + workflows: + - Test and Publish NuGet + types: [completed] +permissions: {} + +jobs: + publish-test-results: + if: github.event.workflow_run.conclusion != 'skipped' && github.event.workflow_run.conclusion != 'cancelled' + runs-on: ubuntu-latest + name: Publish Test Results + + permissions: + checks: write + pull-requests: write + contents: write + issues: read + actions: read + statuses: read + + steps: + - uses: actions/checkout@v4 + + - name: Download and Publish Test Results + uses: ./.github/actions/test-results-download-publish + with: + workflow_run: ${{toJSON(github.event.workflow_run)}} + + - name: Download and Publish Test Results (Experimental) + uses: ./.github/actions/test-results-download-publish + with: + workflow_run: ${{toJSON(github.event.workflow_run)}} + experimental: true \ No newline at end of file diff --git a/AsmResolver.sln b/AsmResolver.sln index 492017f8f..ebf8bcb55 100644 --- a/AsmResolver.sln +++ b/AsmResolver.sln @@ -70,6 +70,9 @@ EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AsmResolver.Benchmarks", "test\AsmResolver.Benchmarks\AsmResolver.Benchmarks.csproj", "{CB766958-8D07-4E2D-8A38-C21617B1C45D}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tools", "tools", "{0D04B5DF-8D16-488F-8767-E49803D3AF46}" + ProjectSection(SolutionItems) = preProject + tools\Directory.Build.props = tools\Directory.Build.props + EndProjectSection EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AsmResolver.PE.Exports.OrdinalMapper", "tools\AsmResolver.PE.Exports.OrdinalMapper\AsmResolver.PE.Exports.OrdinalMapper.csproj", "{3E4B6896-269F-4129-9746-965338779C31}" EndProject @@ -118,6 +121,10 @@ Global {4EA3F800-1A1B-4465-931F-4E9949C3373B}.Release|Any CPU.Build.0 = Release|Any CPU {4EA3F800-1A1B-4465-931F-4E9949C3373B}.Release|x64.ActiveCfg = Release|Any CPU {4EA3F800-1A1B-4465-931F-4E9949C3373B}.Release|x86.ActiveCfg = Release|Any CPU + {4EA3F800-1A1B-4465-931F-4E9949C3373B}.Release|x64.Build.0 = Release|Any CPU + {4EA3F800-1A1B-4465-931F-4E9949C3373B}.Release|x86.Build.0 = Release|Any CPU + {4EA3F800-1A1B-4465-931F-4E9949C3373B}.Debug|x86.Build.0 = Debug|Any CPU + {4EA3F800-1A1B-4465-931F-4E9949C3373B}.Debug|x64.Build.0 = Debug|Any CPU {7609C0D1-B65C-4C12-B520-EAF611B0E68F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {7609C0D1-B65C-4C12-B520-EAF611B0E68F}.Debug|Any CPU.Build.0 = Debug|Any CPU {7609C0D1-B65C-4C12-B520-EAF611B0E68F}.Debug|x64.ActiveCfg = Debug|Any CPU @@ -138,6 +145,10 @@ Global {89F2A014-E503-4328-9601-6D93B9E221D8}.Release|Any CPU.Build.0 = Release|Any CPU {89F2A014-E503-4328-9601-6D93B9E221D8}.Release|x64.ActiveCfg = Release|Any CPU {89F2A014-E503-4328-9601-6D93B9E221D8}.Release|x86.ActiveCfg = Release|Any CPU + {89F2A014-E503-4328-9601-6D93B9E221D8}.Release|x64.Build.0 = Release|Any CPU + {89F2A014-E503-4328-9601-6D93B9E221D8}.Release|x86.Build.0 = Release|Any CPU + {89F2A014-E503-4328-9601-6D93B9E221D8}.Debug|x86.Build.0 = Debug|Any CPU + {89F2A014-E503-4328-9601-6D93B9E221D8}.Debug|x64.Build.0 = Debug|Any CPU {239BD2AF-D7CF-44C5-BF56-09913166710E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {239BD2AF-D7CF-44C5-BF56-09913166710E}.Debug|Any CPU.Build.0 = Debug|Any CPU {239BD2AF-D7CF-44C5-BF56-09913166710E}.Debug|x64.ActiveCfg = Debug|Any CPU @@ -158,6 +169,10 @@ Global {856EEF27-8430-4360-9E4C-F923AF142D23}.Release|Any CPU.Build.0 = Release|Any CPU {856EEF27-8430-4360-9E4C-F923AF142D23}.Release|x64.ActiveCfg = Release|Any CPU {856EEF27-8430-4360-9E4C-F923AF142D23}.Release|x86.ActiveCfg = Release|Any CPU + {856EEF27-8430-4360-9E4C-F923AF142D23}.Release|x64.Build.0 = Release|Any CPU + {856EEF27-8430-4360-9E4C-F923AF142D23}.Release|x86.Build.0 = Release|Any CPU + {856EEF27-8430-4360-9E4C-F923AF142D23}.Debug|x86.Build.0 = Debug|Any CPU + {856EEF27-8430-4360-9E4C-F923AF142D23}.Debug|x64.Build.0 = Debug|Any CPU {4BCE8E05-9A72-4C7C-8A4C-130133F4FC56}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {4BCE8E05-9A72-4C7C-8A4C-130133F4FC56}.Debug|Any CPU.Build.0 = Debug|Any CPU {4BCE8E05-9A72-4C7C-8A4C-130133F4FC56}.Debug|x64.ActiveCfg = Debug|Any CPU @@ -166,6 +181,10 @@ Global {4BCE8E05-9A72-4C7C-8A4C-130133F4FC56}.Release|Any CPU.Build.0 = Release|Any CPU {4BCE8E05-9A72-4C7C-8A4C-130133F4FC56}.Release|x64.ActiveCfg = Release|Any CPU {4BCE8E05-9A72-4C7C-8A4C-130133F4FC56}.Release|x86.ActiveCfg = Release|Any CPU + {4BCE8E05-9A72-4C7C-8A4C-130133F4FC56}.Release|x64.Build.0 = Release|Any CPU + {4BCE8E05-9A72-4C7C-8A4C-130133F4FC56}.Release|x86.Build.0 = Release|Any CPU + {4BCE8E05-9A72-4C7C-8A4C-130133F4FC56}.Debug|x86.Build.0 = Debug|Any CPU + {4BCE8E05-9A72-4C7C-8A4C-130133F4FC56}.Debug|x64.Build.0 = Debug|Any CPU {6F5D18B2-8536-452E-83C4-4FE594E5A37F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {6F5D18B2-8536-452E-83C4-4FE594E5A37F}.Debug|Any CPU.Build.0 = Debug|Any CPU {6F5D18B2-8536-452E-83C4-4FE594E5A37F}.Debug|x64.ActiveCfg = Debug|Any CPU @@ -403,13 +422,11 @@ Global {E7D186F7-B2BC-451D-98CC-427866CABE54}.Release|x86.ActiveCfg = Release|Win32 {E7D186F7-B2BC-451D-98CC-427866CABE54}.Release|x86.Build.0 = Release|Win32 {40483E28-C703-4933-BA5B-9512EF6E6A21}.Debug|Any CPU.ActiveCfg = Debug|x64 - {40483E28-C703-4933-BA5B-9512EF6E6A21}.Debug|Any CPU.Build.0 = Debug|x64 {40483E28-C703-4933-BA5B-9512EF6E6A21}.Debug|x64.ActiveCfg = Debug|x64 {40483E28-C703-4933-BA5B-9512EF6E6A21}.Debug|x64.Build.0 = Debug|x64 {40483E28-C703-4933-BA5B-9512EF6E6A21}.Debug|x86.ActiveCfg = Debug|Win32 {40483E28-C703-4933-BA5B-9512EF6E6A21}.Debug|x86.Build.0 = Debug|Win32 {40483E28-C703-4933-BA5B-9512EF6E6A21}.Release|Any CPU.ActiveCfg = Release|x64 - {40483E28-C703-4933-BA5B-9512EF6E6A21}.Release|Any CPU.Build.0 = Release|x64 {40483E28-C703-4933-BA5B-9512EF6E6A21}.Release|x64.ActiveCfg = Release|x64 {40483E28-C703-4933-BA5B-9512EF6E6A21}.Release|x64.Build.0 = Release|x64 {40483E28-C703-4933-BA5B-9512EF6E6A21}.Release|x86.ActiveCfg = Release|Win32 diff --git a/Directory.Build.props b/Directory.Build.props index d2dca83f1..91039a58c 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -2,14 +2,19 @@ Copyright © Washi 2016-2024 - https://github.com/Washi1337/AsmResolver https://github.com/Washi1337/AsmResolver/LICENSE.md - https://github.com/Washi1337/AsmResolver - git + true + true + $(AllowedOutputExtensionsInPackageBuildOutputFolder);.pdb 10 - 6.0.0-beta.1 + 6.0.0 + beta.1 true true + + true + + diff --git a/appveyor.yml b/appveyor.yml index 69dc8beed..1d11d753d 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -11,6 +11,21 @@ files: - docs/* + #---------------------------------# + # Install .NET # + #---------------------------------# + install: + - ps: $env:DOTNET_INSTALL_DIR = "$pwd\.dotnetsdk" + - ps: mkdir $env:DOTNET_INSTALL_DIR -Force | Out-Null + - ps: Invoke-WebRequest -Uri "https://dot.net/v1/dotnet-install.ps1" -OutFile "$($env:DOTNET_INSTALL_DIR)/dotnet-install.ps1" + - ps: '& "$($env:DOTNET_INSTALL_DIR)/dotnet-install.ps1" -Channel 3.1 -InstallDir $env:DOTNET_INSTALL_DIR' + - ps: '& "$($env:DOTNET_INSTALL_DIR)/dotnet-install.ps1" -Channel 5.0 -InstallDir $env:DOTNET_INSTALL_DIR' + - ps: '& "$($env:DOTNET_INSTALL_DIR)/dotnet-install.ps1" -Channel 6.0 -InstallDir $env:DOTNET_INSTALL_DIR' + - ps: '& "$($env:DOTNET_INSTALL_DIR)/dotnet-install.ps1" -Channel 7.0 -InstallDir $env:DOTNET_INSTALL_DIR' + - ps: '& "$($env:DOTNET_INSTALL_DIR)/dotnet-install.ps1" -Channel 8.0 -InstallDir $env:DOTNET_INSTALL_DIR' + - ps: $env:Path = "$env:DOTNET_INSTALL_DIR;$env:Path" + - ps: dotnet --info + before_build: - dotnet restore @@ -40,6 +55,21 @@ files: - docs/* + #---------------------------------# + # Install .NET # + #---------------------------------# + install: + - ps: $env:DOTNET_INSTALL_DIR = "$pwd\.dotnetsdk" + - ps: mkdir $env:DOTNET_INSTALL_DIR -Force | Out-Null + - ps: Invoke-WebRequest -Uri "https://dot.net/v1/dotnet-install.ps1" -OutFile "$($env:DOTNET_INSTALL_DIR)/dotnet-install.ps1" + - ps: '& "$($env:DOTNET_INSTALL_DIR)/dotnet-install.ps1" -Channel 3.1 -InstallDir $env:DOTNET_INSTALL_DIR' + - ps: '& "$($env:DOTNET_INSTALL_DIR)/dotnet-install.ps1" -Channel 5.0 -InstallDir $env:DOTNET_INSTALL_DIR' + - ps: '& "$($env:DOTNET_INSTALL_DIR)/dotnet-install.ps1" -Channel 6.0 -InstallDir $env:DOTNET_INSTALL_DIR' + - ps: '& "$($env:DOTNET_INSTALL_DIR)/dotnet-install.ps1" -Channel 7.0 -InstallDir $env:DOTNET_INSTALL_DIR' + - ps: '& "$($env:DOTNET_INSTALL_DIR)/dotnet-install.ps1" -Channel 8.0 -InstallDir $env:DOTNET_INSTALL_DIR' + - ps: $env:Path = "$env:DOTNET_INSTALL_DIR;$env:Path" + - ps: dotnet --info + before_build: - dotnet restore diff --git a/src/AsmResolver.DotNet.Dynamic/AsmResolver.DotNet.Dynamic.csproj b/src/AsmResolver.DotNet.Dynamic/AsmResolver.DotNet.Dynamic.csproj index 6db621977..a3ab5f7fd 100644 --- a/src/AsmResolver.DotNet.Dynamic/AsmResolver.DotNet.Dynamic.csproj +++ b/src/AsmResolver.DotNet.Dynamic/AsmResolver.DotNet.Dynamic.csproj @@ -1,33 +1,22 @@ - - AsmResolver.DotNet.Dynamic - Dynamic method support for the AsmResolver executable file inspection toolsuite. - exe pe directories imports exports resources dotnet cil inspection manipulation assembly disassembly dynamic - 1701;1702;NU5105 - + + AsmResolver.DotNet.Dynamic + Dynamic method support for the AsmResolver executable file inspection toolsuite. + exe pe directories imports exports resources dotnet cil inspection manipulation assembly disassembly dynamic + false + - - bin\Debug\AsmResolver.DotNet.Dynamic.xml - + + bin\Debug\AsmResolver.DotNet.Dynamic.xml + - - bin\Release\AsmResolver.DotNet.Dynamic.xml - + + bin\Release\AsmResolver.DotNet.Dynamic.xml + - - - - - - - all - runtime; build; native; contentfiles; analyzers; buildtransitive - - - all - runtime; build; native; contentfiles; analyzers; buildtransitive - - + + + diff --git a/src/AsmResolver.DotNet/AsmResolver.DotNet.csproj b/src/AsmResolver.DotNet/AsmResolver.DotNet.csproj index 9de9ad8f8..59a99df5a 100644 --- a/src/AsmResolver.DotNet/AsmResolver.DotNet.csproj +++ b/src/AsmResolver.DotNet/AsmResolver.DotNet.csproj @@ -1,33 +1,21 @@ - - AsmResolver.DotNet - High level .NET image models for the AsmResolver executable file inspection toolsuite. - exe pe directories imports exports resources dotnet cil inspection manipulation assembly disassembly - 1701;1702;NU5105 - true - + + AsmResolver.DotNet + High level .NET image models for the AsmResolver executable file inspection toolsuite. + exe pe directories imports exports resources dotnet cil inspection manipulation assembly disassembly + - - bin\Debug\AsmResolver.DotNet.xml - + + bin\Debug\AsmResolver.DotNet.xml + - - bin\Release\AsmResolver.DotNet.xml - + + bin\Release\AsmResolver.DotNet.xml + - - - + + + - - - all - runtime; build; native; contentfiles; analyzers; buildtransitive - - - all - runtime; build; native; contentfiles; analyzers; buildtransitive - - diff --git a/src/AsmResolver.PE.File/AsmResolver.PE.File.csproj b/src/AsmResolver.PE.File/AsmResolver.PE.File.csproj index fb00775e4..f03ccca79 100644 --- a/src/AsmResolver.PE.File/AsmResolver.PE.File.csproj +++ b/src/AsmResolver.PE.File/AsmResolver.PE.File.csproj @@ -1,35 +1,23 @@ - - AsmResolver.PE.File - Raw PE file models for the AsmResolver executable file inspection toolsuite. - exe pe headers sections inspection manipulation assembly disassembly - 1701;1702;NU5105 - true - true - + + AsmResolver.PE.File + Raw PE file models for the AsmResolver executable file inspection toolsuite. + exe pe headers sections inspection manipulation assembly disassembly + 1701;1702;NU5105 + true + - - bin\Debug\AsmResolver.PE.File.xml - + + bin\Debug\AsmResolver.PE.File.xml + - - bin\Release\AsmResolver.PE.File.xml - + + bin\Release\AsmResolver.PE.File.xml + - - - - - - - all - runtime; build; native; contentfiles; analyzers; buildtransitive - - - all - runtime; build; native; contentfiles; analyzers; buildtransitive - - + + + diff --git a/src/AsmResolver.PE.File/OptionalHeader.cs b/src/AsmResolver.PE.File/OptionalHeader.cs index 196b33a64..d9821cb55 100644 --- a/src/AsmResolver.PE.File/OptionalHeader.cs +++ b/src/AsmResolver.PE.File/OptionalHeader.cs @@ -414,8 +414,10 @@ public void SetDataDirectory(DataDirectoryIndex index, DataDirectory directory) /// Maps a segment to a data directory. /// /// The index. - /// The contents of the data directory. - public void SetDataDirectory(DataDirectoryIndex index, ISegment contents) + /// + /// The contents of the data directory, or null to indicate an absence of the directory. + /// + public void SetDataDirectory(DataDirectoryIndex index, ISegment? contents) { SetDataDirectory(index, DataDirectory.CreateForSegment(contents)); } diff --git a/src/AsmResolver.PE.Win32Resources/AsmResolver.PE.Win32Resources.csproj b/src/AsmResolver.PE.Win32Resources/AsmResolver.PE.Win32Resources.csproj index 6af1f8737..96725bd6e 100644 --- a/src/AsmResolver.PE.Win32Resources/AsmResolver.PE.Win32Resources.csproj +++ b/src/AsmResolver.PE.Win32Resources/AsmResolver.PE.Win32Resources.csproj @@ -1,35 +1,22 @@ - - AsmResolver.PE.Win32Resources - exe pe directories imports exports resources dotnet cil inspection manipulation assembly disassembly - 1701;1702;NU5105 - true - 12 - + + AsmResolver.PE.Win32Resources + exe pe directories imports exports resources dotnet cil inspection manipulation assembly disassembly + 12 + - - bin\Debug\AsmResolver.PE.Win32Resources.xml - + + bin\Debug\AsmResolver.PE.Win32Resources.xml + - - bin\Release\AsmResolver.PE.Win32Resources.xml - + + bin\Release\AsmResolver.PE.Win32Resources.xml + - - - all - runtime; build; native; contentfiles; analyzers; buildtransitive - - - all - runtime; build; native; contentfiles; analyzers; buildtransitive - - - - - - - + + + + diff --git a/src/AsmResolver.PE/AsmResolver.PE.csproj b/src/AsmResolver.PE/AsmResolver.PE.csproj index 699fbbd7a..2cafd88fb 100644 --- a/src/AsmResolver.PE/AsmResolver.PE.csproj +++ b/src/AsmResolver.PE/AsmResolver.PE.csproj @@ -1,34 +1,21 @@ - - AsmResolver.PE - PE image models for the AsmResolver executable file inspection toolsuite. - exe pe directories imports exports resources dotnet cil inspection manipulation assembly disassembly - 1701;1702;NU5105 - true - + + AsmResolver.PE + PE image models for the AsmResolver executable file inspection toolsuite. + exe pe directories imports exports resources dotnet cil inspection manipulation assembly disassembly + - - bin\Debug\AsmResolver.PE.xml - + + bin\Debug\AsmResolver.PE.xml + - - bin\Release\AsmResolver.PE.xml - + + bin\Release\AsmResolver.PE.xml + - - - - - - - all - runtime; build; native; contentfiles; analyzers; buildtransitive - - - all - runtime; build; native; contentfiles; analyzers; buildtransitive - - + + + diff --git a/src/AsmResolver.PE/Builder/UnmanagedPEFileBuilder.cs b/src/AsmResolver.PE/Builder/UnmanagedPEFileBuilder.cs index 7af2d90b8..bc816699a 100644 --- a/src/AsmResolver.PE/Builder/UnmanagedPEFileBuilder.cs +++ b/src/AsmResolver.PE/Builder/UnmanagedPEFileBuilder.cs @@ -188,29 +188,26 @@ protected override void AssignDataDirectories(BuilderContext context, PEFile out header.EnsureDataDirectoryCount(OptionalHeader.DefaultNumberOfRvasAndSizes); + // NOTE: We need to explicitly check if imports.count == 0 because the buffer may not be populated if + // IAT trampolining (and thus IAT rebuilding) is disabled. In such a case, we want to preserve the existing IAT + // rather than remove it. if (!context.ImportDirectory.IsEmpty) { header.SetDataDirectory(DataDirectoryIndex.ImportDirectory, context.ImportDirectory); header.SetDataDirectory(DataDirectoryIndex.IatDirectory, context.ImportDirectory.ImportAddressDirectory); } + else if (context.Image.Imports.Count == 0) + { + header.SetDataDirectory(DataDirectoryIndex.ImportDirectory, null); + header.SetDataDirectory(DataDirectoryIndex.IatDirectory, null); + } - if (!context.ExportDirectory.IsEmpty) - header.SetDataDirectory(DataDirectoryIndex.ExportDirectory, context.ExportDirectory); - - if (!context.DebugDirectory.IsEmpty) - header.SetDataDirectory(DataDirectoryIndex.DebugDirectory, context.DebugDirectory); - - if (!context.ResourceDirectory.IsEmpty) - header.SetDataDirectory(DataDirectoryIndex.ResourceDirectory, context.ResourceDirectory); - - if (context.Image.DotNetDirectory is not null) - header.SetDataDirectory(DataDirectoryIndex.ClrDirectory, context.Image.DotNetDirectory); - - if (context.Image.TlsDirectory is not null) - header.SetDataDirectory(DataDirectoryIndex.TlsDirectory, context.Image.TlsDirectory); - - if (!context.RelocationsDirectory.IsEmpty) - header.SetDataDirectory(DataDirectoryIndex.BaseRelocationDirectory, context.RelocationsDirectory); + header.SetDataDirectory(DataDirectoryIndex.ExportDirectory, !context.ExportDirectory.IsEmpty ? context.ExportDirectory : null); + header.SetDataDirectory(DataDirectoryIndex.DebugDirectory, !context.DebugDirectory.IsEmpty ? context.DebugDirectory : null); + header.SetDataDirectory(DataDirectoryIndex.ResourceDirectory, !context.ResourceDirectory.IsEmpty ? context.ResourceDirectory : null); + header.SetDataDirectory(DataDirectoryIndex.ClrDirectory, context.Image.DotNetDirectory); + header.SetDataDirectory(DataDirectoryIndex.TlsDirectory, context.Image.TlsDirectory); + header.SetDataDirectory(DataDirectoryIndex.BaseRelocationDirectory, !context.RelocationsDirectory.IsEmpty ? context.RelocationsDirectory : null); } /// @@ -234,10 +231,6 @@ protected override void AssignDataDirectories(BuilderContext context, PEFile out if (TrampolineImports && !context.ImportDirectory.IsEmpty) contents.Add(context.ImportDirectory); - // Reconstructed exports. - if (!context.ExportDirectory.IsEmpty) - contents.Add(context.ExportDirectory); - // Reconstructed debug directory. if (!context.DebugDirectory.IsEmpty) { @@ -258,7 +251,7 @@ protected override void AssignDataDirectories(BuilderContext context, PEFile out context.ImportTrampolines.ApplyPatches(context.ClonedSections); } - // Code for newly added exports. + // Add newly added exports code. if (context.Image.Exports is { Entries: { Count: > 0 } entries }) { for (int i = 0; i < entries.Count; i++) @@ -350,6 +343,13 @@ void AddOrPatch(ISegment? segment, ISegment? originalSegment) AddOrPatch(directory.CallbackFunctions, originalDirectory?.CallbackFunctions); } + // Add export directory. + if (image.Exports is { Entries.Count: > 0 }) + { + if (!TryPatchDataDirectory(context, context.ExportDirectory, DataDirectoryIndex.ExportDirectory)) + contents.Add(context.ExportDirectory, (uint) context.Platform.PointerSize); + } + if (contents.Count == 0) return null; @@ -386,10 +386,6 @@ void AddOrPatch(ISegment? newSegment, ISegment? originalSegment) contents.Add(fixups[i].Tokens, (uint) context.Platform.PointerSize); } - // Add export directory. - if (image.Exports is { Entries.Count: > 0 }) - contents.Add(context.ExportDirectory, (uint) context.Platform.PointerSize); - if (image.TlsDirectory is { } directory) { // Add TLS index segment. diff --git a/src/AsmResolver.PE/Debug/Builder/DebugDirectoryBuffer.cs b/src/AsmResolver.PE/Debug/Builder/DebugDirectoryBuffer.cs index 2cc85880d..c3a0dc300 100644 --- a/src/AsmResolver.PE/Debug/Builder/DebugDirectoryBuffer.cs +++ b/src/AsmResolver.PE/Debug/Builder/DebugDirectoryBuffer.cs @@ -27,7 +27,7 @@ public class DebugDirectoryBuffer : ISegment public void AddEntry(DebugDataEntry entry) { _headers.Add(entry); - if (entry.Contents != null) + if (entry.Contents is not null and not EmptyDebugDataSegment) _streamsTable.Add(entry.Contents, 4); } diff --git a/src/AsmResolver.PE/Debug/EmptyDebugDataSegment.cs b/src/AsmResolver.PE/Debug/EmptyDebugDataSegment.cs new file mode 100644 index 000000000..402079a8e --- /dev/null +++ b/src/AsmResolver.PE/Debug/EmptyDebugDataSegment.cs @@ -0,0 +1,43 @@ +using System.Diagnostics; +using AsmResolver.IO; + +namespace AsmResolver.PE.Debug; + +/// +/// Represents the contents of an empty debug data entry. +/// +public sealed class EmptyDebugDataSegment : IDebugDataSegment +{ + /// + /// Creates a new empty debug data segment for the provided debug data content. + /// + /// The content type. + public EmptyDebugDataSegment(DebugDataType type) + { + Type = type; + } + + /// + public DebugDataType Type { get; } + + bool ISegment.CanUpdateOffsets => false; + + ulong IOffsetProvider.Offset => 0; + + uint IOffsetProvider.Rva => 0; + + /// + void ISegment.UpdateOffsets(in RelocationParameters parameters) + { + } + + /// + uint IWritable.GetPhysicalSize() => 0; + + /// + uint ISegment.GetVirtualSize() => 0; + + void IWritable.Write(BinaryStreamWriter writer) + { + } +} diff --git a/src/AsmResolver.PE/Debug/RsdsDataSegment.cs b/src/AsmResolver.PE/Debug/RsdsDataSegment.cs index e26e19c33..77450a1b2 100644 --- a/src/AsmResolver.PE/Debug/RsdsDataSegment.cs +++ b/src/AsmResolver.PE/Debug/RsdsDataSegment.cs @@ -38,7 +38,7 @@ public class RsdsDataSegment : CodeViewDataSegment reader.ReadBytes(buffer, 0, 16); result.Guid = new Guid(buffer); result.Age = reader.ReadUInt32(); - result.Path = Encoding.UTF8.GetString(reader.ReadBytesUntil(0x00)); + result.Path = Encoding.UTF8.GetString(reader.ReadBytesUntil(0x00, false)); return result; } diff --git a/src/AsmResolver.PE/Debug/SerializedDebugDataEntry.cs b/src/AsmResolver.PE/Debug/SerializedDebugDataEntry.cs index 4711a6063..311adfeaf 100644 --- a/src/AsmResolver.PE/Debug/SerializedDebugDataEntry.cs +++ b/src/AsmResolver.PE/Debug/SerializedDebugDataEntry.cs @@ -43,17 +43,25 @@ public SerializedDebugDataEntry( /// protected override IDebugDataSegment? GetContents() { + BinaryStreamReader reader; + if (_sizeOfData == 0) - return null; + return new EmptyDebugDataSegment(_type); - var reference = _context.File.GetReferenceToRva(_addressOfRawData); - if (!reference.CanRead) + if (_addressOfRawData == 0 || _context.File.MappingMode == File.PEMappingMode.Unmapped) + { + if (!_context.File.TryCreateReaderAtFileOffset(_pointerToRawData, out reader)) + { + _context.BadImage("Debug data entry contains an invalid file offset."); + return null; + } + } + else if (!_context.File.TryCreateReaderAtRva(_addressOfRawData, out reader)) { _context.BadImage("Debug data entry contains an invalid RVA."); return null; } - var reader = reference.CreateReader(); if (_sizeOfData > reader.Length) { _context.BadImage("Debug data entry contains a too large size."); diff --git a/src/AsmResolver.PE/Relocations/Builder/RelocationBlock.cs b/src/AsmResolver.PE/Relocations/Builder/RelocationBlock.cs index 53a36a08e..f1fceac48 100644 --- a/src/AsmResolver.PE/Relocations/Builder/RelocationBlock.cs +++ b/src/AsmResolver.PE/Relocations/Builder/RelocationBlock.cs @@ -1,5 +1,4 @@ using System.Collections.Generic; -using System.Threading; using AsmResolver.IO; namespace AsmResolver.PE.Relocations.Builder @@ -36,18 +35,27 @@ public IList Entries } /// - public override uint GetPhysicalSize() => (uint) (Entries.Count + 1) * sizeof(ushort) + 2 * sizeof(uint); + public override uint GetPhysicalSize() + { + // Ensure the ending zero entry is included in the size. + int totalCount = Entries.Count + (Entries[Entries.Count - 1].IsEmpty ? 0 : 1); + return (uint) totalCount * sizeof(ushort) + 2 * sizeof(uint); + } /// public override void Write(BinaryStreamWriter writer) { + // Block header. writer.WriteUInt32(PageRva); writer.WriteUInt32(GetPhysicalSize()); + // Write all entries in block. for (int i = 0; i < Entries.Count; i++) Entries[i].Write(writer); - default(RelocationEntry).Write(writer); + // Ensure block ends with zero entry. + if (!Entries[Entries.Count - 1].IsEmpty) + default(RelocationEntry).Write(writer); } } diff --git a/src/AsmResolver.PE/Relocations/Builder/RelocationEntry.cs b/src/AsmResolver.PE/Relocations/Builder/RelocationEntry.cs index 6cc559611..eb1a792e7 100644 --- a/src/AsmResolver.PE/Relocations/Builder/RelocationEntry.cs +++ b/src/AsmResolver.PE/Relocations/Builder/RelocationEntry.cs @@ -47,6 +47,11 @@ public RelocationEntry(RelocationType type, int offset) /// public int Offset => _value & 0xFFF; + /// + /// Gets a value indicating the entry is a zero entry. + /// + public bool IsEmpty => _value == 0; + /// public uint GetPhysicalSize() => sizeof(ushort); diff --git a/src/AsmResolver.Symbols.Pdb/AsmResolver.Symbols.Pdb.csproj b/src/AsmResolver.Symbols.Pdb/AsmResolver.Symbols.Pdb.csproj index 61bad1f34..74a5401c0 100644 --- a/src/AsmResolver.Symbols.Pdb/AsmResolver.Symbols.Pdb.csproj +++ b/src/AsmResolver.Symbols.Pdb/AsmResolver.Symbols.Pdb.csproj @@ -1,36 +1,23 @@ - - AsmResolver - Windows PDB models for the AsmResolver executable file inspection toolsuite. - true - true - + + AsmResolver + Windows PDB models for the AsmResolver executable file inspection toolsuite. + - - true - bin\Debug\netstandard2.0\AsmResolver.Symbols.Pdb.xml - + + true + bin\Debug\netstandard2.0\AsmResolver.Symbols.Pdb.xml + - - true - bin\Release\netstandard2.0\AsmResolver.Symbols.Pdb.xml - + + true + bin\Release\netstandard2.0\AsmResolver.Symbols.Pdb.xml + - - - - - - - - all - runtime; build; native; contentfiles; analyzers; buildtransitive - - - all - runtime; build; native; contentfiles; analyzers; buildtransitive - - + + + + diff --git a/src/AsmResolver/AsmResolver.csproj b/src/AsmResolver/AsmResolver.csproj index ddaa59dfb..804809d85 100644 --- a/src/AsmResolver/AsmResolver.csproj +++ b/src/AsmResolver/AsmResolver.csproj @@ -1,36 +1,23 @@ - - AsmResolver - The base library for the AsmResolver executable file inspection toolsuite. - exe pe dotnet cil inspection manipulation assembly disassembly - 1701;1702;NU5105 - true - + + AsmResolver + The base library for the AsmResolver executable file inspection toolsuite. + exe pe dotnet cil inspection manipulation assembly disassembly + - - true - bin\Debug\netstandard2.0\AsmResolver.xml - + + true + bin\Debug\netstandard2.0\AsmResolver.xml + - - true - bin\Release\netstandard2.0\AsmResolver.xml - + + true + bin\Release\netstandard2.0\AsmResolver.xml + - - - all - runtime; build; native; contentfiles; analyzers; buildtransitive - - - all - runtime; build; native; contentfiles; analyzers; buildtransitive - - - - - - + + + diff --git a/src/Directory.Build.props b/src/Directory.Build.props index 59bb459dd..cf799acc9 100644 --- a/src/Directory.Build.props +++ b/src/Directory.Build.props @@ -1,10 +1,25 @@ - + + net8.0;net6.0;net35;netcoreapp3.1;netstandard2.0;netstandard2.1 true enable - $(MSBuildThisFileDirectory)..\artifacts + true + 1701;1702;NU5105 + $(MSBuildThisFileDirectory)..\artifacts\src + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + diff --git a/test/AsmResolver.DotNet.Tests/Bundles/BundleManifestTest.cs b/test/AsmResolver.DotNet.Tests/Bundles/BundleManifestTest.cs index aa32bde45..e343fdf8f 100644 --- a/test/AsmResolver.DotNet.Tests/Bundles/BundleManifestTest.cs +++ b/test/AsmResolver.DotNet.Tests/Bundles/BundleManifestTest.cs @@ -307,9 +307,8 @@ private void AssertPatchAndRepackageChangesOutput( "HelloWorld.exe", bundleStream.ToArray(), null, - 5000, - className, - methodName); + testClass: className, + testMethod: methodName); Assert.Equal("Hello, Mars!\n", output); } @@ -337,9 +336,8 @@ private void AssertWriteManifestWindowsPreservesOutput( Path.ChangeExtension(fileName, ".exe"), stream.ToArray(), null, - 5000, - className, - methodName); + testClass: className, + testMethod: methodName); Assert.Equal(expectedOutput.Replace("\r\n", "\n"), output); } diff --git a/test/AsmResolver.DotNet.Tests/TestUtils.cs b/test/AsmResolver.DotNet.Tests/TestUtils.cs index 4a3b7e23f..ad33bd7d0 100644 --- a/test/AsmResolver.DotNet.Tests/TestUtils.cs +++ b/test/AsmResolver.DotNet.Tests/TestUtils.cs @@ -12,7 +12,7 @@ public static class TestUtils // We want unit tests to always throw reader errors as opposed to ignore them. public static readonly ModuleReaderParameters TestReaderParameters = new(ThrowErrorListener.Instance); - public static void RebuildAndRun(this PERunner runner, ModuleDefinition module, string fileName, string expectedOutput, int timeout = 5000, + public static void RebuildAndRun(this PERunner runner, ModuleDefinition module, string fileName, string expectedOutput, int timeout = 30000, [CallerFilePath] string testClass = "File", [CallerMemberName] string testMethod = "Test") { diff --git a/test/AsmResolver.PE.Tests/Builder/UnmanagedPEFileBuilderTest.cs b/test/AsmResolver.PE.Tests/Builder/UnmanagedPEFileBuilderTest.cs index 249ef6b2e..303b2b593 100644 --- a/test/AsmResolver.PE.Tests/Builder/UnmanagedPEFileBuilderTest.cs +++ b/test/AsmResolver.PE.Tests/Builder/UnmanagedPEFileBuilderTest.cs @@ -3,6 +3,7 @@ using System.Linq; using AsmResolver.PE.Builder; using AsmResolver.PE.DotNet.Metadata; +using AsmResolver.PE.Exports; using AsmResolver.PE.File; using AsmResolver.PE.Imports; using AsmResolver.Shims; @@ -233,4 +234,19 @@ public void AddMetadataToMixedModeAssembly() expectedOutput ); } + + [Fact] + public void AddExportToExistingDirectory() + { + var image = PEImage.FromBytes(Properties.Resources.SimpleDll_Exports, TestReaderParameters); + image.Exports!.Entries.Add(new ExportedSymbol(new VirtualAddress(0x13371337), "MySymbol")); + + var file = image.ToPEFile(new UnmanagedPEFileBuilder()); + using var stream = new MemoryStream(); + file.Write(stream); + + var newImage = PEImage.FromBytes(stream.ToArray(), TestReaderParameters); + Assert.NotNull(newImage.Exports); + Assert.Equal(image.Exports.Entries.Select(x => x.Name), newImage.Exports.Entries.Select(x => x.Name)); + } } diff --git a/test/AsmResolver.Tests/Runners/PERunner.cs b/test/AsmResolver.Tests/Runners/PERunner.cs index 4f6761cb4..3769ae6a3 100644 --- a/test/AsmResolver.Tests/Runners/PERunner.cs +++ b/test/AsmResolver.Tests/Runners/PERunner.cs @@ -25,7 +25,7 @@ protected abstract string ExecutableExtension get; } - public void RebuildAndRun(PEFile peFile, string fileName, string expectedOutput, int timeout = 5000, + public void RebuildAndRun(PEFile peFile, string fileName, string expectedOutput, int timeout = 30000, [CallerFilePath] string testClass = "File", [CallerMemberName] string testMethod = "Test") { @@ -59,7 +59,7 @@ public string Rebuild(PEFile peFile, string fileName, string testClass, string t } public string RunAndCaptureOutput(string fileName, byte[] contents, string[]? arguments = null, - int timeout = 5000, + int timeout = 30000, [CallerFilePath] string testClass = "File", [CallerMemberName] string testMethod = "Test") { @@ -69,7 +69,7 @@ public string RunAndCaptureOutput(string fileName, byte[] contents, string[]? ar return RunAndCaptureOutput(testExecutablePath, arguments, timeout); } - public string RunAndCaptureOutput(string filePath, string[]? arguments = null, int timeout = 5000) + public string RunAndCaptureOutput(string filePath, string[]? arguments = null, int timeout = 30000) { var info = GetStartInfo(filePath, arguments); info.RedirectStandardError = true; diff --git a/test/Directory.Build.props b/test/Directory.Build.props index 171c6ac9d..8bd4deeda 100644 --- a/test/Directory.Build.props +++ b/test/Directory.Build.props @@ -1,5 +1,6 @@ - + + $(MSBuildThisFileDirectory)..\artifacts\test diff --git a/test/TestBinaries/DotNet/HelloWorld/HelloWorld.csproj b/test/TestBinaries/DotNet/HelloWorld/HelloWorld.csproj index 90588ca1e..af0779346 100644 --- a/test/TestBinaries/DotNet/HelloWorld/HelloWorld.csproj +++ b/test/TestBinaries/DotNet/HelloWorld/HelloWorld.csproj @@ -2,7 +2,7 @@ Exe - net47;netcoreapp3.1;net6.0;net8.0 + netcoreapp3.1;net6.0;net8.0 Resources\Icon.ico true diff --git a/test/TestBinaries/DotNet/TheAnswer/TheAnswer.csproj b/test/TestBinaries/DotNet/TheAnswer/TheAnswer.csproj index 02d35264b..e15f8ab2e 100644 --- a/test/TestBinaries/DotNet/TheAnswer/TheAnswer.csproj +++ b/test/TestBinaries/DotNet/TheAnswer/TheAnswer.csproj @@ -2,7 +2,7 @@ Exe - net47;netcoreapp3.1 + net472;netcoreapp3.1 diff --git a/tools/Directory.Build.props b/tools/Directory.Build.props new file mode 100644 index 000000000..f28236508 --- /dev/null +++ b/tools/Directory.Build.props @@ -0,0 +1,10 @@ + + + + + + $(MSBuildThisFileDirectory)..\artifacts\tools + false + + +