]> git.ipfire.org Git - thirdparty/gcc.git/blame - contrib/gcc-changelog/git_update_version.py
Update crontab and git_update_version.py
[thirdparty/gcc.git] / contrib / gcc-changelog / git_update_version.py
CommitLineData
c10aa1f0 1#!/usr/bin/env python3
81f86cb9 2
83ffe9cd 3# Copyright (C) 2020-2023 Free Software Foundation, Inc.
c10aa1f0
ML
4#
5# This file is part of GCC.
6#
7# GCC is free software; you can redistribute it and/or modify it under
8# the terms of the GNU General Public License as published by the Free
9# Software Foundation; either version 3, or (at your option) any later
10# version.
11#
12# GCC is distributed in the hope that it will be useful, but WITHOUT ANY
13# WARRANTY; without even the implied warranty of MERCHANTABILITY or
14# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
15# for more details.
16#
17# You should have received a copy of the GNU General Public License
18# along with GCC; see the file COPYING3. If not see
19# <http://www.gnu.org/licenses/>. */
20
21import argparse
22import datetime
ed7278d9 23import logging
c10aa1f0
ML
24import os
25
26from git import Repo
27
28from git_repository import parse_git_revisions
29
62b5b53e 30current_timestamp = datetime.datetime.now().strftime('%Y%m%d\n')
c10aa1f0 31
5f6a43d6 32# Skip the following commits, they cannot be correctly processed
e01874cd
ML
33IGNORED_COMMITS = (
34 'c2be82058fb40f3ae891c68d185ff53e07f14f45',
e4604715 35 '04a040d907a83af54e0a98bdba5bfabc0ef4f700',
0268c547 36 '2e96b5f14e4025691b57d2301d71aa6092ed44bc',
865e36a0 37 '3ab5c8cd03d92bf4ec41e351820349d92fbc40c4',
2175b397 38 '86d8e0c0652ef5236a460b75c25e4f7093cc0651',
f003fdff
JJ
39 'e4cba49413ca429dc82f6aa2e88129ecb3fdd943',
40 '1957bedf29a1b2cc231972aba680fe80199d5498')
5f6a43d6 41
ed7278d9
ML
42FORMAT = '%(asctime)s:%(levelname)s:%(name)s:%(message)s'
43logging.basicConfig(level=logging.INFO, format=FORMAT,
44 handlers=[
45 logging.FileHandler('/tmp/git_update_version.txt'),
46 logging.StreamHandler()
47 ])
48
c10aa1f0
ML
49
50def read_timestamp(path):
bb07057a
PMR
51 with open(path) as f:
52 return f.read()
c10aa1f0
ML
53
54
c8462662 55def prepend_to_changelog_files(repo, folder, git_commit, add_to_git):
c10aa1f0
ML
56 if not git_commit.success:
57 for error in git_commit.errors:
ed7278d9 58 logging.info(error)
62b5b53e 59 raise AssertionError()
4a5d072a 60 for entry, output in git_commit.to_changelog_entries(use_commit_ts=True):
62b5b53e 61 full_path = os.path.join(folder, entry, 'ChangeLog')
ed7278d9 62 logging.info('writing to %s' % full_path)
c10aa1f0 63 if os.path.exists(full_path):
bb07057a
PMR
64 with open(full_path) as f:
65 content = f.read()
c10aa1f0
ML
66 else:
67 content = ''
68 with open(full_path, 'w+') as f:
69 f.write(output)
70 if content:
71 f.write('\n\n')
72 f.write(content)
c8462662
ML
73 if add_to_git:
74 repo.git.add(full_path)
c10aa1f0
ML
75
76
c6264357 77active_refs = ['master', 'releases/gcc-10',
f46ab321 78 'releases/gcc-11', 'releases/gcc-12', 'releases/gcc-13']
c10aa1f0
ML
79
80parser = argparse.ArgumentParser(description='Update DATESTAMP and generate '
81 'ChangeLog entries')
82parser.add_argument('-g', '--git-path', default='.',
83 help='Path to git repository')
c8462662
ML
84parser.add_argument('-p', '--push', action='store_true',
85 help='Push updated active branches')
86parser.add_argument('-d', '--dry-mode',
87 help='Generate patch for ChangeLog entries and do it'
88 ' even if DATESTAMP is unchanged; folder argument'
89 ' is expected')
be11812e
ML
90parser.add_argument('-c', '--current', action='store_true',
91 help='Modify current branch (--push argument is ignored)')
c10aa1f0
ML
92args = parser.parse_args()
93
94repo = Repo(args.git_path)
95origin = repo.remotes['origin']
96
be11812e 97
5caadfbd 98def update_current_branch(ref_name):
be11812e
ML
99 commit = repo.head.commit
100 commit_count = 1
101 while commit:
102 if (commit.author.email == 'gccadmin@gcc.gnu.org'
103 and commit.message.strip() == 'Daily bump.'):
104 break
2c535665
ML
105 # We support merge commits but only with 2 parensts
106 assert len(commit.parents) <= 2
107 commit = commit.parents[-1]
be11812e
ML
108 commit_count += 1
109
ed7278d9 110 logging.info('%d revisions since last Daily bump' % commit_count)
be11812e
ML
111 datestamp_path = os.path.join(args.git_path, 'gcc/DATESTAMP')
112 if (read_timestamp(datestamp_path) != current_timestamp
113 or args.dry_mode or args.current):
2c535665
ML
114 head = repo.head.commit
115 # if HEAD is a merge commit, start with second parent
116 # (branched that is being merged into the current one)
117 assert len(head.parents) <= 2
118 if len(head.parents) == 2:
119 head = head.parents[1]
120 commits = parse_git_revisions(args.git_path, '%s..%s'
5caadfbd 121 % (commit.hexsha, head.hexsha), ref_name)
5f6a43d6 122 commits = [c for c in commits if c.info.hexsha not in IGNORED_COMMITS]
be11812e
ML
123 for git_commit in reversed(commits):
124 prepend_to_changelog_files(repo, args.git_path, git_commit,
125 not args.dry_mode)
126 if args.dry_mode:
127 diff = repo.git.diff('HEAD')
128 patch = os.path.join(args.dry_mode,
129 branch.name.split('/')[-1] + '.patch')
130 with open(patch, 'w+') as f:
131 f.write(diff)
ed7278d9 132 logging.info('branch diff written to %s' % patch)
be11812e 133 repo.git.checkout(force=True)
c10aa1f0 134 else:
be11812e 135 # update timestamp
ed7278d9 136 logging.info('DATESTAMP will be changed:')
be11812e
ML
137 with open(datestamp_path, 'w+') as f:
138 f.write(current_timestamp)
139 repo.git.add(datestamp_path)
140 if not args.current:
c8462662 141 repo.index.commit('Daily bump.')
fce601fd 142 logging.info('commit is done')
c8462662 143 if args.push:
ed7278d9
ML
144 try:
145 repo.git.push('origin', branch)
146 logging.info('branch is pushed')
147 except Exception:
148 logging.exception('git push failed')
be11812e 149 else:
ed7278d9 150 logging.info('DATESTAMP unchanged')
be11812e
ML
151
152
153if args.current:
ed7278d9 154 logging.info('=== Working on the current branch ===')
be11812e
ML
155 update_current_branch()
156else:
157 for ref in origin.refs:
158 assert ref.name.startswith('origin/')
159 name = ref.name[len('origin/'):]
160 if name in active_refs:
161 if name in repo.branches:
162 branch = repo.branches[name]
163 else:
164 branch = repo.create_head(name, ref).set_tracking_branch(ref)
ed7278d9 165 logging.info('=== Working on: %s ===' % branch)
be11812e 166 branch.checkout()
9b4bdaf7 167 origin.pull(rebase=True)
ed7278d9 168 logging.info('branch pulled and checked out')
5caadfbd 169 update_current_branch(name)
be11812e 170 assert not repo.index.diff(None)
ed7278d9
ML
171 logging.info('branch is done')
172 logging.info('')