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

Misc. updates to script #9

Merged
merged 8 commits into from
Feb 22, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/tox.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
python-version: ['3.7', '3.8', '3.9', '3.10', '3.11']
python-version: ['3.8', '3.9', '3.10', '3.11', '3.12']

steps:
- uses: actions/checkout@v3
Expand Down
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
# Python build artifacts
build
dist
lib/galaxy.egg-info
galaxy_release_util.egg-info
.eggs

# Python bytecode
Expand Down
95 changes: 70 additions & 25 deletions galaxy_release_util/point_release.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,13 @@

"""
RELEASE_BRANCH_REGEX = re.compile(r"^release_(\d{2}\.\d{1,2})$")
FIRST_RELEASE_CHANGELOG_TEXT = "First release"


@dataclass
class ReleaseItem:
version: Version
date: Optional[str] = None


@dataclass
Expand Down Expand Up @@ -87,6 +94,7 @@ class Package:
prs: Set[PullRequest.PullRequest] = field(default_factory=set)
modified_paths: List[pathlib.Path] = field(default_factory=list)
package_history: List[ChangelogItem] = field(default_factory=list)
release_items: List[ReleaseItem] = field(default_factory=list)

@property
def name(self) -> str:
Expand All @@ -109,6 +117,22 @@ def write_history(self):
self.history_rst.write_text(self.changelog)
self.modified_paths.append(self.history_rst)

def add_release(self, item: ReleaseItem) -> None:
self.release_items.append(item)

@property
def is_new(self) -> bool:
"""Package has not been released:
- has only one release item,
- which is a devrelease,
- and has no date.
"""
return (
len(self.release_items) == 1
and self.release_items[0].version.is_devrelease
and not self.release_items[0].date
)

def __repr__(self) -> str:
pretty_string = f"[Package: {self.name}, Current Version: {self.current_version}"
return pretty_string
Expand Down Expand Up @@ -137,6 +161,11 @@ def read_package(package_path: pathlib.Path) -> Package:


def parse_changelog(package: Package) -> List[ChangelogItem]:
def add_changelog_item(changes, child):
rawsource = child.rawsource.strip()
if rawsource:
changes.append(f"* {rawsource}")

settings = frontend.get_default_settings(Parser) # type: ignore[attr-defined] ## upstream type stubs not updated?
document = utils.new_document(str(package.history_rst), settings)
Parser().parse(package.history_rst.read_text(), document)
Expand All @@ -159,12 +188,13 @@ def parse_changelog(package: Package) -> List[ChangelogItem]:
# we will just omit this later
version_str = release_version
current_version = Version(version_str)
package.add_release(ReleaseItem(version=current_version, date=current_date))
changes = []
for changelog_item in release[1:]:
# could be bullet list or a nested section with bugfix, docs, etc
if changelog_item.tagname == "bullet_list":
for child in changelog_item.children:
changes.append(f"* {child.rawsource.strip()}")
add_changelog_item(changes, child)
elif changelog_item.tagname == "paragraph":
changes = changelog_item.rawsource.splitlines()
elif changelog_item.tagname == "section":
Expand All @@ -173,17 +203,17 @@ def parse_changelog(package: Package) -> List[ChangelogItem]:
changes.append(f"\n{section_delimiter}\n{kind}\n{section_delimiter}\n")
for section_changelog_item in changelog_item[1:]:
for child in section_changelog_item:
changes.append(f"* {child.rawsource.strip()}")
add_changelog_item(changes, child)
changelog_items.append(ChangelogItem(version=current_version, date=current_date, changes=changes))

# Filter out dev release versions without changelog,
# we're going to add these back after committing the release version
clean_changelog_items: List[ChangelogItem] = []
for item in changelog_items:
if not item.is_empty_devrelease:
if not (item.is_empty_devrelease or package.is_new):
if item.date is None:
raise Exception(
f"Error in '{package.history_rst}'. Changelog entry for version '{item.version}' has no date but contains changes. You have to fix this manually."
f"Error in '{package.history_rst}'. Changelog entry for non-dev version '{item.version}' has no date but contains changes. You have to fix this manually."
)
clean_changelog_items.append(item)
return sorted(
Expand Down Expand Up @@ -242,9 +272,12 @@ def commits_to_prs(packages: List[Package]):
commits = set.union(*(p.commits for p in packages))
pr_cache = {}
commit_to_pr = {}
for commit in commits:
repo = g.get_repo(REPO)
total_commits = len(commits)
for i, commit in enumerate(commits):
click.echo(f"Processing commit {i} of {total_commits}")
# Get the list of pull requests associated with the commit
commit_obj = g.get_repo(REPO).get_commit(commit)
commit_obj = repo.get_commit(commit)
prs = commit_obj.get_pulls()
if not prs:
raise Exception(f"commit {commit} has no associated PRs")
Expand All @@ -264,7 +297,10 @@ def update_package_history(package: Package, new_version: Version):
"Enhancements": [],
"Other changes": [],
}
if not package.prs:
if package.is_new:
# For new packages, replace any current text; do not list PRs.
sorted_and_formatted_changes.append(FIRST_RELEASE_CHANGELOG_TEXT)
elif not package.prs:
# Skip publishing packages if no change ?
sorted_and_formatted_changes.append("No recorded changes since last release")
else:
Expand Down Expand Up @@ -334,7 +370,7 @@ def set_root_version(galaxy_root: pathlib.Path, new_version: Version) -> pathlib


def is_git_clean(galaxy_root: pathlib.Path):
click.echo(f"Making sure galaxy clone at '{galaxy_root}' is clean")
click.echo(f"Making sure galaxy clone at '{galaxy_root}' is clean:")
command = ["git", "diff-index", "--quiet", "HEAD"]
result = subprocess.run(command, capture_output=True, text=True, cwd=galaxy_root)
if result.returncode == 0:
Expand Down Expand Up @@ -403,7 +439,8 @@ def merge_and_resolve_branches(
"checkout",
new_branch,
str(galaxy_root / "lib" / "galaxy" / "version.py"),
]
],
cwd=galaxy_root,
)
# we rewrite the packages changelog
for new_package in packages_to_rewrite:
Expand Down Expand Up @@ -431,14 +468,16 @@ def merge_and_resolve_branches(
dev_version = get_root_version(galaxy_root)
previous_package.package_history.insert(0, ChangelogItem(version=dev_version, changes=[], date=None))
previous_package.write_history()
subprocess.run(["git", "add", str(previous_package.history_rst)])
subprocess.run(["git", "add", str(previous_package.history_rst)], cwd=galaxy_root)
# restore setup.cfg
subprocess.run(["git", "checkout", new_branch, str(previous_package.setup_cfg)]).check_returncode()
subprocess.run(
["git", "checkout", new_branch, str(previous_package.setup_cfg)], cwd=galaxy_root
).check_returncode()
# Commit changes
if merge_conflict:
subprocess.run(["git", "commit", "--no-edit"]).check_returncode()
subprocess.run(["git", "commit", "--no-edit"], cwd=galaxy_root).check_returncode()
else:
subprocess.run(["git", "commit", "--amend", "--no-edit"]).check_returncode()
subprocess.run(["git", "commit", "--amend", "--no-edit"], cwd=galaxy_root).check_returncode()


def get_next_devN_version(galaxy_root) -> Version:
Expand All @@ -459,9 +498,10 @@ def is_merge_required(base_branch: str, new_branch: str, galaxy_root: pathlib.Pa
process = subprocess.run(
["git", "merge", "--no-commit", "--no-ff", base_branch],
cwd=galaxy_root,
capture_output=False,
capture_output=True,
)
subprocess.run(["git", "merge", "--abort"], cwd=galaxy_root)
if not process.stdout == b"Already up to date.\n":
subprocess.run(["git", "merge", "--abort"], cwd=galaxy_root)
if process.returncode == 0:
return False
return True
Expand All @@ -473,12 +513,13 @@ def ensure_branches_up_to_date(branches: List[str], base_branch: str, upstream:
# Check that the head commit matches the commit for the same branch at the specified remote repo url
result = subprocess.run(
["git", "ls-remote", upstream, f"refs/heads/{branch}"],
cwd=galaxy_root,
capture_output=True,
text=True,
)
result.check_returncode()
remote_commit_hash = result.stdout.split("\t")[0]
result = subprocess.run(["git", "rev-parse", "HEAD"], capture_output=True, text=True)
result = subprocess.run(["git", "rev-parse", "HEAD"], cwd=galaxy_root, capture_output=True, text=True)
result.check_returncode()
local_commit_hash = result.stdout.strip()
if remote_commit_hash != local_commit_hash:
Expand All @@ -488,9 +529,11 @@ def ensure_branches_up_to_date(branches: List[str], base_branch: str, upstream:
subprocess.run(["git", "checkout", base_branch], cwd=galaxy_root).check_returncode()


def push_references(references: List[str], upstream: str = "https://github.com/galaxyproject/galaxy.git"):
def push_references(
references: List[str], galaxy_root: pathlib.Path, upstream: str = "https://github.com/galaxyproject/galaxy.git"
):
for reference in references:
subprocess.run(["git", "push", upstream, reference]).check_returncode()
subprocess.run(["git", "push", upstream, reference], cwd=galaxy_root).check_returncode()


@click.group(help="Subcommands of this script can create new releases and build and upload package artifacts")
Expand Down Expand Up @@ -564,10 +607,12 @@ def create_point_release(
abort=True,
)
root_version = get_root_version(galaxy_root)
click.echo(f"Current Galaxy version is {root_version}, will create new version {new_version}")
base_branch = current_branch = get_current_branch(galaxy_root)
click.echo(
f"- Current Galaxy version: {root_version}\n- New Galaxy version: {new_version}\n- Base branch: {base_branch}"
)
if not no_confirm:
click.confirm("Does this look correct?", abort=True)
base_branch = current_branch = get_current_branch(galaxy_root)
newer_branches = get_branches(galaxy_root, new_version, base_branch)
all_branches = newer_branches + [base_branch]
click.echo("Making sure that all branches are up to date")
Expand Down Expand Up @@ -621,11 +666,11 @@ def create_point_release(
cmd.extend(changed_paths)
release_tag = f"v{new_version}"
subprocess.run(cmd, cwd=galaxy_root)
subprocess.run(["git", "commit", "-m" f"Create version {new_version}"])
subprocess.run(["git", "commit", "-m" f"Create version {new_version}"], cwd=galaxy_root)
if not no_confirm:
click.confirm(f"Create git tag '{release_tag}'?", abort=True)

subprocess.run(["git", "tag", release_tag])
subprocess.run(["git", "tag", release_tag], cwd=galaxy_root)
dev_version = get_next_devN_version(galaxy_root)
version_py = set_root_version(galaxy_root, dev_version)
modified_paths = [version_py]
Expand All @@ -636,8 +681,8 @@ def create_point_release(
modified_paths.extend(package.modified_paths)
cmd = ["git", "add"]
cmd.extend([str(p) for p in modified_paths])
subprocess.run(cmd)
subprocess.run(["git", "commit", "-m", f"Start work on {dev_version}"])
subprocess.run(cmd, cwd=galaxy_root)
subprocess.run(["git", "commit", "-m", f"Start work on {dev_version}"], cwd=galaxy_root)
# merge changes into newer branches
# special care needs to be taken for changelog files
if not no_confirm and newer_branches:
Expand All @@ -652,7 +697,7 @@ def create_point_release(
current_branch = new_branch
references = [release_tag] + all_branches
if no_confirm or click.confirm(f"Push {','.join(references)} to upstream '{upstream}' ?", abort=True):
push_references(references=references, upstream=upstream)
push_references(references=references, galaxy_root=galaxy_root, upstream=upstream)


if __name__ == "__main__":
Expand Down
3 changes: 1 addition & 2 deletions tox.ini
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,11 @@ envlist = py37, py38, py39, py310, py311

[gh]
python =
3.12 = unit
3.12 = unit,lint
3.11 = unit
3.10 = unit
3.9 = unit
3.8 = unit
3.7 = unit,mypy,lint

[testenv]
commands =
Expand Down
Loading