diff --git a/.editorconfig b/.editorconfig index 55b36d5..fabbed8 100644 --- a/.editorconfig +++ b/.editorconfig @@ -5,13 +5,13 @@ charset = utf-8 indent_style = tab indent_size = 4 # Spell checker configuration -spelling_exclusion_path = ./build/exclusion.dic +spelling_exclusion_path = "./build/exclusion.dic" -[*.{fs,fsx,yml}] +[*.{fs,fsx}] indent_style = space indent_size = 4 -[*.{md,markdown,json,js,csproj,fsproj,targets,targets,props}] +[*.{md,markdown,json,js,yml,csproj,fsproj,targets,targets,props}] indent_style = space indent_size = 2 diff --git a/.github/workflows/bootstrap/action.yml b/.github/workflows/bootstrap/action.yml new file mode 100644 index 0000000..1ee0518 --- /dev/null +++ b/.github/workflows/bootstrap/action.yml @@ -0,0 +1,49 @@ +--- +name: Bootstrap Checkout +description: Ensures all actions bootstrap the same + +outputs: + agent-version: + description: "The current agent version number" + value: ${{ steps.dotnet.outputs.agent-version }} + major-version: + description: "The current major version number, semver" + value: ${{ steps.dotnet.outputs.major-version }} + +runs: + using: "composite" + steps: + # Ensure we fetch all tags + - shell: bash + run: | + git fetch --prune --unshallow --tags + git tag --list + + - uses: actions/cache@v3 + with: + path: ~/.nuget/packages + key: ${{ runner.os }}-nuget-${{ hashFiles('**/*.[cf]sproj*') }} + restore-keys: | + ${{ runner.os }}-nuget + + - name: Setup dotnet + uses: actions/setup-dotnet@v3 + with: + dotnet-version: | + 6.0.x + 8.0.x + 6.0.x + - id: dotnet + shell: bash + run: | + dotnet --list-sdks + dotnet tool restore + AGENT_VERSION=$(dotnet minver -t=v -p=canary.0 -v=e) + echo "Version Number: ${AGENT_VERSION}" + echo "AGENT_VERSION=${AGENT_VERSION}" >> $GITHUB_ENV + echo "agent-version=${AGENT_VERSION}" >> $GITHUB_OUTPUT + echo "major-version=$(echo ${AGENT_VERSION} | cut -d"." -f1)" >> $GITHUB_OUTPUT + + + # Setup git config + - uses: elastic/apm-pipeline-library/.github/actions/setup-git@current \ No newline at end of file diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml deleted file mode 100644 index ffb3d0c..0000000 --- a/.github/workflows/ci.yml +++ /dev/null @@ -1,79 +0,0 @@ -name: Always be deploying - -on: - pull_request: - paths-ignore: - - 'README.md' - - '.editorconfig' - push: - paths-ignore: - - 'README.md' - - '.editorconfig' - branches: - - main - tags: - - "*.*.*" - -jobs: - test-windows: - runs-on: windows-latest - steps: - - uses: actions/checkout@v2 - with: - fetch-depth: 1 - - run: | - git fetch --prune --unshallow --tags - echo exit code $? - git tag --list - - uses: actions/setup-dotnet@v1 - with: - dotnet-version: | - 8.0.x - 6.0.x - source-url: https://nuget.pkg.github.com/elastic/index.json - env: - NUGET_AUTH_TOKEN: ${{secrets.GITHUB_TOKEN}} - - run: build.bat test - shell: cmd - name: Test - - build: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v2 - with: - fetch-depth: 1 - - run: | - git fetch --prune --unshallow --tags - echo exit code $? - git tag --list - - uses: actions/setup-dotnet@v1 - with: - # .NET 7 is sadly required for the licenses check tool - # https://github.com/tomchavakis/nuget-license/issues/200 - dotnet-version: | - 6.0.x - 7.0.x - 8.0.x - source-url: https://nuget.pkg.github.com/elastic/index.json - env: - NUGET_AUTH_TOKEN: ${{secrets.GITHUB_TOKEN}} - - - run: ./build.sh release - name: Release - - - name: publish canary packages github package repository - if: github.event_name == 'push' && startswith(github.ref, 'refs/heads') - shell: bash - # this is a best effort to push to GHPR, we've observed it being unavailable intermittently - continue-on-error: true - run: dotnet nuget push '.artifacts/package/release/*.nupkg' -k ${{secrets.GITHUB_TOKEN}} --skip-duplicate --no-symbols - - # Github packages requires authentication, this is likely going away in the future so for now we publish to feedz.io - - run: dotnet nuget push '.artifacts/package/release/*.nupkg' -k ${{secrets.FEEDZ_IO_API_KEY}} -s https://f.feedz.io/elastic/all/nuget/index.json --skip-duplicate --no-symbols - name: publish canary packages to feedz.io - if: false && github.event_name == 'push' && startswith(github.ref, 'refs/heads') - - - run: dotnet nuget push '.artifacts/package/release/*.nupkg' -k ${{secrets.NUGET_ORG_API_KEY}} -s https://api.nuget.org/v3/index.json --skip-duplicate --no-symbols - name: release to nuget.org - if: false && github.event_name == 'push' && startswith(github.ref, 'refs/tags') diff --git a/.github/workflows/license.yml b/.github/workflows/license.yml index c42f591..8d916ba 100644 --- a/.github/workflows/license.yml +++ b/.github/workflows/license.yml @@ -1,6 +1,6 @@ name: License headers -on: [pull_request] +on: [ pull_request ] jobs: build: @@ -8,8 +8,8 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v2 - - name: Check license headers - run: | - ./.github/check-license-headers.sh \ No newline at end of file + - name: Check license headers + run: | + ./.github/check-license-headers.sh \ No newline at end of file diff --git a/.github/workflows/prerelease.yml b/.github/workflows/prerelease.yml new file mode 100644 index 0000000..f73cc0e --- /dev/null +++ b/.github/workflows/prerelease.yml @@ -0,0 +1,37 @@ +name: release-main + +on: + push: + branches: [ "main" ] + +permissions: + contents: write + issues: write + packages: write + +env: + NUGET_PACKAGES: ${{ github.workspace }}/.nuget/packages + +jobs: + release: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Bootstrap Action Workspace + id: bootstrap + uses: ./.github/workflows/bootstrap + + - run: ./build.sh release + name: Release + + - name: publish canary packages github package repository + shell: bash + # this is a best effort to push to GHPR, we've observed it being unavailable intermittently + continue-on-error: true + run: dotnet nuget push '.artifacts/package/release/*.nupkg' -k ${{secrets.GITHUB_TOKEN}} --skip-duplicate --no-symbols + + # Github packages requires authentication, this is likely going away in the future so for now we publish to feedz.io + - run: dotnet nuget push '.artifacts/package/release/*.nupkg' -k ${{secrets.FEEDZ_IO_API_KEY}} -s https://f.feedz.io/elastic/all/nuget/index.json --skip-duplicate --no-symbols + name: publish canary packages to feedz.io + if: false && github.event_name == 'push' && startswith(github.ref, 'refs/heads') + diff --git a/.github/workflows/pull-request.yml b/.github/workflows/pull-request.yml new file mode 100644 index 0000000..d877e51 --- /dev/null +++ b/.github/workflows/pull-request.yml @@ -0,0 +1,50 @@ +name: Pull Request Validation + +on: + push: + branches: + - main + paths-ignore: + - '*.md' + - '*.asciidoc' + - 'docs/**' + pull_request: + paths-ignore: + - '*.md' + - '*.asciidoc' + - 'docs/**' + +permissions: + contents: read + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: ${{ github.ref != 'refs/heads/main' }} + +env: + NUGET_PACKAGES: ${{ github.workspace }}/.nuget/packages + +jobs: + test-windows: + runs-on: windows-latest + steps: + - uses: actions/checkout@v4 + - name: Bootstrap Action Workspace + id: bootstrap + uses: ./.github/workflows/bootstrap + + - run: build.bat test + shell: cmd + name: Test + + build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Bootstrap Action Workspace + id: bootstrap + uses: ./.github/workflows/bootstrap + + # We still run the full release build on pull-requests this ensures packages are validated ahead of time + - run: ./build.sh release + name: Release diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..410ac1c --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,112 @@ +name: release + +on: + release: + types: [published] + +permissions: + contents: write + issues: write + pull-requests: write + +env: + NUGET_PACKAGES: ${{ github.workspace }}/.nuget/packages + JOB_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }} + SLACK_CHANNEL: "#apm-agent-dotnet" + +jobs: + release: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + - name: Bootstrap Action Workspace + id: bootstrap + uses: ./.github/workflows/bootstrap + + - run: ./build.sh release --skiptests + name: Release + + - name: Prepare Nuget + uses: hashicorp/vault-action@v2.7.4 + with: + url: ${{ secrets.VAULT_ADDR }} + method: approle + roleId: ${{ secrets.VAULT_ROLE_ID }} + secretId: ${{ secrets.VAULT_SECRET_ID }} + secrets: | + secret/apm-team/ci/elastic-observability-nuget apiKey | REPO_API_KEY ; + secret/apm-team/ci/elastic-observability-nuget url | REPO_API_URL + + - name: Release to Nuget + run: dotnet nuget push '.artifacts/package/release/*.nupkg' -k ${REPO_API_KEY} -s ${REPO_API_URL} --skip-duplicate --no-symbols + + - if: ${{ success() }} + uses: elastic/apm-pipeline-library/.github/actions/slack-message@current + with: + url: ${{ secrets.VAULT_ADDR }} + roleId: ${{ secrets.VAULT_ROLE_ID }} + secretId: ${{ secrets.VAULT_SECRET_ID }} + channel: ${{ env.SLACK_CHANNEL }} + message: | + :large_green_circle: [${{ github.repository }}] Release *${{ github.ref_name }}* published. + Build: (<${{ env.JOB_URL }}|here>) + Release URL: () + + - if: ${{ failure() }} + uses: elastic/apm-pipeline-library/.github/actions/slack-message@current + with: + url: ${{ secrets.VAULT_ADDR }} + roleId: ${{ secrets.VAULT_ROLE_ID }} + secretId: ${{ secrets.VAULT_SECRET_ID }} + channel: ${{ env.SLACK_CHANNEL }} + message: | + :large_yellow_circle: [${{ github.repository }}] Release *${{ github.ref_name }}* could not be published. + Build: (<${{ env.JOB_URL }}|here>) + + post-release: + needs: [ 'release'] + runs-on: ubuntu-latest + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + GIT_TAG: v${{ needs.release.outputs.agent-version }} + NEW_BRANCH: update/${{ needs.release.outputs.agent-version }} + TARGET_BRANCH: ${{ needs.release.outputs.major-version }}.x + + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Setup git config + uses: elastic/apm-pipeline-library/.github/actions/setup-git@current + + - name: Create GitHub Pull Request if minor release. + run: | + echo "as long as there is a major.x branch" + existed_in_local=$(git ls-remote --heads origin ${TARGET_BRANCH}) + if [ -z "${existed_in_local}" ]; then + echo -e "::warning::Target branch '${TARGET_BRANCH}' does not exist." + exit 0 + fi + git checkout $TARGET_BRANCH + git checkout -b ${NEW_BRANCH} + git format-patch -k --stdout ${TARGET_BRANCH}...origin/main -- docs CHANGELOG.asciidoc | git am -3 -k + git push origin ${NEW_BRANCH} + gh pr create \ + --title "post-release: ${GIT_TAG}" \ + --body "Generated automatically with ${JOB_URL}" \ + --head "elastic:${NEW_BRANCH}" \ + --base "$TARGET_BRANCH" \ + --repo "${{ github.repository }}" + + - name: Create branch if major release + run: | + echo "as long as there is no a major.x branch" + existed_in_local=$(git ls-remote --heads origin ${TARGET_BRANCH}) + if [ -n "${existed_in_local}" ]; then + echo -e "::warning::Target branch '${TARGET_BRANCH}' does exist." + exit 0 + fi + git branch -D $TARGET_BRANCH + git push origin $TARGET_BRANCH diff --git a/build/scripts/CommandLine.fs b/build/scripts/CommandLine.fs index 321e6a0..4998afa 100644 --- a/build/scripts/CommandLine.fs +++ b/build/scripts/CommandLine.fs @@ -26,6 +26,7 @@ type Build = | [] SingleTarget | [] Token of string | [] SkipDirtyCheck + | [] SkipTests with interface IArgParserTemplate with member this.Usage = @@ -49,6 +50,7 @@ with | SingleTarget -> "Runs the provided sub command without running their dependencies" | Token _ -> "Token to be used to authenticate with github" | SkipDirtyCheck -> "Skip the clean checkout check that guards the release/publish targets" + | SkipTests -> "Skips running tests" member this.StepName = match FSharpValue.GetUnionFields(this, typeof) with diff --git a/build/scripts/Targets.fs b/build/scripts/Targets.fs index adaff74..da94794 100644 --- a/build/scripts/Targets.fs +++ b/build/scripts/Targets.fs @@ -40,7 +40,7 @@ let private pristineCheck (arguments:ParseResults) = | _, true -> printfn "The checkout folder does not have pending changes, proceeding" | _ -> failwithf "The checkout folder has pending changes, aborting. Specify -c to ./build.sh to skip this check" -let private test _ = +let private runTests _ = let testOutputPath = Paths.ArtifactPath "tests" let junitOutput = Path.Combine(testOutputPath.FullName, "junit-{assembly}-{framework}-test-results.xml") let loggerPathArgs = $"LogFilePath=%s{junitOutput}" @@ -53,7 +53,12 @@ let private test _ = @ tfmArgs @ ["--"; "RunConfiguration.CollectSourceInformation=true"] ) - } + } + +let private test (arguments:ParseResults) = + match arguments.TryGetResult SkipTests with + | Some _ -> runTests arguments + | None -> printfn "Skipping tests because --skiptests was provided" let private validateLicenses _ = let args = ["-u"; "-t"; "-i"; "Elastic.OpenTelemetry.sln"; "--use-project-assets-json" @@ -143,6 +148,7 @@ let Setup (parsed:ParseResults) = // flags | SingleTarget + | SkipTests | Token _ | SkipDirtyCheck -> Build.Ignore