Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
bc7643dba6 |
+39
-174
@@ -1,201 +1,66 @@
|
||||
name: Publish Package
|
||||
name: Publicar paquete PyPI
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- "8.0"
|
||||
branches: ["7.0"]
|
||||
workflow_dispatch:
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
packages: write
|
||||
|
||||
jobs:
|
||||
publish:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: https://gitea.com/actions/checkout@v4
|
||||
with:
|
||||
token: ${{ secrets.GITEA_TOKEN }}
|
||||
github-server-url: "http://unpaismejor-gitea-app:3000"
|
||||
ref: "8.0"
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Detect package branch
|
||||
run: |
|
||||
python - <<'PY'
|
||||
import os
|
||||
import re
|
||||
|
||||
branch = (
|
||||
os.environ.get('GITEA_REF_NAME')
|
||||
or os.environ.get('GITEA_HEAD_REF')
|
||||
or os.environ.get('GITHUB_REF_NAME')
|
||||
or os.environ.get('GITHUB_HEAD_REF')
|
||||
or '')
|
||||
publish = bool(re.fullmatch(r'\d+\.\d+', branch))
|
||||
with open(os.environ['GITHUB_ENV'], 'a') as env:
|
||||
env.write(f'PUBLISH_PACKAGE={"true" if publish else "false"}\n')
|
||||
if publish:
|
||||
env.write(f'PACKAGE_SERIES={branch}\n')
|
||||
if publish:
|
||||
print(f'Publishing package series: {branch}')
|
||||
else:
|
||||
print(f'Skipping package publish for branch: {branch}')
|
||||
PY
|
||||
|
||||
- name: Set up Python
|
||||
if: env.PUBLISH_PACKAGE == 'true'
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: "3.11"
|
||||
|
||||
- name: Install build tools
|
||||
if: env.PUBLISH_PACKAGE == 'true'
|
||||
run: |
|
||||
python -m pip install --upgrade pip
|
||||
python -m pip install 'build>=1.2' 'twine>=7' 'packaging>=26'
|
||||
|
||||
- name: Check publishing credentials
|
||||
if: env.PUBLISH_PACKAGE == 'true'
|
||||
env:
|
||||
TWINE_USERNAME: ${{ secrets.REGISTRY_USER }}
|
||||
TWINE_PASSWORD: ${{ secrets.REGISTRY_PASSWORD }}
|
||||
GITEA_TOKEN: ${{ secrets.GITEA_TOKEN }}
|
||||
run: |
|
||||
test -n "$TWINE_USERNAME" || { echo "Missing REGISTRY_USER secret"; exit 1; }
|
||||
test -n "$TWINE_PASSWORD" || { echo "Missing REGISTRY_PASSWORD secret"; exit 1; }
|
||||
test -n "$GITEA_TOKEN" || { echo "Missing GITEA_TOKEN secret"; exit 1; }
|
||||
git init .
|
||||
git remote add origin http://unpaismejor-gitea-app:3000/tryton-do/account_invoice_do.git
|
||||
git -c http.extraHeader="Authorization: token $GITEA_TOKEN" \
|
||||
fetch --depth=1 origin 7.0
|
||||
git checkout --detach FETCH_HEAD
|
||||
|
||||
- name: Set CI package version
|
||||
if: env.PUBLISH_PACKAGE == 'true'
|
||||
env:
|
||||
TWINE_USERNAME: ${{ secrets.REGISTRY_USER }}
|
||||
TWINE_PASSWORD: ${{ secrets.REGISTRY_PASSWORD }}
|
||||
- name: Verificar Python
|
||||
run: python3 --version
|
||||
|
||||
- name: Instalar herramientas
|
||||
run: |
|
||||
python - <<'PY'
|
||||
python3 -m venv .ci-venv
|
||||
.ci-venv/bin/python -m pip install --upgrade \
|
||||
"setuptools>=68,<81" "wheel>=0.41,<1" "twine>=6,<7"
|
||||
|
||||
- name: Comprobar credenciales
|
||||
env:
|
||||
TWINE_PASSWORD: ${{ secrets.REGISTRY_PASSWORD }}
|
||||
run: test -n "$TWINE_PASSWORD" || { echo "Missing REGISTRY_PASSWORD secret"; exit 1; }
|
||||
|
||||
- name: Fijar versión CI
|
||||
env:
|
||||
PACKAGE_VERSION: 7.0.${{ gitea.run_number }}
|
||||
run: |
|
||||
.ci-venv/bin/python - <<'PY'
|
||||
from pathlib import Path
|
||||
from urllib.error import HTTPError
|
||||
from urllib.parse import urlencode
|
||||
from urllib.request import Request, urlopen
|
||||
import base64
|
||||
import json
|
||||
import os
|
||||
import re
|
||||
import tomllib
|
||||
|
||||
OWNER = 'tryton-do'
|
||||
PACKAGE_TYPE = 'pypi'
|
||||
API_ROOT = 'https://code.unpaismejor.org.do/api/v1'
|
||||
|
||||
def normalize(name):
|
||||
return re.sub(r'[-_.]+', '-', name).lower()
|
||||
|
||||
cfg_path = Path('tryton.cfg')
|
||||
cfg_text = cfg_path.read_text()
|
||||
cfg_match = re.search(r'(?m)^version=(.+)$', cfg_text)
|
||||
if not cfg_match:
|
||||
raise SystemExit('tryton.cfg has no version entry')
|
||||
series = os.environ['PACKAGE_SERIES']
|
||||
major, minor = map(int, series.split('.'))
|
||||
|
||||
pyproject = tomllib.loads(Path('pyproject.toml').read_text())
|
||||
package_name = pyproject['project']['name']
|
||||
normalized_name = normalize(package_name)
|
||||
|
||||
username = os.environ['TWINE_USERNAME']
|
||||
password = os.environ['TWINE_PASSWORD']
|
||||
token = base64.b64encode(
|
||||
f'{username}:{password}'.encode()).decode()
|
||||
|
||||
def request_json(path, params=None, missing_ok=False):
|
||||
url = f'{API_ROOT}{path}'
|
||||
if params:
|
||||
url = f'{url}?{urlencode(params)}'
|
||||
request = Request(url, headers={
|
||||
'Accept': 'application/json',
|
||||
'Authorization': f'Basic {token}',
|
||||
})
|
||||
try:
|
||||
with urlopen(request, timeout=30) as response:
|
||||
return json.load(response)
|
||||
except HTTPError as error:
|
||||
if missing_ok and error.code == 404:
|
||||
return []
|
||||
raise
|
||||
|
||||
def collect_versions(payload, package_specific=False):
|
||||
versions = []
|
||||
if isinstance(payload, list):
|
||||
for item in payload:
|
||||
versions.extend(collect_versions(item, package_specific))
|
||||
elif isinstance(payload, dict):
|
||||
item_name = payload.get('name') or payload.get('package_name')
|
||||
item_type = payload.get('type') or payload.get('package_type')
|
||||
item_version = payload.get('version')
|
||||
if item_version and (
|
||||
package_specific
|
||||
or (item_type == PACKAGE_TYPE
|
||||
and normalize(item_name or '') == normalized_name)):
|
||||
versions.append(str(item_version))
|
||||
for value in payload.values():
|
||||
if isinstance(value, (list, dict)):
|
||||
versions.extend(collect_versions(value, package_specific))
|
||||
return versions
|
||||
|
||||
versions = []
|
||||
for page in range(1, 11):
|
||||
payload = request_json(
|
||||
f'/packages/{OWNER}/{PACKAGE_TYPE}/{package_name}',
|
||||
{'page': page, 'limit': 100},
|
||||
missing_ok=True)
|
||||
page_versions = collect_versions(payload, package_specific=True)
|
||||
versions.extend(page_versions)
|
||||
if not page_versions:
|
||||
break
|
||||
|
||||
for page in range(1, 11):
|
||||
payload = request_json(
|
||||
f'/packages/{OWNER}',
|
||||
{'page': page, 'limit': 100, 'type': PACKAGE_TYPE,
|
||||
'q': package_name})
|
||||
page_versions = collect_versions(payload)
|
||||
versions.extend(page_versions)
|
||||
if not page_versions:
|
||||
break
|
||||
|
||||
patch_pattern = re.compile(rf'^{major}\.{minor}\.(\d+)$')
|
||||
patches = []
|
||||
for version in set(versions):
|
||||
match = patch_pattern.fullmatch(version)
|
||||
if match:
|
||||
patches.append(int(match.group(1)))
|
||||
|
||||
next_patch = max(patches) + 1 if patches else 0
|
||||
ci_version = f'{major}.{minor}.{next_patch}'
|
||||
cfg_text = re.sub(
|
||||
r'(?m)^version=.+$', f'version={ci_version}', cfg_text)
|
||||
cfg_path.write_text(cfg_text)
|
||||
print(f'Package name: {package_name}')
|
||||
print(f'Published versions found: {sorted(set(versions))}')
|
||||
print(f'Package version: {ci_version}')
|
||||
import os, re
|
||||
path = Path('tryton.cfg')
|
||||
text = path.read_text()
|
||||
path.write_text(re.sub(r'(?m)^version=.*$',
|
||||
f"version={os.environ['PACKAGE_VERSION']}", text))
|
||||
PY
|
||||
|
||||
- name: Build package
|
||||
if: env.PUBLISH_PACKAGE == 'true'
|
||||
- name: Construir y validar
|
||||
run: |
|
||||
python -m build
|
||||
.ci-venv/bin/python setup.py sdist bdist_wheel
|
||||
.ci-venv/bin/python -m twine check dist/*
|
||||
|
||||
- name: Check package
|
||||
if: env.PUBLISH_PACKAGE == 'true'
|
||||
run: |
|
||||
python -m twine check dist/*
|
||||
|
||||
- name: Publish to Gitea PyPI registry
|
||||
if: env.PUBLISH_PACKAGE == 'true'
|
||||
- name: Publicar en Gitea PyPI
|
||||
env:
|
||||
TWINE_USERNAME: ${{ secrets.REGISTRY_USER }}
|
||||
TWINE_USERNAME: unpaismejor
|
||||
TWINE_PASSWORD: ${{ secrets.REGISTRY_PASSWORD }}
|
||||
run: |
|
||||
python -m twine upload \
|
||||
.ci-venv/bin/python -m twine upload --non-interactive \
|
||||
--repository-url https://code.unpaismejor.org.do/api/packages/tryton-do/pypi \
|
||||
dist/*
|
||||
|
||||
@@ -1,3 +1,10 @@
|
||||
Version 7.0.0 - 2026-09-30
|
||||
--------------------------
|
||||
|
||||
* Add a Tryton 7.0 compatible series.
|
||||
* Restore explicit module registration for Tryton 7.0.
|
||||
* Publish 7.0 packages to the Gitea PyPI registry.
|
||||
|
||||
Version 8.0.0 - 2026-08-14
|
||||
--------------------------
|
||||
|
||||
|
||||
+3
-3
@@ -24,6 +24,6 @@ Install the package and activate the module in the database::
|
||||
Publishing
|
||||
**********
|
||||
|
||||
The Gitea Actions workflow builds and publishes the package from the ``8.0``
|
||||
series branch. Configure ``REGISTRY_USER`` and ``REGISTRY_PASSWORD`` as
|
||||
repository secrets.
|
||||
The Gitea Actions workflow builds and publishes the package from version-series
|
||||
branches such as ``7.0``. Configure ``REGISTRY_PASSWORD`` as a repository
|
||||
secret.
|
||||
|
||||
+10
-3
@@ -1,5 +1,12 @@
|
||||
from trytond.pool import Pool
|
||||
|
||||
from . import invoice
|
||||
|
||||
__all__ = [
|
||||
'invoice',
|
||||
]
|
||||
__all__ = ['register']
|
||||
|
||||
|
||||
def register():
|
||||
Pool.register(
|
||||
invoice.Invoice,
|
||||
invoice.InvoiceLine,
|
||||
module='account_invoice_do', type_='model')
|
||||
|
||||
@@ -1,60 +0,0 @@
|
||||
[build-system]
|
||||
requires = ['hatchling >= 1', 'hatch-tryton']
|
||||
build-backend = 'hatchling.build'
|
||||
|
||||
[project]
|
||||
name = 'unpaismejor_account_invoice_do'
|
||||
dynamic = ['version', 'dependencies', 'optional-dependencies', 'authors', 'readme']
|
||||
requires-python = '>=3.10'
|
||||
maintainers = [
|
||||
{name = "Fundación Un País Mejor", email = "jgarcia@unpaismejor.org.do"},
|
||||
]
|
||||
description = "Dominican Republic invoices for Tryton"
|
||||
license = 'GPL-3.0-or-later'
|
||||
license-files = ["LICENSE", "COPYRIGHT"]
|
||||
keywords = ["tryton", "accounting", "invoice", "dominican-republic"]
|
||||
classifiers = [
|
||||
"Development Status :: 5 - Production/Stable",
|
||||
"Environment :: Plugins",
|
||||
"Framework :: Tryton",
|
||||
"Topic :: Office/Business",
|
||||
"Topic :: Office/Business :: Financial :: Accounting",
|
||||
"Topic :: Software Development :: Libraries :: Python Modules",
|
||||
]
|
||||
|
||||
[project.entry-points.'trytond.modules']
|
||||
account_invoice_do = 'trytond.modules.account_invoice_do'
|
||||
|
||||
[project.urls]
|
||||
homepage = "https://www.unpaismejor.org.do/"
|
||||
repository = "https://code.unpaismejor.org.do/tryton-do/account_invoice_do"
|
||||
|
||||
[tool.hatch.build]
|
||||
include = [
|
||||
'CHANGELOG',
|
||||
'COPYRIGHT',
|
||||
'LICENSE',
|
||||
'README.rst',
|
||||
'**/tryton.cfg',
|
||||
'**/*.py',
|
||||
'**/*.xml',
|
||||
'view/**/*.xml',
|
||||
'locale/**/*.po',
|
||||
'doc/**/*.rst',
|
||||
'**/*.fodt',
|
||||
'icons/**/*.svg',
|
||||
'tests/**/*.py',
|
||||
'tests/**/*.rst',
|
||||
'tests/**/*.json',
|
||||
]
|
||||
|
||||
[tool.hatch.build.targets.wheel.sources]
|
||||
"" = "trytond/modules/account_invoice_do"
|
||||
|
||||
[tool.hatch.metadata.hooks.tryton]
|
||||
copyright = 'COPYRIGHT'
|
||||
readme = 'README.rst'
|
||||
prefixes = {account_do = 'unpaismejor'}
|
||||
|
||||
[tool.hatch.metadata.hooks.tryton.tryton-optional-dependencies]
|
||||
test = ['proteus']
|
||||
@@ -0,0 +1,84 @@
|
||||
from configparser import ConfigParser
|
||||
from pathlib import Path
|
||||
|
||||
from setuptools import setup
|
||||
|
||||
|
||||
MODULE = 'account_invoice_do'
|
||||
PREFIX = 'trytond.modules'
|
||||
PACKAGE = f'{PREFIX}.{MODULE}'
|
||||
MODULE2PREFIX = {
|
||||
'account_do': 'unpaismejor',
|
||||
}
|
||||
|
||||
|
||||
def read(path):
|
||||
return Path(path).read_text(encoding='utf-8')
|
||||
|
||||
|
||||
config = ConfigParser()
|
||||
config.read('tryton.cfg')
|
||||
version = config.get('tryton', 'version')
|
||||
depends = [
|
||||
dep.strip()
|
||||
for dep in config.get('tryton', 'depends', fallback='').splitlines()
|
||||
if dep.strip()
|
||||
]
|
||||
major, minor, _ = version.split('.', 2)
|
||||
series = f'{major}.{minor}'
|
||||
next_series = f'{major}.{int(minor) + 1}'
|
||||
|
||||
|
||||
def require(name):
|
||||
prefix = MODULE2PREFIX.get(name, 'trytond')
|
||||
return f'{prefix}_{name} >= {series}, < {next_series}'
|
||||
|
||||
|
||||
setup(
|
||||
name='unpaismejor_account_invoice_do',
|
||||
version=version,
|
||||
description='Dominican Republic invoices for Tryton',
|
||||
long_description=read('README.rst'),
|
||||
long_description_content_type='text/x-rst',
|
||||
author='Fundación Un País Mejor',
|
||||
maintainer='Fundación Un País Mejor',
|
||||
maintainer_email='jgarcia@unpaismejor.org.do',
|
||||
url='https://code.unpaismejor.org.do/tryton-do/account_invoice_do',
|
||||
keywords='tryton accounting invoice dominican-republic',
|
||||
license='GPL-3.0-or-later',
|
||||
python_requires='>=3.8',
|
||||
packages=[PACKAGE],
|
||||
package_dir={PACKAGE: '.'},
|
||||
package_data={
|
||||
PACKAGE: [
|
||||
'tryton.cfg',
|
||||
'*.xml',
|
||||
'view/*.xml',
|
||||
'locale/*.po',
|
||||
'doc/*.rst',
|
||||
],
|
||||
},
|
||||
classifiers=[
|
||||
'Development Status :: 5 - Production/Stable',
|
||||
'Environment :: Plugins',
|
||||
'Framework :: Tryton',
|
||||
'Topic :: Office/Business',
|
||||
'Topic :: Office/Business :: Financial :: Accounting',
|
||||
'Topic :: Software Development :: Libraries :: Python Modules',
|
||||
],
|
||||
install_requires=[
|
||||
*(require(dep) for dep in depends if dep not in {'ir', 'res'}),
|
||||
f'trytond >= {series}, < {next_series}',
|
||||
],
|
||||
extras_require={
|
||||
'test': [
|
||||
f'proteus >= {series}, < {next_series}',
|
||||
],
|
||||
},
|
||||
entry_points={
|
||||
'trytond.modules': [
|
||||
f'{MODULE} = {PACKAGE}',
|
||||
],
|
||||
},
|
||||
zip_safe=False,
|
||||
)
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
[tryton]
|
||||
version=8.0.0
|
||||
version=7.0.0
|
||||
depends:
|
||||
account_do
|
||||
account_invoice
|
||||
|
||||
Reference in New Issue
Block a user