From cf9c3290b561d70340cd93ab3c82c46d84b9a3e2 Mon Sep 17 00:00:00 2001 From: Matt Date: Sun, 21 Nov 2021 15:43:29 -0500 Subject: [PATCH] Migrate CI to github actions --- .ci/azure-pipelines.yml | 22 ----- .ci/build.yml | 45 ---------- .ci/publish.yml | 27 ------ .github/dependabot.yaml | 16 ++++ .github/release-drafter.yml | 22 +++++ .github/releasing.md | 12 +++ .github/tools/reformat_changelog.py | 87 +++++++++++++++++++ .github/workflows/build.yaml | 39 +++++++++ .github/workflows/codeql.yaml | 41 +++++++++ .../workflows/create-prepare-release-pr.yaml | 72 +++++++++++++++ .github/workflows/publish.yaml | 64 ++++++++++++++ .github/workflows/release-drafter.yaml | 16 ++++ .github/workflows/test.yaml | 49 +++++++++++ 13 files changed, 418 insertions(+), 94 deletions(-) delete mode 100644 .ci/azure-pipelines.yml delete mode 100644 .ci/build.yml delete mode 100644 .ci/publish.yml create mode 100644 .github/dependabot.yaml create mode 100644 .github/release-drafter.yml create mode 100644 .github/releasing.md create mode 100755 .github/tools/reformat_changelog.py create mode 100644 .github/workflows/build.yaml create mode 100644 .github/workflows/codeql.yaml create mode 100644 .github/workflows/create-prepare-release-pr.yaml create mode 100644 .github/workflows/publish.yaml create mode 100644 .github/workflows/release-drafter.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 0a275f3..0000000 --- a/.ci/azure-pipelines.yml +++ /dev/null @@ -1,22 +0,0 @@ -trigger: - batch: true - branches: - include: - - '*' - tags: - include: - - '*' - -jobs: - - 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 d835ef3..0000000 --- a/.ci/build.yml +++ /dev/null @@ -1,45 +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 -r jellycon/requirements-dev.txt - displayName: 'Install dev dependencies' - - - task: CopyFiles@2 - displayName: 'Create clean addon directory' - inputs: - sourceFolder: 'jellycon' - cleanTargetFolder: true - contents: | - **/* - !.ci/* - !.git/**/* - !.github/* - TargetFolder: '$(Build.ArtifactStagingDirectory)/plugin.video.jellycon' - - - script: python3 '$(Build.ArtifactStagingDirectory)/plugin.video.jellycon/build.py' --version ${{ py_version }} --target '$(Build.ArtifactStagingDirectory)/' - displayName: 'Create ${{ py_version }} addon.xml' - - - task: ArchiveFiles@2 - displayName: 'Create ${{ py_version }} zip file' - inputs: - rootFolderOrFile: '$(Build.ArtifactStagingDirectory)/plugin.video.jellycon' - includeRootFolder: True - archiveType: 'zip' - tarCompression: 'none' - archiveFile: '$(Build.ArtifactStagingDirectory)/plugin.video.jellycon-${{ py_version }}.zip' - - - task: PublishPipelineArtifact@1 - displayName: 'Publish ${{ py_version }} artifact' - inputs: - targetPath: '$(Build.ArtifactStagingDirectory)/plugin.video.jellycon' - artifactName: 'plugin.video.jellycon-${{ py_version }}-$(Build.BuildNumber)' - diff --git a/.ci/publish.yml b/.ci/publish.yml deleted file mode 100644 index c8cf9fc..0000000 --- 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.jellycon-${{ 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.jellycon-${{ 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.jellycon-${{ py_version }}.zip' diff --git a/.github/dependabot.yaml b/.github/dependabot.yaml new file mode 100644 index 0000000..26938a8 --- /dev/null +++ b/.github/dependabot.yaml @@ -0,0 +1,16 @@ +version: 2 +updates: + - package-ecosystem: github-actions + directory: / + schedule: + interval: weekly + labels: + - ci + - github-actions + - package-ecosystem: pip + directory: / + schedule: + interval: weekly + labels: + - pip + - dependencies diff --git a/.github/release-drafter.yml b/.github/release-drafter.yml new file mode 100644 index 0000000..abf5733 --- /dev/null +++ b/.github/release-drafter.yml @@ -0,0 +1,22 @@ +_extends: jellyfin/jellyfin-meta-plugins + +name-template: "Release $RESOLVED_VERSION" +tag-template: "v$RESOLVED_VERSION" +version-template: "$MAJOR.$MINOR.$PATCH" + +version-resolver: + major: + labels: + - 'major' + minor: + labels: + - 'minor' + patch: + labels: + - 'patch' + default: patch + +template: | + ## :sparkles: What's New + + $CHANGES diff --git a/.github/releasing.md b/.github/releasing.md new file mode 100644 index 0000000..2e80816 --- /dev/null +++ b/.github/releasing.md @@ -0,0 +1,12 @@ +# Releasing a new Version via GitHub Actions + +0. (optional) label the PRs you want to include in this release (if you want to group them in the GH release based on topics). \ + Supported labels can be found in the Release Drafter [config-file](https://github.com/jellyfin/jellyfin-meta-plugins/blob/master/.github/release-drafter.yml) (currently inherited from `jellyfin/jellyfin-meta-plugins`) +1. ensure you have merged the PRs you want to include in the release and that the so far drafted GitHub release has captured them +2. Create a `release-prep` PR by manually triggering the 'Create Prepare-Release PR' Workflow from the Actions tab on GitHub +3. check the newly created `Prepare for release vx.y.z` PR if updated the `release.yaml` properly (update it manually if need be) +4. merge the `Prepare for release vx.y.z` and let the Actions triggered by doing that finis (should just be a couple of seconds) +5. FINALLY, trigger the `Publish JellyCon` manually from the Actions tab on GitHub. + 1. this will release the up to that point drafted GitHub Release and tag the default branch accordingly + 2. this will package and deploy `JellyCon` in the new version to the deployment server and trigger the 'kodirepo' script on it +6. Done, assuming everything ran successfully, you have now successfully published a new version! :tada: diff --git a/.github/tools/reformat_changelog.py b/.github/tools/reformat_changelog.py new file mode 100755 index 0000000..00ce597 --- /dev/null +++ b/.github/tools/reformat_changelog.py @@ -0,0 +1,87 @@ +#!/usr/bin/env python3.8 + +import argparse +import sys +import re +from typing import Dict, List, Pattern, Union, TypedDict + +from emoji.core import emojize, demojize, replace_emoji + + +ITEM_FORMAT = "+ {title} (#{issue}) @{username}" +OUTPUT_EMOJI = False + +ITEM_PATTERN: Pattern = re.compile( + r"^\s*(?P[-*+])\s*(?P.*?)\s*\(#(?P<issue>[0-9]+)\)\s*@(?P<username>[^\s]*)$" +) + + +class SectionType(TypedDict): + title: str + items: List[Dict[str, str]] + + +def reformat(item_format: str, output_emoji: bool) -> None: + data = [ + emojize(x.strip(), use_aliases=True, variant="emoji_type") + for x in sys.stdin.readlines() + if x.strip() + ] + + sections = [] + + section: Union[SectionType, Dict] = {} + for line in data: + if line.startswith("## "): + pass + if line.startswith("### "): + if section: + sections.append(section) + _section: SectionType = { + "title": line.strip("# "), + "items": [], + } + section = _section + + m = ITEM_PATTERN.match(line) + if m: + gd = m.groupdict() + section["items"].append(gd) + + sections.append(section) + + first = True + + for section in sections: + if not section: + continue + if first: + first = False + else: + print() + + title = section["title"] + if not output_emoji: + title = replace_emoji(title).strip() + + print(title) + print("-" * len(title)) + + for item in section["items"]: + formatted_item = item_format.format(**item) + if not output_emoji: + formatted_item = demojize(formatted_item) + print(formatted_item) + + +if __name__ == "__main__": + parser = argparse.ArgumentParser() + parser.add_argument("--format", type=str, default=ITEM_FORMAT) + + parser.add_argument("--no-emoji", dest="emoji", action="store_false") + parser.add_argument("--emoji", dest="emoji", action="store_true") + parser.set_defaults(emoji=OUTPUT_EMOJI) + + args = parser.parse_args() + + reformat(args.format, args.emoji) diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml new file mode 100644 index 0000000..75ac99d --- /dev/null +++ b/.github/workflows/build.yaml @@ -0,0 +1,39 @@ +name: Build JellyCon + +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 build.py --version ${{ matrix.py_version }} + + - name: Publish Build Artifact + uses: actions/upload-artifact@v2 + with: + retention-days: 14 + name: ${{ matrix.py_version }}-build-artifact + path: | + *.zip diff --git a/.github/workflows/codeql.yaml b/.github/workflows/codeql.yaml new file mode 100644 index 0000000..9c1f978 --- /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/jellycon' }} + 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/create-prepare-release-pr.yaml b/.github/workflows/create-prepare-release-pr.yaml new file mode 100644 index 0000000..aec8f3c --- /dev/null +++ b/.github/workflows/create-prepare-release-pr.yaml @@ -0,0 +1,72 @@ +name: Create Prepare-Release PR + +on: + workflow_dispatch: + +jobs: + create_pr: + name: "Create Pump Version PR" + runs-on: ubuntu-latest + steps: + + - name: Update Draft + uses: release-drafter/release-drafter@v5.15.0 + id: draft + env: + GITHUB_TOKEN: ${{ secrets.JF_BOT_TOKEN }} + + - name: Setup YQ + uses: chrisdickinson/setup-yq@latest + with: + yq-version: v4.9.1 + + - name: Checkout repository + uses: actions/checkout@v2 + + - name: Parse Changlog + run: | + pip install emoji + cat << EOF >> cl.md + ${{ steps.draft.outputs.body }} + EOF + TAG="${{ steps.draft.outputs.tag_name }}" + echo "VERSION=${TAG#v}" >> $GITHUB_ENV + echo "YAML_CHANGELOG<<EOF" >> $GITHUB_ENV + cat cl.md | python .github/tools/reformat_changelog.py --no-emoji >> $GITHUB_ENV + echo "EOF" >> $GITHUB_ENV + echo "CHANGELOG<<EOF" >> $GITHUB_ENV + cat cl.md | python .github/tools/reformat_changelog.py --emoji --format='+ #{issue} by @{username}' >> $GITHUB_ENV + echo "EOF" >> $GITHUB_ENV + rm cl.md + + - name: Update release.yaml + run: | + yq eval '.version = env(VERSION) | .changelog = strenv(YAML_CHANGELOG) | .changelog style="literal"' -i release.yaml + + - name: Commit Changes + run: | + git config user.name "jellyfin-bot" + git config user.email "team@jellyfin.org" + + git checkout -b prepare-${{ env.VERSION }} + git commit -am "bump version to ${{ env.VERSION }}" + + if [[ -z "$(git ls-remote --heads origin prepare-${{ env.VERSION }})" ]]; then + git push origin prepare-${{ env.VERSION }} + else + git push -f origin prepare-${{ env.VERSION }} + fi + + - name: Create or Update PR + uses: k3rnels-actions/pr-update@v1 + with: + token: ${{ secrets.JF_BOT_TOKEN }} + pr_title: Prepare for release ${{ steps.draft.outputs.tag_name }} + pr_source: prepare-${{ env.VERSION }} + pr_labels: 'release-prep,skip-changelog' + pr_body: | + :robot: This is a generated PR to bump the `release.yaml` version and update the changelog. + + --- + + ${{ env.CHANGELOG }} diff --git a/.github/workflows/publish.yaml b/.github/workflows/publish.yaml new file mode 100644 index 0000000..705db71 --- /dev/null +++ b/.github/workflows/publish.yaml @@ -0,0 +1,64 @@ +name: Publish JellyCon + +on: + workflow_dispatch: + +jobs: + publish: + runs-on: ubuntu-latest + strategy: + matrix: + py_version: [ 'py2', 'py3' ] + steps: + - name: Update Draft + uses: release-drafter/release-drafter@v5.15.0 + if: ${{ matrix.py_version == 'py3' }} + with: + publish: true + env: + GITHUB_TOKEN: ${{ secrets.JF_BOT_TOKEN }} + + - 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 build.py --version ${{ matrix.py_version }} + + - name: Publish Build Artifact + uses: actions/upload-artifact@v2 + with: + retention-days: 14 + name: ${{ matrix.py_version }}-build-artifact + path: | + *.zip + + - name: Upload to repo server + uses: burnett01/rsync-deployments@5.1 + with: + switches: -vrptz + path: '*.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 }} + script_stop: true + script: | + python3 /usr/local/bin/kodirepo add /srv/repository/incoming/kodi/plugin.video.jellycon+${{ matrix.py_version }}.zip --datadir /srv/repository/releases/client/kodi/${{ matrix.py_version }}; + rm /srv/repository/incoming/kodi/plugin.video.jellycon+${{ matrix.py_version }}.zip; diff --git a/.github/workflows/release-drafter.yaml b/.github/workflows/release-drafter.yaml new file mode 100644 index 0000000..9a45190 --- /dev/null +++ b/.github/workflows/release-drafter.yaml @@ -0,0 +1,16 @@ +name: Release Drafter + +on: + push: + branches: + - master + +jobs: + update_release_draft: + name: Update release draft + runs-on: ubuntu-latest + steps: + - name: Update Release Draft + uses: release-drafter/release-drafter@v5.15.0 + env: + GITHUB_TOKEN: ${{ secrets.JF_BOT_TOKEN }} diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml new file mode 100644 index 0000000..e4111a6 --- /dev/null +++ b/.github/workflows/test.yaml @@ -0,0 +1,49 @@ +name: Test JellyCon + +on: + push: + branches: + - master + pull_request: + branches: + - master + +env: + PR_TRIGGERED: ${{ github.event_name == 'pull_request' && github.repository == 'jellyfin/jellycon' }} + +jobs: + test: + runs-on: ubuntu-latest + strategy: + fail-fast: false + 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: 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: Publish Test Atrifact + uses: actions/upload-artifact@v2 + with: + retention-days: 14 + name: ${{ matrix.py_version }}-test-results + path: | + flake8.output