mirror of https://github.com/OpenIdentityPlatform/OpenDJ.git

Valery Kharseko
yesterday b5cb2b48d17d114eece4c1bec2e1126eade5d2af
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
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
# The contents of this file are subject to the terms of the Common Development and
# Distribution License (the License). You may not use this file except in compliance with the
# License.
#
# You can obtain a copy of the License at legal/CDDLv1.0.txt. See the License for the
# specific language governing permission and limitations under the License.
#
# When distributing Covered Software, include this CDDL Header Notice in each file and include
# the License file at legal/CDDLv1.0.txt. If applicable, add the following below the CDDL
# Header, with the fields enclosed by brackets [] replaced by your own identifying
# information: "Portions copyright [year] [name of copyright owner]".
#
# Copyright 2021-2026 3A Systems, LLC.
 
name: Package/Deploy
 
on:
  workflow_run:
    branches: [ 'sustaining/4.10.x','master' ]
    workflows: ["Build","Release"]
    types: [completed]
 
concurrency:
  group: ${{ github.workflow }}-${{ github.event.workflow_run.head_branch }}
  cancel-in-progress: false
 
# contents: write is required to push the generated documentation to the project wiki
# with github.token. The doc site push uses a separate PAT, not this token.
# actions: read is required to download the MSI artifact from the triggering Build run
# (a permissions block sets every unlisted scope to none).
permissions:
  contents: write
  actions: read
 
jobs:
  package-deploy-maven:
    # head_repository states the trust boundary instead of leaving it to be re-derived.
    # The checkout below takes its ref from the triggering run, and the branches filter
    # above matches that run's head branch NAME - which a fork can also call master. What
    # actually keeps the ref trusted is event=='push': a Build run for a pull request
    # carries event 'pull_request', and a push to a fork runs the fork's own workflows,
    # never ours. The repository check makes that explicit for the next reader, and for
    # the next person tempted to relax the event condition.
    if: ${{ github.event.workflow_run.conclusion == 'success' && github.event.workflow_run.event == 'push' && github.event.workflow_run.head_repository.full_name == github.repository }}
    runs-on: 'ubuntu-latest'
    steps:
      - name: Print github context
        env:
          GITHUB_CONTEXT: ${{ toJSON(github) }}
        run: echo "$GITHUB_CONTEXT"
      - name: Install rpm for distribution
        if: runner.os == 'Linux'
        shell: bash
        run:   |
          sudo apt-get update
          sudo apt-get install -y rpm
      - uses: actions/checkout@v6
        with:
          fetch-depth: 0
          submodules: recursive
          ref: ${{ github.event.workflow_run.head_branch }}
      # The committed opendj-server-legacy/lib/*.exe are what every Linux-built server zip
      # ships - the snapshots this job publishes, and later the tagged releases and their
      # Maven Central artifacts - while only a Windows job can rebuild them. Nothing used
      # to make the two meet, so a native source change that was never re-committed as a
      # refreshed binary shipped the old wrapper while CI stayed green (master carried such
      # a gap for weeks). The triggering Build run compiled them from source already, so
      # take its binaries and commit them here rather than rebuild.
      #
      # Here rather than in build.yml: this workflow already holds contents: write for the
      # wiki push, so build-maven - which runs the whole Maven plugin tree - stays
      # read-only, and it only runs at all once the Build succeeded on a push to a release
      # branch. The cost is latency: the refresh lands after the full matrix, not minutes
      # into it. Committing before the Maven steps below also means the snapshot zip this
      # job publishes carries the fresh launchers.
      #
      # This only works because the Makefile passes /Brepro to both cl and link: the output
      # is a function of the sources, not of the build time. Without it every run would
      # produce different bytes and this would commit on every push. An MSVC toolchain bump
      # on the runner image does change them, and that refresh commit is correct - the
      # committed binary then matches what CI verifies. Pushes made with GITHUB_TOKEN do
      # not start new workflow runs, so this cannot loop; a PAT would break that.
      - name: Download the launchers built by the triggering Build run
        continue-on-error: true
        uses: actions/download-artifact@v8
        with:
          name: windows-exe-11
          run-id: ${{ github.event.workflow_run.id }}
          github-token: ${{ secrets.GITHUB_TOKEN }}
          path: ${{ runner.temp }}/windows-exe
      - name: Commit the rebuilt launchers
        shell: bash
        env:
          # NOT github.ref: on a workflow_run event that is the default branch, not the
          # branch the triggering run was for.
          BRANCH: ${{ github.event.workflow_run.head_branch }}
          BUILT: ${{ runner.temp }}/windows-exe
          HEAD_SHA: ${{ github.event.workflow_run.head_sha }}
          RUN_ID: ${{ github.event.workflow_run.id }}
        run: |
          set -e
          if ! ls "$BUILT"/*.exe >/dev/null 2>&1; then
            echo "::warning title=No launcher binaries from the Build run::windows-exe-11 could not be downloaded, leaving opendj-server-legacy/lib/*.exe as committed."
            exit 0
          fi
          cp "$BUILT"/*.exe opendj-server-legacy/lib/
          # status --porcelain, not diff: it reports a brand-new launcher that was never
          # git-added just as well as a modified one.
          if [ -z "$(git status --porcelain -- opendj-server-legacy/lib)" ]; then
            echo "Committed launchers already match the sources."
            exit 0
          fi
          git status --porcelain -- opendj-server-legacy/lib
          git config user.name "Open Identity Platform Community"
          git config user.email "open-identity-platform-opendj@googlegroups.com"
          git add -- opendj-server-legacy/lib
          git commit --quiet \
            -m "Refresh the Windows native launchers" \
            -m "Rebuilt from opendj-server-legacy/src/build-tools/windows for ${HEAD_SHA} by the Build workflow (run ${RUN_ID})."
          # The checkout is of the branch, which may have moved on since the Build run, and
          # it can move again while we push: rebase onto the current tip and retry. An
          # identical refresh already there leaves an empty commit that rebase drops, and
          # the push then has nothing to send.
          #
          # This step runs before the Maven deploy, the package uploads and the wiki push,
          # so it must not be the thing that costs them: a refresh that cannot be landed
          # warns and lets the job carry on. The next push to this branch retries it, and
          # nothing downstream depends on the committed binaries being current - the Build
          # run that produced them compiled its own.
          #
          # The Maven steps below must build the tree the triggering Build validated. The
          # rebase moves the worktree onto the branch tip, which can carry commits that
          # Build run never saw, so remember the refresh as it was made - the tree as
          # checked out, plus the launchers - and come back to it however this step ends.
          # (The checkout above takes the branch by NAME, not the triggering run's SHA, so
          # that tree is the tip as of a moment ago rather than HEAD_SHA itself; what this
          # keeps is the rebase from widening the gap.)
          REFRESHED=$(git rev-parse HEAD)
          # A trap rather than a line on the push-success path: all four ways out of the
          # loop below - fetch failure, rebase conflict, three lost races, and the push
          # that lands - can be taken after a rebase has already moved the worktree, and
          # 'git rebase --abort' returns to the state that rebase started from, which on
          # attempt 2 or 3 is the result of the previous attempt rather than $REFRESHED.
          #
          # --force matters: when the abort above fails - it is masked by '|| true' - a
          # plain 'checkout --detach' stops on "you need to resolve your current index
          # first" and leaves the worktree mid-rebase for the Maven steps.
          trap 'git checkout --quiet --force --detach "$REFRESHED" || echo "::warning title=Could not restore the validated tree::the build continues on the current $BRANCH tip."' EXIT
          for attempt in 1 2 3; do
            # Guarded like everything else in this block: bare, it is the one command left
            # that could still take the job down with it. The step runs under set -e with
            # no continue-on-error, so a transient fetch failure would skip the Maven
            # deploy, all nine artifact uploads, the MSI attachment and both documentation
            # pushes over a refresh that is allowed to fail.
            if ! git fetch --quiet origin "$BRANCH"; then
              echo "::warning title=Could not refresh the launcher binaries::$BRANCH could not be fetched. Refresh opendj-server-legacy/lib/*.exe from the windows-exe-11 artifact of Build run ${RUN_ID} and commit them."
              exit 0
            fi
            if ! git rebase --quiet FETCH_HEAD; then
              git rebase --abort || true
              echo "::warning title=Could not refresh the launcher binaries::$BRANCH moved on and the rebuilt launchers conflict with it. Refresh opendj-server-legacy/lib/*.exe from the windows-exe-11 artifact of Build run ${RUN_ID} and commit them."
              exit 0
            fi
            if git push --quiet origin "HEAD:refs/heads/$BRANCH"; then
              # A refresh that already landed leaves the rebase with nothing to replay and
              # the push with nothing to send, both of them silently successful: report
              # what happened rather than claiming a push that was a no-op.
              if [ "$(git rev-parse HEAD)" = "$(git rev-parse FETCH_HEAD)" ]; then
                echo "The launchers committed on $BRANCH already match the rebuilt ones."
              else
                echo "Refreshed launchers pushed to $BRANCH."
              fi
              exit 0
            fi
            echo "$BRANCH moved while pushing - retrying ($attempt/3)."
          done
          echo "::warning title=Could not refresh the launcher binaries::$BRANCH kept moving under this job. Refresh opendj-server-legacy/lib/*.exe from the windows-exe-11 artifact of Build run ${RUN_ID} and commit them."
      - name: Set up Java for publishing to Maven Central Repository OSS
        uses: actions/setup-java@v5
        with:
          java-version: ${{ github.event.workflow_run.head_branch == 'sustaining/4.10.x' && '8' || '11'}}
          distribution: 'temurin'
          server-id: ossrh
          server-username: MAVEN_USERNAME
          server-password: MAVEN_PASSWORD
      - name: Cache Maven packages
        uses: actions/cache@v5
        with:
         path: ~/.m2/repository
         key: ${{ runner.os }}-m2-repository-${{ hashFiles('**/pom.xml') }}
         restore-keys: ${{ runner.os }}-m2-repository
      - name: Install gpg secret key
        env:
           GPG_PRIVATE_KEY: ${{ secrets.GPG_PRIVATE_KEY }}
        if: ${{ env.GPG_PRIVATE_KEY!=''}}
        run: |
           cat <(echo -e "${{ secrets.GPG_PRIVATE_KEY }}") | gpg --batch --import
           gpg --list-secret-keys --keyid-format LONG
      - name: Build package local
        env:
          MAVEN_USERNAME: ${{ secrets.OSSRH_USERNAME }}
          MAVEN_PASSWORD: ${{ secrets.OSSRH_TOKEN }}
          MAVEN_OPTS: -Dhttps.protocols=TLSv1.2 -Dmaven.wagon.httpconnectionManager.ttlSeconds=120 -Dmaven.wagon.http.retryHandler.requestSentEnabled=true -Dmaven.wagon.http.retryHandler.count=10
        if: ${{ !(github.event.workflow_run.event=='push' && env.MAVEN_USERNAME!='' && env.MAVEN_PASSWORD!='')}}
        run: mvn --batch-mode --errors --update-snapshots -Dgpg.passphrase=${{ secrets.GPG_PASSPHRASE }} package --file pom.xml
      - name: Publish to the Maven Central Repository
        env:
          MAVEN_USERNAME: ${{ secrets.OSSRH_USERNAME }}
          MAVEN_PASSWORD: ${{ secrets.OSSRH_TOKEN }}
          MAVEN_OPTS: -Dhttps.protocols=TLSv1.2 -Dmaven.wagon.httpconnectionManager.ttlSeconds=120 -Dmaven.wagon.http.retryHandler.requestSentEnabled=true -Dmaven.wagon.http.retryHandler.count=10
        if: ${{ github.event.workflow_run.event=='push' && env.MAVEN_USERNAME!='' && env.MAVEN_PASSWORD!=''}}
        run: mvn --batch-mode --errors --update-snapshots -Dgpg.passphrase=${{ secrets.GPG_PASSPHRASE }} deploy --file pom.xml
      - name: Build Javadoc
        continue-on-error: true
        run: mvn javadoc:aggregate
      - name: Upload artifacts OpenDJ Server
        uses: actions/upload-artifact@v7
        with:
         name: OpenDJ Server
         path: opendj-server-legacy/target/package/*.zip
      - name: Upload artifacts OpenDJ SDK Toolkit
        uses: actions/upload-artifact@v7
        with:
         name: OpenDJ SDK Toolkit
         path: opendj-ldap-toolkit/target/*.zip
      - name: Upload artifacts OpenDJ Debian Package
        uses: actions/upload-artifact@v7
        with:
         name: OpenDJ Debian Package
         path: opendj-packages/opendj-deb/opendj-deb-standard/target/*.deb
      - name: Upload artifacts OpenDJ RPM Package
        uses: actions/upload-artifact@v7
        with:
         name: OpenDJ RPM Package
         path: opendj-packages/opendj-rpm/opendj-rpm-standard/target/rpm/opendj/RPMS/noarch/*.rpm
      # The MSI can only be built on Windows; reuse the one already built by the triggering
      # Build run (windows-latest-11 artifact) instead of rebuilding it here.
      - name: Download Windows build artifact (contains the MSI)
        continue-on-error: true
        uses: actions/download-artifact@v8
        with:
          name: windows-latest-11
          run-id: ${{ github.event.workflow_run.id }}
          github-token: ${{ secrets.GITHUB_TOKEN }}
          path: windows-build
      - name: Upload artifacts OpenDJ MSI Package
        continue-on-error: true
        uses: actions/upload-artifact@v7
        with:
         name: OpenDJ MSI Package
         path: windows-build/opendj-packages/opendj-msi/opendj-msi-standard/target/*.msi
         # Make a silently-missing MSI visible: the step fails (job continues via
         # continue-on-error) instead of warning and publishing nothing.
         if-no-files-found: error
      - name: Upload artifacts OpenDJ Docker Packages
        uses: actions/upload-artifact@v7
        with:
         name: OpenDJ Docker Packages
         path: opendj-packages/opendj-docker/target/Dockerfile.zip
      - name: Upload artifacts OpenDJ Openshift template
        uses: actions/upload-artifact@v7
        with:
         name: OpenDJ Openshift template
         path: opendj-packages/opendj-openshift-template/*.yaml
      - name: Upload artifacts OpenDJ Doc Generated Reference
        uses: actions/upload-artifact@v7
        with:
         name: OpenDJ Doc Generated References
         path: opendj-doc-generated-ref/target/*.zip
      - name: Upload artifacts OpenDJ DSML Gateway
        uses: actions/upload-artifact@v7
        with:
         name: OpenDJ DSML Gateway
         path: opendj-dsml-servlet/target/*.war
      - name: Upload artifacts OpenDJ Commons REST LDAP Gateway
        uses: actions/upload-artifact@v7
        with:
         name: OpenDJ Commons REST LDAP Gateway
         path: opendj-rest2ldap-servlet/target/*.war
      - name: Configure Git User
        run: |
          git config --global user.name "Open Identity Platform Community"
          git config --global user.email "open-identity-platform-opendj@googlegroups.com"
          cd ..
      - uses: actions/checkout@v6
        continue-on-error: true
        with:
          repository: ${{ github.repository }}.wiki
          path: ${{ github.event.repository.name }}.wiki
      - name: Publish docs to wiki
        continue-on-error: true
        shell: bash
        env:
          GITHUB_ACTOR: ${{ github.actor }}
          GITHUB_TOKEN: ${{ github.token }}
        run:   |
          cd ${{ github.event.repository.name }}.wiki
          rm -rf asciidoc
          mkdir asciidoc
          cp -R ../opendj-doc-generated-ref/target/asciidoc/pdf ../${{ github.event.repository.name }}.wiki/asciidoc        
          git add -A
          git commit -a -m "upload docs after deploy ${{ github.sha }}"
          git push --quiet --force
 
      - uses: actions/checkout@v6
        continue-on-error: true
        with:
          repository: OpenIdentityPlatform/doc.openidentityplatform.org
          path: doc.openidentityplatform.org
          token: ${{ secrets.OIP_PAT_GH_TOKEN }}
 
      - name: Publish docs to site
        continue-on-error: true
        shell: bash
        run: |
          export REPO_NAME_LC=$(echo '${{github.event.repository.name}}' | tr '[:upper:]' '[:lower:]')
          export SITE_DOC_FOLDER=${REPO_NAME_LC}-doc-generated-ref
          cd doc.openidentityplatform.org
          rm -rf ${REPO_NAME_LC}/modules
          cp -R ../${SITE_DOC_FOLDER}/target/asciidoc/antora/modules ../doc.openidentityplatform.org/${REPO_NAME_LC}
          rm -rf ${REPO_NAME_LC}/apidocs
          cp -R ../target/reports/apidocs ../doc.openidentityplatform.org/${REPO_NAME_LC}
          git add -A
          if ! git diff-index --quiet HEAD; then
            echo "committing changes to the docs repository"
            git commit -a -m "upload ${{github.event.repository.name}} docs after deploy ${{ github.sha }}"
            git push --force https://github.com/OpenIdentityPlatform/doc.openidentityplatform.org.git
          fi