If we assign the message (which might contain quotes) to an
environment variable and then echo it, this should prevent the
problem of having a double quote (").
Also fix a problem in docs script for checking TAGs in commits.
150 lines
5.2 KiB
Python
150 lines
5.2 KiB
Python
# Copyright (C) 2025 The Android Open Source Project
|
|
#
|
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
# you may not use this file except in compliance with the License.
|
|
# You may obtain a copy of the License at
|
|
#
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
#
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
# See the License for the specific language governing permissions and
|
|
# limitations under the License.
|
|
|
|
# This script contains several checks on the current commit, each corresponds to `possible_conditions`
|
|
# in the main function below
|
|
# - Direct (non-filamentbot) edits of /docs
|
|
# - Edits to sources of READMEs that are duplicated to /docs
|
|
# or edits to /docs_src sources
|
|
# - Commit message has DOCS_BYPASS
|
|
# - Commit message has DOCS_FORCE
|
|
# - Commit message has DOCS_ALLOW_DIRECT_EDITS
|
|
|
|
import json
|
|
import sys
|
|
import os
|
|
|
|
from utils import execute, ArgParseImpl
|
|
|
|
CUR_DIR = os.path.dirname(os.path.abspath(__file__))
|
|
ROOT_DIR = os.path.join(CUR_DIR, '../../')
|
|
|
|
DOCS_SRC_DIR = os.path.abspath(os.path.join(CUR_DIR, '../'))
|
|
MARKDEEP_SRC_DIR = os.path.join(DOCS_SRC_DIR, 'src_markdeep')
|
|
MDBOOK_SRC_DIR = os.path.join(DOCS_SRC_DIR, 'src_mdbook')
|
|
RAW_SRC_DIR = os.path.join(DOCS_SRC_DIR, 'src_raw')
|
|
|
|
SRC_SRC_DIRS = [MARKDEEP_SRC_DIR, MDBOOK_SRC_DIR, RAW_SRC_DIR]
|
|
|
|
def get_edited_files(commit_hash):
|
|
INSERT = '#####?????'
|
|
res, ret = execute(f'git show --name-only --pretty=%b{INSERT} {commit_hash}')
|
|
assert res == 0, f'Failed to get edited filed {res}: ' + ret
|
|
files = []
|
|
_, after = ret.split(INSERT)
|
|
for r in filter(lambda a: len(a) > 0, after.split('\n')):
|
|
if r.startswith('commit'):
|
|
break
|
|
files.append(os.path.abspath(os.path.join(ROOT_DIR, r)))
|
|
return files
|
|
|
|
# Returns True if there were no direct edits to '/docs'
|
|
def check_no_direct_edits(commit_hash, printing=True):
|
|
bad = [f'\t{f}' for f in get_edited_files(commit_hash) if f.startswith('docs/')]
|
|
if printing and len(bad) > 0:
|
|
print(f'Found edits to /docs:\n' + '\n'.join(bad))
|
|
return len(bad) == 0
|
|
|
|
# Returns True if docs sources have been modified
|
|
def check_has_source_edits(commit_hash, printing=True):
|
|
config = {}
|
|
with open(f'{CUR_DIR}/duplicates.json') as config_txt:
|
|
config = json.loads(config_txt.read())
|
|
source_files = set(os.path.abspath(os.path.join(ROOT_DIR, k)) for k in config.keys())
|
|
edited_files = set(get_edited_files(commit_hash))
|
|
|
|
# find any changes to docs_src sources
|
|
is_docs_src_edit = lambda f: any(f.startswith(prefix) for prefix in SRC_SRC_DIRS)
|
|
|
|
final_edited = [f'\t{f}' for f in \
|
|
list(source_files & edited_files) + \
|
|
list(filter(is_docs_src_edit, edited_files))]
|
|
|
|
if printing and len(final_edited) > 0:
|
|
print(f'Found edited source files:\n' + '\n'.join(final_edited))
|
|
return len(final_edited) > 0
|
|
|
|
# Returns true in a given TAG is found in the commit msg
|
|
def commit_msg_has_tag(commit_hash, tag, printing=True):
|
|
res, ret = execute(f'git log -n1 --pretty=%B {commit_hash}', cwd=ROOT_DIR)
|
|
for l in ret.split('\n'):
|
|
if tag == l.strip():
|
|
if printing:
|
|
print(f'Found tag={tag} in commit={commit_hash}')
|
|
return True
|
|
return False
|
|
|
|
if __name__ == "__main__":
|
|
parser = ArgParseImpl()
|
|
|
|
TAG_DOCS_BYPASS = 'DOCS_BYPASS'
|
|
TAG_DOCS_FORCE = 'DOCS_FORCE'
|
|
TAG_DOCS_ALLOW_DIRECT_EDITS = 'DOCS_ALLOW_DIRECT_EDITS'
|
|
|
|
possible_conditions = {
|
|
'no_direct_edits':
|
|
check_no_direct_edits,
|
|
'source_edits':
|
|
check_has_source_edits,
|
|
'commit_docs_bypass':
|
|
lambda h: commit_msg_has_tag(h, TAG_DOCS_BYPASS),
|
|
'commit_docs_force':
|
|
lambda h: commit_msg_has_tag(h, TAG_DOCS_FORCE),
|
|
'commit_docs_allow_direct_edits':
|
|
lambda h: commit_msg_has_tag(h, TAG_DOCS_ALLOW_DIRECT_EDITS),
|
|
}
|
|
|
|
possible_str = ', '.join(list(possible_conditions.keys()))
|
|
parser.add_argument(
|
|
'--do-and',
|
|
type=str,
|
|
help=(
|
|
f'A conjunction of boolean conditions. Possible values are={possible_str}. '
|
|
'Negation is done with `-`'
|
|
)
|
|
)
|
|
parser.add_argument(
|
|
'--do-or',
|
|
type=str,
|
|
help=(
|
|
f'A disjunction of boolean conditions. Possible values are={possible_str}. '
|
|
'Negation is done with `-`'
|
|
)
|
|
)
|
|
|
|
args, _ = parser.parse_known_args(sys.argv[1:len(sys.argv) - 1])
|
|
commit_hash = sys.argv[-1]
|
|
|
|
assert not (args.do_and and args.do_or), "Must not supply both '--do-and' and '--do-or'"
|
|
assert args.do_and or args.do_or, "Must supply argument '--do-and' or '--do-or'"
|
|
conds = args.do_and.split(',') if args.do_and else args.do_or.split(',')
|
|
conds = [c.strip() for c in conds]
|
|
assert all(
|
|
[c in possible_conditions.keys() for c in
|
|
[(c.replace('-', '') if c.startswith('-') else c) for c in conds]]),\
|
|
f"Not all conditions are valid names. Only {possible_str} are accepted"
|
|
|
|
res = []
|
|
for cond in conds:
|
|
if cond.startswith('-'):
|
|
f = lambda: not possible_conditions[cond.replace('-', '')]()
|
|
else:
|
|
f = possible_conditions[cond]
|
|
res.append(f(commit_hash))
|
|
|
|
if args.do_and:
|
|
exit(0 if all(res) else 1)
|
|
else:
|
|
exit(0 if any(res) else 1)
|