Modify repository so HEAD contains the Matrix version (#100)

This commit is contained in:
Michaël Arnauts 2022-02-02 17:49:48 +01:00 committed by GitHub
parent bcb5caceeb
commit 16bb1ceab3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
16 changed files with 397 additions and 99 deletions

View File

@ -4,3 +4,11 @@ ADDON_PASSWORD=
KODI_HOME=tests/home
KODI_INTERACTIVE=0
KODI_STUB_VERBOSE=1
KODI_STUB_RPC_RESPONSES=tests/rpc
#HTTP_PROXY=
#HTTPS_PROXY=
GH_USERNAME=
GH_TOKEN=
EMAIL=

1
.gitattributes vendored
View File

@ -6,3 +6,4 @@ tests/ export-ignore
.pylintrc export-ignore
Makefile export-ignore
requirements.txt export-ignore
scripts/ export-ignore

View File

@ -11,10 +11,6 @@ jobs:
kodi-addon-checker:
name: Addon checker
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
kodi-version: [ leia, matrix ]
steps:
- name: Check out ${{ github.sha }} from repository ${{ github.repository }}
uses: actions/checkout@v2
@ -22,6 +18,5 @@ jobs:
- name: Run kodi-addon-checker
uses: xbmc/action-kodi-addon-checker@v1.2
with:
kodi-version: ${{ matrix.kodi-version }}
rewrite-for-matrix: ${{ matrix.kodi-version == 'matrix' }}
kodi-version: matrix
addon-id: ${{ github.event.repository.name }}

View File

@ -3,10 +3,10 @@ on:
# Run action when pushed to master, or for commits in a pull request.
push:
branches:
- master
- master
pull_request:
branches:
- master
- master
jobs:
tests:
name: Add-on testing
@ -54,7 +54,7 @@ jobs:
KODI_INTERACTIVE: 0
KODI_STUB_RPC_RESPONSES: ${{ github.workspace }}/tests/rpc
HTTP_PROXY: ${{ secrets.HTTP_PROXY }}
run: pytest -v --cov=./ --cov-report=xml tests
run: pytest -x -v --cov=./ --cov-report=xml tests
- name: Upload code coverage to CodeCov
uses: codecov/codecov-action@v1

View File

@ -6,22 +6,13 @@ on:
jobs:
build:
name: Release plugin.video.viervijfzes
if: startsWith(github.ref, 'refs/tags/') # prevent from running if it's not a tag
runs-on: ubuntu-latest
steps:
- name: Checkout code
- name: Check out ${{ github.sha }} from repository ${{ github.repository }}
uses: actions/checkout@v2
- name: Build zip files
id: build
run: |
sudo apt-get install libxml2-utils
make multizip release=1
echo ::set-output name=leia-filename::$(cd ..;ls plugin.video.viervijfzes*.zip | grep -v '+matrix.' | head -1)
echo ::set-output name=matrix-filename::$(cd ..;ls plugin.video.viervijfzes*+matrix.*.zip | head -1)
- name: Get body
id: get-body
- name: Get changelog
id: get-changelog
run: |
description=$(sed '1,6d;/^## /,$d' CHANGELOG.md)
echo $description
@ -30,47 +21,14 @@ jobs:
description="${description//$'\r'/'%0D'}"
echo ::set-output name=body::$description
- name: Create Release
id: create_release
uses: actions/create-release@v1
env:
GITHUB_TOKEN: ${{ secrets.GH_TOKEN }}
- name: Generate distribution zips
run: scripts/build.py
- name: Create Release on Github
uses: softprops/action-gh-release@v1
with:
tag_name: ${{ github.ref }}
release_name: ${{ github.ref }}
body: ${{ steps.get-body.outputs.body }}
body: ${{ steps.get-changelog.outputs.body }}
draft: false
prerelease: false
- name: Upload Leia zip
uses: actions/upload-release-asset@v1
env:
GITHUB_TOKEN: ${{ secrets.GH_TOKEN }}
with:
upload_url: ${{ steps.create_release.outputs.upload_url }}
asset_name: ${{ steps.build.outputs.leia-filename }}
asset_path: ../${{ steps.build.outputs.leia-filename }}
asset_content_type: application/zip
- name: Upload Matrix zip
uses: actions/upload-release-asset@v1
env:
GITHUB_TOKEN: ${{ secrets.GH_TOKEN }}
with:
upload_url: ${{ steps.create_release.outputs.upload_url }}
asset_name: ${{ steps.build.outputs.matrix-filename }}
asset_path: ../${{ steps.build.outputs.matrix-filename }}
asset_content_type: application/zip
- name: Generate distribution zip and submit to official kodi repository
id: kodi-addon-submitter
uses: xbmc/action-kodi-addon-submitter@v1.2
with:
kodi-repository: repo-plugins
addon-id: plugin.video.viervijfzes
kodi-version: leia
kodi-matrix: true
env:
GH_USERNAME: ${{ secrets.GH_USERNAME }}
GH_TOKEN: ${{ secrets.GH_TOKEN }}
EMAIL: ${{ secrets.EMAIL }}
files: "dist/*.zip"
token: ${{ secrets.GH_TOKEN }}

2
.gitignore vendored
View File

@ -18,3 +18,5 @@ tests/home/userdata/addon_data
Pipfile
Pipfile.lock
dist/

View File

@ -1,25 +1,12 @@
export KODI_HOME := $(CURDIR)/tests/home
export KODI_INTERACTIVE := 0
PYTHON := python
KODI_PYTHON_ABIS := 3.0.0 2.26.0
# Collect information to build as sensible package name
name = $(shell xmllint --xpath 'string(/addon/@id)' addon.xml)
version = $(shell xmllint --xpath 'string(/addon/@version)' addon.xml)
git_branch = $(shell git rev-parse --abbrev-ref HEAD)
git_hash = $(shell git rev-parse --short HEAD)
ifdef release
zip_name = $(name)-$(version).zip
else
zip_name = $(name)-$(version)-$(git_branch)-$(git_hash).zip
endif
zip_dir = $(name)/
languages = $(filter-out en_gb, $(patsubst resources/language/resource.language.%, %, $(wildcard resources/language/*)))
all: check test build
zip: build
multizip: build
check: check-pylint check-translations
@ -30,15 +17,15 @@ check-pylint:
check-translations:
@printf ">>> Running translation checks\n"
@$(foreach lang,$(languages), \
msgcmp resources/language/resource.language.$(lang)/strings.po resources/language/resource.language.en_gb/strings.po; \
msgcmp --use-untranslated resources/language/resource.language.$(lang)/strings.po resources/language/resource.language.en_gb/strings.po; \
)
@tests/check_for_unused_translations.py
@scripts/check_for_unused_translations.py
check-addon: clean build
check-addon: build
@printf ">>> Running addon checks\n"
$(eval TMPDIR := $(shell mktemp -d))
@unzip ../${zip_name} -d ${TMPDIR}
cd ${TMPDIR} && kodi-addon-checker --branch=leia
@unzip dist/plugin.video.viervijfzes-*+matrix.1.zip -d ${TMPDIR}
cd ${TMPDIR} && kodi-addon-checker --branch=matrix
@rm -rf ${TMPDIR}
codefix:
@ -56,17 +43,16 @@ clean:
@find . -name '__pycache__' -type d -delete
@rm -rf .pytest_cache/ tests/cdm tests/userdata/temp
@rm -f *.log .coverage
@rm -rf dist/
build: clean
@printf ">>> Building package\n"
@rm -f ../$(zip_name)
@git archive --format zip --worktree-attributes -v -o ../$(zip_name) --prefix $(zip_dir) $(or $(shell git stash create), HEAD)
@printf ">>> Successfully wrote package as: ../$(zip_name)\n"
@printf ">>> Building add-on\n"
@scripts/build.py
@ls -lah dist/*.zip
# You first need to run sudo gem install github_changelog_generator for this
release:
ifneq ($(release),)
@github_changelog_generator -u add-ons -p $(name) --no-issues --exclude-labels duplicate,question,invalid,wontfix release --future-release v$(release);
docker run -it --rm --env CHANGELOG_GITHUB_TOKEN=$(GH_TOKEN) -v "$(shell pwd)":/usr/local/src/your-app githubchangeloggenerator/github-changelog-generator -u add-ons -p plugin.video.viervijfzes --no-issues --exclude-labels duplicate,question,invalid,wontfix,release,testing --future-release v$(release)
@printf "cd /addon/@version\nset $$release\nsave\nbye\n" | xmllint --shell addon.xml; \
date=$(shell date '+%Y-%m-%d'); \
@ -80,11 +66,4 @@ else
@printf "Usage: make release release=1.0.0\n"
endif
multizip: clean
@-$(foreach abi,$(KODI_PYTHON_ABIS), \
printf "cd /addon/requires/import[@addon='xbmc.python']/@version\nset $(abi)\nsave\nbye\n" | xmllint --shell addon.xml; \
matrix=$(findstring $(abi), $(word 1,$(KODI_PYTHON_ABIS))); \
if [ $$matrix ]; then version=$(version)+matrix.1; else version=$(version); fi; \
printf "cd /addon/@version\nset $$version\nsave\nbye\n" | xmllint --shell addon.xml; \
make build; \
)
.PHONY: check codefix test clean build release

View File

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<addon id="plugin.video.viervijfzes" name="GoPlay" version="0.4.5" provider-name="Michaël Arnauts">
<requires>
<import addon="xbmc.python" version="2.26.0"/>
<import addon="xbmc.python" version="3.0.0"/>
<import addon="script.module.dateutil" version="2.6.0"/>
<import addon="script.module.inputstreamhelper" version="0.5.1"/>
<import addon="script.module.pysocks" version="1.6.8" optional="true"/>

View File

@ -4,7 +4,7 @@
from __future__ import absolute_import, division, unicode_literals
import logging
from datetime import timedelta, datetime
from datetime import datetime, timedelta
from resources.lib import kodiutils
from resources.lib.viervijfzes import CHANNELS

View File

@ -15,6 +15,7 @@ try: # Python 3
from urllib.parse import quote, urlparse
except ImportError: # Python 2
from urllib import quote
from urlparse import urlparse
_LOGGER = logging.getLogger(__name__)

View File

@ -13,7 +13,7 @@ from datetime import datetime
import requests
from resources.lib.kodiutils import html_to_kodi, STREAM_DASH, STREAM_HLS
from resources.lib.kodiutils import STREAM_DASH, STREAM_HLS, html_to_kodi
from resources.lib.viervijfzes import ResolvedStream
try: # Python 3

View File

@ -9,7 +9,7 @@ import logging
import requests
from resources.lib import kodiutils
from resources.lib.viervijfzes.content import Program, ContentApi, CACHE_ONLY
from resources.lib.viervijfzes.content import CACHE_ONLY, ContentApi, Program
_LOGGER = logging.getLogger(__name__)

89
scripts/build.py Executable file
View File

@ -0,0 +1,89 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
""" Build ZIP files for all brands. """
from __future__ import absolute_import, division, unicode_literals
import os
import shutil
import sys
import xml.etree.ElementTree as ET
BRANDS_DIR = 'brands'
DIST_DIR = 'dist'
def get_files():
""" Get a list of files that we should package. """
# Start with all non-hidden files
files = [f for f in os.listdir() if not f.startswith('.')]
# Exclude files from .gitattributes
with open('.gitattributes', 'r') as f:
for line in f.read().splitlines():
filename, mode = line.split(' ')
filename = filename.strip('/')
if mode == 'export-ignore' and filename in files:
files.remove(filename)
# Exclude files from .gitignore. I know, this won't do matching
with open('.gitignore', 'r') as f:
for filename in f.read().splitlines():
filename = filename.strip('/')
if filename in files:
files.remove(filename)
return files
def modify_xml(file, version, news, python=None):
""" Modify an addon.xml. """
with open(file, 'r+') as f:
tree = ET.fromstring(f.read())
# Update values
tree.set('version', version)
tree.find("./extension[@point='xbmc.addon.metadata']/news").text = news
if python:
tree.find("./requires/import[@addon='xbmc.python']").set('version', python)
# Save file
f.seek(0)
f.truncate()
f.write('<?xml version="1.0" encoding="UTF-8" standalone="yes"?>\n' +
ET.tostring(tree, encoding='UTF-8').decode())
if __name__ == '__main__':
# Read base addon.xml info
with open('addon.xml', 'r') as f:
tree = ET.fromstring(f.read())
addon_info = {
'id': tree.get('id'),
'version': tree.get('version'),
'news': tree.find("./extension[@point='xbmc.addon.metadata']/news").text
}
# Make sure dist folder exists
if not os.path.isdir(DIST_DIR):
os.mkdir(DIST_DIR)
# Build addon
brand = addon_info['id']
dest = os.path.join(DIST_DIR, brand)
if not os.path.isdir(dest):
os.mkdir(dest)
# Copy files from add-on source
for f in get_files():
if os.path.isfile(f):
shutil.copy(f, dest)
else:
shutil.copytree(f, os.path.join(dest, f), dirs_exist_ok=True)
# Update addon.xml for matrix and create zip
modify_xml(os.path.join(dest, 'addon.xml'), addon_info['version'] + '+matrix.1', addon_info['news'])
shutil.make_archive(os.path.join(DIST_DIR, "%s-%s+matrix.1" % (brand, addon_info['version'])), 'zip', DIST_DIR, brand)
# Modify addon.xml for leia and create zip
modify_xml(os.path.join(dest, 'addon.xml'), addon_info['version'], addon_info['news'], '2.26.0')
shutil.make_archive(os.path.join(DIST_DIR, "%s-%s" % (brand, addon_info['version'])), 'zip', DIST_DIR, brand)

225
scripts/publish.py Executable file
View File

@ -0,0 +1,225 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
""" Publish a ZIP file to the Kodi repository. """
# Based on code from https://github.com/xbmc/kodi-addon-submitter
from __future__ import absolute_import, division, unicode_literals
import logging
import os
import shutil
import subprocess
import sys
import time
import xml.etree.ElementTree as ET
from pprint import pformat
from tempfile import TemporaryDirectory
from zipfile import ZipFile
import requests
_LOGGER = logging.getLogger(__name__)
GH_REPO = 'repo-plugins'
GH_USERNAME = os.getenv('GH_USERNAME')
GH_TOKEN = os.getenv('GH_TOKEN')
GH_EMAIL = os.getenv('EMAIL')
def get_addon_info(xml: str):
""" Parse the passed addon.xml file and extract some information. """
tree = ET.fromstring(xml)
return {
'id': tree.get('id'),
'name': tree.get('name'),
'version': tree.get('version'),
'description': tree.find("./extension[@point='xbmc.addon.metadata']/description").text,
'news': tree.find("./extension[@point='xbmc.addon.metadata']/news").text,
'python': tree.find("./requires/import[@addon='xbmc.python']").get('version'),
'source': tree.find("./extension[@point='xbmc.addon.metadata']/source").text,
}
def user_fork_exists(repo, gh_username, gh_token):
""" Check if the user has a fork of the repository on Github. """
resp = requests.get(
'https://api.github.com/repos/{}/{}'.format(
gh_username,
repo
),
headers={'Accept': 'application/vnd.github.v3+json'},
params={
'type': 'all'
},
auth=(gh_username, gh_token)
)
resp_json = resp.json()
return resp.ok and resp_json.get('fork')
def create_personal_fork(repo, gh_username, gh_token):
"""Create a personal fork for the official repo on GitHub. """
resp = requests.post(
'https://api.github.com/repos/xbmc/{}/forks'.format(
repo
),
headers={'Accept': 'application/vnd.github.v3+json'},
auth=(gh_username, gh_token)
)
if resp.ok:
elapsed_time = 0
while elapsed_time < 5 * 60:
if not user_fork_exists(repo, gh_username, gh_token):
time.sleep(20)
elapsed_time += 20
else:
return
raise Exception("Timeout waiting for fork creation exceeded")
raise Exception('GitHub API error: {}\n{}'.format(resp.status_code, resp.text))
def shell(*args):
""" Execute a shell command. """
subprocess.run(args, check=True)
def create_addon_branch(repo, branch, source, addon_info, gh_username, gh_token, gh_email):
""" Create and addon branch in your fork of the respective addon repo. """
cur_dir = os.getcwd()
os.chdir('dist')
local_branch_name = '{}@{}'.format(addon_info['id'], branch)
if os.path.isdir(repo):
# We already have a checked out repo locally, update this with upstream code
os.chdir(repo)
shell('git', 'reset', '--hard') # Remove all local changes
shell('git', 'remote', 'set-branches', '--add', 'upstream', branch) # Make sure the upstream branch exists
shell('git', 'fetch', '-f', 'upstream', branch) # Fetch upstream
else:
# Clone the upstream repo
shell('git', 'clone', '--branch', branch, '--origin', 'upstream', '--single-branch', 'git://github.com/xbmc/{}.git'.format(repo))
os.chdir(repo)
# Create local branch
shell('git', 'checkout', '-B', local_branch_name, 'upstream/{}'.format(branch))
# Remove current code
if os.path.isdir(addon_info['id']):
shutil.rmtree(addon_info['id'], ignore_errors=False)
# Add new code
shutil.copytree(source, addon_info['id'])
shell('git', 'add', '--', addon_info['id'])
shell('git', 'status')
# Create a commit with the new code
shell('git', 'config', 'user.name', gh_username)
shell('git', 'config', 'user.email', gh_email)
shell('git', 'commit', '-m', '[{}] {}'.format(addon_info['id'], addon_info['version']))
# Push branch to fork
shell('git', 'push', '-f', 'https://{}:{}@github.com/{}/{}.git'.format(gh_username, gh_token, gh_username, repo), local_branch_name)
# Restore working directory
os.chdir(cur_dir)
def create_pull_request(repo, branch, addon_info, gh_username, gh_token):
""" Create a pull request in the official repo on GitHub. """
local_branch_name = '{}@{}'.format(addon_info['id'], branch)
# Check if pull request already exists.
resp = requests.get(
'https://api.github.com/repos/xbmc/{}/pulls'.format(repo),
params={
'head': '{}:{}'.format(gh_username, local_branch_name),
'base': branch,
},
headers={'Accept': 'application/vnd.github.v3+json'},
auth=(gh_username, gh_token)
)
if resp.status_code == 200 and not resp.json():
# Create a new Pull Request
template = """### Description
- **General**
- Add-on name: {name}
- Add-on ID: {id}
- Version number: {version}
- Kodi/repository version: {kodi_repo_branch}
- **Code location**
- URL: {source}
{description}
### What's new
{news}
### Checklist:
- [X] My code follows the [add-on rules](http://kodi.wiki/view/Add-on_rules) and [piracy stance](http://kodi.wiki/view/Official:Forum_rules#Piracy_Policy) of this project.
- [X] I have read the [CONTRIBUTING](https://github.com/xbmc/repo-plugins/blob/master/CONTRIBUTING.md) document
- [X] Each add-on submission should be a single commit with using the following style: [plugin.video.foo] v1.0.0
"""
pr_body = template.format(
name=addon_info['name'],
id=addon_info['id'],
version=addon_info['version'],
kodi_repo_branch=branch,
source=addon_info['source'],
description=addon_info['description'],
news=addon_info['news']
)
resp = requests.post(
'https://api.github.com/repos/xbmc/{}/pulls'.format(repo),
json={
'title': '[{}] {}'.format(local_branch_name, addon_info['version']),
'head': '{}:{}'.format(gh_username, local_branch_name),
'base': branch,
'body': pr_body,
'maintainer_can_modify': True,
},
headers={'Accept': 'application/vnd.github.v3+json'},
auth=(gh_username, gh_token)
)
if resp.status_code != 201:
raise Exception('GitHub API error: {}\n{}'.format(resp.status_code, pformat(resp.json())))
elif resp.status_code == 200 and resp.json():
_LOGGER.info('Pull request in {} for {}:{} already exists.'.format(branch, gh_username, local_branch_name))
else:
raise Exception('Unexpected GitHub error: {}\n{}'.format(resp.status_code, pformat(resp.json())))
if __name__ == '__main__':
filenames = sys.argv[1:]
for filename in filenames:
# Fork the repo if the user does not have a personal repo fork
if not user_fork_exists(GH_REPO, GH_USERNAME, GH_TOKEN):
create_personal_fork(GH_REPO, GH_USERNAME, GH_TOKEN)
with TemporaryDirectory() as extract_dir:
with ZipFile(filename) as z:
# Look for addon.xml in zip and load the details
xmlfile = next(f.filename for f in z.filelist if f.filename.endswith('addon.xml'))
addon_info = get_addon_info(z.read(xmlfile).decode('utf-8'))
if addon_info['python'] != '3.0.0':
branch = 'leia'
else:
branch = 'matrix'
# Extract the ZIP file to the extract_dir
z.extractall(extract_dir)
# Checkout the fork locally and create a branch with our new code from the extract_dir
create_addon_branch(GH_REPO, branch, os.path.join(extract_dir, addon_info['id']), addon_info, GH_USERNAME, GH_TOKEN, GH_EMAIL)
# Create pull request
create_pull_request(GH_REPO, branch, addon_info, GH_USERNAME, GH_TOKEN)

40
scripts/update_translations.py Executable file
View File

@ -0,0 +1,40 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# pylint: disable=missing-docstring,no-self-use,wrong-import-order,wrong-import-position,invalid-name
import sys
from glob import glob
import polib
original_file = 'resources/language/resource.language.en_gb/strings.po'
original = polib.pofile(original_file, wrapwidth=0)
for translated_file in glob('resources/language/resource.language.*/strings.po'):
# Skip original file
if translated_file == original_file:
continue
print('Updating %s...' % translated_file)
# Load po-files
translated = polib.pofile(translated_file, wrapwidth=0)
for entry in original:
# Find a translation
translation = translated.find(entry.msgctxt, 'msgctxt')
if translation and entry.msgid == translation.msgid:
entry.msgstr = translation.msgstr
original.metadata = translated.metadata
if sys.platform.startswith('win'):
# On Windows save the file keeping the Linux return character
with open(translated_file, 'wb') as _file:
content = str(original).encode('utf-8')
content = content.replace(b'\r\n', b'\n')
_file.write(content)
else:
# Save it now over the translation
original.save(translated_file)