Repository navigation
build(deps): bump the gradle-minor-patch group with 2 updates #153
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Tests | |
| # Triggers only on pull request lifecycle events: | |
| # - opened (PR creation) | |
| # - synchronize (push to the PR branch while the PR is open) | |
| # - reopened | |
| # These are the default `pull_request` activity types — listed explicitly | |
| # here for clarity. Pre-PR pushes don't run CI by design (saves minutes | |
| # during early WIP commits). | |
| on: | |
| pull_request: | |
| types: [opened, synchronize, reopened] | |
| branches: ['**'] | |
| permissions: | |
| contents: read | |
| # Cancel an in-progress run when a new commit lands on the same PR. | |
| concurrency: | |
| group: pr-${{ github.event.pull_request.number }} | |
| cancel-in-progress: true | |
| jobs: | |
| changes: | |
| # A documentation-only pull request does not need the suite below. But a | |
| # required status check can never be conditional -- the list is static -- and | |
| # a matrix job that GitHub SKIPS does not expand its name, so it reports no | |
| # per-combination context at all and the pull request waits forever for | |
| # checks that never arrive. Measured on MarketDataApp/sdk-php#95. | |
| # | |
| # So `Tests passed` at the bottom is the single context branch protection | |
| # requires, and this job decides whether the suite does any work. | |
| name: Decide whether the suite applies | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 2 | |
| outputs: | |
| code: ${{ steps.filter.outputs.code }} | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v7 | |
| with: | |
| fetch-depth: 0 | |
| - name: Detect whether anything but documentation changed | |
| id: filter | |
| env: | |
| BASE: ${{ github.event.pull_request.base.sha }} | |
| HEAD: ${{ github.event.pull_request.head.sha }} | |
| run: | | |
| # Only a pull request can be documentation-only here. A push, a release | |
| # and a workflow_call all run the suite. | |
| if [ "${{ github.event_name }}" != "pull_request" ]; then | |
| echo "code=true" >> "$GITHUB_OUTPUT" | |
| echo "Not a pull request, so running the suite." | |
| exit 0 | |
| fi | |
| # Every path out of here that is not a confident "documentation only" | |
| # says true. A gate that cannot see both ends of the diff must never | |
| # conclude that no code changed. | |
| for sha in "$BASE" "$HEAD"; do | |
| if ! git cat-file -e "$sha^{commit}" 2>/dev/null; then | |
| echo "code=true" >> "$GITHUB_OUTPUT" | |
| echo "Cannot reach $sha, so running the suite rather than guessing." | |
| exit 0 | |
| fi | |
| done | |
| # Three dots: the diff from the merge base, not from wherever the base | |
| # branch has moved to since. | |
| files=$(git diff --name-only "$BASE...$HEAD") | |
| echo "changed files:" | |
| printf '%s\n' "$files" | sed 's/^/ /' | |
| # Inverted deliberately. This lists what DOCUMENTATION looks like and | |
| # runs the suite for everything else. Enumerating code paths instead | |
| # would skip the suite the first time somebody adds a source directory | |
| # nobody remembered to list. | |
| if [ -n "$files" ] && ! printf '%s\n' "$files" | grep -qvE '(^docs/|\.md$)'; then | |
| echo "code=false" >> "$GITHUB_OUTPUT" | |
| echo "Documentation only: the suite skips, and Tests passed says so." | |
| else | |
| echo "code=true" >> "$GITHUB_OUTPUT" | |
| echo "Something other than documentation changed: running the suite." | |
| fi | |
| verify: | |
| needs: changes | |
| # `!= 'false'`, not `== 'true'`. A failed gate leaves this empty, | |
| # and the safe reading of empty is RUN THE SUITE. | |
| if: needs.changes.outputs.code != 'false' | |
| name: Verify (JDK 17) | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v7 | |
| # PRs only run on JDK 17 (the minimum target). Forward-compat | |
| # regressions on JDK 21/25 are caught post-merge by main.yml. | |
| - name: Set up JDK 17 | |
| uses: actions/setup-java@v5 | |
| with: | |
| distribution: temurin | |
| java-version: '17' | |
| # Validates the wrapper jar hash and caches Gradle home + wrapper | |
| # dists between runs. | |
| - name: Set up Gradle | |
| uses: gradle/actions/setup-gradle@v4 | |
| - name: Build, test, lint, coverage | |
| run: ./gradlew build --stacktrace | |
| - name: Upload test reports on failure | |
| if: failure() | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: test-reports | |
| path: | | |
| build/reports/tests/ | |
| build/test-results/ | |
| retention-days: 14 | |
| # Coverage ratchet lives in Codecov: codecov.yml at the repo root | |
| # configures `threshold: 5%` so a PR fails the Codecov status check | |
| # if line coverage drops more than 5 pp vs the base branch. | |
| - name: Upload coverage to Codecov | |
| uses: codecov/codecov-action@v7 | |
| with: | |
| token: ${{ secrets.CODECOV_TOKEN }} | |
| files: build/reports/jacoco/test/jacocoTestReport.xml | |
| fail_ci_if_error: true | |
| integration: | |
| name: Integration tests (live API, JDK 17) | |
| # SDK requirements §13: the live suite runs on every pull request. JDK 17 | |
| # only, like `/integrationtest`; the full {17, 21, 25} matrix stays in | |
| # main.yml and behind `/integrationtestfull`. | |
| # | |
| # `needs: changes` and NOT `needs: verify`. The code review starts when | |
| # this workflow completes and reads the result of this job, so running the | |
| # two side by side is what keeps the wait at the longer of them rather | |
| # than their sum. The live suite takes about two minutes and a build that | |
| # does not compile fails here before a single request is sent, so the | |
| # quota a red `verify` would have saved is small. sdk-py, sdk-csharp, | |
| # sdk-go and sdk-php gate their live job on `changes` alone as well. | |
| needs: changes | |
| # Three conditions, and `Tests passed` below accepts a skip for exactly | |
| # these three and no other: | |
| # 1. the gate did not say "documentation only", so a markdown change | |
| # spends no live API quota. `!= 'false'` so a failed gate still runs; | |
| # 2. the pull request was not opened by dependabot, and | |
| # 3. it does not come from a fork: neither receives repository secrets | |
| # on `pull_request`. They skip this JOB, which shows as "skipped" in | |
| # the checks, not as a green run that tested nothing. | |
| # Clause 2 reads the AUTHOR of the pull request, not `github.actor`, which | |
| # is whoever triggered this run. A maintainer who reopens a dependabot | |
| # pull request becomes the actor, and the run then does receive the | |
| # token, so a test on the actor would send a freshly bumped dependency's | |
| # code to the live API without anybody having decided to. A dependabot | |
| # pull request never runs the suite on its own, whoever triggers the run; | |
| # a maintainer runs it for one, or for a fork, with `/integrationtest`. | |
| # A head repository that has since been deleted reads as empty, which is | |
| # not this repository, so it skips too. | |
| if: >- | |
| needs.changes.outputs.code != 'false' && | |
| github.event.pull_request.user.login != 'dependabot[bot]' && | |
| github.event.pull_request.head.repo.full_name == github.repository | |
| runs-on: ubuntu-latest | |
| # Every test talks to the live API; without a cap one hung request would | |
| # hold the runner until the 6-hour default. | |
| timeout-minutes: 15 | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v7 | |
| - name: Set up JDK 17 | |
| uses: actions/setup-java@v5 | |
| with: | |
| distribution: temurin | |
| java-version: '17' | |
| - name: Set up Gradle | |
| uses: gradle/actions/setup-gradle@v4 | |
| # SDK requirements §17.3: a missing token fails the job, never skips it. | |
| - name: Run integration tests against live API | |
| env: | |
| MARKETDATA_TOKEN: ${{ secrets.MARKETDATA_TOKEN }} | |
| MARKETDATA_RUN_INTEGRATION_TESTS: 'true' | |
| run: | | |
| if [ -z "$MARKETDATA_TOKEN" ]; then | |
| echo "::error::MARKETDATA_TOKEN secret is missing; the live integration suite fails rather than skips (SDK requirements 17.3)." | |
| exit 1 | |
| fi | |
| ./gradlew integrationTest -PtestJdk=17 --stacktrace | |
| - name: Upload integration-test reports on failure | |
| if: failure() | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: integration-test-reports-jdk17 | |
| path: | | |
| build/reports/tests/integrationTest/ | |
| build/test-results/integrationTest/ | |
| retention-days: 14 | |
| tests-passed: | |
| # The single context branch protection requires. It always reports, so it is | |
| # always a decision rather than a silence. | |
| name: Tests passed | |
| needs: [changes, verify, integration] | |
| if: always() | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 2 | |
| steps: | |
| - name: Require the suite to have passed, or to have been skipped for cause | |
| env: | |
| CODE: ${{ needs.changes.outputs.code }} | |
| R0: ${{ needs.verify.result }} | |
| R1: ${{ needs.integration.result }} | |
| # The negation of the last two clauses of the `integration` job's | |
| # `if:`, evaluated by the same expression engine so the two cannot | |
| # disagree: `true` for a pull request opened by dependabot, whoever | |
| # triggered this run, and for a fork. | |
| NO_SECRETS: ${{ github.event.pull_request.user.login == 'dependabot[bot]' || github.event.pull_request.head.repo.full_name != github.repository }} | |
| run: | | |
| echo "gate said code=${CODE:-<nothing: the gate itself failed>}" | |
| echo "verify: ${R0}" | |
| echo "integration: ${R1} (pull request without secrets: ${NO_SECRETS})" | |
| # Two classes of job, because they skip for different reasons. | |
| # | |
| # STRICT jobs apply to every change, so the only acceptable skip is the | |
| # one this workflow's gate asked for. If the gate failed, CODE is empty, | |
| # the job skipped for some other reason, and a green here would cover | |
| # untested code. | |
| for result in "${R0}"; do | |
| case "$result" in | |
| success) ;; | |
| skipped) | |
| if [ "$CODE" != "false" ]; then | |
| echo "A required job was skipped and the gate did not ask for it." | |
| exit 1 | |
| fi | |
| ;; | |
| *) echo "A required job reported: $result"; exit 1 ;; | |
| esac | |
| done | |
| # LIVE jobs need the API token, so they have one more acceptable skip: | |
| # a pull request opened by dependabot or coming from a fork, which | |
| # never runs the suite on its own. Nothing else is accepted, and a | |
| # FAILURE always fails: that includes the job refusing to run without | |
| # its token on a pull request that should have had one. | |
| for result in "${R1}"; do | |
| case "$result" in | |
| success) ;; | |
| skipped) | |
| if [ "$CODE" != "false" ] && [ "$NO_SECRETS" != "true" ]; then | |
| echo "The live suite was skipped, and neither the gate nor a pull request without secrets explains it." | |
| exit 1 | |
| fi | |
| ;; | |
| *) echo "The live suite reported: $result"; exit 1 ;; | |
| esac | |
| done | |
| echo "Every job passed, or skipped for a reason this gate accepts." |