Hi Sandra, hello world,

Sandra Loosemore wrote:
I have created the devel/omp/gcc-15 (aka "OG15") branch, ...

For previous branches we'd been using ChangeLog.omp files paralleling the normal ChangeLog files, that were updated manually and committed with the corresponding patch.  In preparing the current patch set, though, I found that
...

corresponding ChangeLog.omp patch hunks.
...

It seems like the easiest solution is just to extend the mechanism used to manage ChangeLogs automatically on master and release branches, which is what the attached patch attempts to do.

It seems to me as if your approach causes merge issues. Namely, as
git_update_version.py updates DATESTAMP and ChangeLog, there is a
clash with the updates to the same files on the GCC 15 branch, when
merging.

Additionally, I am not really sure that nightly bumps, updating usually
only the DATESTAMP, are really useful.

How about the attached patch? With it, running

./contrib/gcc-changelog/git_update_version.py \
    --suffix '.omp' -c \
    --exclude-branch=origin/releases/gcc-15 \
    --last-commit=0b76b58a5875d519f95a5af661fb64e42a42ed8e

works where --last-commit could be, e.g.,

git log -1 --pretty=format:%H --grep "ChangeLog.omp Bump"

This could be wrapped in some script to (e.g. committed to this
the branch of interest) to handle the arguments and, possibly,
commit - with the possibility to skip commits if only
DATESTAMP<suffix> has changed.

This could then be run manually - or as someone's cronjob.

* * *

What do you - and anyone else - think about this approach?
Or about the original one? Or has yet another good alternative
or additional idea?

Tobias
git_update_version.py: Support vendor-branch version bumps

contrib/ChangeLog:

	* gcc-changelog/git_repository.py (parse_git_revisions): Optional
	exclude_branch_name argument
	* gcc-changelog/git_update_version.py: Add --suffix, --exclude-branch
	and --last-commit to handle vendor branches.

 contrib/gcc-changelog/git_repository.py     |  7 +++-
 contrib/gcc-changelog/git_update_version.py | 55 +++++++++++++++++++++++------
 2 files changed, 51 insertions(+), 11 deletions(-)

diff --git a/contrib/gcc-changelog/git_repository.py b/contrib/gcc-changelog/git_repository.py
index 2b2efffe77a..dc658af83b9 100755
--- a/contrib/gcc-changelog/git_repository.py
+++ b/contrib/gcc-changelog/git_repository.py
@@ -31,7 +31,8 @@ except ImportError:
 from git_commit import GitCommit, GitInfo, decode_path
 
 
-def parse_git_revisions(repo_path, revisions, ref_name=None):
+def parse_git_revisions(repo_path, revisions, ref_name=None,
+                        exclude_branch_name=None):
     repo = Repo(repo_path)
 
     def commit_to_info(commit):
@@ -67,6 +68,8 @@ def parse_git_revisions(repo_path, revisions, ref_name=None):
         except ValueError:
             return None
 
+    exclude_branch = (repo.commit(exclude_branch_name)
+                      if exclude_branch_name is not None else None)
     parsed_commits = []
     if '..' in revisions:
         commits = list(repo.iter_commits(revisions))
@@ -74,6 +77,8 @@ def parse_git_revisions(repo_path, revisions, ref_name=None):
         commits = [repo.commit(revisions)]
 
     for commit in commits:
+        if exclude_branch is not None and repo.is_ancestor(commit, exclude_branch):
+            continue
         git_commit = GitCommit(commit_to_info(commit.hexsha),
                                commit_to_info_hook=commit_to_info,
                                ref_name=ref_name)
diff --git a/contrib/gcc-changelog/git_update_version.py b/contrib/gcc-changelog/git_update_version.py
index 8e36c745836..4412c974791 100755
--- a/contrib/gcc-changelog/git_update_version.py
+++ b/contrib/gcc-changelog/git_update_version.py
@@ -23,6 +23,8 @@ import datetime
 import logging
 import os
 import re
+import shutil
+import sys
 
 from git import Repo
 
@@ -62,14 +64,14 @@ def read_timestamp(path):
         return f.read()
 
 
-def prepend_to_changelog_files(repo, folder, git_commit, add_to_git):
+def prepend_to_changelog_files(repo, folder, git_commit, add_to_git, suffix):
     if not git_commit.success:
         logging.info(f"While processing {git_commit.info.hexsha}:")
         for error in git_commit.errors:
             logging.info(error)
         raise AssertionError()
     for entry, output in git_commit.to_changelog_entries(use_commit_ts=True):
-        full_path = os.path.join(folder, entry, 'ChangeLog')
+        full_path = os.path.join(folder, entry, 'ChangeLog' + suffix)
         logging.info('writing to %s' % full_path)
         if os.path.exists(full_path):
             with open(full_path) as f:
@@ -89,7 +91,10 @@ active_refs = ['master',
                'releases/gcc-12', 'releases/gcc-13', 'releases/gcc-14']
 
 parser = argparse.ArgumentParser(description='Update DATESTAMP and generate '
-                                 'ChangeLog entries')
+                                 'ChangeLog entries',
+                                 epilog='For vendor branches, only; e.g: -s .suffix '
+                                 '-x releases/gcc-15 -l '
+                                 '`git log -1 --pretty=format:%H --grep "Vendor Bump"`')
 parser.add_argument('-g', '--git-path', default='.',
                     help='Path to git repository')
 parser.add_argument('-p', '--push', action='store_true',
@@ -102,18 +107,31 @@ parser.add_argument('-c', '--current', action='store_true',
                     help='Modify current branch (--push argument is ignored)')
 parser.add_argument('-i', '--ignore', action='append',
                     help='list of commits to ignore')
+# Useful only for vendor branches
+parser.add_argument('-s', '--suffix', default="",
+                    help='suffix for the ChangeLog and DATESTAMP files')
+parser.add_argument('-l', '--last-commit',
+                    help='hash of the last DATESTAMP commit')
+parser.add_argument('-x', '--exclude-branch',
+                    help='commits to be ignored if in this branch')
 args = parser.parse_args()
 
 repo = Repo(args.git_path)
 origin = repo.remotes['origin']
 
 
-def update_current_branch(ref_name=None):
+def update_current_branch(ref_name=None, suffix="", last_commit_ref=None,
+                          exclude_branch=None):
     commit = repo.head.commit
     commit_count = 1
+    last_commit = (repo.commit(last_commit_ref)
+                   if last_commit_ref is not None else None)
     while commit:
-        if (commit.author.email == 'gccad...@gcc.gnu.org'
-                and commit.message.strip() == 'Daily bump.'):
+        if last_commit is not None:
+            if last_commit == commit:
+                break
+        elif (commit.author.email == 'gccad...@gcc.gnu.org'
+              and commit.message.strip() == 'Daily bump.'):
             break
         # We support merge commits but only with 2 parensts
         assert len(commit.parents) <= 2
@@ -122,6 +140,12 @@ def update_current_branch(ref_name=None):
 
     logging.info('%d revisions since last Daily bump' % commit_count)
     datestamp_path = os.path.join(args.git_path, 'gcc/DATESTAMP')
+    if suffix != "":
+        if not os.path.exists(datestamp_path + suffix):
+            logging.info('Create DATESTAMP%s by copying DATESTAMP' % suffix)
+            shutil.copyfile(datestamp_path, datestamp_path + suffix)
+        datestamp_path += suffix
+
     if (read_timestamp(datestamp_path) != current_timestamp
             or args.dry_mode or args.current):
         head = repo.head.commit
@@ -131,11 +155,12 @@ def update_current_branch(ref_name=None):
         if len(head.parents) == 2:
             head = head.parents[1]
         commits = parse_git_revisions(args.git_path, '%s..%s'
-                                      % (commit.hexsha, head.hexsha), ref_name)
+                                      % (commit.hexsha, head.hexsha), ref_name,
+                                      exclude_branch)
         commits = [c for c in commits if c.info.hexsha not in ignored_commits]
         for git_commit in reversed(commits):
             prepend_to_changelog_files(repo, args.git_path, git_commit,
-                                       not args.dry_mode)
+                                       not args.dry_mode, args.suffix)
         if args.dry_mode:
             diff = repo.git.diff('HEAD')
             patch = os.path.join(args.dry_mode,
@@ -162,14 +187,24 @@ def update_current_branch(ref_name=None):
     else:
         logging.info('DATESTAMP unchanged')
 
+
 if args.ignore is not None:
     for item in args.ignore:
         ignored_commits.update(set(i for i in re.split(r'\s*,\s*|\s+', item)))
 
 if args.current:
     logging.info('=== Working on the current branch ===')
-    update_current_branch()
+    if args.suffix != "" and args.last_commit is None:
+        logging.error('--suffix requires --last-commit')
+        sys.exit(1)
+    update_current_branch(None, args.suffix, args.last_commit,
+                          args.exclude_branch)
 else:
+    if args.suffix != "" or args.last_commit is not None \
+       or update_current_branch is not None:
+        logging.error('--suffix, --last-commit and --exclude-branch '
+                      'require --current')
+        sys.exit(1)
     for ref in origin.refs:
         assert ref.name.startswith('origin/')
         name = ref.name[len('origin/'):]
@@ -182,7 +217,7 @@ else:
             branch.checkout()
             origin.pull(rebase=True)
             logging.info('branch pulled and checked out')
-            update_current_branch(name)
+            update_current_branch(name, args.suffix)
             assert not repo.index.diff(None)
             logging.info('branch is done')
             logging.info('')

Reply via email to