From 5ac02e80f652484be085ee3a92f17a34b8bd0df0 Mon Sep 17 00:00:00 2001 From: Sergio Pedri Date: Mon, 30 Jun 2025 10:54:51 -0700 Subject: [PATCH 1/7] Add initial GitHub Actions workflow --- .github/workflows/ci-build.yml | 64 ++++++++++++++++++++++++++++++++++ 1 file changed, 64 insertions(+) create mode 100644 .github/workflows/ci-build.yml diff --git a/.github/workflows/ci-build.yml b/.github/workflows/ci-build.yml new file mode 100644 index 000000000..5d75d47d9 --- /dev/null +++ b/.github/workflows/ci-build.yml @@ -0,0 +1,64 @@ +name: CI-build + +# This workflow should trigger in the following cases: +# - The commit is any push in any branch in the repo +# - The commit is a published PR from anyone else +# +# This setup is done to avoid duplicate runs for the same exact commits, for cases when +# the PR is done from a branch in this repo, which would already trigger the "push" +# condition. This way, only PRs from forks will actually trigger the workflow. +# +# Because we can't really check these conditions from the global triggers here, they are +# added to the two root jobs below instead. If canceled, the whole workflow will stop. +on: [push, pull_request] + +jobs: + build-and-test: + if: >- + github.event_name == 'push' || + github.event.pull_request.user.login != github.repository_owner + strategy: + matrix: + configuration: [Debug, Release] + runs-on: windows-2022 + steps: + - name: Git checkout + uses: actions/checkout@v4 + + # Build the whole solution + - name: Build solution + run: dotnet build -c ${{matrix.configuration}} /bl + - name: Upload MSBuild binary log + uses: actions/upload-artifact@v4 + with: + name: msbuild_log_${{matrix.configuration}} + path: msbuild.binlog + if-no-files-found: error + + # Run tests + - name: Test solution + run: dotnet test --no--build -c ${{matrix.configuration}} -l "trx;LogFileName=VSTestResults.trx" + + # Publish test results + - name: Publish test results + uses: actions/upload-artifact@v4 + with: + name: '**/TestResults/VSTestResults.trx' + path: VSTestResults + if-no-files-found: error + + # Pack solution + - name: Pack solution + run: dotnet pack --no-build -c ${{matrix.configuration}} + + # Sign packages + - name: Sign packages + run: echo "TODO" + + # Publish build artifacts + - name: Publish package artifacts + uses: actions/upload-artifact@v4 + with: + name: 'bin/nupkg/*.nupkg' + path: Packages + if-no-files-found: error From 11cec6634289a6712bf0e4fa93e319508807b60a Mon Sep 17 00:00:00 2001 From: Sergio Pedri Date: Mon, 7 Jul 2025 10:21:55 -0700 Subject: [PATCH 2/7] Delete azure-pipelines.yml --- azure-pipelines.yml | 73 --------------------------------------------- 1 file changed, 73 deletions(-) delete mode 100644 azure-pipelines.yml diff --git a/azure-pipelines.yml b/azure-pipelines.yml deleted file mode 100644 index 50ebd69aa..000000000 --- a/azure-pipelines.yml +++ /dev/null @@ -1,73 +0,0 @@ -trigger: -- main -- dev/* -- rel/* - -pr: -- main -- dev/* -- rel/* - -pool: - vmImage: windows-latest - -variables: - Build.Configuration: Release - -jobs: -- job: BuildBits - displayName: Build and Test solution - timeoutInMinutes: 60 - steps: - - # Set Build Version - - script: nbgv cloud - displayName: Set NBGV version - - # Restore solution - - script: dotnet restore -p:Configuration=$(Build.Configuration) - displayName: Restore solution - - # Build solution - - script: dotnet build --no-restore -c $(Build.Configuration) - displayName: Build solution - - # Test solution # - - # Run .NET 8 unit tests - - script: dotnet test --no-build -c $(Build.Configuration) -f net8.0 -l "trx;LogFileName=VSTestResults_net8.0.trx" - displayName: Run .NET 8 unit tests - - # Run .NET 7 unit tests - - script: dotnet test --no-build -c $(Build.Configuration) -f net7.0 -l "trx;LogFileName=VSTestResults_net7.0.trx" - displayName: Run .NET 7 unit tests - - # Run .NET Framework 4.7.2 unit tests - - script: dotnet test --no-build -c $(Build.Configuration) -f net472 -l "trx;LogFileName=VSTestResults_net472.trx" - displayName: Run .NET Framework 4.7.2 unit tests - - # Publish test results - - task: PublishTestResults@2 - displayName: Publish test results - inputs: - testResultsFormat: VSTest - testResultsFiles: '**/TestResults/VSTestResults*.trx' - condition: always() - - # Pack solution - - script: dotnet pack --no-build -c $(Build.Configuration) - displayName: Pack solution - - # Sign packages - - pwsh: build/Sign-Package.ps1 - displayName: Authenticode sign packages - env: - SignClientUser: $(SignClientUser) - SignClientSecret: $(SignClientSecret) - ArtifactDirectory: bin/nupkg - condition: and(succeeded(), ne(variables['Build.Reason'], 'PullRequest'), ne(variables['SignClientUser'], ''), ne(variables['SignClientSecret'], '')) - - # Publish build artifacts - - publish: bin/nupkg - artifact: Packages - displayName: Publish package artifacts From 7633a20fd9a7c1e165036fa27c644768c1019f10 Mon Sep 17 00:00:00 2001 From: Sergio Pedri Date: Mon, 7 Jul 2025 10:27:12 -0700 Subject: [PATCH 3/7] Install the .NET SDK in the workflow --- .github/workflows/ci-build.yml | 6 +++++- global.json | 2 +- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci-build.yml b/.github/workflows/ci-build.yml index 5d75d47d9..737477003 100644 --- a/.github/workflows/ci-build.yml +++ b/.github/workflows/ci-build.yml @@ -23,7 +23,11 @@ jobs: runs-on: windows-2022 steps: - name: Git checkout - uses: actions/checkout@v4 + uses: actions/checkout@v4 + - name: Install .NET SDK + uses: actions/setup-dotnet@v4 + with: + global-json-file: global.json # Build the whole solution - name: Build solution diff --git a/global.json b/global.json index 00b67caef..a14813522 100644 --- a/global.json +++ b/global.json @@ -1,6 +1,6 @@ { "sdk": { - "version": "9.0.100", + "version": "9.0.301", "rollForward": "latestFeature", "allowPrerelease": false } From 5ccc08786d28a3ab832bfad5fade66aca129b83c Mon Sep 17 00:00:00 2001 From: Michael Hawker <24302614+michael-hawker@users.noreply.github.com> Date: Tue, 4 Nov 2025 17:13:50 -0800 Subject: [PATCH 4/7] Add Signing and Release steps to GitHub Actions Pipeline --- .github/workflows/SignClientFileList.txt | 1 + .github/workflows/ci-build.yml | 127 +++++++++++++++++++++-- 2 files changed, 120 insertions(+), 8 deletions(-) create mode 100644 .github/workflows/SignClientFileList.txt diff --git a/.github/workflows/SignClientFileList.txt b/.github/workflows/SignClientFileList.txt new file mode 100644 index 000000000..85960db79 --- /dev/null +++ b/.github/workflows/SignClientFileList.txt @@ -0,0 +1 @@ +**/CommunityToolkit.* diff --git a/.github/workflows/ci-build.yml b/.github/workflows/ci-build.yml index 737477003..d3e19c460 100644 --- a/.github/workflows/ci-build.yml +++ b/.github/workflows/ci-build.yml @@ -12,6 +12,12 @@ name: CI-build # added to the two root jobs below instead. If canceled, the whole workflow will stop. on: [push, pull_request] +env: + DOTNET_VERSION: ${{ '9.0.x' }} + IS_MAIN: ${{ github.ref == 'refs/heads/main' }} + IS_PR: ${{ startsWith(github.ref, 'refs/pull/') }} + IS_RELEASE: ${{ startsWith(github.ref, 'refs/heads/rel/') }} + jobs: build-and-test: if: >- @@ -24,6 +30,7 @@ jobs: steps: - name: Git checkout uses: actions/checkout@v4 + - name: Install .NET SDK uses: actions/setup-dotnet@v4 with: @@ -53,16 +60,120 @@ jobs: # Pack solution - name: Pack solution - run: dotnet pack --no-build -c ${{matrix.configuration}} + run: dotnet pack --no-build -c ${{matrix.configuration}} + + # Push Pull Request Packages to our DevOps Artifacts Feed (see nuget.config) + - name: Push Pull Request Packages (if not fork) + if: ${{ env.IS_PR == 'true' && matrix.configuration == 'Release' && github.event.pull_request.head.repo.full_name == github.repository && github.actor != 'dependabot[bot]' }} + run: | + dotnet nuget add source https://pkgs.dev.azure.com/dotnet/CommunityToolkit/_packaging/CommunityToolkit-PullRequests/nuget/v3/index.json ` + --name PullRequests ` + --username dummy --password ${{ secrets.DEVOPS_PACKAGE_PUSH_TOKEN }} + dotnet nuget push "*.nupkg" --api-key dummy --source PullRequests --skip-duplicate - # Sign packages - - name: Sign packages - run: echo "TODO" + - name: Upload Package List + uses: actions/upload-artifact@v4 + if: ${{ env.IS_PR == 'false' && matrix.configuration == 'Release' }} + with: + name: nuget-list-dotnet + if-no-files-found: error + path: | + ${{ github.workspace }}/.github/workflows/SignClientFileList.txt - # Publish build artifacts - - name: Publish package artifacts + # if we're not doing a PR build (or it's a PR from a fork) then we upload our packages so we can sign as a separate job or have available to test. + - name: Upload Packages Artifacts uses: actions/upload-artifact@v4 + if: ${{ env.IS_PR == 'false' || github.event.pull_request.head.repo.full_name != github.repository }} with: - name: 'bin/nupkg/*.nupkg' - path: Packages + name: nuget-packages-dotnet if-no-files-found: error + path: | + ./*.nupkg + + + sign: + needs: [build-and-test] + if: ${{ env.IS_MAIN == 'true' || env.Is_RELEASE == 'true' }} + runs-on: windows-latest + permissions: + id-token: write # Required for requesting the JWT + + steps: + - name: Install .NET SDK v${{ env.DOTNET_VERSION }} + uses: actions/setup-dotnet@v4 + with: + dotnet-version: ${{ env.DOTNET_VERSION }} + + - name: Download Package List + uses: actions/download-artifact@v4 + with: + name: nuget-list-dotnet + path: ./ + + - name: Download built packages for .NCT + uses: actions/download-artifact@v4 + with: + name: nuget-packages-dotnet + path: ./packages + + - name: Install Signing Tool + run: dotnet tool install --tool-path ./tools sign --version 0.9.1-beta.25379.1 + + - name: Sign Packages + run: > + ./tools/sign code azure-key-vault + **/*.nupkg + --base-directory "${{ github.workspace }}/packages" + --file-list "${{ github.workspace }}/SignClientFileList.txt" + --timestamp-url "http://timestamp.digicert.com" + --publisher-name ".NET Foundation" + --description ".NET Community Toolkit" + --description-url "https://github.com/CommunityToolkit/dotnet" + --azure-key-vault-url "${{ secrets.SIGN_KEY_VAULT_URL }}" + --azure-key-vault-client-id ${{ secrets.SIGN_CLIENT_ID }} + --azure-key-vault-client-secret "${{ secrets.SIGN_CLIENT_SECRET }}" + --azure-key-vault-tenant-id ${{ secrets.SIGN_TENANT_ID }} + --azure-key-vault-certificate "${{ secrets.SIGN_CERTIFICATE }}" + --verbosity Information + + - name: Push Signed Packages + run: | + dotnet nuget add source https://pkgs.dev.azure.com/dotnet/CommunityToolkit/_packaging/CommunityToolkit-MainLatest/nuget/v3/index.json ` + --name MainLatest ` + --username dummy --password ${{ secrets.DEVOPS_PACKAGE_PUSH_TOKEN }} + dotnet nuget push "**/*.nupkg" --api-key dummy --source MainLatest --skip-duplicate + + - name: Upload Signed Packages as Artifacts (for release) + uses: actions/upload-artifact@v4 + if: ${{ env.IS_RELEASE == 'true' }} + with: + name: signed-nuget-packages-dotnet + if-no-files-found: error + path: | + ${{ github.workspace }}/packages/**/*.nupkg + + release: + if: ${{ env.IS_RELEASE == 'true' }} + needs: [sign] + environment: nuget-release-gate # This gates this job until manually approved + runs-on: ubuntu-latest + + steps: + - name: Install .NET SDK v${{ env.DOTNET_VERSION }} + uses: actions/setup-dotnet@v4 + with: + dotnet-version: ${{ env.DOTNET_VERSION }} + + - name: Download signed packages for .NCT + uses: actions/download-artifact@v4 + with: + name: signed-nuget-packages-dotnet + path: ./packages + + - name: Push to NuGet.org + run: > + dotnet nuget push + **/*.nupkg + --source https://api.nuget.org/v3/index.json + --api-key ${{ secrets.NUGET_PACKAGE_PUSH_TOKEN }} + --skip-duplicate From aad705cc2140190c6ef4a7c075d4e97a024a5ea8 Mon Sep 17 00:00:00 2001 From: Michael Hawker <24302614+michael-hawker@users.noreply.github.com> Date: Tue, 4 Nov 2025 17:34:52 -0800 Subject: [PATCH 5/7] Forgot extra gate for uploading release build only --- .github/workflows/ci-build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci-build.yml b/.github/workflows/ci-build.yml index d3e19c460..346b96f29 100644 --- a/.github/workflows/ci-build.yml +++ b/.github/workflows/ci-build.yml @@ -83,7 +83,7 @@ jobs: # if we're not doing a PR build (or it's a PR from a fork) then we upload our packages so we can sign as a separate job or have available to test. - name: Upload Packages Artifacts uses: actions/upload-artifact@v4 - if: ${{ env.IS_PR == 'false' || github.event.pull_request.head.repo.full_name != github.repository }} + if: ${{ (env.IS_PR == 'false' || github.event.pull_request.head.repo.full_name != github.repository) && matrix.configuration == 'Release' }} with: name: nuget-packages-dotnet if-no-files-found: error From 4cab9faae633b7cf0fbd7bfb046d3d66d48b68b7 Mon Sep 17 00:00:00 2001 From: Sergio Pedri Date: Wed, 5 Nov 2025 10:58:50 -0800 Subject: [PATCH 6/7] Apply suggestions from code review MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Edouard Choinière <27212526+echoix@users.noreply.github.com> --- .github/workflows/ci-build.yml | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/.github/workflows/ci-build.yml b/.github/workflows/ci-build.yml index 346b96f29..a6a069502 100644 --- a/.github/workflows/ci-build.yml +++ b/.github/workflows/ci-build.yml @@ -29,10 +29,10 @@ jobs: runs-on: windows-2022 steps: - name: Git checkout - uses: actions/checkout@v4 + uses: actions/checkout@v5 - name: Install .NET SDK - uses: actions/setup-dotnet@v4 + uses: actions/setup-dotnet@v5 with: global-json-file: global.json @@ -40,7 +40,7 @@ jobs: - name: Build solution run: dotnet build -c ${{matrix.configuration}} /bl - name: Upload MSBuild binary log - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v5 with: name: msbuild_log_${{matrix.configuration}} path: msbuild.binlog @@ -52,7 +52,7 @@ jobs: # Publish test results - name: Publish test results - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v5 with: name: '**/TestResults/VSTestResults.trx' path: VSTestResults @@ -72,7 +72,7 @@ jobs: dotnet nuget push "*.nupkg" --api-key dummy --source PullRequests --skip-duplicate - name: Upload Package List - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v5 if: ${{ env.IS_PR == 'false' && matrix.configuration == 'Release' }} with: name: nuget-list-dotnet @@ -82,7 +82,7 @@ jobs: # if we're not doing a PR build (or it's a PR from a fork) then we upload our packages so we can sign as a separate job or have available to test. - name: Upload Packages Artifacts - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v5 if: ${{ (env.IS_PR == 'false' || github.event.pull_request.head.repo.full_name != github.repository) && matrix.configuration == 'Release' }} with: name: nuget-packages-dotnet @@ -100,18 +100,18 @@ jobs: steps: - name: Install .NET SDK v${{ env.DOTNET_VERSION }} - uses: actions/setup-dotnet@v4 + uses: actions/setup-dotnet@v5 with: dotnet-version: ${{ env.DOTNET_VERSION }} - name: Download Package List - uses: actions/download-artifact@v4 + uses: actions/download-artifact@v5 with: name: nuget-list-dotnet path: ./ - name: Download built packages for .NCT - uses: actions/download-artifact@v4 + uses: actions/download-artifact@v5 with: name: nuget-packages-dotnet path: ./packages @@ -144,7 +144,7 @@ jobs: dotnet nuget push "**/*.nupkg" --api-key dummy --source MainLatest --skip-duplicate - name: Upload Signed Packages as Artifacts (for release) - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v5 if: ${{ env.IS_RELEASE == 'true' }} with: name: signed-nuget-packages-dotnet @@ -160,12 +160,12 @@ jobs: steps: - name: Install .NET SDK v${{ env.DOTNET_VERSION }} - uses: actions/setup-dotnet@v4 + uses: actions/setup-dotnet@v5 with: dotnet-version: ${{ env.DOTNET_VERSION }} - name: Download signed packages for .NCT - uses: actions/download-artifact@v4 + uses: actions/download-artifact@v5 with: name: signed-nuget-packages-dotnet path: ./packages From 69a5aa44146a7dd3efd2c2d47ee53e37e1fc3f9d Mon Sep 17 00:00:00 2001 From: Sergio Pedri Date: Wed, 5 Nov 2025 11:13:17 -0800 Subject: [PATCH 7/7] Refactor CI workflow job names and .NET setup Standardized job and step names in the CI workflow for clarity and consistency. Updated .NET SDK installation to use global.json instead of a hardcoded version. Improved comments and formatting for better maintainability. --- .github/workflows/ci-build.yml | 32 +++++++++++++++++--------------- 1 file changed, 17 insertions(+), 15 deletions(-) diff --git a/.github/workflows/ci-build.yml b/.github/workflows/ci-build.yml index a6a069502..ee57e5f1a 100644 --- a/.github/workflows/ci-build.yml +++ b/.github/workflows/ci-build.yml @@ -13,12 +13,13 @@ name: CI-build on: [push, pull_request] env: - DOTNET_VERSION: ${{ '9.0.x' }} IS_MAIN: ${{ github.ref == 'refs/heads/main' }} IS_PR: ${{ startsWith(github.ref, 'refs/pull/') }} IS_RELEASE: ${{ startsWith(github.ref, 'refs/heads/rel/') }} jobs: + + # Build the solution, run all tests, push packages to the PR feed build-and-test: if: >- github.event_name == 'push' || @@ -62,8 +63,8 @@ jobs: - name: Pack solution run: dotnet pack --no-build -c ${{matrix.configuration}} - # Push Pull Request Packages to our DevOps Artifacts Feed (see nuget.config) - - name: Push Pull Request Packages (if not fork) + # Push PR packages to our DevOps artifacts feed (see nuget.config) + - name: Push PR packages (if not fork) if: ${{ env.IS_PR == 'true' && matrix.configuration == 'Release' && github.event.pull_request.head.repo.full_name == github.repository && github.actor != 'dependabot[bot]' }} run: | dotnet nuget add source https://pkgs.dev.azure.com/dotnet/CommunityToolkit/_packaging/CommunityToolkit-PullRequests/nuget/v3/index.json ` @@ -71,7 +72,7 @@ jobs: --username dummy --password ${{ secrets.DEVOPS_PACKAGE_PUSH_TOKEN }} dotnet nuget push "*.nupkg" --api-key dummy --source PullRequests --skip-duplicate - - name: Upload Package List + - name: Upload packages list uses: actions/upload-artifact@v5 if: ${{ env.IS_PR == 'false' && matrix.configuration == 'Release' }} with: @@ -80,8 +81,8 @@ jobs: path: | ${{ github.workspace }}/.github/workflows/SignClientFileList.txt - # if we're not doing a PR build (or it's a PR from a fork) then we upload our packages so we can sign as a separate job or have available to test. - - name: Upload Packages Artifacts + # If we're not doing a PR build (or it's a PR from a fork) then we upload our packages so we can sign as a separate job or have available to test + - name: Upload packages artifacts uses: actions/upload-artifact@v5 if: ${{ (env.IS_PR == 'false' || github.event.pull_request.head.repo.full_name != github.repository) && matrix.configuration == 'Release' }} with: @@ -90,7 +91,7 @@ jobs: path: | ./*.nupkg - + # Sign the packages for release sign: needs: [build-and-test] if: ${{ env.IS_MAIN == 'true' || env.Is_RELEASE == 'true' }} @@ -99,12 +100,12 @@ jobs: id-token: write # Required for requesting the JWT steps: - - name: Install .NET SDK v${{ env.DOTNET_VERSION }} + - name: Install .NET SDK uses: actions/setup-dotnet@v5 with: - dotnet-version: ${{ env.DOTNET_VERSION }} + global-json-file: global.json - - name: Download Package List + - name: Download packages list uses: actions/download-artifact@v5 with: name: nuget-list-dotnet @@ -119,7 +120,7 @@ jobs: - name: Install Signing Tool run: dotnet tool install --tool-path ./tools sign --version 0.9.1-beta.25379.1 - - name: Sign Packages + - name: Sign packages run: > ./tools/sign code azure-key-vault **/*.nupkg @@ -136,14 +137,14 @@ jobs: --azure-key-vault-certificate "${{ secrets.SIGN_CERTIFICATE }}" --verbosity Information - - name: Push Signed Packages + - name: Push signed packages run: | dotnet nuget add source https://pkgs.dev.azure.com/dotnet/CommunityToolkit/_packaging/CommunityToolkit-MainLatest/nuget/v3/index.json ` --name MainLatest ` --username dummy --password ${{ secrets.DEVOPS_PACKAGE_PUSH_TOKEN }} dotnet nuget push "**/*.nupkg" --api-key dummy --source MainLatest --skip-duplicate - - name: Upload Signed Packages as Artifacts (for release) + - name: Upload signed packages as artifacts (for release) uses: actions/upload-artifact@v5 if: ${{ env.IS_RELEASE == 'true' }} with: @@ -152,6 +153,7 @@ jobs: path: | ${{ github.workspace }}/packages/**/*.nupkg + # Push official packages to NuGet release: if: ${{ env.IS_RELEASE == 'true' }} needs: [sign] @@ -159,10 +161,10 @@ jobs: runs-on: ubuntu-latest steps: - - name: Install .NET SDK v${{ env.DOTNET_VERSION }} + - name: Install .NET SDK uses: actions/setup-dotnet@v5 with: - dotnet-version: ${{ env.DOTNET_VERSION }} + global-json-file: global.json - name: Download signed packages for .NCT uses: actions/download-artifact@v5