Skip to content

Commit

Permalink
docs: add github presubmit workflow to prevent /docs edits
Browse files Browse the repository at this point in the history
The content of /docs should be generated and not manually
generated. We add a script to check for edits and also allow for
tags to override the check.
  • Loading branch information
poweifeng committed Jan 16, 2025
1 parent eac99e5 commit dfe908a
Show file tree
Hide file tree
Showing 4 changed files with 173 additions and 3 deletions.
13 changes: 12 additions & 1 deletion .github/workflows/presubmit.yml
Original file line number Diff line number Diff line change
Expand Up @@ -77,9 +77,20 @@ jobs:
run: |
cd build/web && printf "y" | ./build.sh presubmit
validate-docs:
name: validate-docs
runs-on: ubuntu-22.04-4core
steps:
- uses: actions/[email protected]
with:
fetch-depth: 0
- name: Check unpermitted edits to /docs
run: |
bash docs_src/build/presubmit_check.sh ${{ github.event.pull_request.head.sha }}
test-renderdiff:
name: test-renderdiff
runs-on: ubuntu-22.04-32core
runs-on: ubuntu-22.04-16core

steps:
- uses: actions/[email protected]
Expand Down
4 changes: 2 additions & 2 deletions docs/index.xml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
<title>Filament</title>
<link>https://google.github.io/filament/</link>
<description>Recent content on Filament</description>
<generator>Hugo -- gohugo.io</generator>
<generator>Hugo ABC -- gohugo.io</generator>
<language>en-us</language>
<lastBuildDate>Thu, 09 Jul 2020 14:48:51 -0700</lastBuildDate>

Expand Down Expand Up @@ -51,4 +51,4 @@ We&amp;rsquo;ll be walking through 7 steps to get the rotating triangle up and r
</item>

</channel>
</rss>
</rss>
140 changes: 140 additions & 0 deletions docs_src/build/checks.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
# 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, '../../')

def get_last_commit_hash():
res, ret = execute('git rev-parse HEAD', cwd=ROOT_DIR)
assert res == 0, 'Failed to get the last commit hash'
return ret.strip()

def get_edited_files(commit_hash):
INSERT = '#####?????'
res, ret = execute(f'git show --name-only --pretty=%b{INSERT} {commit_hash}')
assert res == 0, 'Failed to get edited filed'
files = []
_, after = ret.split(INSERT)
for r in filter(lambda a: len(a) > 0, after.split('\n')):
if r.startswith('commit'):
break
files.append(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 direct 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(config.keys())
edited_files = set(get_edited_files(commit_hash))
overlap = [f'\t{f}' for f in list(source_files & edited_files)]
if printing and len(overlap) > 0:
print(f'Found edited source files:\n' + '\n'.join(overlap))
return len(overlap) > 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 --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 message')
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)
19 changes: 19 additions & 0 deletions docs_src/build/presubmit_check.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
#!/usr/bin/bash

# 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.

COMMIT_HASH=$1
python3 docs_src/build/checks.py --do-or="no_direct_edits,commit_docs_allow_direct_edits" $COMMIT_HASH ||\
(echo "There are direct edits to /docs. Please see /docs_src/README.md if you need to bypass this check" && exit 1)

0 comments on commit dfe908a

Please sign in to comment.