Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[pontos-release]: Remove project parameter, f-string-ed strings, refactor #105

Merged
merged 9 commits into from
Jun 8, 2021
8 changes: 5 additions & 3 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,19 @@ and this project adheres to [Calendar Versioning](https://calver.org).

## [Unreleased]
### Added
- Template for header [85](https://github.com/greenbone/pontos/pull/85)
- Template for header [#85](https://github.com/greenbone/pontos/pull/85)

### Changed
- For `pontos-release` the `--release-version` argument is not required anymore. You can choose between `--release-version` and `--calendar` now. [104](https://github.com/greenbone/pontos/pull/104)
- For `pontos-release` the `--release-version` argument is not required anymore. You can choose between `--release-version` and `--calendar` now. [#104](https://github.com/greenbone/pontos/pull/104)
- `--calendar` will automatically look up the next calendar release version number
- `--release-version` can still be used for setting the release version number manually
- `--next-version` is not required anymore, it will be set by calculating the next `dev` version, if not manually set.
- The new Changelog and setting the next version is now done after the release within `pontos-release release` [104](https://github.com/greenbone/pontos/pull/104)
- The new Changelog and setting the next version is now done after the release within `pontos-release release` [#104](https://github.com/greenbone/pontos/pull/104)

### Deprecated
### Removed
- Removed the parameter `--project` in pontos-release, it is now resolved by `get_project_name()` [#105](https://github.com/greenbone/pontos/pull/105)

### Fixed

[Unreleased]: https://github.com/greenbone/pontos/compare/v21.4.0...HEAD
Expand Down
14 changes: 9 additions & 5 deletions RELEASE.md
Original file line number Diff line number Diff line change
Expand Up @@ -152,10 +152,11 @@ if it has been lost.

## Create the Release

* Run pontos-release release
* Run pontos-release release. If you use a "non-Greenbone" project, you may set
the argument `--space <my-workspace>`.

```sh
poetry run pontos-release --project pontos --space greenbone release --release-version <version> --next-version <dev-version> --git-remote-name upstream
poetry run pontos-release release --release-version <version> --next-version <dev-version> --git-remote-name upstream
```

## Create Release without giving a version
Expand All @@ -168,9 +169,10 @@ if it has been lost.

* Pontos can also automatically set the next dev version for you. If you do not explicitly set a `--next-version` it will set to the next dev version:
* e.g. release-version is 0.0.1, pontos will set next-version to 0.0.2.dev1
* If you use a "non-Greenbone" project, you may set the argument `--space <my-workspace>`.

```sh
poetry run pontos-release --project pontos --space greenbone release --git-remote-name upstream
poetry run pontos-release --space greenbone release --git-remote-name upstream
```

## Uploading to the 'real' PyPI
Expand All @@ -188,8 +190,10 @@ if it has been lost.
## Sign tar and zipball

* May run pontos-release sign

* If you use a "non-Greenbone" project, you may set the argument `--space <my-workspace>`.
* The `--release-version` is not required, latest will be looked up in the project
definition, if not set explicitly

```sh
poetry run pontos-release --project pontos --space greenbone sign --release-version <version>
poetry run pontos-release sign --release-version <version>
```
224 changes: 224 additions & 0 deletions pontos/release/helper.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,224 @@
# -*- coding: utf-8 -*-
# pontos/release/release.py
# Copyright (C) 2020 - 2021 Greenbone Networks GmbH
#
# SPDX-License-Identifier: GPL-3.0-or-later
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#

from typing import Callable, Dict, List, Tuple, Union
import json
import tempfile
from pathlib import Path
import shutil

import requests

from pontos import version


def build_release_dict(
release_version: str,
release_changelog: str,
*,
name: str = '',
target_commitish: str = '',
draft: bool = False,
prerelease: bool = False,
) -> Dict[str, Union[str, bool]]:
"""
builds the dict for release post on github, see:
https://docs.github.com/en/rest/reference/repos#create-a-release
for more details.

Arguments:
release_version: The version (str) that will be set
release_changelog: content of the Changelog (str) for the release
name: name (str) of the release, e.g. 'pontos 1.0.0'
target_commitish: needed when tag is not there yet (str)
draft: If the release is a draft (bool)
prerelease: If the release is a pre release (bool)

Returns:
The dictionary containing the release information.
"""
tag_name = (
release_version
if release_version.startswith('v')
else "v" + release_version
)
return {
'tag_name': tag_name,
'target_commitish': target_commitish,
'name': name,
'body': release_changelog,
'draft': draft,
'prerelease': prerelease,
}


def commit_files(
filename: str,
commit_msg: str,
shell_cmd_runner: Callable,
*,
git_signing_key: str = '',
):
"""Add files to staged and commit staged files.

filename: The filename of file to add and commit
commit_msg: The commit message for the commit
shell_cmd_runner:
git_signing_key: The signing key to sign this commit

Arguments:
to: The version (str) that will be set
develop: Wether to set version to develop or not (bool)

Returns:
executed: True if successfully executed, False else
filename: The filename of the project definition
"""

shell_cmd_runner(f"git add {filename}")
shell_cmd_runner("git add *__version__.py || echo 'ignoring __version__'")
shell_cmd_runner("git add CHANGELOG.md")
shell_cmd_runner(
f"git commit -S {git_signing_key} -m '{commit_msg}'",
)


def download(
url: str,
filename: str,
requests_module: requests,
path: Path,
) -> Path:
"""Download file in url to filename

Arguments:
url: The url of the file we want to download
filename: The name of the file to store the download in
requests_module: the python request module
path: the python pathlib.Path module

Returns:
Path to the downloaded file
"""

file_path = path(tempfile.gettempdir()) / filename

with requests_module.get(url, stream=True) as resp, file_path.open(
mode='wb'
) as download_file:
shutil.copyfileobj(resp.raw, download_file)

return file_path


def get_project_name(
shell_cmd_runner: Callable,
*,
remote: str = 'origin',
) -> str:
"""Get the git repository name"""
# https://stackoverflow.com/a/42543006
ret = shell_cmd_runner(f'git remote get-url {remote}')
return ret.stdout.split('/')[-1].replace('.git', '').replace('\n', '')


def update_version(
to: str, _version: version, *, develop: bool = False
) -> Tuple[bool, str]:
"""Use pontos-version to update the version.

Arguments:
to: The version (str) that will be set
_version: Version module
develop: Wether to set version to develop or not (bool)

Returns:
executed: True if successfully executed, False else
filename: The filename of the project definition
"""
args = ['--quiet']
args.append('update')
args.append(to)
if develop:
args.append('--develop')
executed, filename = _version.main(False, args=args)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would recommend to only pass boolean args by keyword.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The called main looks like this:
def main(leave=True, args=None):
So i can not pass any parameter but leave and args...

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For the readability it is always better to pass pass booleans as keywords. somefunc(True, False, True) is not readable. In our case version.main(leave=False, args=args) is easier to read.

y0urself marked this conversation as resolved.
Show resolved Hide resolved

if not executed:
if filename == "":
print("No project definition found.")
else:
print(f"Unable to update version {to} in {filename}")

return executed, filename


def upload_assets(
username: str,
token: str,
pathnames: List[str],
github_json: Dict,
path: Path,
requests_module: requests,
) -> bool:
"""Function to upload assets

Arguments:
username: The GitHub username to use for the upload
token: That username's GitHub token
pathnames: List of paths to asset files
github_json: The github dictionary, containing relevant information
for the uplaod
path: the python pathlib.Path module
requests_module: the python request module

Returns:
True on success, false else
"""
print(f"Uploading assets: {pathnames}")

asset_url = github_json['upload_url'].replace('{?name,label}', '')
paths = [path(f'{p}.asc') for p in pathnames]

headers = {
'Accept': 'application/vnd.github.v3+json',
'content-type': 'application/octet-stream',
}
auth = (username, token)

for path in paths:
to_upload = path.read_bytes()
resp = requests_module.post(
f"{asset_url}?name={path.name}",
headers=headers,
auth=auth,
data=to_upload,
)

if resp.status_code != 201:
print(
f"Wrong response status {resp.status_code}"
f" while uploading {path.name}"
)
print(json.dumps(resp.text, indent=4, sort_keys=True))
return False
else:
print(f"uploaded: {path.name}")

return True