mirror of
https://github.com/cookiecutter/cookiecutter-django.git
synced 2025-07-11 08:32:21 +03:00
Switch template to calendar versioning & automate releases (#3415)
This commit is contained in:
parent
f49141d333
commit
183ca2088a
1
.github/changelog-template.md
vendored
1
.github/changelog-template.md
vendored
|
@ -1,4 +1,3 @@
|
||||||
## [{{merge_date.strftime('%Y-%m-%d')}}]
|
|
||||||
{%- for change_type, pulls in grouped_pulls.items() %}
|
{%- for change_type, pulls in grouped_pulls.items() %}
|
||||||
{%- if pulls %}
|
{%- if pulls %}
|
||||||
### {{ change_type }}
|
### {{ change_type }}
|
||||||
|
|
29
.github/release-drafter.yml
vendored
29
.github/release-drafter.yml
vendored
|
@ -1,29 +0,0 @@
|
||||||
categories:
|
|
||||||
- title: 'Breaking Changes'
|
|
||||||
labels:
|
|
||||||
- 'breaking'
|
|
||||||
- title: 'Major Changes'
|
|
||||||
labels:
|
|
||||||
- 'major'
|
|
||||||
- title: 'Minor Changes'
|
|
||||||
labels:
|
|
||||||
- 'enhancement'
|
|
||||||
- title: 'Bugfixes'
|
|
||||||
labels:
|
|
||||||
- 'bug'
|
|
||||||
- title: 'Removals'
|
|
||||||
labels:
|
|
||||||
- 'removed'
|
|
||||||
- title: 'Documentation updates'
|
|
||||||
labels:
|
|
||||||
- 'docs'
|
|
||||||
|
|
||||||
exclude-labels:
|
|
||||||
- 'skip-changelog'
|
|
||||||
- 'update'
|
|
||||||
- 'project infrastructure'
|
|
||||||
|
|
||||||
template: |
|
|
||||||
## Changes
|
|
||||||
|
|
||||||
$CHANGES
|
|
14
.github/workflows/draft-release.yml
vendored
14
.github/workflows/draft-release.yml
vendored
|
@ -1,14 +0,0 @@
|
||||||
name: Release Drafter
|
|
||||||
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches:
|
|
||||||
- master
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
release_notes:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- uses: release-drafter/release-drafter@v5
|
|
||||||
env:
|
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
15
.github/workflows/update-changelog.yml
vendored
15
.github/workflows/update-changelog.yml
vendored
|
@ -8,7 +8,10 @@ on:
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build:
|
release:
|
||||||
|
# Disables this workflow from running in a repository that is not part of the indicated organization/user
|
||||||
|
if: github.repository_owner == 'cookiecutter'
|
||||||
|
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
|
@ -22,13 +25,11 @@ jobs:
|
||||||
run: |
|
run: |
|
||||||
python -m pip install --upgrade pip
|
python -m pip install --upgrade pip
|
||||||
pip install -r requirements.txt
|
pip install -r requirements.txt
|
||||||
|
- name: Set git details
|
||||||
|
run: |
|
||||||
|
git config --global user.name "github-actions"
|
||||||
|
git config --global user.email "action@github.com"
|
||||||
- name: Update list
|
- name: Update list
|
||||||
run: python scripts/update_changelog.py
|
run: python scripts/update_changelog.py
|
||||||
env:
|
env:
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
|
||||||
- name: Commit changes
|
|
||||||
uses: stefanzweifel/git-auto-commit-action@v4.12.0
|
|
||||||
with:
|
|
||||||
commit_message: Update Changelog
|
|
||||||
file_pattern: CHANGELOG.md
|
|
||||||
|
|
|
@ -21,5 +21,6 @@ pyyaml==6.0
|
||||||
# Scripting
|
# Scripting
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
PyGithub==1.55
|
PyGithub==1.55
|
||||||
|
gitpython==3.1.24
|
||||||
jinja2==3.0.3
|
jinja2==3.0.3
|
||||||
requests==2.26.0
|
requests==2.26.0
|
||||||
|
|
|
@ -1,26 +1,31 @@
|
||||||
import datetime as dt
|
import datetime as dt
|
||||||
import os
|
import os
|
||||||
|
import re
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Iterable
|
from typing import Iterable
|
||||||
|
|
||||||
from github import Github
|
import git
|
||||||
import github.PullRequest
|
import github.PullRequest
|
||||||
|
import github.Repository
|
||||||
|
from github import Github
|
||||||
from jinja2 import Template
|
from jinja2 import Template
|
||||||
|
|
||||||
CURRENT_FILE = Path(__file__)
|
CURRENT_FILE = Path(__file__)
|
||||||
ROOT = CURRENT_FILE.parents[1]
|
ROOT = CURRENT_FILE.parents[1]
|
||||||
GITHUB_TOKEN = os.getenv("GITHUB_TOKEN", None)
|
GITHUB_TOKEN = os.getenv("GITHUB_TOKEN")
|
||||||
GITHUB_REPO = os.getenv("GITHUB_REPOSITORY", None)
|
GITHUB_REPO = os.getenv("GITHUB_REPOSITORY")
|
||||||
|
GIT_BRANCH = os.getenv("GITHUB_REF_NAME")
|
||||||
# Generate changelog for PRs merged yesterday
|
|
||||||
MERGED_DATE = dt.date.today() - dt.timedelta(days=1)
|
|
||||||
|
|
||||||
|
|
||||||
def main() -> None:
|
def main() -> None:
|
||||||
"""
|
"""
|
||||||
Script entry point.
|
Script entry point.
|
||||||
"""
|
"""
|
||||||
merged_pulls = list(iter_pulls())
|
# Generate changelog for PRs merged yesterday
|
||||||
|
merged_date = dt.date.today() - dt.timedelta(days=1)
|
||||||
|
repo = Github(login_or_token=GITHUB_TOKEN).get_repo(GITHUB_REPO)
|
||||||
|
merged_pulls = list(iter_pulls(repo, merged_date))
|
||||||
|
print(f"Merged pull requests: {merged_pulls}")
|
||||||
if not merged_pulls:
|
if not merged_pulls:
|
||||||
print("Nothing was merged, existing.")
|
print("Nothing was merged, existing.")
|
||||||
return
|
return
|
||||||
|
@ -29,26 +34,44 @@ def main() -> None:
|
||||||
grouped_pulls = group_pulls_by_change_type(merged_pulls)
|
grouped_pulls = group_pulls_by_change_type(merged_pulls)
|
||||||
|
|
||||||
# Generate portion of markdown
|
# Generate portion of markdown
|
||||||
rendered_content = generate_md(grouped_pulls)
|
release_changes_summary = generate_md(grouped_pulls)
|
||||||
|
print(f"Summary of changes: {release_changes_summary}")
|
||||||
|
|
||||||
# Update CHANGELOG.md file
|
# Update CHANGELOG.md file
|
||||||
file_path = ROOT / "CHANGELOG.md"
|
release = f"{merged_date:%Y.%m.%d}"
|
||||||
old_content = file_path.read_text()
|
changelog_path = ROOT / "CHANGELOG.md"
|
||||||
updated_content = old_content.replace(
|
write_changelog(changelog_path, release, release_changes_summary)
|
||||||
"<!-- GENERATOR_PLACEHOLDER -->",
|
print(f"Wrote {changelog_path}")
|
||||||
f"<!-- GENERATOR_PLACEHOLDER -->\n\n{rendered_content}",
|
|
||||||
|
# Update version
|
||||||
|
setup_py_path = ROOT / "setup.py"
|
||||||
|
update_version(setup_py_path, release)
|
||||||
|
print(f"Updated version in {setup_py_path}")
|
||||||
|
|
||||||
|
# Commit changes, create tag and push
|
||||||
|
update_git_repo([changelog_path, setup_py_path], release)
|
||||||
|
|
||||||
|
# Create GitHub release
|
||||||
|
github_release = repo.create_git_release(
|
||||||
|
tag=release,
|
||||||
|
name=release,
|
||||||
|
message=release_changes_summary,
|
||||||
)
|
)
|
||||||
file_path.write_text(updated_content)
|
print(f"Created release on GitHub {github_release}")
|
||||||
|
|
||||||
|
|
||||||
def iter_pulls() -> Iterable[github.PullRequest.PullRequest]:
|
def iter_pulls(
|
||||||
|
repo: github.Repository.Repository,
|
||||||
|
merged_date: dt.date,
|
||||||
|
) -> Iterable[github.PullRequest.PullRequest]:
|
||||||
"""Fetch merged pull requests at the date we're interested in."""
|
"""Fetch merged pull requests at the date we're interested in."""
|
||||||
repo = Github(login_or_token=GITHUB_TOKEN).get_repo(GITHUB_REPO)
|
|
||||||
recent_pulls = repo.get_pulls(
|
recent_pulls = repo.get_pulls(
|
||||||
state="closed", sort="updated", direction="desc"
|
state="closed",
|
||||||
|
sort="updated",
|
||||||
|
direction="desc",
|
||||||
).get_page(0)
|
).get_page(0)
|
||||||
for pull in recent_pulls:
|
for pull in recent_pulls:
|
||||||
if pull.merged and pull.merged_at.date() == MERGED_DATE:
|
if pull.merged and pull.merged_at.date() == merged_date:
|
||||||
yield pull
|
yield pull
|
||||||
|
|
||||||
|
|
||||||
|
@ -77,7 +100,50 @@ def generate_md(grouped_pulls: dict[str, list[github.PullRequest.PullRequest]])
|
||||||
"""Generate markdown file from Jinja template."""
|
"""Generate markdown file from Jinja template."""
|
||||||
changelog_template = ROOT / ".github" / "changelog-template.md"
|
changelog_template = ROOT / ".github" / "changelog-template.md"
|
||||||
template = Template(changelog_template.read_text(), autoescape=True)
|
template = Template(changelog_template.read_text(), autoescape=True)
|
||||||
return template.render(merge_date=MERGED_DATE, grouped_pulls=grouped_pulls)
|
return template.render(grouped_pulls=grouped_pulls)
|
||||||
|
|
||||||
|
|
||||||
|
def write_changelog(file_path: Path, release: str, content: str) -> None:
|
||||||
|
"""Write Release details to the changelog file."""
|
||||||
|
content = f"## {release}\n{content}"
|
||||||
|
old_content = file_path.read_text()
|
||||||
|
updated_content = old_content.replace(
|
||||||
|
"<!-- GENERATOR_PLACEHOLDER -->",
|
||||||
|
f"<!-- GENERATOR_PLACEHOLDER -->\n\n{content}",
|
||||||
|
)
|
||||||
|
file_path.write_text(updated_content)
|
||||||
|
|
||||||
|
|
||||||
|
def update_version(file_path: Path, release: str) -> None:
|
||||||
|
"""Update template version in setup.py."""
|
||||||
|
old_content = file_path.read_text()
|
||||||
|
updated_content = re.sub(
|
||||||
|
r'\nversion = "\d+\.\d+\.\d+"\n',
|
||||||
|
f'\nversion = "{release}"\n',
|
||||||
|
old_content,
|
||||||
|
)
|
||||||
|
file_path.write_text(updated_content)
|
||||||
|
|
||||||
|
|
||||||
|
def update_git_repo(paths: list[Path], release: str) -> None:
|
||||||
|
"""Commit, tag changes in git repo and push to origin."""
|
||||||
|
repo = git.Repo(ROOT)
|
||||||
|
for path in paths:
|
||||||
|
repo.git.add(path)
|
||||||
|
message = f"Release {release}"
|
||||||
|
|
||||||
|
user = repo.git.config("--get", "user.name")
|
||||||
|
email = repo.git.config("--get", "user.email")
|
||||||
|
|
||||||
|
repo.git.commit(
|
||||||
|
m=message,
|
||||||
|
author=f"{user} <{email}>",
|
||||||
|
)
|
||||||
|
repo.git.tag("-a", release, m=message)
|
||||||
|
server = f"https://{GITHUB_TOKEN}@github.com/{GITHUB_REPO}.git"
|
||||||
|
print(f"Pushing changes to {GIT_BRANCH} branch of {GITHUB_REPO}")
|
||||||
|
repo.git.push(server, GIT_BRANCH)
|
||||||
|
repo.git.push("--tags", server, GIT_BRANCH)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
@ -85,4 +151,8 @@ if __name__ == "__main__":
|
||||||
raise RuntimeError(
|
raise RuntimeError(
|
||||||
"No github repo, please set the environment variable GITHUB_REPOSITORY"
|
"No github repo, please set the environment variable GITHUB_REPOSITORY"
|
||||||
)
|
)
|
||||||
|
if GIT_BRANCH is None:
|
||||||
|
raise RuntimeError(
|
||||||
|
"No git branch set, please set the GITHUB_REF_NAME environment variable"
|
||||||
|
)
|
||||||
main()
|
main()
|
||||||
|
|
14
setup.py
14
setup.py
|
@ -1,21 +1,11 @@
|
||||||
#!/usr/bin/env python
|
#!/usr/bin/env python
|
||||||
|
|
||||||
import os
|
|
||||||
import sys
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from setuptools import setup
|
from setuptools import setup
|
||||||
except ImportError:
|
except ImportError:
|
||||||
from distutils.core import setup
|
from distutils.core import setup
|
||||||
|
|
||||||
# Our version ALWAYS matches the version of Django we support
|
# We use calendar versioning
|
||||||
# If Django has a new release, we branch, tag, then update this setting after the tag.
|
version = "2021.11.17"
|
||||||
version = "3.1.13-01"
|
|
||||||
|
|
||||||
if sys.argv[-1] == "tag":
|
|
||||||
os.system(f'git tag -a {version} -m "version {version}"')
|
|
||||||
os.system("git push --tags")
|
|
||||||
sys.exit()
|
|
||||||
|
|
||||||
with open("README.rst") as readme_file:
|
with open("README.rst") as readme_file:
|
||||||
long_description = readme_file.read()
|
long_description = readme_file.read()
|
||||||
|
|
Loading…
Reference in New Issue
Block a user