Modify repository so HEAD contains the Matrix version (#100)
This commit is contained in:
parent
bcb5caceeb
commit
16bb1ceab3
@ -4,3 +4,11 @@ ADDON_PASSWORD=
|
|||||||
KODI_HOME=tests/home
|
KODI_HOME=tests/home
|
||||||
KODI_INTERACTIVE=0
|
KODI_INTERACTIVE=0
|
||||||
KODI_STUB_VERBOSE=1
|
KODI_STUB_VERBOSE=1
|
||||||
|
KODI_STUB_RPC_RESPONSES=tests/rpc
|
||||||
|
|
||||||
|
#HTTP_PROXY=
|
||||||
|
#HTTPS_PROXY=
|
||||||
|
|
||||||
|
GH_USERNAME=
|
||||||
|
GH_TOKEN=
|
||||||
|
EMAIL=
|
1
.gitattributes
vendored
1
.gitattributes
vendored
@ -6,3 +6,4 @@ tests/ export-ignore
|
|||||||
.pylintrc export-ignore
|
.pylintrc export-ignore
|
||||||
Makefile export-ignore
|
Makefile export-ignore
|
||||||
requirements.txt export-ignore
|
requirements.txt export-ignore
|
||||||
|
scripts/ export-ignore
|
||||||
|
7
.github/workflows/addon-check.yml
vendored
7
.github/workflows/addon-check.yml
vendored
@ -11,10 +11,6 @@ jobs:
|
|||||||
kodi-addon-checker:
|
kodi-addon-checker:
|
||||||
name: Addon checker
|
name: Addon checker
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
strategy:
|
|
||||||
fail-fast: false
|
|
||||||
matrix:
|
|
||||||
kodi-version: [ leia, matrix ]
|
|
||||||
steps:
|
steps:
|
||||||
- name: Check out ${{ github.sha }} from repository ${{ github.repository }}
|
- name: Check out ${{ github.sha }} from repository ${{ github.repository }}
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v2
|
||||||
@ -22,6 +18,5 @@ jobs:
|
|||||||
- name: Run kodi-addon-checker
|
- name: Run kodi-addon-checker
|
||||||
uses: xbmc/action-kodi-addon-checker@v1.2
|
uses: xbmc/action-kodi-addon-checker@v1.2
|
||||||
with:
|
with:
|
||||||
kodi-version: ${{ matrix.kodi-version }}
|
kodi-version: matrix
|
||||||
rewrite-for-matrix: ${{ matrix.kodi-version == 'matrix' }}
|
|
||||||
addon-id: ${{ github.event.repository.name }}
|
addon-id: ${{ github.event.repository.name }}
|
6
.github/workflows/ci.yml
vendored
6
.github/workflows/ci.yml
vendored
@ -3,10 +3,10 @@ on:
|
|||||||
# Run action when pushed to master, or for commits in a pull request.
|
# Run action when pushed to master, or for commits in a pull request.
|
||||||
push:
|
push:
|
||||||
branches:
|
branches:
|
||||||
- master
|
- master
|
||||||
pull_request:
|
pull_request:
|
||||||
branches:
|
branches:
|
||||||
- master
|
- master
|
||||||
jobs:
|
jobs:
|
||||||
tests:
|
tests:
|
||||||
name: Add-on testing
|
name: Add-on testing
|
||||||
@ -54,7 +54,7 @@ jobs:
|
|||||||
KODI_INTERACTIVE: 0
|
KODI_INTERACTIVE: 0
|
||||||
KODI_STUB_RPC_RESPONSES: ${{ github.workspace }}/tests/rpc
|
KODI_STUB_RPC_RESPONSES: ${{ github.workspace }}/tests/rpc
|
||||||
HTTP_PROXY: ${{ secrets.HTTP_PROXY }}
|
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
|
- name: Upload code coverage to CodeCov
|
||||||
uses: codecov/codecov-action@v1
|
uses: codecov/codecov-action@v1
|
||||||
|
64
.github/workflows/release.yml
vendored
64
.github/workflows/release.yml
vendored
@ -6,22 +6,13 @@ on:
|
|||||||
jobs:
|
jobs:
|
||||||
build:
|
build:
|
||||||
name: Release plugin.video.viervijfzes
|
name: Release plugin.video.viervijfzes
|
||||||
if: startsWith(github.ref, 'refs/tags/') # prevent from running if it's not a tag
|
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout code
|
- name: Check out ${{ github.sha }} from repository ${{ github.repository }}
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v2
|
||||||
|
|
||||||
- name: Build zip files
|
- name: Get changelog
|
||||||
id: build
|
id: get-changelog
|
||||||
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
|
|
||||||
run: |
|
run: |
|
||||||
description=$(sed '1,6d;/^## /,$d' CHANGELOG.md)
|
description=$(sed '1,6d;/^## /,$d' CHANGELOG.md)
|
||||||
echo $description
|
echo $description
|
||||||
@ -30,47 +21,14 @@ jobs:
|
|||||||
description="${description//$'\r'/'%0D'}"
|
description="${description//$'\r'/'%0D'}"
|
||||||
echo ::set-output name=body::$description
|
echo ::set-output name=body::$description
|
||||||
|
|
||||||
- name: Create Release
|
- name: Generate distribution zips
|
||||||
id: create_release
|
run: scripts/build.py
|
||||||
uses: actions/create-release@v1
|
|
||||||
env:
|
- name: Create Release on Github
|
||||||
GITHUB_TOKEN: ${{ secrets.GH_TOKEN }}
|
uses: softprops/action-gh-release@v1
|
||||||
with:
|
with:
|
||||||
tag_name: ${{ github.ref }}
|
body: ${{ steps.get-changelog.outputs.body }}
|
||||||
release_name: ${{ github.ref }}
|
|
||||||
body: ${{ steps.get-body.outputs.body }}
|
|
||||||
draft: false
|
draft: false
|
||||||
prerelease: false
|
prerelease: false
|
||||||
|
files: "dist/*.zip"
|
||||||
- name: Upload Leia zip
|
token: ${{ secrets.GH_TOKEN }}
|
||||||
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 }}
|
|
||||||
|
2
.gitignore
vendored
2
.gitignore
vendored
@ -18,3 +18,5 @@ tests/home/userdata/addon_data
|
|||||||
|
|
||||||
Pipfile
|
Pipfile
|
||||||
Pipfile.lock
|
Pipfile.lock
|
||||||
|
|
||||||
|
dist/
|
||||||
|
45
Makefile
45
Makefile
@ -1,25 +1,12 @@
|
|||||||
export KODI_HOME := $(CURDIR)/tests/home
|
export KODI_HOME := $(CURDIR)/tests/home
|
||||||
export KODI_INTERACTIVE := 0
|
export KODI_INTERACTIVE := 0
|
||||||
PYTHON := python
|
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/*)))
|
languages = $(filter-out en_gb, $(patsubst resources/language/resource.language.%, %, $(wildcard resources/language/*)))
|
||||||
|
|
||||||
all: check test build
|
all: check test build
|
||||||
zip: build
|
zip: build
|
||||||
|
multizip: build
|
||||||
|
|
||||||
check: check-pylint check-translations
|
check: check-pylint check-translations
|
||||||
|
|
||||||
@ -30,15 +17,15 @@ check-pylint:
|
|||||||
check-translations:
|
check-translations:
|
||||||
@printf ">>> Running translation checks\n"
|
@printf ">>> Running translation checks\n"
|
||||||
@$(foreach lang,$(languages), \
|
@$(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"
|
@printf ">>> Running addon checks\n"
|
||||||
$(eval TMPDIR := $(shell mktemp -d))
|
$(eval TMPDIR := $(shell mktemp -d))
|
||||||
@unzip ../${zip_name} -d ${TMPDIR}
|
@unzip dist/plugin.video.viervijfzes-*+matrix.1.zip -d ${TMPDIR}
|
||||||
cd ${TMPDIR} && kodi-addon-checker --branch=leia
|
cd ${TMPDIR} && kodi-addon-checker --branch=matrix
|
||||||
@rm -rf ${TMPDIR}
|
@rm -rf ${TMPDIR}
|
||||||
|
|
||||||
codefix:
|
codefix:
|
||||||
@ -56,17 +43,16 @@ clean:
|
|||||||
@find . -name '__pycache__' -type d -delete
|
@find . -name '__pycache__' -type d -delete
|
||||||
@rm -rf .pytest_cache/ tests/cdm tests/userdata/temp
|
@rm -rf .pytest_cache/ tests/cdm tests/userdata/temp
|
||||||
@rm -f *.log .coverage
|
@rm -f *.log .coverage
|
||||||
|
@rm -rf dist/
|
||||||
|
|
||||||
build: clean
|
build: clean
|
||||||
@printf ">>> Building package\n"
|
@printf ">>> Building add-on\n"
|
||||||
@rm -f ../$(zip_name)
|
@scripts/build.py
|
||||||
@git archive --format zip --worktree-attributes -v -o ../$(zip_name) --prefix $(zip_dir) $(or $(shell git stash create), HEAD)
|
@ls -lah dist/*.zip
|
||||||
@printf ">>> Successfully wrote package as: ../$(zip_name)\n"
|
|
||||||
|
|
||||||
# You first need to run sudo gem install github_changelog_generator for this
|
|
||||||
release:
|
release:
|
||||||
ifneq ($(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; \
|
@printf "cd /addon/@version\nset $$release\nsave\nbye\n" | xmllint --shell addon.xml; \
|
||||||
date=$(shell date '+%Y-%m-%d'); \
|
date=$(shell date '+%Y-%m-%d'); \
|
||||||
@ -80,11 +66,4 @@ else
|
|||||||
@printf "Usage: make release release=1.0.0\n"
|
@printf "Usage: make release release=1.0.0\n"
|
||||||
endif
|
endif
|
||||||
|
|
||||||
multizip: clean
|
.PHONY: check codefix test clean build release
|
||||||
@-$(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; \
|
|
||||||
)
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
<?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">
|
<addon id="plugin.video.viervijfzes" name="GoPlay" version="0.4.5" provider-name="Michaël Arnauts">
|
||||||
<requires>
|
<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.dateutil" version="2.6.0"/>
|
||||||
<import addon="script.module.inputstreamhelper" version="0.5.1"/>
|
<import addon="script.module.inputstreamhelper" version="0.5.1"/>
|
||||||
<import addon="script.module.pysocks" version="1.6.8" optional="true"/>
|
<import addon="script.module.pysocks" version="1.6.8" optional="true"/>
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
from __future__ import absolute_import, division, unicode_literals
|
from __future__ import absolute_import, division, unicode_literals
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
from datetime import timedelta, datetime
|
from datetime import datetime, timedelta
|
||||||
|
|
||||||
from resources.lib import kodiutils
|
from resources.lib import kodiutils
|
||||||
from resources.lib.viervijfzes import CHANNELS
|
from resources.lib.viervijfzes import CHANNELS
|
||||||
|
@ -15,6 +15,7 @@ try: # Python 3
|
|||||||
from urllib.parse import quote, urlparse
|
from urllib.parse import quote, urlparse
|
||||||
except ImportError: # Python 2
|
except ImportError: # Python 2
|
||||||
from urllib import quote
|
from urllib import quote
|
||||||
|
|
||||||
from urlparse import urlparse
|
from urlparse import urlparse
|
||||||
|
|
||||||
_LOGGER = logging.getLogger(__name__)
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
@ -13,7 +13,7 @@ from datetime import datetime
|
|||||||
|
|
||||||
import requests
|
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
|
from resources.lib.viervijfzes import ResolvedStream
|
||||||
|
|
||||||
try: # Python 3
|
try: # Python 3
|
||||||
|
@ -9,7 +9,7 @@ import logging
|
|||||||
import requests
|
import requests
|
||||||
|
|
||||||
from resources.lib import kodiutils
|
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__)
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
89
scripts/build.py
Executable file
89
scripts/build.py
Executable 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
225
scripts/publish.py
Executable 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
40
scripts/update_translations.py
Executable 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)
|
Loading…
x
Reference in New Issue
Block a user