mirror of
https://github.com/php-curl-class/php-curl-class.git
synced 2026-08-18 20:02:53 +00:00
237 lines
7.9 KiB
Python
237 lines
7.9 KiB
Python
import json
|
|
import os
|
|
import pprint
|
|
import subprocess
|
|
from copy import copy
|
|
from datetime import datetime, timezone
|
|
from pathlib import Path
|
|
|
|
import git
|
|
from github import Github
|
|
|
|
|
|
# The owner and repository name. For example, octocat/Hello-World.
|
|
GITHUB_REPOSITORY = os.getenv('GITHUB_REPOSITORY')
|
|
|
|
GITHUB_TOKEN = os.getenv('GITHUB_TOKEN')
|
|
GITHUB_REF_NAME = os.getenv('GITHUB_REF_NAME')
|
|
|
|
CURRENT_FILE = Path(__file__)
|
|
ROOT = CURRENT_FILE.parents[1]
|
|
CHANGELOG_PATH = ROOT / 'CHANGELOG.md'
|
|
LIBRARY_FILE_PATH = ROOT / 'src/Curl/Curl.php'
|
|
|
|
# TODO: Adjust number of recent pull requests to include likely number of
|
|
# pull requests since the last release.
|
|
RECENT_PULL_REQUEST_LIMIT = 10
|
|
|
|
|
|
def main():
|
|
# Find most recent tag and timestamp.
|
|
# git for-each-ref --format="%(refname:short) | %(creatordate)" "refs/tags/*"
|
|
local_repo = git.Repo(ROOT)
|
|
|
|
# Fetch tags since `git fetch' is run with --no-tags during actions/checkout.
|
|
# git fetch --tags
|
|
for remote in local_repo.remotes:
|
|
remote.fetch('--tags')
|
|
|
|
# Sort the tags by version.
|
|
# git tag --list | sort --reverse --version-sort
|
|
tags = sorted(
|
|
local_repo.tags,
|
|
key=lambda tag: list(map(int, tag.name.split('.'))), reverse=True)
|
|
|
|
most_recent_tag = tags[0]
|
|
print('most_recent_tag: {}'.format(most_recent_tag))
|
|
most_recent_tag_datetime = most_recent_tag.commit.committed_datetime
|
|
print('most_recent_tag_datetime: {}'.format(most_recent_tag_datetime))
|
|
|
|
# Find merged pull requests since the most recent tag.
|
|
github_repo = Github(login_or_token=GITHUB_TOKEN).get_repo(GITHUB_REPOSITORY)
|
|
recent_pulls = github_repo.get_pulls(
|
|
state='closed',
|
|
sort='updated',
|
|
direction='desc',
|
|
)[:RECENT_PULL_REQUEST_LIMIT]
|
|
|
|
pull_request_changes = []
|
|
|
|
# Group pull requests by semantic version change type.
|
|
pull_request_by_type = {
|
|
'major': [],
|
|
'minor': [],
|
|
'patch': [],
|
|
'unspecified': [],
|
|
}
|
|
|
|
# Track if any pull request is missing a semantic version change type.
|
|
pulls_missing_semver_label = []
|
|
|
|
for pull in recent_pulls:
|
|
# print('-' * 10)
|
|
|
|
if not pull.merged:
|
|
# print('skipping since not merged: {}'.format(pull.title))
|
|
# print(pull.html_url)
|
|
continue
|
|
|
|
# Make merged_at timestamp offset-aware. Without this, the following
|
|
# error will appear:
|
|
# TypeError: can't compare offset-naive and offset-aware datetimes
|
|
pull_merged_at = copy(pull.merged_at).replace(tzinfo=timezone.utc)
|
|
|
|
if pull_merged_at < most_recent_tag_datetime:
|
|
# print('skipping since merged prior to last release: {}'.format(pull.title))
|
|
# print(pull.html_url)
|
|
continue
|
|
|
|
pull_labels = {
|
|
label.name for label in pull.labels
|
|
}
|
|
if 'major-incompatible-changes' in pull_labels:
|
|
group_name = 'major'
|
|
elif 'minor-backwards-compatible-added-functionality' in pull_labels:
|
|
group_name = 'minor'
|
|
elif 'patch-backwards-compatible-bug-fixes' in pull_labels:
|
|
group_name = 'patch'
|
|
else:
|
|
group_name = 'unspecified'
|
|
pulls_missing_semver_label.append(pull)
|
|
pull_request_by_type[group_name].append(pull)
|
|
|
|
# pprint.pprint(pull.title)
|
|
# pprint.pprint('most recent: {}'.format(most_recent_tag_datetime))
|
|
# pprint.pprint('merged at: {}'.format(pull.merged_at))
|
|
# print(pull.html_url)
|
|
|
|
pull_request_changes.append(
|
|
'- {} ([#{}]({}))'.format(pull.title, pull.number, pull.html_url)
|
|
)
|
|
|
|
# print('-' * 10)
|
|
|
|
# pprint.pprint(pull_request_changes)
|
|
|
|
if not pull_request_changes:
|
|
print('No merged pull requests found')
|
|
return
|
|
|
|
# pprint.pprint(pull_request_by_type)
|
|
highest_semantic_version = None
|
|
php_file_path = ''
|
|
if pull_request_by_type.get('major'):
|
|
highest_semantic_version = 'major'
|
|
php_file_path = 'scripts/bump_major_version.php'
|
|
elif pull_request_by_type.get('minor'):
|
|
highest_semantic_version = 'minor'
|
|
php_file_path = 'scripts/bump_minor_version.php'
|
|
elif pull_request_by_type.get('patch'):
|
|
highest_semantic_version = 'patch'
|
|
php_file_path = 'scripts/bump_patch_version.php'
|
|
print('highest_semantic_version: {}'.format(highest_semantic_version))
|
|
|
|
# Bump version and get next semantic version.
|
|
command = ['php', php_file_path]
|
|
print('running command: {}'.format(command))
|
|
proc = subprocess.Popen(command, shell=False, stdout=subprocess.PIPE, stdin=subprocess.PIPE)
|
|
stdout, stderr = proc.communicate()
|
|
print('stdout: {}'.format(stdout))
|
|
print('stderr: {}'.format(stderr))
|
|
result = json.loads(stdout)
|
|
pprint.pprint(result)
|
|
|
|
release_version = result['new_version']
|
|
today = datetime.today()
|
|
print('today: {} (tzinfo={})'.format(today, today.tzinfo))
|
|
today = today.replace(tzinfo=timezone.utc)
|
|
print('today: {} (tzinfo={})'.format(today, today.tzinfo))
|
|
release_date = today.strftime('%Y-%m-%d')
|
|
print('release_date: {}'.format(release_date))
|
|
release_title = '{} - {}'.format(release_version, release_date)
|
|
print('release_title: {}'.format(release_title))
|
|
|
|
release_content = (
|
|
'## {}\n'
|
|
'\n'
|
|
'{}'
|
|
).format(release_title, '\n'.join(pull_request_changes))
|
|
|
|
old_content = CHANGELOG_PATH.read_text()
|
|
new_content = old_content.replace(
|
|
'<!-- CHANGELOG_PLACEHOLDER -->',
|
|
'<!-- CHANGELOG_PLACEHOLDER -->\n\n{}'.format(release_content),
|
|
)
|
|
# print(new_content[:800])
|
|
CHANGELOG_PATH.write_text(new_content)
|
|
|
|
# Raise error if any pull request is missing a semantic version change type.
|
|
if pulls_missing_semver_label:
|
|
error_message = (
|
|
'Merged pull request(s) found without semantic version label:\n'
|
|
'{}'.format('\n'.join(
|
|
' {}'.format(pull.html_url)
|
|
for pull in pulls_missing_semver_label)))
|
|
raise Exception(error_message)
|
|
|
|
# print('before:')
|
|
# print(local_repo.git.status())
|
|
|
|
local_repo.git.add(CHANGELOG_PATH)
|
|
local_repo.git.add(LIBRARY_FILE_PATH)
|
|
|
|
# print('after:')
|
|
# print(local_repo.git.status())
|
|
|
|
print('diff:')
|
|
print(local_repo.git.diff(cached=True, color='always'))
|
|
|
|
local_repo.git.commit(
|
|
message=result['message'],
|
|
author='{} <{}>'.format(
|
|
local_repo.git.config('--get', 'user.name'),
|
|
local_repo.git.config('--get', 'user.email')))
|
|
|
|
print('diff after commit:')
|
|
# git log --max-count=1 --patch
|
|
print(local_repo.git.log(max_count='1', patch=True, color='always'))
|
|
|
|
# Push local changes.
|
|
server = 'https://{}@github.com/{}.git'.format(
|
|
GITHUB_TOKEN, GITHUB_REPOSITORY)
|
|
print('pushing changes to branch "{}" of repository "{}"'.format(
|
|
GITHUB_REF_NAME, GITHUB_REPOSITORY))
|
|
local_repo.git.push(server, GITHUB_REF_NAME)
|
|
|
|
# Create tag and release.
|
|
tag = result['new_version']
|
|
tag_message = result['message']
|
|
release_name = 'Release {}'.format(release_version)
|
|
release_message = (
|
|
'See [change log](https://github.com/php-curl-class/php-curl-class/blob/master/CHANGELOG.md) for changes.\n'
|
|
'\n'
|
|
'https://github.com/php-curl-class/php-curl-class/compare/{}...{}'.format(
|
|
result['old_version'],
|
|
result['new_version']))
|
|
commit_sha = local_repo.head.commit.hexsha
|
|
print('tag: {}'.format(tag))
|
|
print('tag_message: "{}"'.format(tag_message))
|
|
print('release_name: "{}"'.format(release_name))
|
|
print('release_message: "{}"'.format(release_message))
|
|
print('commit_sha: {}'.format(commit_sha))
|
|
|
|
github_repo.create_git_tag_and_release(
|
|
tag=tag,
|
|
tag_message=tag_message,
|
|
release_name=release_name,
|
|
release_message=release_message,
|
|
object=commit_sha,
|
|
type='commit',
|
|
draft=False,
|
|
)
|
|
print('created tag and release')
|
|
|
|
|
|
if __name__ == '__main__':
|
|
main()
|