diff --git a/.github/workflows/ci-cd.yml b/.github/workflows/ci-cd.yml new file mode 100644 index 000000000..4ab9ed7c3 --- /dev/null +++ b/.github/workflows/ci-cd.yml @@ -0,0 +1,143 @@ +name: CI/CD Pipeline + +on: [push, pull_request, workflow_dispatch] + +jobs: + ci: + name: Continuous Integration + runs-on: ubuntu-latest + outputs: + latest_version: ${{ steps.tag_generator.outputs.new_version }} + is_default_branch: ${{ steps.conditionals_handler.outputs.is_default_branch }} + env: + ARTIFACTS_FOLDER: ${{ github.workspace }}/Artifacts + GITHUB_RUN_NUMBER: ${{ github.run_number }} + steps: + - name: Setup .NET + uses: actions/setup-dotnet@v1 + with: + dotnet-version: 5.0.x + + - name: Data gatherer + id: data_gatherer + shell: pwsh + run: | + # Get default branch + $repo = 'microsoft/OpenAPI.NET' + $defaultBranch = Invoke-RestMethod -Method GET -Uri https://api.github.com/repos/$repo | Select-Object -ExpandProperty default_branch + Write-Output "::set-output name=default_branch::$(echo $defaultBranch)" + + - name: Conditionals handler + id: conditionals_handler + shell: pwsh + run: | + $defaultBranch = "${{ steps.data_gatherer.outputs.default_branch }}" + $githubRef = "${{ github.ref }}" + $isDefaultBranch = 'false' + if ( $githubRef -like "*$defaultBranch*" ) { + $isDefaultBranch = 'true' + } + Write-Output "::set-output name=is_default_branch::$(echo $isDefaultBranch)" + + - name: Checkout repository + id: checkout_repo + uses: actions/checkout@v2 + with: + token: ${{ secrets.GITHUB_TOKEN }} + fetch-depth: 0 + + - if: steps.conditionals_handler.outputs.is_default_branch == 'true' + name: Bump GH tag + id: tag_generator + uses: mathieudutour/github-tag-action@v5.4 + with: + github_token: ${{ secrets.GITHUB_TOKEN }} + default_bump: false + release_branches: ${{ steps.data_gatherer.outputs.default_branch }} + + - name: Build projects + id: build_projects + shell: pwsh + run: | + $projectsArray = @( + '.\src\Microsoft.OpenApi\Microsoft.OpenApi.csproj', + '.\src\Microsoft.OpenApi.Readers\Microsoft.OpenApi.Readers.csproj', + '.\src\Microsoft.OpenApi.Tool\Microsoft.OpenApi.Tool.csproj' + ) + $gitNewVersion = if ("${{ steps.tag_generator.outputs.new_version }}") {"${{ steps.tag_generator.outputs.new_version }}"} else {$null} + $projectCurrentVersion = ([xml](Get-Content .\src\Microsoft.OpenApi\Microsoft.OpenApi.csproj)).Project.PropertyGroup.Version + $projectNewVersion = $gitNewVersion ?? $projectCurrentVersion + + $projectsArray | ForEach-Object { + dotnet build $PSItem ` + -c Release # ` + # -o $env:ARTIFACTS_FOLDER ` + # /p:Version=$projectNewVersion + } + + # Move NuGet packages to separate folder for pipeline convenience + # New-Item Artifacts/NuGet -ItemType Directory + # Get-ChildItem Artifacts/*.nupkg | Move-Item -Destination "Artifacts/NuGet" + + - name: Run unit tests + id: run_unit_tests + shell: pwsh + run: | + $testProjectsArray = @( + '.\test\Microsoft.OpenApi.Tests\Microsoft.OpenApi.Tests.csproj', + '.\test\Microsoft.OpenApi.Readers.Tests\Microsoft.OpenApi.Readers.Tests.csproj', + '.\test\Microsoft.OpenApi.SmokeTests\Microsoft.OpenApi.SmokeTests.csproj' + ) + + $testProjectsArray | ForEach-Object { + dotnet test $PSItem ` + -c Release + } + + # - if: steps.tag_generator.outputs.new_version != '' + # name: Upload NuGet packages as artifacts + # id: ul_packages_artifact + # uses: actions/upload-artifact@v1 + # with: + # name: NuGet packages + # path: Artifacts/NuGet/ + + cd: + if: needs.ci.outputs.is_default_branch == 'true' && needs.ci.outputs.latest_version != '' + name: Continuous Deployment + needs: ci + runs-on: ubuntu-latest + steps: + # - name: Download and extract NuGet packages + # id: dl_packages_artifact + # uses: actions/download-artifact@v2 + # with: + # name: NuGet packages + # path: NuGet/ + + # - name: Push NuGet packages to NuGet.org + # id: push_nuget_packages + # continue-on-error: true + # shell: pwsh + # run: | + # Get-ChildItem NuGet/*.nupkg | ForEach-Object { + # nuget push $PSItem ` + # -ApiKey $env:NUGET_API_KEY ` + # -Source https://api.nuget.org/v3/index.json + # } + # env: + # NUGET_API_KEY: ${{ secrets.NUGET_API_KEY }} + + - name: Create and publish release + id: create_release + uses: softprops/action-gh-release@v1 + with: + name: OpenApi v${{ needs.ci.outputs.latest_version }} + tag_name: v${{ needs.ci.outputs.latest_version }} + # files: | + # NuGet/Microsoft.OpenApi.${{ needs.ci.outputs.latest_version }}.nupkg + # NuGet/Microsoft.OpenApi.Readers.${{ needs.ci.outputs.latest_version }}.nupkg + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + +# Built with ❤ by [Pipeline Foundation](https://pipeline.foundation) \ No newline at end of file diff --git a/docs/CI-CD_DOCUMENTATION.md b/docs/CI-CD_DOCUMENTATION.md new file mode 100644 index 000000000..40053cf82 --- /dev/null +++ b/docs/CI-CD_DOCUMENTATION.md @@ -0,0 +1,81 @@ +# CI/CD documentation + +## 1. Run workflow manually + +1. Go to the project's GitHub repository and click on the **Actions** tab + +2. From the "Workflows" list on the left, click on "CI/CD Pipeline" + +3. On the right, next to the "This workflow has a workflow_dispatch event trigger" label, click on the "Run workflow" dropdown, make sure the default branch is selected (if not manually changed, should be main or master) in the "Use workflow from" dropdown and click the "Run workflow" button + +![Actions_workflow_dispatch](images/Actions_workflow_dispatch.png) + +NOTE: **screenshots are only exemplary** + +
+ +## 2. Automated NuGet publishing + +To setup the automated publishing to NuGet: + +1. Go to the repo **Settings** tab -> **Secrets** + +2. Add a secret with the name `NUGET_API_KEY` and as value use an API key from NuGet.org that is assigned to the packages for this project + +NOTE: the automated NuGet publishing is execute **only** when a release is triggered by the ["Automated versioning" feature](#3-automated-versioning) + +
+ +## 3. Automated versioning + +Automatically bumps up the GitHub tag in the repo and executes the CD job + +Note: **not every commit to your default branch creates a release** + +Follow these instructions for any commit (push or PR merge) to your default branch, you would like to execute the automated versioning. + +You would need one of three keywords at the start of your commit title. Each of the three keywords corresponds to a number in your release version i.e. v1.2.3. The release versioning uses the ["Conventional Commits" specification](https://www.conventionalcommits.org/en/v1.0.0/): + +- "fix: ..." - this keyword corresponds to the last number v1.2.**3**, also known as PATCH; +- "feat: ..." - this keyword corresponds to the middle number v1.**2**.3, also known as MINOR; +- "perf: ..." - this keyword corresponds to the first number v**1**.2.3, also known as MAJOR. In addition, to trigger a MAJOR release, you would need to write "BREAKING CHANGE: ..." in the description of the commit, with an empty line above it to indicate it is in the