|
1 | 1 | name: interop |
2 | 2 |
|
3 | | -# Reusable cross-stack interop workflow. A consumer middleware repo calls this from its own PR CI to |
4 | | -# run the php-soap interop suite (PHP middleware <-> Dockerised WSS4J oracle) against the EXACT PR commit |
5 | | -# under review. The override is the same composer path-repository mechanism used for local dev: the |
6 | | -# harness's path repo is simply repointed at the PR checkout, so local and PR runs share one code path. |
| 3 | +# Reusable cross-stack interop workflow. A middleware repo calls this from its own PR CI to run the |
| 4 | +# php-soap interop suite (PHP middleware against a Dockerised WSS4J oracle) on the exact commit under |
| 5 | +# review. Nothing about the branch or repository is hardcoded: the caller is checked out by the standard |
| 6 | +# action, which for a pull request resolves the originating commit (forks included). That checkout is the |
| 7 | +# package source, so the workflow works on whatever branch is being tested. |
7 | 8 | on: |
8 | 9 | workflow_call: |
9 | 10 | inputs: |
10 | 11 | package: |
11 | | - description: 'Composer package name of the consumer middleware (e.g. php-soap/psr18-wsse-middleware).' |
| 12 | + description: 'Composer package name of the calling middleware, e.g. php-soap/psr18-wsse-middleware.' |
12 | 13 | required: true |
13 | 14 | type: string |
14 | 15 | suites: |
15 | | - description: 'PHPUnit testsuite(s) to run (e.g. wsse or attachments).' |
| 16 | + description: 'PHPUnit testsuite(s) to run, e.g. wsse or attachments.' |
| 17 | + required: true |
| 18 | + type: string |
| 19 | + php-versions: |
| 20 | + description: 'JSON array of PHP versions to run the matrix on.' |
16 | 21 | required: false |
17 | 22 | type: string |
18 | | - default: 'wsse' |
| 23 | + default: '["8.4", "8.5"]' |
19 | 24 |
|
20 | 25 | jobs: |
21 | 26 | interop: |
22 | 27 | runs-on: ubuntu-latest |
| 28 | + strategy: |
| 29 | + fail-fast: false |
| 30 | + matrix: |
| 31 | + php: ${{ fromJSON(inputs.php-versions) }} |
| 32 | + name: ${{ inputs.suites }} on PHP ${{ matrix.php }} |
23 | 33 | steps: |
24 | | - # The interop harness (this repo): oracle, Dockerfile, certs, tests, harness composer.json. Its |
25 | | - # composer.json declares path repos to ../<sibling-middleware>; we lay the checkouts out to match. |
26 | | - - name: Checkout interop harness |
27 | | - uses: actions/checkout@v4 |
| 34 | + # The calling middleware at the commit under review. A plain checkout in a reusable workflow pulls |
| 35 | + # the caller; for a pull request it resolves the originating repository and ref (forks included). |
| 36 | + - name: Checkout the middleware under test |
| 37 | + uses: actions/checkout@v7 |
28 | 38 | with: |
29 | | - repository: php-soap/java-interop |
30 | | - path: harness |
| 39 | + path: middleware |
31 | 40 |
|
32 | | - # The consumer PR code, checked out into the sibling path the harness already points at. In a |
33 | | - # reusable workflow a plain checkout pulls the CALLER repo = the PR commit under review, so the |
34 | | - # harness's existing path repo now resolves to the PR working copy. ONE mechanism, repointed. |
35 | | - - name: Checkout consumer PR |
36 | | - uses: actions/checkout@v4 |
| 41 | + - name: Checkout the interop harness |
| 42 | + uses: actions/checkout@v7 |
37 | 43 | with: |
38 | | - path: consumer |
39 | | - |
40 | | - # The OTHER sibling middleware the harness path repos reference (the one not under review) is |
41 | | - # checked out at its expected released/main version so the harness graph still resolves. |
42 | | - - name: Checkout sibling http-wsse-middleware |
43 | | - if: ${{ inputs.package != 'php-soap/psr18-wsse-middleware' }} |
44 | | - uses: actions/checkout@v4 |
45 | | - with: |
46 | | - repository: php-soap/http-wsse-middleware |
47 | | - path: http-wsse-middleware |
48 | | - - name: Checkout sibling psr18-attachments-middleware |
49 | | - if: ${{ inputs.package != 'php-soap/psr18-attachments-middleware' }} |
50 | | - uses: actions/checkout@v4 |
51 | | - with: |
52 | | - repository: php-soap/psr18-attachments-middleware |
53 | | - path: psr18-attachments-middleware |
| 44 | + repository: php-soap/java-interop |
| 45 | + path: harness |
54 | 46 |
|
55 | 47 | - name: Setup PHP |
56 | 48 | uses: shivammathur/setup-php@v2 |
57 | 49 | with: |
58 | | - php-version: '8.4' |
| 50 | + php-version: ${{ matrix.php }} |
59 | 51 | extensions: dom, openssl, intl, gmp, bcmath |
60 | 52 | coverage: none |
61 | 53 |
|
62 | | - - name: Set up JDK 17 |
63 | | - uses: actions/setup-java@v4 |
| 54 | + - name: Set up JDK 21 |
| 55 | + uses: actions/setup-java@v5 |
64 | 56 | with: |
65 | 57 | distribution: temurin |
66 | | - java-version: '17' |
| 58 | + java-version: '21' |
67 | 59 |
|
68 | 60 | - name: Cache Maven repository |
69 | | - uses: actions/cache@v4 |
| 61 | + uses: actions/cache@v6 |
70 | 62 | with: |
71 | 63 | path: ~/.m2 |
72 | 64 | key: ${{ runner.os }}-m2-${{ hashFiles('harness/oracle/pom.xml') }} |
73 | 65 | restore-keys: ${{ runner.os }}-m2- |
74 | 66 |
|
75 | | - # Two-step build: jar on the host (cached ~/.m2), then a copy-only docker build (seconds). |
76 | | - - name: Build oracle jar |
77 | | - run: mvn -B -f harness/oracle/pom.xml -DskipTests package |
78 | | - |
79 | | - - name: Build oracle image |
80 | | - run: docker build -t java-interop-oracle harness |
81 | | - |
82 | | - - name: Generate certs |
83 | | - run: bash harness/certs/generate.sh |
84 | | - |
85 | | - - name: Start oracle |
| 67 | + - name: Build and start the oracle |
86 | 68 | run: | |
87 | | - docker run -d --name oracle -p 8080:8080 \ |
88 | | - -v "$PWD/harness/certs:/certs" java-interop-oracle |
| 69 | + mvn -B -f harness/oracle/pom.xml -DskipTests package |
| 70 | + docker build -t java-interop-oracle harness |
| 71 | + bash harness/certs/generate.sh |
| 72 | + docker run -d --name oracle -p 8080:8080 -v "$PWD/harness/certs:/certs" java-interop-oracle |
89 | 73 | for i in $(seq 1 30); do |
90 | | - if curl -fsS http://127.0.0.1:8080/health >/dev/null 2>&1; then |
91 | | - echo "oracle healthy"; exit 0 |
92 | | - fi |
| 74 | + if curl -fsS http://127.0.0.1:8080/health >/dev/null 2>&1; then echo "oracle healthy"; break; fi |
93 | 75 | sleep 1 |
94 | 76 | done |
95 | | - echo "oracle failed to become healthy"; docker logs oracle; exit 1 |
96 | | -
|
97 | | - # THE OVERRIDE: repoint the harness path repository at the PR checkout, then update only the |
98 | | - # consumer package (+ its deps) from there. A path repository wins over Packagist, so the harness |
99 | | - # vendor/ is built from the PR working copy = the exact commit under review. |
100 | | - # |
101 | | - # Detached-HEAD wrinkle: actions/checkout leaves PR checkouts on a detached HEAD, which can stop |
102 | | - # composer from inferring a branch/version for the path dependency. We pin it explicitly with |
103 | | - # COMPOSER_ROOT_VERSION on the path repo by requiring the alias "*@dev" and letting prefer-stable |
104 | | - # fall through to the path version. To be robust we also alias the detached HEAD to a dev branch. |
105 | | - - name: Override the harness path repo with the PR checkout |
106 | | - working-directory: harness |
107 | | - run: | |
108 | | - # Give the detached PR checkout a real branch name so composer's path version guesser resolves |
109 | | - # a dev-<branch> constraint instead of failing on actions/checkout's bare detached HEAD. |
110 | | - git -C ../consumer checkout -B interop-pr-under-test |
111 | | -
|
112 | | - # Repoint the SAME named path repo the harness already declares at the PR working copy. This |
113 | | - # reuses the local-dev path-repo mechanism verbatim; only the url changes to the PR commit. |
114 | | - case "${{ inputs.package }}" in |
115 | | - php-soap/psr18-wsse-middleware) REPO=wsse-middleware ;; |
116 | | - php-soap/psr18-attachments-middleware) REPO=attachments-middleware ;; |
117 | | - *) echo "Unsupported package: ${{ inputs.package }}"; exit 1 ;; |
118 | | - esac |
119 | | - composer config "repositories.$REPO" \ |
120 | | - '{"type":"path","url":"../consumer","options":{"symlink":false}}' |
121 | | -
|
122 | | - # Require the package at "*@dev" so the path version is eligible, then a full update resolves |
123 | | - # the whole graph (the harness ships no lock file, so a partial update is not possible). |
124 | | - composer require "${{ inputs.package }}:*@dev" --no-update |
125 | | - composer update --with-all-dependencies |
126 | 77 |
|
127 | | - # Prove the path version (not a Packagist release) was selected. |
128 | | - - name: Verify PR version is in use |
| 78 | + # Point the harness at the checked-out middleware. The checkout above is the commit under test, so a |
| 79 | + # path repository to it is the source; composer derives the package version from the checkout's branch. |
| 80 | + # Give the (possibly detached) PR checkout that branch name so the derived dev-<branch> is unambiguous. |
| 81 | + - name: Resolve the middleware from the checkout |
129 | 82 | working-directory: harness |
| 83 | + env: |
| 84 | + PACKAGE: ${{ inputs.package }} |
| 85 | + BRANCH: ${{ github.head_ref || github.ref_name }} |
130 | 86 | run: | |
131 | | - composer show "${{ inputs.package }}" |
132 | | - composer show "${{ inputs.package }}" | grep -E 'source|dist' \ |
133 | | - && echo "Resolved from path repo (PR checkout)." |
| 87 | + git -C ../middleware checkout -B "$BRANCH" |
| 88 | + composer config repositories.middleware path ../middleware |
| 89 | + composer require "$PACKAGE:dev-$BRANCH" --no-update |
| 90 | + composer update --with-all-dependencies --no-interaction --no-progress |
134 | 91 |
|
135 | 92 | - name: Run interop tests |
136 | 93 | working-directory: harness |
|
0 commit comments