diff --git a/.github/actions/publish/action.yml b/.github/actions/publish/action.yml deleted file mode 100644 index 4773f3f3..00000000 --- a/.github/actions/publish/action.yml +++ /dev/null @@ -1,55 +0,0 @@ -inputs: - version: - required: true - type: string - description: 'Three digits version like 5.6.0' - MARKETPLACE_TOKEN: - required: true - type: string - NUGET_TOKEN: - required: true - type: string - -runs: - using: "composite" - steps: - - name: Zip security-scan 4.x - shell: bash - run: 7z a security-scan4x.zip "./SecurityCodeScan.Tool/.NET 4.x/bin/Release/net48/*" - - - name: Create draft release - uses: softprops/action-gh-release@8a65c813553f4d05769635eb1b70180d25b9b61b - with: - draft: true - name: ${{inputs.version}} - tag_name: ${{inputs.version}} - fail_on_unmatched_files: true - files: | - ./SecurityCodeScan/bin/Release/**/*.nupkg - ./SecurityCodeScan.Vsix/bin/Release/*.vsix - ./SecurityCodeScan.Tool/.NET Core/bin/Release/*.nupkg - security-scan4x.zip - - - name: Publish vsix - shell: powershell - env: - marketplace_token: ${{ inputs.MARKETPLACE_TOKEN }} - run: | - Write-Host "Pushing to visual studio market place" - $visualStudioInstallation = & "${env:ProgramFiles(x86)}\Microsoft Visual Studio\Installer\vswhere.exe" -latest -products * -requires Microsoft.VisualStudio.Component.VSSDK -property installationPath - $vsixPublisher = Join-Path $visualStudioInstallation 'VSSDK\VisualStudioIntegration\Tools\Bin\VsixPublisher.exe' - & $vsixPublisher login -publisherName JaroslavLobacevski -personalAccessToken $env:marketplace_token - $vsix = Get-ChildItem -File .\SecurityCodeScan.Vsix\bin -recurse | Where-Object { $_.Extension -eq ".vsix" } | Select-Object -First 1 -ExpandProperty FullName - $ManifestPath = ".\SecurityCodeScan.Vsix\marketplace.json" - & $vsixPublisher publish -payload $vsix -publishManifest $ManifestPath -personalAccessToken $env:marketplace_token - # currently vsixpublisher.exe throws non critical telemetry exception but does the job done - # force successful exit code - [Environment]::Exit(0) - - - name: Publish nugets - shell: bash - env: - nuget_token: ${{ inputs.NUGET_TOKEN }} - run: | - dotnet nuget push "./SecurityCodeScan/bin/Release/netstandard2.0/SecurityCodeScan.VS2019.${{inputs.version}}.nupkg" -k $nuget_token -s https://api.nuget.org/v3/index.json - dotnet nuget push "./SecurityCodeScan.Tool/.NET Core/bin/Release/security-scan.${{inputs.version}}.nupkg" -k $nuget_token -s https://api.nuget.org/v3/index.json diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index c1c5d01f..dd741616 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -1,3 +1,4 @@ +name: "Reusable build" on: workflow_call: inputs: @@ -7,15 +8,12 @@ on: configuration: required: true type: string - publish: + makeartifacts: required: false type: boolean default: false - secrets: - MARKETPLACE_TOKEN: - required: false - NUGET_TOKEN: - required: false + +permissions: {} jobs: build: @@ -27,16 +25,17 @@ jobs: DOTNET_CLI_TELEMETRY_OPTOUT: 1 steps: + - name: Checkout uses: actions/checkout@v2 with: - fetch-depth: 0 persist-credentials: false - name: Setup .NET SDK uses: actions/setup-dotnet@v1 with: dotnet-version: | + 3.1.x 5.0.x 6.0.x include-prerelease: false @@ -56,14 +55,23 @@ jobs: run: msbuild -m $env:Solution_Name /p:Configuration=$env:Configuration env: Configuration: ${{ inputs.configuration }} - + - name: Run Tests run: vstest.console.exe ./SecurityCodeScan.Test/bin/${{ inputs.configuration }}/SecurityCodeScan.Test.dll - - name: Publish - if: ${{ inputs.publish }} - uses: ./.github/actions/publish - with: - version: ${{ inputs.version }} - MARKETPLACE_TOKEN: ${{ secrets.MARKETPLACE_TOKEN }} - NUGET_TOKEN: ${{ secrets.NUGET_TOKEN }} + - name: Zip security-scan 4.x + if: ${{ inputs.makeartifacts }} + shell: bash + run: 7z a security-scan4x.zip "./SecurityCodeScan.Tool/.NET 4.x/bin/Release/net48/*" + + - name: Upload artifacts + if: ${{ inputs.makeartifacts }} + uses: actions/upload-artifact@3cea5372237819ed00197afe530f5a7ea3e805c8 + with: + retention-days: 1 + name: packages + path: | + security-scan4x.zip + ./SecurityCodeScan/bin/Release/**/*.nupkg + ./SecurityCodeScan.Vsix/bin/Release/*.vsix + ./SecurityCodeScan.Tool/.NET Core/bin/Release/*.nupkg diff --git a/.github/workflows/pr.yml b/.github/workflows/pr.yml index fa15ff65..2be5f40a 100644 --- a/.github/workflows/pr.yml +++ b/.github/workflows/pr.yml @@ -1,3 +1,4 @@ +name: "Pull request" on: pull_request: diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml new file mode 100644 index 00000000..9047c176 --- /dev/null +++ b/.github/workflows/publish.yml @@ -0,0 +1,82 @@ +name: "2. Publish" +on: + release: + types: [published] + +permissions: {} + +jobs: + release-notes: + permissions: + contents: write + runs-on: ubuntu-latest + steps: + + - uses: actions/checkout@v2 + with: + ref: vs2019 + persist-credentials: true + + - name: Append release body to release notes + env: + release_notes: ${{github.event.release.body}} + run: | + git config --global user.email "octokit@github.com" + git config --global user.name "Octokit" + head --lines=2 website/releasenotes.md > website/new_releasenotes.md + echo "$release_notes" >> website/new_releasenotes.md + tail --lines=+2 website/releasenotes.md >> website/new_releasenotes.md + mv website/new_releasenotes.md website/releasenotes.md + sed -i 's/[0-9]\.[0-9]\.[0-9]\.[0-9]<\/AssemblyVersionNumber>/${{github.event.release.tag_name}}.9<\/AssemblyVersionNumber>/g' Directory.Build.props + git add . + git commit -a -m "Update release notes & bump dev version" + git push + shell: bash + + publish: + needs: [release-notes] + runs-on: windows-2022 + steps: + + - uses: actions/checkout@v2 + with: + persist-credentials: false + + - name: Download artifacts + uses: dsaltares/fetch-gh-release-asset@c3deec3cfc2231c6f842eef6d624b55223743c43 + with: + file: 'security-scan.${{github.event.release.tag_name}}.nupkg' + + - name: Download artifacts + uses: dsaltares/fetch-gh-release-asset@c3deec3cfc2231c6f842eef6d624b55223743c43 + with: + file: 'SecurityCodeScan.VS2019.${{github.event.release.tag_name}}.nupkg' + + - name: Download artifacts + uses: dsaltares/fetch-gh-release-asset@c3deec3cfc2231c6f842eef6d624b55223743c43 + with: + file: 'SecurityCodeScan.VS2019.Vsix.vsix' + + - name: Publish vsix + shell: powershell + env: + marketplace_token: ${{ secrets.MARKETPLACE_TOKEN }} + run: | + Write-Host "Pushing to visual studio market place" + $visualStudioInstallation = & "${env:ProgramFiles(x86)}\Microsoft Visual Studio\Installer\vswhere.exe" -latest -products * -requires Microsoft.VisualStudio.Component.VSSDK -property installationPath + $vsixPublisher = Join-Path $visualStudioInstallation 'VSSDK\VisualStudioIntegration\Tools\Bin\VsixPublisher.exe' + & $vsixPublisher login -publisherName JaroslavLobacevski -personalAccessToken $env:marketplace_token + $vsix = Get-ChildItem -File SecurityCodeScan.VS2019.Vsix.vsix -recurse | Select-Object -First 1 -ExpandProperty FullName + $ManifestPath = ".\SecurityCodeScan.Vsix\marketplace.json" + & $vsixPublisher publish -payload $vsix -publishManifest $ManifestPath -personalAccessToken $env:marketplace_token + # currently vsixpublisher.exe throws non critical telemetry exception but does the job done + # force successful exit code + [Environment]::Exit(0) + + - name: Publish nugets + shell: bash + env: + nuget_token: ${{ secrets.NUGET_TOKEN }} + run: | + dotnet nuget push "SecurityCodeScan.VS2019.${{github.event.release.tag_name}}.nupkg" -k $nuget_token -s https://api.nuget.org/v3/index.json + dotnet nuget push "security-scan.${{github.event.release.tag_name}}.nupkg" -k $nuget_token -s https://api.nuget.org/v3/index.json diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 56c25364..ecf1dd6b 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -1,3 +1,4 @@ +name: "1. Make release draft" on: workflow_dispatch: inputs: @@ -6,13 +7,39 @@ on: required: true type: string +permissions: {} + jobs: - release: + build: uses: security-code-scan/security-code-scan/.github/workflows/build.yml@vs2019 with: - version: ${{ github.event.inputs.version }} configuration: Release - publish: true - secrets: - MARKETPLACE_TOKEN: ${{ secrets.MARKETPLACE_TOKEN }} - NUGET_TOKEN: ${{ secrets.NUGET_TOKEN }} + version: ${{inputs.version}} + makeartifacts: true + + release: + permissions: + contents: write + needs: build + runs-on: ubuntu-latest + steps: + + - name: Download artifacts + uses: actions/download-artifact@fb598a63ae348fa914e94cd0ff38f362e927b741 + with: + name: packages + path: artifacts + + - name: Create draft release + uses: softprops/action-gh-release@8a65c813553f4d05769635eb1b70180d25b9b61b + with: + draft: true + name: ${{inputs.version}} + tag_name: ${{inputs.version}} + fail_on_unmatched_files: true + generate_release_notes: false + files: | + ./artifacts/security-scan4x.zip + ./artifacts/SecurityCodeScan/bin/Release/**/*.nupkg + ./artifacts/SecurityCodeScan.Vsix/bin/Release/*.vsix + ./artifacts/SecurityCodeScan.Tool/.NET Core/bin/Release/*.nupkg diff --git a/Directory.Build.props b/Directory.Build.props index fe8917fc..be344e8a 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -10,7 +10,7 @@ - 5.6.7.0 + 5.6.7.9 diff --git a/SecurityCodeScan.Tool/.NET Core/security-scan.csproj b/SecurityCodeScan.Tool/.NET Core/security-scan.csproj index 1b785cd6..3c065b7c 100644 --- a/SecurityCodeScan.Tool/.NET Core/security-scan.csproj +++ b/SecurityCodeScan.Tool/.NET Core/security-scan.csproj @@ -3,7 +3,7 @@ enable Exe - netcoreapp3.1;net5.0;net6.0 + net6.0;net5.0;netcoreapp3.1 false true security-scan diff --git a/SecurityCodeScan.Tool/Program.cs b/SecurityCodeScan.Tool/Program.cs index 7a2ebc5e..5a2a2dfe 100644 --- a/SecurityCodeScan.Tool/Program.cs +++ b/SecurityCodeScan.Tool/Program.cs @@ -159,6 +159,7 @@ internal class ParsedOptions public HashSet includeWarnings = new HashSet(); public List excludeProjects = new List(); public List includeProjects = new List(); + public string sdkPath = null; public OptionSet inputOptions = null; @@ -185,6 +186,7 @@ public void Parse(string[] args) { "n|no-banner", "(Optional) don't show the banner", r => { showBanner = r == null; } }, { "v|verbose", "(Optional) more diagnostic messages", r => { verbose = r != null; } }, { "ignore-msbuild-errors", "(Optional) Don't stop on MSBuild errors", r => { ignoreMsBuildErrors = r != null; } }, + { "sdk-path=", "(Optional) Path to .NET SDK to use.", r => { sdkPath = r; } }, { "f|fail-any-warn","(Optional) fail on any warnings with non-zero exit code", r => { failOnWarning = r != null; } }, { "h|?|help", "show this message and exit", h => shouldShowHelp = h != null }, }; @@ -266,13 +268,53 @@ private static async Task Main(string[] args) var returnCode = 0; // Attempt to set the version of MSBuild. - var visualStudioInstances = MSBuildLocator.QueryVisualStudioInstances().ToArray(); - var instance = visualStudioInstances.OrderByDescending(x => x.Version).FirstOrDefault(); - if (instance != null) + if (parsedOptions.sdkPath != null) { - if (parsedOptions.verbose) - Console.WriteLine($"Using MSBuild at '{instance.MSBuildPath}' to load projects."); - MSBuildLocator.RegisterInstance(instance); + void ApplyDotNetSdkEnvironmentVariables(string dotNetSdkPath) + { + const string MSBUILD_EXE_PATH = nameof(MSBUILD_EXE_PATH); + const string MSBuildExtensionsPath = nameof(MSBuildExtensionsPath); + const string MSBuildSDKsPath = nameof(MSBuildSDKsPath); + + var variables = new Dictionary + { + [MSBUILD_EXE_PATH] = Path.Combine(dotNetSdkPath, "MSBuild.dll"), + [MSBuildExtensionsPath] = dotNetSdkPath, + [MSBuildSDKsPath] = Path.Combine(dotNetSdkPath, "Sdks") + }; + + foreach (var kvp in variables) + { + Environment.SetEnvironmentVariable(kvp.Key, kvp.Value); + } + } + ApplyDotNetSdkEnvironmentVariables(parsedOptions.sdkPath); + // Find and load NuGet assemblies if msbuildPath is in a VS installation + string nugetPath = Path.GetFullPath(Path.Combine(parsedOptions.sdkPath, "..", "..", "..", "Common7", "IDE", "CommonExtensions", "Microsoft", "NuGet")); + if (Directory.Exists(nugetPath)) + { + MSBuildLocator.RegisterMSBuildPath(new string[] { parsedOptions.sdkPath, nugetPath }); + } + else + { + MSBuildLocator.RegisterMSBuildPath(parsedOptions.sdkPath); + } + } + else + { + var visualStudioInstances = MSBuildLocator.QueryVisualStudioInstances().ToArray(); + var instance = visualStudioInstances.OrderByDescending(x => x.Version).FirstOrDefault(); + if (instance != null) + { + if (parsedOptions.verbose) + Console.WriteLine($"Using MSBuild at '{instance.MSBuildPath}' to load projects."); + MSBuildLocator.RegisterInstance(instance); + } + else + { + Console.WriteLine($"Failed to find MSBuild path. Try specifying `sdk-path=` as a command line parameter."); + return 1; + } } var properties = new Dictionary() { { "AdditionalFileItemNames", "$(AdditionalFileItemNames);Content" } }; @@ -340,6 +382,8 @@ private static async Task Main(string[] args) Console.WriteLine($"Skipped: {project.FilePath} excluded from analysis"); continue; } + + projects.Add(project); } } else