Add build script and set up pipeline
This commit is contained in:
22
.ci/azure-pipelines.yml
Normal file
22
.ci/azure-pipelines.yml
Normal file
@@ -0,0 +1,22 @@
|
||||
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' ]
|
||||
45
.ci/build.yml
Normal file
45
.ci/build.yml
Normal file
@@ -0,0 +1,45 @@
|
||||
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: 'jellyfin-kodi'
|
||||
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)'
|
||||
|
||||
27
.ci/publish.yml
Normal file
27
.ci/publish.yml
Normal file
@@ -0,0 +1,27 @@
|
||||
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'
|
||||
70
.config/generate_xml.py
Normal file
70
.config/generate_xml.py
Normal file
@@ -0,0 +1,70 @@
|
||||
import xml.etree.ElementTree as ET
|
||||
import sys
|
||||
import os
|
||||
from datetime import datetime
|
||||
|
||||
import yaml
|
||||
|
||||
|
||||
def indent(elem, level=0):
|
||||
'''
|
||||
Nicely formats output xml with newlines and spaces
|
||||
https://stackoverflow.com/a/33956544
|
||||
'''
|
||||
i = "\n" + level*" "
|
||||
if len(elem):
|
||||
if not elem.text or not elem.text.strip():
|
||||
elem.text = i + " "
|
||||
if not elem.tail or not elem.tail.strip():
|
||||
elem.tail = i
|
||||
for elem in elem:
|
||||
indent(elem, level+1)
|
||||
if not elem.tail or not elem.tail.strip():
|
||||
elem.tail = i
|
||||
else:
|
||||
if level and (not elem.tail or not elem.tail.strip()):
|
||||
elem.tail = i
|
||||
|
||||
|
||||
try:
|
||||
py_version = sys.argv[1]
|
||||
except IndexError:
|
||||
print('No version specified')
|
||||
sys.exit(1)
|
||||
|
||||
dir_path = os.path.dirname(os.path.realpath(__file__))
|
||||
|
||||
# Load template file
|
||||
with open('{dir_path}/template.xml'.format(**locals()), 'r') as f:
|
||||
tree = ET.parse(f)
|
||||
root = tree.getroot()
|
||||
|
||||
# Load version dependencies
|
||||
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:
|
||||
data = yaml.safe_load(f)
|
||||
|
||||
# Populate xml template
|
||||
for dep in deps:
|
||||
ET.SubElement(root.find('requires'), 'import', attrib=dep)
|
||||
|
||||
# Update version string
|
||||
addon_version = data.get('version')
|
||||
root.attrib['version'] = '{addon_version}+{py_version}'.format(**locals())
|
||||
|
||||
# Changelog
|
||||
date = datetime.today().strftime('%Y-%m-%d')
|
||||
changelog = data.get('changelog')
|
||||
for section in root.findall('extension'):
|
||||
news = section.findall('news')
|
||||
if news:
|
||||
news[0].text = 'v{addon_version} ({date}):\n{changelog}'.format(**locals())
|
||||
|
||||
# Format xml tree
|
||||
indent(root)
|
||||
|
||||
# Write addon.xml
|
||||
tree.write('jellyfin-kodi/addon.xml', encoding='utf-8', xml_declaration=True)
|
||||
@@ -1,15 +1,9 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||
<addon id="plugin.video.jellycon"
|
||||
name="JellyCon"
|
||||
version="0.3.1"
|
||||
version=""
|
||||
provider-name="Jellyfin Contributors">
|
||||
<requires>
|
||||
<import addon="xbmc.python" version="2.25.0"/>
|
||||
<import addon="script.module.pil" version="1.1.7"/>
|
||||
<import addon="script.module.requests" version="2.22.0"/>
|
||||
<import addon="script.module.six" version="1.13.0"/>
|
||||
<import addon="script.module.kodi-six" />
|
||||
<import addon="script.module.websocket" />
|
||||
</requires>
|
||||
<extension point="xbmc.python.pluginsource" library="default.py">
|
||||
<provides>video audio</provides>
|
||||
110
build.py
Executable file
110
build.py
Executable file
@@ -0,0 +1,110 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
import argparse
|
||||
from datetime import datetime
|
||||
import os
|
||||
from pathlib import Path
|
||||
import xml.etree.ElementTree as ET
|
||||
import zipfile
|
||||
|
||||
import yaml
|
||||
|
||||
|
||||
def indent(elem, level=0):
|
||||
'''
|
||||
Nicely formats output xml with newlines and spaces
|
||||
https://stackoverflow.com/a/33956544
|
||||
'''
|
||||
i = "\n" + level*" "
|
||||
if len(elem):
|
||||
if not elem.text or not elem.text.strip():
|
||||
elem.text = i + " "
|
||||
if not elem.tail or not elem.tail.strip():
|
||||
elem.tail = i
|
||||
for elem in elem:
|
||||
indent(elem, level+1)
|
||||
if not elem.tail or not elem.tail.strip():
|
||||
elem.tail = i
|
||||
else:
|
||||
if level and (not elem.tail or not elem.tail.strip()):
|
||||
elem.tail = i
|
||||
|
||||
|
||||
def create_addon_xml(config, source, py_version):
|
||||
'''
|
||||
Create addon.xml from template file
|
||||
'''
|
||||
# Load template file
|
||||
with open('{}/.config/template.xml'.format(source), 'r') as f:
|
||||
tree = ET.parse(f)
|
||||
root = tree.getroot()
|
||||
|
||||
# Populate dependencies in template
|
||||
dependencies = config['dependencies'].get(py_version)
|
||||
for dep in dependencies:
|
||||
ET.SubElement(root.find('requires'), 'import', attrib=dep)
|
||||
|
||||
# Populate version string
|
||||
addon_version = config.get('version')
|
||||
root.attrib['version'] = '{}+{}'.format(addon_version, py_version)
|
||||
|
||||
# Populate Changelog
|
||||
date = datetime.today().strftime('%Y-%m-%d')
|
||||
changelog = config.get('changelog')
|
||||
for section in root.findall('extension'):
|
||||
news = section.findall('news')
|
||||
if news:
|
||||
news[0].text = 'v{} ({}):\n{}'.format(addon_version, date, changelog)
|
||||
|
||||
# Format xml tree
|
||||
indent(root)
|
||||
|
||||
# Write addon.xml
|
||||
tree.write('{}/addon.xml'.format(source), encoding='utf-8', xml_declaration=True)
|
||||
|
||||
|
||||
def zip_files(py_version, source, target):
|
||||
'''
|
||||
Create installable addon zip archive
|
||||
'''
|
||||
archive_name = 'plugin.video.jellyfin+{}.zip'.format(py_version)
|
||||
|
||||
with zipfile.ZipFile('{}/{}'.format(target, archive_name), 'w') as z:
|
||||
for root, dirs, files in os.walk(args.source):
|
||||
for filename in files:
|
||||
if 'plugin.video.jellyfin' not in filename and 'pyo' not in filename:
|
||||
file_path = os.path.join(root, filename)
|
||||
relative_path = os.path.join('plugin.video.jellyfin', os.path.relpath(file_path, source))
|
||||
z.write(file_path, relative_path)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
parser = argparse.ArgumentParser(description='Build flags:')
|
||||
parser.add_argument(
|
||||
'--version',
|
||||
type=str,
|
||||
choices=('py2', 'py3'),
|
||||
default='py3')
|
||||
|
||||
parser.add_argument(
|
||||
'--source',
|
||||
type=Path,
|
||||
default=Path(__file__).absolute().parent)
|
||||
|
||||
parser.add_argument(
|
||||
'--target',
|
||||
type=Path,
|
||||
default=Path(__file__).absolute().parent)
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
# Load config file
|
||||
config_path = os.path.join(args.source, 'release.yaml')
|
||||
with open(config_path, 'r') as fh:
|
||||
config = yaml.safe_load(fh)
|
||||
|
||||
#py_version = 'py{}'.format(args.version)
|
||||
|
||||
create_addon_xml(config, args.source, args.version)
|
||||
|
||||
zip_files(args.version, args.source, args.target)
|
||||
38
release.yaml
Normal file
38
release.yaml
Normal file
@@ -0,0 +1,38 @@
|
||||
version: '0.3.1'
|
||||
changelog: |
|
||||
- #37 - Don't urlencode auth json payload
|
||||
- #39 - Fix clone skin function
|
||||
- #40 - Show proper language names for external subs
|
||||
dependencies:
|
||||
py2:
|
||||
- addon: 'xbmc.python'
|
||||
version: '2.25.0'
|
||||
- addon: 'script.module.requests'
|
||||
version: '2.22.0'
|
||||
- addon: 'script.module.dateutil'
|
||||
version: '2.8.1'
|
||||
- addon: 'script.module.six'
|
||||
version: '1.13.0'
|
||||
- addon: 'script.module.kodi-six'
|
||||
version: '0.0.7'
|
||||
- addon: 'script.module.addon.signals'
|
||||
version: '0.0.5'
|
||||
- addon: 'script.module.futures'
|
||||
version: '2.2.0'
|
||||
- addon: 'script.module.websocket'
|
||||
version: '0.57.0'
|
||||
py3:
|
||||
- addon: 'xbmc.python'
|
||||
version: '3.0.0'
|
||||
- addon: 'script.module.requests'
|
||||
version: '2.22.0+matrix.1'
|
||||
- addon: 'script.module.dateutil'
|
||||
version: '2.8.1+matrix.1'
|
||||
- addon: 'script.module.six'
|
||||
version: '1.14.0+matrix.2'
|
||||
- addon: 'script.module.kodi-six'
|
||||
version: '0.1.3+1'
|
||||
- addon: 'script.module.addon.signals'
|
||||
version: '0.0.5+matrix.1'
|
||||
- addon: 'script.module.websocket'
|
||||
version: '0.57.0+matrix.1'
|
||||
1
requirements-dev.txt
Normal file
1
requirements-dev.txt
Normal file
@@ -0,0 +1 @@
|
||||
pyyaml
|
||||
Reference in New Issue
Block a user