aboutsummaryrefslogtreecommitdiff
path: root/.github/workflows/ci-openapi.yml
blob: 0a391dbe1b5509d4c3c837beb5a3272ecbd1af65 (plain)
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
name: OpenAPI
on:
  push:
    branches:
      - master
    tags:
      - 'v*'
  pull_request_target:

permissions: {}

jobs:
  openapi-head:
    name: OpenAPI - HEAD
    runs-on: ubuntu-latest
    permissions: read-all
    steps:
      - name: Checkout repository
        uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
        with:
          ref: ${{ github.event.pull_request.head.sha }}
          repository: ${{ github.event.pull_request.head.repo.full_name }}
      - name: Setup .NET
        uses: actions/setup-dotnet@2016bd2012dba4e32de620c46fe006a3ac9f0602 # v5.0.1
        with:
          dotnet-version: '9.0.x'
      - name: Generate openapi.json
        run: dotnet test tests/Jellyfin.Server.Integration.Tests/Jellyfin.Server.Integration.Tests.csproj -c Release --filter "Jellyfin.Server.Integration.Tests.OpenApiSpecTests"
      - name: Upload openapi.json
        uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5.0.0
        with:
          name: openapi-head
          retention-days: 14
          if-no-files-found: error
          path: tests/Jellyfin.Server.Integration.Tests/bin/Release/net9.0/openapi.json

  openapi-base:
    name: OpenAPI - BASE
    if: ${{ github.base_ref != '' }}
    runs-on: ubuntu-latest
    permissions: read-all
    steps:
      - name: Checkout repository
        uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
        with:
          ref: ${{ github.event.pull_request.head.sha }}
          repository: ${{ github.event.pull_request.head.repo.full_name }}
          fetch-depth: 0
      - name: Checkout common ancestor
        env:
          HEAD_REF: ${{ github.head_ref }}
        run: |
          git remote add upstream https://github.com/${{ github.event.pull_request.base.repo.full_name }}
          git -c protocol.version=2 fetch --prune --progress --no-recurse-submodules upstream +refs/heads/*:refs/remotes/upstream/* +refs/tags/*:refs/tags/*
          ANCESTOR_REF=$(git merge-base upstream/${{ github.base_ref }} origin/$HEAD_REF)
          git checkout --progress --force $ANCESTOR_REF
      - name: Setup .NET
        uses: actions/setup-dotnet@2016bd2012dba4e32de620c46fe006a3ac9f0602 # v5.0.1
        with:
          dotnet-version: '9.0.x'
      - name: Generate openapi.json
        run: dotnet test tests/Jellyfin.Server.Integration.Tests/Jellyfin.Server.Integration.Tests.csproj -c Release --filter "Jellyfin.Server.Integration.Tests.OpenApiSpecTests"
      - name: Upload openapi.json
        uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5.0.0
        with:
          name: openapi-base
          retention-days: 14
          if-no-files-found: error
          path: tests/Jellyfin.Server.Integration.Tests/bin/Release/net9.0/openapi.json

  openapi-diff:
    permissions:
      pull-requests: write  #  to create or update comment (peter-evans/create-or-update-comment)

    name: OpenAPI - Difference
    if: ${{ github.event_name == 'pull_request_target' }}
    runs-on: ubuntu-latest
    needs:
      - openapi-head
      - openapi-base
    steps:
      - name: Download openapi-head
        uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # v6.0.0
        with:
          name: openapi-head
          path: openapi-head
      - name: Download openapi-base
        uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # v6.0.0
        with:
          name: openapi-base
          path: openapi-base
      - name: Workaround openapi-diff issue
        run: |
          sed -i 's/"allOf"/"oneOf"/g' openapi-head/openapi.json
          sed -i 's/"allOf"/"oneOf"/g' openapi-base/openapi.json
      - name: Calculate OpenAPI difference
        uses: docker://openapitools/openapi-diff
        continue-on-error: true
        with:
          args: --fail-on-changed --markdown openapi-changes.md openapi-base/openapi.json openapi-head/openapi.json
      - id: read-diff
        name: Read openapi-diff output
        run: |
          # Read and fix markdown
          body=$(cat openapi-changes.md)
          # Write to workflow summary
          echo "$body" >> $GITHUB_STEP_SUMMARY
          # Set ApiChanged var
          if [ "$body" != '' ]; then
            echo "ApiChanged=1" >> "$GITHUB_OUTPUT"
          else
            echo "ApiChanged=0" >> "$GITHUB_OUTPUT"
          fi
          # Add header/footer for diff comment
          echo '<!--openapi-diff-workflow-comment-->' > openapi-changes-reply.md
          echo "<details>" >> openapi-changes-reply.md
          echo "<summary>Changes in OpenAPI specification found. Expand to see details.</summary>" >> openapi-changes-reply.md
          echo "" >> openapi-changes-reply.md
          echo "$body" >> openapi-changes-reply.md
          echo "" >> openapi-changes-reply.md
          echo "</details>" >> openapi-changes-reply.md
      - name: Find difference comment
        uses: peter-evans/find-comment@b30e6a3c0ed37e7c023ccd3f1db5c6c0b0c23aad # v4.0.0
        id: find-comment
        with:
          issue-number: ${{ github.event.pull_request.number }}
          direction: last
          body-includes: openapi-diff-workflow-comment
      - name: Reply or edit difference comment (changed)
        uses: peter-evans/create-or-update-comment@e8674b075228eee787fea43ef493e45ece1004c9 # v5.0.0
        if: ${{ steps.read-diff.outputs.ApiChanged == '1' }}
        with:
          issue-number: ${{ github.event.pull_request.number }}
          comment-id: ${{ steps.find-comment.outputs.comment-id }}
          edit-mode: replace
          body-path: openapi-changes-reply.md
      - name: Edit difference comment (unchanged)
        uses: peter-evans/create-or-update-comment@e8674b075228eee787fea43ef493e45ece1004c9 # v5.0.0
        if: ${{ steps.read-diff.outputs.ApiChanged == '0' && steps.find-comment.outputs.comment-id != '' }}
        with:
          issue-number: ${{ github.event.pull_request.number }}
          comment-id: ${{ steps.find-comment.outputs.comment-id }}
          edit-mode: replace
          body: |
            <!--openapi-diff-workflow-comment-->

            No changes to OpenAPI specification found. See history of this comment for previous changes.

  publish-unstable:
    name: OpenAPI - Publish Unstable Spec
    if: ${{ github.event_name != 'pull_request_target' && !startsWith(github.ref, 'refs/tags/v') && contains(github.repository_owner, 'jellyfin') }}
    runs-on: ubuntu-latest
    needs:
      - openapi-head
    steps:
      - name: Set unstable dated version
        id: version
        run: |-
          echo "JELLYFIN_VERSION=$(date +'%Y%m%d%H%M%S')" >> $GITHUB_ENV
      - name: Download openapi-head
        uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # v6.0.0
        with:
          name: openapi-head
          path: openapi-head
      - name: Upload openapi.json (unstable) to repository server
        uses: appleboy/scp-action@ff85246acaad7bdce478db94a363cd2bf7c90345 # v1.0.0
        with:
          host: "${{ secrets.REPO_HOST }}"
          username: "${{ secrets.REPO_USER }}"
          key: "${{ secrets.REPO_KEY }}"
          source: openapi-head/openapi.json
          strip_components: 1
          target: "/srv/incoming/openapi/unstable/jellyfin-openapi-${{ env.JELLYFIN_VERSION }}"
      - name: Move openapi.json (unstable) into place
        uses: appleboy/ssh-action@823bd89e131d8d508129f9443cad5855e9ba96f0 # v1.2.4
        with:
          host: "${{ secrets.REPO_HOST }}"
          username: "${{ secrets.REPO_USER }}"
          key: "${{ secrets.REPO_KEY }}"
          debug: false
          script_stop: false
          script: |
            if ! test -d /run/workflows; then
                sudo mkdir -p /run/workflows
                sudo chown ${{ secrets.REPO_USER }} /run/workflows
            fi
            (
            flock -x -w 300 200 || exit 1
            TGT_DIR="/srv/repository/main/openapi"
            LAST_SPEC="$( ls -lt ${TGT_DIR}/unstable/ | grep 'jellyfin-openapi' | head -1 | awk '{ print $NF }' )"
            # If new and previous spec don't differ (diff retcode 0), remove incoming and finish
            if diff /srv/incoming/openapi/unstable/jellyfin-openapi-${{ env.JELLYFIN_VERSION }}/openapi.json ${TGT_DIR}/unstable/${LAST_SPEC} &>/dev/null; then
                rm -r /srv/incoming/openapi/unstable/jellyfin-openapi-${{ env.JELLYFIN_VERSION }}
                exit 0
            fi
            # Move new spec into place
            sudo mv /srv/incoming/openapi/unstable/jellyfin-openapi-${{ env.JELLYFIN_VERSION }}/openapi.json ${TGT_DIR}/unstable/jellyfin-openapi-${{ env.JELLYFIN_VERSION }}.json
            # Delete previous jellyfin-openapi-unstable_previous.json
            sudo rm ${TGT_DIR}/jellyfin-openapi-unstable_previous.json
            # Move current jellyfin-openapi-unstable.json symlink to jellyfin-openapi-unstable_previous.json
            sudo mv ${TGT_DIR}/jellyfin-openapi-unstable.json ${TGT_DIR}/jellyfin-openapi-unstable_previous.json
            # Create new jellyfin-openapi-unstable.json symlink
            sudo ln -s unstable/jellyfin-openapi-${{ env.JELLYFIN_VERSION }}.json ${TGT_DIR}/jellyfin-openapi-unstable.json
            # Check that the previous openapi unstable spec link is correct
            if [[ "$( readlink ${TGT_DIR}/jellyfin-openapi-unstable_previous.json )" != "unstable/${LAST_SPEC}" ]]; then
                sudo rm ${TGT_DIR}/jellyfin-openapi-unstable_previous.json
                sudo ln -s unstable/${LAST_SPEC} ${TGT_DIR}/jellyfin-openapi-unstable_previous.json
            fi
            ) 200>/run/workflows/openapi-unstable.lock

  publish-stable:
    name: OpenAPI - Publish Stable Spec
    if: ${{ startsWith(github.ref, 'refs/tags/v') && contains(github.repository_owner, 'jellyfin') }}
    runs-on: ubuntu-latest
    needs:
      - openapi-head
    steps:
      - name: Set version number
        id: version
        run: |-
          echo "JELLYFIN_VERSION=${GITHUB_REF#refs/tags/v}" >> $GITHUB_ENV
      - name: Download openapi-head
        uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # v6.0.0
        with:
          name: openapi-head
          path: openapi-head
      - name: Upload openapi.json (stable) to repository server
        uses: appleboy/scp-action@ff85246acaad7bdce478db94a363cd2bf7c90345 # v1.0.0
        with:
          host: "${{ secrets.REPO_HOST }}"
          username: "${{ secrets.REPO_USER }}"
          key: "${{ secrets.REPO_KEY }}"
          source: openapi-head/openapi.json
          strip_components: 1
          target: "/srv/incoming/openapi/stable/jellyfin-openapi-${{ env.JELLYFIN_VERSION }}"
      - name: Move openapi.json (stable) into place
        uses: appleboy/ssh-action@823bd89e131d8d508129f9443cad5855e9ba96f0 # v1.2.4
        with:
          host: "${{ secrets.REPO_HOST }}"
          username: "${{ secrets.REPO_USER }}"
          key: "${{ secrets.REPO_KEY }}"
          debug: false
          script_stop: false
          script: |
            if ! test -d /run/workflows; then
                sudo mkdir -p /run/workflows
                sudo chown ${{ secrets.REPO_USER }} /run/workflows
            fi
            (
            flock -x -w 300 200 || exit 1
            TGT_DIR="/srv/repository/main/openapi"
            LAST_SPEC="$( ls -lt ${TGT_DIR}/stable/ | grep 'jellyfin-openapi' | head -1 | awk '{ print $NF }' )"
            # If new and previous spec don't differ (diff retcode 0), remove incoming and finish
            if diff /srv/incoming/openapi/stable/jellyfin-openapi-${{ env.JELLYFIN_VERSION }}/openapi.json ${TGT_DIR}/stable/${LAST_SPEC} &>/dev/null; then
                rm -r /srv/incoming/openapi/stable/jellyfin-openapi-${{ env.JELLYFIN_VERSION }}
                exit 0
            fi
            # Move new spec into place
            sudo mv /srv/incoming/openapi/stable/jellyfin-openapi-${{ env.JELLYFIN_VERSION }}/openapi.json ${TGT_DIR}/stable/jellyfin-openapi-${{ env.JELLYFIN_VERSION }}.json
            # Delete previous jellyfin-openapi-stable_previous.json
            sudo rm ${TGT_DIR}/jellyfin-openapi-stable_previous.json
            # Move current jellyfin-openapi-stable.json symlink to jellyfin-openapi-stable_previous.json
            sudo mv ${TGT_DIR}/jellyfin-openapi-stable.json ${TGT_DIR}/jellyfin-openapi-stable_previous.json
            # Create new jellyfin-openapi-stable.json symlink
            sudo ln -s stable/jellyfin-openapi-${{ env.JELLYFIN_VERSION }}.json ${TGT_DIR}/jellyfin-openapi-stable.json
            # Check that the previous openapi stable spec link is correct
            if [[ "$( readlink ${TGT_DIR}/jellyfin-openapi-stable_previous.json )" != "stable/${LAST_SPEC}" ]]; then
                sudo rm ${TGT_DIR}/jellyfin-openapi-stable_previous.json
                sudo ln -s stable/${LAST_SPEC} ${TGT_DIR}/jellyfin-openapi-stable_previous.json
            fi
            ) 200>/run/workflows/openapi-stable.lock