diff --git a/.github/workflows/basic-python3.yml b/.github/workflows/basic-python3.yml index 62e9f51eae2..b55587a03da 100644 --- a/.github/workflows/basic-python3.yml +++ b/.github/workflows/basic-python3.yml @@ -24,8 +24,6 @@ jobs: # signalling mechanism such as an Event." - pytest --no-cov -k 'not test_BaseType_Unicode and not test_nestedStructure and not testLockedClass' - pytest --no-cov src/DIRAC/Core/Security/test - # Ensure the README can be parsed by PyPI - - python -m readme_renderer README.rst -o README.html steps: - uses: actions/checkout@v2 diff --git a/.github/workflows/deployment.yml b/.github/workflows/deployment.yml new file mode 100644 index 00000000000..049249e6ffe --- /dev/null +++ b/.github/workflows/deployment.yml @@ -0,0 +1,50 @@ +name: Deployment + +on: [push, pull_request] + +jobs: + deploy-pypi: + name: PyPI deployment + runs-on: "ubuntu-latest" + if: github.event_name != 'push' || github.repository == 'chrisburr/DIRAC' + defaults: + run: + shell: bash -l {0} + steps: + - uses: actions/checkout@v2 + - run: | + git fetch --prune --unshallow + - uses: conda-incubator/setup-miniconda@master + with: + environment-file: environment-py3.yml + miniforge-variant: Mambaforge + use-mamba: true + - name: Validate README for PyPI + run: | + python -m readme_renderer README.rst -o /tmp/README.html + - name: Build distributions + run: | + python setup.py sdist bdist_wheel + - name: Check Tag + id: check-tag + run: | + if [[ ${{ github.event.ref }} =~ ^refs/tags/v7r2(p[0-9]+)?(-pre[0-9]+)?$ ]]; then + echo ::set-output name=create-release::true + fi + - name: Make PEP-440 style release on GitHub + if: steps.check-tag.outputs.create-release == 'true' + run: | + OLD_STYLE=${GITHUB_REF##*/} + NEW_STYLE=$(python -c "import diraccfg; major, minor, patch, pre = diraccfg.parseVersion('${OLD_STYLE}'); print(f'{major}.{minor}.{patch}', f'a{pre}' if pre else '', sep='')") + echo "Converted ${OLD_STYLE} version to ${NEW_STYLE}" + scripts/make_release.py \ + --token="${{ secrets.GITHUB_TOKEN }}" \ + --version="v${NEW_STYLE}" \ + --rev="$(git rev-parse --short HEAD)" + git fetch --all --tags + - name: Publish package on PyPI + if: steps.check-tag.outputs.create-release == 'true' + uses: pypa/gh-action-pypi-publish@master + with: + user: __token__ + password: ${{ secrets.pypi_password }} diff --git a/environment-py3.yml b/environment-py3.yml index 6805bef057b..bca601ef223 100644 --- a/environment-py3.yml +++ b/environment-py3.yml @@ -61,9 +61,10 @@ dependencies: # unused - funcsigs - jinja2 - # pypi + # PyPI deployment - readme_renderer - twine + - uritemplate # - readline >=6.2.4 in the standard library - simplejson >=3.8.1 #- tornado >=5.0.0,<6.0.0 diff --git a/scripts/make_release.py b/scripts/make_release.py new file mode 100755 index 00000000000..b1f1ca55adb --- /dev/null +++ b/scripts/make_release.py @@ -0,0 +1,73 @@ +#!/usr/bin/env python +import argparse + +from packaging.version import Version +import requests +from uritemplate import expand as uri_expand + + +def make_release(version, commit_hash, release_notes=""): + """Create a new GitHub release using the given data + + This function always makes a pre-release first to ensure the "latest" release never corresponds + to one without artifacts uploaded. If the new version number is not a pre-release, as + determined by PEP-440, it is promoted to at full release after the uploads have completed + successfully. + + :param str version: The version of the new release + :param str commit_hash: Git revision used for the release + :param str release_notes: Release notes + """ + # Create a draft release + r = requests.post( + f"{api_root}/releases", + json={ + "tag_name": version, + "target_commitish": commit_hash, + "body": release_notes, + "draft": True, + "prerelease": Version(version).is_prerelease, + }, + headers=headers, + ) + r.raise_for_status() + release_data = r.json() + print(f"Created draft release at: {release_data['html_url']}") + + # Publish the release + r = requests.patch( + release_data["url"], + json={ + "draft": False, + }, + headers=headers, + ) + r.raise_for_status() + release_data = r.json() + print(f"Published release at: {release_data['html_url']}") + + +if __name__ == "__main__": + parser = argparse.ArgumentParser() + parser.add_argument("--token", required=True) + parser.add_argument("--owner", default="chrisburr") + parser.add_argument("--repo", default="DIRAC") + parser.add_argument("--version", required=True) + parser.add_argument("--rev", required=True) + args = parser.parse_args() + + token = args.token + headers = { + "Accept": "application/vnd.github.v3+json", + "Authorization": f"token {token}", + } + api_root = f"https://api.github.com/repos/{args.owner}/{args.repo}" + + if not args.version.startswith("v"): + raise ValueError('For consistency versions must start with "v"') + + v = Version(args.version) + if (v.major, v.minor) < (7, 2): + raise NotImplementedError("Only supported for DIRAC 7.2 or later") + + make_release(args.version, args.rev, release_notes="")