From 9b3edc8bd1120abfa69bc5b0b06b6924e37ba101 Mon Sep 17 00:00:00 2001
From: h1dden-da3m0n <33120068+h1dden-da3m0n@users.noreply.github.com>
Date: Fri, 14 May 2021 17:18:54 +0200
Subject: [PATCH] migrate Azure Pipelines to GitHub Actions

---
 .ci/azure-pipelines.yml              | 35 ------------
 .ci/build.yml                        | 46 ----------------
 .ci/publish.yml                      | 27 ----------
 .ci/validate.yml                     | 58 --------------------
 .config/generate_xml.py              |  4 +-
 .github/workflows/build-publish.yaml | 81 ++++++++++++++++++++++++++++
 .github/workflows/codeql.yaml        | 41 ++++++++++++++
 .github/workflows/test.yaml          | 77 ++++++++++++++++++++++++++
 8 files changed, 201 insertions(+), 168 deletions(-)
 delete mode 100644 .ci/azure-pipelines.yml
 delete mode 100644 .ci/build.yml
 delete mode 100644 .ci/publish.yml
 delete mode 100644 .ci/validate.yml
 create mode 100644 .github/workflows/build-publish.yaml
 create mode 100644 .github/workflows/codeql.yaml
 create mode 100644 .github/workflows/test.yaml

diff --git a/.ci/azure-pipelines.yml b/.ci/azure-pipelines.yml
deleted file mode 100644
index a76bfc1d..00000000
--- a/.ci/azure-pipelines.yml
+++ /dev/null
@@ -1,35 +0,0 @@
-trigger:
-  batch: true
-  branches:
-    include:
-      - '*'
-  tags:
-    include:
-      - '*'
-
-jobs:
-  - job: 'Validate'
-    pool:
-      vmImage: 'ubuntu-18.04'
-    strategy:
-      matrix:
-        Python27:
-          python.version: '2.7'
-        Python36:
-          python.version: '3.6'
-    steps:
-      # Run tests and linting
-      - template: validate.yml
-
-  - job: Build
-    steps:
-      # On every PR, build the addon and make it available for download as an artifact
-      - template: build.yml
-        parameters:
-          py_versions: [ 'py2', 'py3' ]
-
-      # When triggered by a tag, publish the built addon to the repo server
-      - ${{ if startsWith(variables['Build.SourceBranch'], 'refs/tags') }}:
-        - template: publish.yml
-          parameters:
-            py_versions: [ 'py2', 'py3' ]
diff --git a/.ci/build.yml b/.ci/build.yml
deleted file mode 100644
index 14865b1e..00000000
--- a/.ci/build.yml
+++ /dev/null
@@ -1,46 +0,0 @@
-parameters:
-  python_versions : []
-
-steps:
-  - ${{ each py_version in parameters.py_versions }}:
-    - task: usePythonVersion@0
-      inputs:
-        versionSpec: '3.6'
-
-    - checkout: self
-      clean: true
-
-    - script: python3 -m pip install --user pyyaml
-      displayName: 'Install PyYaml'
-
-    - script: python3 jellyfin-kodi/.config/generate_xml.py ${{ py_version }}
-      displayName: 'Create ${{ py_version }} addon.xml'
-
-    - task: CopyFiles@2
-      displayName: 'Create clean addon directory'
-      inputs:
-        sourceFolder: 'jellyfin-kodi'
-        cleanTargetFolder: true
-        contents: |
-          **/*
-          !.ci/*
-          !.config/*
-          !.git/**/*
-          !.github/*
-        TargetFolder: '$(Build.ArtifactStagingDirectory)/plugin.video.jellyfin'
-
-    - task: ArchiveFiles@2
-      displayName: 'Create ${{ py_version }} zip file'
-      inputs:
-        rootFolderOrFile: '$(Build.ArtifactStagingDirectory)/plugin.video.jellyfin'
-        includeRootFolder: True
-        archiveType: 'zip'
-        tarCompression: 'none'
-        archiveFile: '$(Build.ArtifactStagingDirectory)/plugin.video.jellyfin-${{ py_version }}.zip'
-
-    - task: PublishPipelineArtifact@1
-      displayName: 'Publish ${{ py_version }} artifact'
-      inputs:
-        targetPath: '$(Build.ArtifactStagingDirectory)/plugin.video.jellyfin'
-        artifactName: 'plugin.video.jellyfin-${{ py_version }}-$(Build.BuildNumber)'
-
diff --git a/.ci/publish.yml b/.ci/publish.yml
deleted file mode 100644
index fddc79a4..00000000
--- a/.ci/publish.yml
+++ /dev/null
@@ -1,27 +0,0 @@
-parameters:
-  python_version : []
-
-steps:
-  - ${{ each py_version in parameters.py_versions }}:
-    - task: CopyFilesOverSSH@0
-      displayName: 'Upload to repo server'
-      inputs:
-        sshEndpoint: repository
-        sourceFolder: '$(Build.ArtifactStagingDirectory)'
-        contents: 'plugin.video.jellyfin-${{ py_version }}.zip'
-        targetFolder: '/srv/repository/incoming/kodi'
-
-    - task: SSH@0
-      displayName: 'Add to Kodi repo'
-      inputs:
-        sshEndpoint: repository
-        runOptions: 'commands'
-        commands: 'python3 /usr/local/bin/kodirepo add /srv/repository/incoming/kodi/plugin.video.jellyfin-${{ py_version }}.zip --datadir /srv/repository/releases/client/kodi/${{ py_version }}'
-        failOnStdErr: false
-
-    - task: SSH@0
-      displayName: 'Clean up zip files'
-      inputs:
-        sshEndpoint: repository
-        runOptions: 'commands'
-        commands: 'rm /srv/repository/incoming/kodi/plugin.video.jellyfin-${{ py_version }}.zip'
diff --git a/.ci/validate.yml b/.ci/validate.yml
deleted file mode 100644
index a4313c3e..00000000
--- a/.ci/validate.yml
+++ /dev/null
@@ -1,58 +0,0 @@
-steps:
-  - task: UsePythonVersion@0
-    inputs:
-      versionSpec: '$(python.version)'
-
-  - script: python -m pip install -r requirements-dev.txt
-    displayName: 'Install dev tools'
-
-  - script: |
-      # Azure pipelines: https://github.com/microsoft/azure-pipelines-tasks/blob/master/docs/authoring/commands.md
-      # GitHub actions: https://docs.github.com/en/free-pro-team@latest/actions/reference/workflow-commands-for-github-actions
-
-      rm -f flake8.output
-      flake8 . --statistics --output-file=flake8.output && {
-        echo "##vso[task.complete result=Succeeded;]"
-      } || {
-        echo "##vso[task.complete result=Failed;]"
-      }
-
-      cat flake8.output | awk -F: '{
-        if ($0 ~ /^\./) {
-          gsub(/^[ \t]+/,"",$4);
-          codesep=index($4, " ");
-          code=substr($4, 1, codesep-1);
-          msg=substr($4, codesep+1);
-          print "##vso[task.logissue type=error;sourcepath=" $1 ";linenumber=" $2 ";columnnumber=" $3 ";code=" code ";]" msg;
-        } else {
-          print $0
-        }
-      }'
-    displayName: 'Run Linter'
-    failOnStderr: false
-
-  - script: |
-      rm -f test.xml coverage.xml
-      coverage run && {
-        echo "##vso[task.complete result=Succeeded;]"
-      } || {
-        echo "##vso[task.complete result=Failed;]"
-      }
-      coverage xml
-      coverage html
-      coverage report
-    displayName: 'Run Tests'
-    failOnStderr: false
-    condition: succeededOrFailed()
-
-  - task: PublishTestResults@2
-    condition: succeededOrFailed()
-    inputs:
-      testResultsFiles: 'test.xml'
-      testRunTitle: 'Publish test results for Python $(python.version)'
-
-  - task: PublishCodeCoverageResults@1
-    condition: succeededOrFailed()
-    inputs:
-      codeCoverageTool: 'cobertura'
-      summaryFileLocation: 'coverage.xml'
diff --git a/.config/generate_xml.py b/.config/generate_xml.py
index a854960b..025e8f74 100644
--- a/.config/generate_xml.py
+++ b/.config/generate_xml.py
@@ -44,7 +44,7 @@ with open('{dir_path}/{py_version}.yaml'.format(**locals()), 'r') as f:
     deps = yaml.safe_load(f)
 
 # Load version and changelog
-with open('jellyfin-kodi/release.yaml', 'r') as f:
+with open('release.yaml', 'r') as f:
     data = yaml.safe_load(f)
 
 # Populate xml template
@@ -67,4 +67,4 @@ for section in root.findall('extension'):
 indent(root)
 
 # Write addon.xml
-tree.write('jellyfin-kodi/addon.xml', encoding='utf-8', xml_declaration=True)
+tree.write('addon.xml', encoding='utf-8', xml_declaration=True)
diff --git a/.github/workflows/build-publish.yaml b/.github/workflows/build-publish.yaml
new file mode 100644
index 00000000..d858df07
--- /dev/null
+++ b/.github/workflows/build-publish.yaml
@@ -0,0 +1,81 @@
+name: Build Jellyfin-Kodi
+
+on:
+  push:
+    branches:
+      - master
+    tags:
+      - '*'
+
+jobs:
+  build:
+    runs-on: ubuntu-latest
+    strategy:
+      matrix:
+        py_version: [ 'py2', 'py3' ]
+    steps:
+      - name: Checkout repository
+        uses: actions/checkout@v2
+
+      - name: Set up Python 3.x
+        uses: actions/setup-python@v2
+        with:
+          python-version: 3.9
+
+      - name: Install dependencies
+        run: |
+          python -m pip install --upgrade pip
+          python -m pip install pyyaml
+
+      - name: Create ${{ matrix.py_version }} addon.xml
+        run: python .config/generate_xml.py ${{ matrix.py_version }}
+
+      - name: Publish Build Atrifact
+        uses: actions/upload-artifact@v2
+        with:
+          retention-days: 14
+          name: ${{ matrix.py_version }}-build-artifact
+          path: |
+            **/*
+            !.ci/*
+            !.config/*
+            !.git/**/*
+            !.github/*
+
+  publish:
+    runs-on: ubuntu-latest
+    needs: build
+    if: ${{ startsWith(github.ref, 'refs/tags/') && github.repository == 'jellyfin/jellyfin-kodi' }}
+    strategy:
+      matrix:
+        py_version: [ 'py2', 'py3' ]
+    steps:
+      - uses: actions/download-artifact@v2
+        with:
+          name: ${{ matrix.py_version }}-build-artifact
+          path: plugin.video.jellyfin-${{ matrix.py_version }}
+
+      - name: Create release Zip
+        run: zip -rq plugin.video.jellyfin-${{ matrix.py_version }}.zip plugin.video.jellyfin-${{ matrix.py_version }}
+
+      - name: Upload to repo server
+        uses: burnett01/rsync-deployments@4.1
+        with:
+          switches: -rltgoDzvO --delete --exclude='*' --include='**/*.apk' --include='*.txt'
+          path: plugin.video.jellyfin-${{ matrix.py_version }}.zip
+          remote_path: /srv/repository/incoming/kodi
+          remote_host: ${{ secrets.DEPLOY_HOST }}
+          remote_user: ${{ secrets.DEPLOY_USER }}
+          remote_key: ${{ secrets.DEPLOY_KEY }}
+
+      - name: Add to Kodi repo and clean up
+        uses: appleboy/ssh-action@v0.1.4
+        with:
+          host: ${{ secrets.DEPLOY_HOST  }}
+          username: ${{ secrets.DEPLOY_USER }}
+          key: ${{ secrets.DEPLOY_KEY }}
+          envs: JELLYFIN_VERSION
+          script_stop: true
+          script: |
+            python3 /usr/local/bin/kodirepo add /srv/repository/incoming/kodi/plugin.video.jellyfin-${{ matrix.py_version }}.zip --datadir /srv/repository/releases/client/kodi/${{ matrix.py_version }};
+            rm /srv/repository/incoming/kodi/plugin.video.jellyfin-${{ matrix.py_version }}.zip;
diff --git a/.github/workflows/codeql.yaml b/.github/workflows/codeql.yaml
new file mode 100644
index 00000000..701c2aef
--- /dev/null
+++ b/.github/workflows/codeql.yaml
@@ -0,0 +1,41 @@
+name: CodeQL Analysis
+
+on:
+  push:
+    branches:
+      - master
+  pull_request:
+    branches:
+      - master
+  schedule:
+    - cron: '38 8 * * 6'
+
+jobs:
+  analyze:
+    runs-on: ubuntu-latest
+    if: ${{ github.repository == 'jellyfin/jellyfin-kodi' }}
+    strategy:
+      fail-fast: false
+      matrix:
+        language: [ 'python' ]
+        version: ['2.7', '3.9']
+    steps:
+      - name: Checkout repository
+        uses: actions/checkout@v2
+
+      - name: Initialize CodeQL
+        uses: github/codeql-action/init@v1
+        with:
+          languages: ${{ matrix.language }}
+          queries: +security-and-quality
+
+      - name: Set up Python
+        uses: actions/setup-python@v2
+        with:
+          python-version: ${{ matrix.version }}
+
+      - name: Autobuild
+        uses: github/codeql-action/autobuild@v1
+
+      - name: Perform CodeQL Analysis
+        uses: github/codeql-action/analyze@v1
diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml
new file mode 100644
index 00000000..bab6f152
--- /dev/null
+++ b/.github/workflows/test.yaml
@@ -0,0 +1,77 @@
+name: Test Jellyfin-Kodi
+
+on:
+  push:
+    branches:
+      - master
+  pull_request:
+    branches:
+      - master
+
+env:
+  PR_TRIGGERED: ${{ github.event_name == 'pull_request' && github.repository == 'jellyfin/jellyfin-kodi' }}
+
+jobs:
+  test:
+    runs-on: ubuntu-latest
+    strategy:
+      matrix:
+        py_version: ['2.7', '3.9']
+    steps:
+      - name: Checkout repository
+        uses: actions/checkout@v2
+
+      - name: Set up Python ${{ matrix.py_version }}
+        uses: actions/setup-python@v2
+        with:
+          python-version: ${{ matrix.py_version }}
+
+      - name: Setup reviewdog
+        uses: reviewdog/action-setup@v1
+        if: ${{ env.PR_TRIGGERED == 'true' && matrix.py_version == '3.9' }}
+        with:
+          reviewdog_version: nightly
+
+      - name: Install dependencies
+        run: |
+          python -m pip install --upgrade pip
+          python -m pip install -r requirements-dev.txt
+
+      - name: Lint with flake8
+        run: |
+          # stop the build if there are Python syntax errors or undefined names
+          flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics
+          # exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide
+          flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics --output-file=flake8.output
+          cat flake8.output
+
+      - name: Test with Coverage
+        run: |
+          coverage run
+          coverage xml
+          coverage report
+
+      - name: Run reviewdog for PR checks-api
+        if: ${{ env.PR_TRIGGERED == 'true' && matrix.py_version == '3.9' }}
+        env:
+          REVIEWDOG_GITHUB_API_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+        run: |
+          cat flake8.output | reviewdog -reporter=github-pr-check -f=flake8 -name="flake8"
+
+      - name: Publish Coverage to PR
+        uses: 5monkeys/cobertura-action@v8
+        if: ${{ env.PR_TRIGGERED == 'true' && matrix.py_version == '3.9' }}
+        with:
+          path: coverage.xml
+          repo_token: ${{ secrets.JF_BOT_TOKEN }}
+          minimum_coverage: 1
+
+      - name: Publish Test Atrifact
+        uses: actions/upload-artifact@v2
+        with:
+          retention-days: 14
+          name: ${{ matrix.py_version }}-test-results
+          path: |
+            flake8.output
+            test.xml
+            coverage.xml