-
Notifications
You must be signed in to change notification settings - Fork 5
166 lines (150 loc) · 7.99 KB
/
Copy pathcontract-tests.yml
File metadata and controls
166 lines (150 loc) · 7.99 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
name: Contract Tests
on:
pull_request:
branches:
- main
- release/*
- flowvault-release/*
jobs:
contract-tests:
# One job per module so a break in one is reported against that module by name,
# and both still run even when the other fails.
name: Contract Tests (${{ matrix.module }})
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
include:
- module: skyvault
artifact: skyflow-java
- module: flowvault
artifact: skyflow-flowvault-java
permissions:
contents: read
pull-requests: write
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Setup Java
uses: actions/setup-java@v4
with:
distribution: 'temurin'
java-version: '11'
cache: 'maven'
- name: Verify API surface snapshot
run: mvn -B install -pl common,${{ matrix.module }} -am -DskipTests -Dmaven.javadoc.skip=true -Dgpg.skip=true
- name: Show API surface diff
if: failure()
run: |
echo "### API surface changes detected in ${{ matrix.module }} ###"
echo "Compared against ${{ matrix.module }}/api-report/${{ matrix.artifact }}.baseline.jar."
echo "If this change is intentional, run:"
echo " scripts/contract-snapshot-update.sh ${{ matrix.module }}"
echo "and commit the updated baseline jar."
echo ""
cat ${{ matrix.module }}/target/japicmp/default-cli.diff || true
- name: Upload API surface diff on failure
if: failure()
uses: actions/upload-artifact@v4
with:
name: api-surface-diff-${{ matrix.module }}
path: ${{ matrix.module }}/target/japicmp/**
retention-days: 7
# The step above only shows a diff when the CURRENT build differs from the
# committed baseline - once someone runs contract-snapshot-update.sh and
# commits the refreshed baseline jar, that check goes green and shows nothing.
# A reviewer looking at a green PR that touches api-report/*.baseline.jar
# (a binary file) would otherwise have no way to see WHAT was just approved as
# the new contract. These steps explicitly diff the OLD committed baseline
# (from the PR's base branch) against the NEW committed baseline (from this PR)
# and post it as a PR comment, regardless of whether the check above passed.
- name: Check if contract baseline was updated in this PR
id: baseline-diff-check
if: always() && github.event.pull_request
run: |
git fetch origin "${{ github.event.pull_request.base.ref }}" --depth=1
BASELINE="${{ matrix.module }}/api-report/${{ matrix.artifact }}.baseline.jar"
if ! git diff --name-only "origin/${{ github.event.pull_request.base.ref }}" HEAD -- "$BASELINE" | grep -q .; then
echo "changed=false" >> "$GITHUB_OUTPUT"
elif git cat-file -e "origin/${{ github.event.pull_request.base.ref }}:$BASELINE" 2>/dev/null; then
echo "changed=true" >> "$GITHUB_OUTPUT"
else
# Added by this PR rather than modified: the module is getting its
# first baseline. git diff reports an addition as a change, but there
# is no old snapshot to `git show`, so a plain "true" here would send
# the next step into `git show <base>:<path>` and exit 128.
echo "changed=new" >> "$GITHUB_OUTPUT"
fi
- name: Diff old vs new contract baseline
if: always() && (steps.baseline-diff-check.outputs.changed == 'true' || steps.baseline-diff-check.outputs.changed == 'new')
run: |
BASELINE="${{ matrix.module }}/api-report/${{ matrix.artifact }}.baseline.jar"
if [ "${{ steps.baseline-diff-check.outputs.changed }}" = "new" ]; then
{
echo "\`$BASELINE\` is **new in this PR** - \`${{ matrix.module }}\` had no committed baseline before, so there is nothing to diff against."
echo ""
echo "This snapshot becomes the approved contract: every later PR is compared against it, and any incompatible change fails the \`Contract Tests (${{ matrix.module }})\` job until someone regenerates it deliberately. Review it as the starting point, not as a change."
} > /tmp/contract-baseline-diff.md
cat /tmp/contract-baseline-diff.md
exit 0
fi
curl -sL -o /tmp/japicmp-cli.jar "https://repo.maven.apache.org/maven2/com/github/siom79/japicmp/japicmp/0.26.0/japicmp-0.26.0-jar-with-dependencies.jar"
mvn -q -B dependency:build-classpath -pl ${{ matrix.module }} -Dmdep.outputFile=/tmp/module-classpath.txt -Dmaven.javadoc.skip=true -Dgpg.skip=true
git show "origin/${{ github.event.pull_request.base.ref }}:$BASELINE" > /tmp/old-baseline.jar
# Same allowlist the poms gate on, so the comment shows the contract and
# nothing else. Keep these in sync with the <includes> in the module poms.
java -jar /tmp/japicmp-cli.jar \
-o /tmp/old-baseline.jar \
-n "$BASELINE" \
-a protected \
-i "com.skyflow.Skyflow;com.skyflow.config;com.skyflow.enums;com.skyflow.errors;com.skyflow.serviceaccount.util;com.skyflow.vault.audit;com.skyflow.vault.bin;com.skyflow.vault.connection;com.skyflow.vault.controller;com.skyflow.vault.data;com.skyflow.vault.detect;com.skyflow.vault.tokens" \
--old-classpath "$(cat /tmp/module-classpath.txt)" \
--new-classpath "$(cat /tmp/module-classpath.txt)" \
-m \
--ignore-missing-classes \
--markdown > /tmp/contract-baseline-diff.md || true
cat /tmp/contract-baseline-diff.md
- name: Comment contract baseline change on PR
if: always() && (steps.baseline-diff-check.outputs.changed == 'true' || steps.baseline-diff-check.outputs.changed == 'new')
uses: actions/github-script@v7
env:
BASELINE_STATE: ${{ steps.baseline-diff-check.outputs.changed }}
with:
script: |
const fs = require('fs');
const module = '${{ matrix.module }}';
const artifact = '${{ matrix.artifact }}';
const summary = fs.readFileSync('/tmp/contract-baseline-diff.md', 'utf8');
// per-module marker so the two matrix jobs update their own comment
const marker = `<!-- contract-baseline-diff:${module} -->`;
const isNew = process.env.BASELINE_STATE === 'new';
const heading = isNew
? `## Contract baseline added (\`${module}\`)`
: `## Contract baseline change detected (\`${module}\`)`;
const preamble = isNew
? `This PR adds \`${module}/api-report/${artifact}.baseline.jar\`, the approved public API contract for this module.`
: `This PR updates \`${module}/api-report/${artifact}.baseline.jar\` (the approved public API contract). Here is exactly what it changes, comparing the baseline on \`${{ github.event.pull_request.base.ref }}\` against the baseline committed in this PR:`;
const body = `${marker}\n${heading}\n\n${preamble}\n\n${summary}`;
const { data: comments } = await github.rest.issues.listComments({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.issue.number,
});
const existing = comments.find(c => c.body && c.body.includes(marker));
if (existing) {
await github.rest.issues.updateComment({
owner: context.repo.owner,
repo: context.repo.repo,
comment_id: existing.id,
body,
});
} else {
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.issue.number,
body,
});
}