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

Add GitHub workflow files for test PyPI and GitHub release #95

Merged
merged 8 commits into from
Oct 8, 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
84 changes: 84 additions & 0 deletions .github/workflows/build-wheel-release-publish.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
name: Release
on:
workflow_dispatch:
push:
tags:
- '*'
permissions:
contents: write
jobs:
build-package:
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Produce wheel/sdist, have them available under dist

runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
ref: ${{ github.ref }}
- uses: hynek/build-and-inspect-python-package@v2

update-changelog:
needs: [build-package]
if: "!contains(github.ref, 'rc')"
Copy link
Contributor Author

Choose a reason for hiding this comment

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

if it has no rc, then update CHANGELOG.rst

runs-on: ubuntu-latest
steps:
- name: Checkout the repository
uses: actions/checkout@v4
with:
ref: ${{ github.ref }}

- name: Update CHANGELOG.rst wit the latest news
run: python .github/workflows/update-changelog.py "${{ github.ref_name }}"

- name: Commite the changes in CHANGELOG.rst
uses: stefanzweifel/git-auto-commit-action@v5
with:
commit_message: update changelog
branch: pypi-build # FIXME: change to main

github-pre-release:
needs: [build-package]
if: contains(github.ref, 'rc')
runs-on: ubuntu-latest
steps:
- name: Generate GH release notes for pre-release
uses: softprops/action-gh-release@v2
with:
draft: true
prerelease: true
generate_release_notes: true

github-release:
needs: [build-package, update-changelog]
if: "!contains(github.ref, 'rc')"
runs-on: ubuntu-latest
steps:
- name: Checkout the repository
uses: actions/checkout@v4
with:
ref: pypi-build # FIXME: change to main
- name: Generate GH release notes for release
run: python .github/workflows/get-latest-changelog.py "${{ github.ref_name }}"
- name: Release
uses: softprops/action-gh-release@v2
with:
body_path: CHANGELOG.txt
draft: true

pypi-publish:
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Upload to pypi - right now test.pypi is used for testing.

needs: [build-package]
environment:
name: testpypi # FIXME: change to pypi
url: https://test/pypi.org/p/diffpy.snmf # FIXME: get the PyPI URL
permissions:
id-token: write
runs-on: ubuntu-latest
steps:
- uses: actions/download-artifact@v4
with:
name: Packages
path: dist

- name: Publish package distributions to PyPI
uses: pypa/gh-action-pypi-publish@release/v1
with:
repository-url: https://test.pypi.org/legacy/ # FIXME: remove test.
verbose: true
58 changes: 58 additions & 0 deletions .github/workflows/get-latest-changelog.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import re
import sys


def get_tag_news_items(tag, filepath):
"""Collect news items after the specified tag until the next version is found."""
collect = False
collected_lines = []
# Regex to match version numbers
version_pattern = re.compile(r"^\d+\.\d+\.\d+")

with open(filepath, "r") as file:
for line in file:
if line.strip().startswith(tag):
collect = True
continue
elif collect and version_pattern.match(line.strip()):
break
elif collect:
collected_lines.append(line.rstrip())

return collected_lines


def remove_two_lines(lines):
"""Remove two lines after the tag in CHANGELOG.rst."""
if lines:
# Remove the first line containing "===="
if "====" in lines[0]:
lines.pop(0)
# Remove the second empty line
if lines[1] == "":
lines.pop(1)
return lines


def save_to_txt_file(lines, filename):
"""Save collected lines to a .txt file used for GH release notes."""
output = "\n".join(lines)
with open(filename, "w") as file:
file.write(output)
return output


if __name__ == "__main__":
if len(sys.argv) < 2:
assert (
False
), "No tag has been provided. Please provide a tag by running python get-latest-changelog.py <tag>"

tag = sys.argv[1]
CHANGELOG_PATH = "CHANGELOG.rst"
LATEST_CHANGELOG_PATH = "CHANGELOG.txt"

collected_lines = get_tag_news_items(tag, CHANGELOG_PATH)
cleaned_lines = remove_two_lines(collected_lines)
latest_changelog_output = save_to_txt_file(cleaned_lines, LATEST_CHANGELOG_PATH)
print(f"CHANGELOG for {tag}:\n{latest_changelog_output}")
92 changes: 92 additions & 0 deletions .github/workflows/update-changelog.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
import os
import sys
from glob import glob

# Get the GitHub reference passed as an argument
tag = sys.argv[1]

# Store category data
news_items = {
"Added": [],
"Changed": [],
"Deprecated": [],
"Removed": [],
"Fixed": [],
"Security": [],
}


def extract_news_items(file_path):
"""Extract news bullet points under each category for each .rst file."""
with open(file_path, "r") as file:
for line in file:
line = line.strip()

# Check if the line is a category header
if line.startswith("**") and line.endswith(":**"):
current_category = line.strip("**:").strip()

# Only add if the line is not empty and not a category header
elif current_category and line and not line.startswith("* <news item>"):
news_items[current_category].append(line)


def write_merged_file():
"""Add the news items under the ".. current developments" section."""
CHANGELOG_PATH = "CHANGELOG.rst"
CHANGELOG_HEADER = ".. current developments"

# Insert news
new_news_content = f"\n{tag}\n=====\n\n"
for category_name in sorted(news_items.keys()):
items = news_items[category_name]
if items:
# Add category name e.g. Added, Changed, etc.
new_news_content += f"**{category_name}:**\n\n"
for item in items:
# Add each item in the category
new_news_content += f"{item}\n"
new_news_content += "\n"

# Read CHANGELOG.rst
with open(CHANGELOG_PATH, "r") as file:
current_content = file.read()

# Find the position to insert news after ".. current developments"
insert_position = current_content.find(CHANGELOG_HEADER) + len(CHANGELOG_HEADER) + 1
final_content = current_content[:insert_position] + new_news_content + current_content[insert_position:]

# Write the updated content back to the file
with open(CHANGELOG_PATH, "w") as file:
file.write(final_content)

return new_news_content


def remove_news_rst_files(news_dir_path):
"""Remove .rst files in the news directory except TEMPLATE.rst"""
rst_files = os.listdir(news_dir_path)
for file_name in rst_files:
rst_file_path = os.path.join(news_dir_path, file_name)
if file_name.endswith(".rst") and file_name != "TEMPLATE.rst":
os.remove(rst_file_path)


if __name__ == "__main__":
NEWS_DIR_PATH = "news"

# Get all news .rst files
news_rst_files = glob(os.path.join(NEWS_DIR_PATH, "*.rst"))

# Extract and store news items into a single dictionary
for rst_file in news_rst_files:
extract_news_items(rst_file)

# Add news under ".. current developments"
new_news_content = write_merged_file()

# Remove all .rst files in the news directory except TEMPLATE.rst
remove_news_rst_files(NEWS_DIR_PATH)

# Print for debugging
print(new_news_content)
23 changes: 23 additions & 0 deletions news/gh-workflow.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
**Added:**

* GitHub workflow files for PyPI and GH release

**Changed:**

* <news item>

**Deprecated:**

* <news item>

**Removed:**

* <news item>

**Fixed:**

* <news item>

**Security:**

* <news item>