Repository navigation
225 lines (217 loc) · 8.77 KB
/
Copy pathci.yaml
File metadata and controls
225 lines (217 loc) · 8.77 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
name: CI
on:
push:
branches:
- main
pull_request:
branches:
- main
workflow_dispatch: {}
schedule:
# “At 08:30 on every day-of-week from Monday through Friday.”
#
# Staggered across the six SDK repos (java :30, python :35, php :40,
# go :45, csharp :50, typescript :55). They all run their live suites
# against the one shared e2e sandbox, and firing together stampedes the
# auth path's cold public-key cache -> Envelope /decrypt times out at 3s
# -> every endpoint 500s (Sentry CORE-API-1N0). Keep these apart.
- cron: 30 8 * * 1-5
# A new push to a PR cancels the previous in-flight run. Runs on main are never
# cancelled: the publish workflow waits for each one to finish.
concurrency:
group: ci-${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: ${{ github.event_name == 'pull_request' }}
permissions:
contents: read
jobs:
# Compile every source + test on each Java version. No key needed, so this
# also protects fork PRs and catches generation drift before the live suite.
build:
runs-on: ubuntu-latest
timeout-minutes: 10
strategy:
matrix:
java: [11, 17, 21]
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- name: Use Java ${{ matrix.java }}
uses: actions/setup-java@c1e323688fd81a25caa38c78aa6df2d33d3e20d9 # v4
with:
distribution: corretto
java-version: ${{ matrix.java }}
- name: Compile main + test sources
run: ./gradlew compileJava compileTestJava --console=plain
# Dependency-light unit tests (JWT auth + webhook signatures) across the full
# Java matrix. These never touch the network, so they run without a key.
offline:
runs-on: ubuntu-latest
timeout-minutes: 10
strategy:
matrix:
java: [11, 17, 21]
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- name: Use Java ${{ matrix.java }}
uses: actions/setup-java@c1e323688fd81a25caa38c78aa6df2d33d3e20d9 # v4
with:
distribution: corretto
java-version: ${{ matrix.java }}
- name: Run offline unit tests
run: ./gradlew test --tests "com.gr4vy.sdk.AuthTest" --tests "com.gr4vy.sdk.WebhooksTest" --console=plain
# The live E2E suite, sharded by package so each shard is a separate JVM
# (= one isolated merchant per shard). GR4VY_TRACK_HTTP records every request
# for the coverage report. Runs on main only (push, schedule, dispatch): the
# key lives in the `e2e` Environment, which only main can use.
e2e:
if: github.event_name != 'pull_request' && github.ref == 'refs/heads/main'
runs-on: ubuntu-latest
timeout-minutes: 20
environment: e2e
strategy:
fail-fast: false
matrix:
shard: [flows, processing, backoffice]
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- name: Use Java 21
uses: actions/setup-java@c1e323688fd81a25caa38c78aa6df2d33d3e20d9 # v4
with:
distribution: corretto
java-version: 21
- name: Require signing key
# Without a key the harness would silently skip, masking a missing secret.
env:
PRIVATE_KEY: ${{ secrets.PRIVATE_KEY }}
run: |
if [ -z "$PRIVATE_KEY" ]; then
echo "PRIVATE_KEY secret is missing on a non-PR run; the live suite would silently skip." >&2
exit 1
fi
- name: Run ${{ matrix.shard }} shard
env:
PRIVATE_KEY: ${{ secrets.PRIVATE_KEY }}
E2E: "true"
GR4VY_TRACK_HTTP: "1"
GR4VY_COVERAGE_DIR: ${{ github.workspace }}/coverage/http
SHARD: ${{ matrix.shard }}
run: ./gradlew test --tests "com.gr4vy.sdk.$SHARD.*" --console=plain
- name: Upload reached-endpoint records
if: always()
uses: actions/upload-artifact@65c4c4a1ddee5b72f698fdd19549f0f0fb45cf08 # v4
with:
name: coverage-${{ matrix.shard }}
path: coverage/http/*.jsonl
if-no-files-found: ignore
retention-days: 3
# Endpoint-reach coverage report from the daily run. Combines every shard's
# recorded calls, writes the report to the run summary, and posts to Slack
# when an operation had no real request. A report, not a gate, and it doesn't
# run on pushes, so it never delays a release.
coverage:
needs: e2e
if: >-
always() && needs.e2e.result != 'cancelled' && needs.e2e.result != 'skipped' &&
(github.event_name == 'schedule' || github.event_name == 'workflow_dispatch')
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- name: Use Java 21
uses: actions/setup-java@c1e323688fd81a25caa38c78aa6df2d33d3e20d9 # v4
with:
distribution: corretto
java-version: 21
- name: Download all shard records
# A failed shard may have uploaded nothing; report on what exists.
continue-on-error: true
uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 # v4
with:
path: coverage/download
pattern: coverage-*
merge-multiple: true
- name: Build coverage report
id: report
env:
E2E_RESULT: ${{ needs.e2e.result }}
run: |
mkdir -p coverage/http
# Flatten any downloaded jsonl into the dir the script reads.
find coverage/download -name '*.jsonl' -exec cp {} coverage/http/ \; 2>/dev/null || true
java scripts/endpoint_coverage/EndpointCoverage.java .
if [ "$E2E_RESULT" != "success" ]; then
echo "> ⚠️ **E2E failed in this run, so the reach below is incomplete.**" >> "$GITHUB_STEP_SUMMARY"
echo >> "$GITHUB_STEP_SUMMARY"
fi
cat coverage/endpoint-coverage.md >> "$GITHUB_STEP_SUMMARY"
{
echo "summary=$(grep -o '[0-9]* / [0-9]*' coverage/endpoint-coverage.md | head -1)"
echo "missing<<EOF"
grep '^- `' coverage/endpoint-coverage.md || true
echo "EOF"
} >> "$GITHUB_OUTPUT"
- name: Post unreached endpoints to Slack
if: steps.report.outputs.missing != ''
uses: rtCamp/action-slack-notify@e31e87e03dd19038e411e38ae27cbad084a90661 # v2
env:
SLACK_USERNAME: Java SDK
SLACK_TITLE: Java SDK
SLACK_WEBHOOK: ${{ secrets.SLACK_SDK_WEBHOOK_URL }}
SLACK_CHANNEL: sdk-updates
SLACK_MSG_AUTHOR: gr4vy
SLACK_ICON_EMOJI: ":gr4vy-sdk:"
SLACK_COLOR: "warning"
SLACK_MESSAGE: "Endpoint coverage ${{ steps.report.outputs.summary }}. No live test reached:\n${{ steps.report.outputs.missing }}"
SLACK_FOOTER: ""
# Stable gate: branch rulesets require THIS single check, not the sharded
# matrix names (which change as shards are added/removed). On a PR it means
# build and offline passed; on main it also means the live suite passed,
# which is what the publish workflow waits for.
ci-complete:
needs: [build, offline, e2e]
if: always()
runs-on: ubuntu-latest
steps:
- name: Verify required jobs succeeded
env:
BUILD: ${{ needs.build.result }}
OFFLINE: ${{ needs.offline.result }}
E2E: ${{ needs.e2e.result }}
ON_MAIN: ${{ github.event_name != 'pull_request' && github.ref == 'refs/heads/main' }}
run: |
if [ "$BUILD" != "success" ] || [ "$OFFLINE" != "success" ]; then
echo "build: $BUILD, offline: $OFFLINE"
exit 1
fi
if [ "$ON_MAIN" != "true" ] && [ "$E2E" = "skipped" ]; then
exit 0
fi
if [ "$E2E" != "success" ]; then
echo "e2e: $E2E"
exit 1
fi
notify:
needs: ci-complete
runs-on: ubuntu-latest
if: ${{ always() && contains(needs.*.result, 'failure') }}
steps:
- name: Slack Notification
uses: rtCamp/action-slack-notify@e31e87e03dd19038e411e38ae27cbad084a90661 # v2
if: github.ref == 'refs/heads/main' || (github.event_name == 'pull_request' && github.event.pull_request.user.login == 'gr4vy-sdk-generate[bot]')
env:
SLACK_USERNAME: Java SDK
SLACK_TITLE: Java SDK
SLACK_WEBHOOK: ${{ secrets.SLACK_SDK_WEBHOOK_URL }}
SLACK_CHANNEL: sdk-updates
SLACK_MSG_AUTHOR: gr4vy
SLACK_ICON_EMOJI: ":gr4vy-sdk:"
SLACK_COLOR: "failure"
SLACK_MESSAGE_ON_FAILURE: "CI failed"
SLACK_FOOTER: ""