Skip to content

Commit 913fe0f

Browse files
authored
Adds a Precommit Script to Eng that Builds, Tests, and Lints passed Artifacts and POMs (Azure#17180)
* Add precommit script that is able to run compile, test, and linting * Add examples to the script * Make the script OS agnostic, add more documentation * Make code more pythonic, add gpg.skip, standardized skip variables, document available parameters
1 parent 2f6c475 commit 913fe0f

File tree

1 file changed

+128
-0
lines changed

1 file changed

+128
-0
lines changed

eng/precommit_local_build.py

Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
# Copyright (c) Microsoft Corporation. All rights reserved.
2+
# Licensed under the MIT License.
3+
4+
# Python version 3.4 or higher is required to run this script.
5+
6+
# Use case: Runs compilation, testing, and linting for the passed artifacts and POM artifacts.
7+
#
8+
# Parameters:
9+
#
10+
# '--artifacts'/'--a': A comma separated list of artifact identifiers (groupId:artifactId)
11+
# '--poms'/'--p': A comma separated list of pom.xml paths
12+
# '--skip-tests'/'--st': Skips running tests
13+
# '--skip-javadocs'/'--sj': Skips javadoc generation
14+
# '--skip-checkstyle'/'--sc': Skips checkstyle linting
15+
# '--skip-spotbugs'/'--ss': Skips spotbugs linting
16+
# '--skip-revapi'/'--sr': Skips revapi linting
17+
# '--command-only'/'--co': Indicates that only the command should be generated and not ran
18+
# '--debug'/'--d': Generates command with verbose logging
19+
#
20+
# Example: Run precommit for artifact com.azure:azure-core
21+
#
22+
# python eng/precommit_local_build.py --a "com.azure:azure-core"
23+
#
24+
# Example: Run precommit for aggregate JAR sdk/storage/pom.xml
25+
#
26+
# python eng/precommit_local_build.py --p "sdk/storage/pom.xml"
27+
#
28+
# Example: Run precommit for artifact com.azure and aggregate JAR sdk/storage/pom.xml and skip testing
29+
#
30+
# python eng/precommit_local_build.py --a "com.azure:azure-core" --p "sdk/storage/pom.xml" --st
31+
#
32+
# The script must be run at the root of azure-sdk-for-java.
33+
34+
import argparse
35+
import os
36+
import xml.etree.ElementTree as ET
37+
38+
base_command = 'mvn clean install -f pom.xml -pl "{}" -am "-Dgpg.skip=true" {}'
39+
xml_namespace = '{http://maven.apache.org/POM/4.0.0}'
40+
41+
def get_artifacts_from_pom(pom_path: str, build_artifacts: list, debug: bool):
42+
# Skip files that don't exist as there still may be artifacts to build.
43+
if not os.path.exists(pom_path):
44+
print("POM {} doesn't exist, skipping".format(pom_path))
45+
return
46+
47+
# Turn the POM into an XML tree so we can walk it.
48+
tree = ET.parse(pom_path)
49+
modules_element = tree.getroot().find(xml_namespace + 'modules')
50+
51+
# If the POM has a <modules> tag assume that it is an aggregate POM.
52+
if modules_element != None:
53+
pom_basedir = os.path.dirname(pom_path)
54+
for module_element in modules_element.iterfind(xml_namespace + 'module'):
55+
module_name = module_element.text
56+
module_pom_path = os.path.normpath(os.path.join(pom_basedir, module_name, 'pom.xml'))
57+
58+
if debug:
59+
print('Getting module artifact for {} from aggregator POM {}'.format(module_name.split('/')[-1], pom_path))
60+
61+
get_artifacts_from_pom(module_pom_path, build_artifacts, debug)
62+
63+
# Otherwise grab its groupId and artifactId to determine the artifact identifier.
64+
else:
65+
group_id = tree.getroot().findtext(xml_namespace + "groupId")
66+
artifact_id = tree.getroot().findtext(xml_namespace + "artifactId")
67+
artifact_identifier = '{}:{}'.format(group_id, artifact_id)
68+
69+
if debug:
70+
print('Adding artifact {} for POM file {}'.format(artifact_identifier, pom_path))
71+
72+
build_artifacts.append(artifact_identifier)
73+
74+
def main():
75+
parser = argparse.ArgumentParser(description='Runs compilation, testing, and linting for the passed artifacts.')
76+
parser.add_argument('--artifacts', '--a', type=str, default=None, help='Comma separated list of groupId:artifactId identifiers')
77+
parser.add_argument('--poms', '--p', type=str, default=None, help='Comma separated list of POM paths')
78+
parser.add_argument('--skip-tests', '--st', action='store_true', help='Skips running tests')
79+
parser.add_argument('--skip-javadocs', '--sj', action='store_true', help='Skips javadoc generation')
80+
parser.add_argument('--skip-checkstyle', '--sc', action='store_true', help='Skips checkstyle linting')
81+
parser.add_argument('--skip-spotbugs', '--ss', action='store_true', help='Skips spotbugs linting')
82+
parser.add_argument('--skip-revapi', '--sr', action='store_true', help='Skips revapi linting')
83+
parser.add_argument('--command-only', '--co', action='store_true', help='Indicates that only the command should be generated and not ran')
84+
parser.add_argument('--debug', '--d', action='store_true', help='Generates command with verbose logging')
85+
args = parser.parse_args()
86+
87+
if args.artifacts == None and args.poms == None:
88+
raise ValueError('--artifacts/--a or --poms/--p must be passed.')
89+
90+
debug = args.debug
91+
92+
build_artifacts = []
93+
if args.poms != None:
94+
for pom in args.poms.split(','):
95+
get_artifacts_from_pom(os.path.abspath(pom), build_artifacts, debug)
96+
97+
if args.artifacts != None:
98+
build_artifacts.extend(args.artifacts.split(','))
99+
100+
# If all passed POMs are invalid fail.
101+
if build_artifacts.count == 0:
102+
raise ValueError('No build artifacts found.')
103+
104+
skip_arguments = []
105+
if args.skip_tests:
106+
skip_arguments.append('"-DskipTests=true"')
107+
108+
if args.skip_javadocs:
109+
skip_arguments.append('"-Dmaven.javadocs.skip=true"')
110+
111+
if args.skip_checkstyle:
112+
skip_arguments.append('"-Dcheckstyle.skip=true"')
113+
114+
if args.skip_spotbugs:
115+
skip_arguments.append('"-Dspotbugs.skip=true"')
116+
117+
if args.skip_revapi:
118+
skip_arguments.append('"-Drevapi.skip=true"')
119+
120+
maven_command = base_command.format(','.join(list(set(build_artifacts))), ' '.join(skip_arguments))
121+
122+
print('Running Maven command: {}'.format(maven_command))
123+
124+
if not args.command_only:
125+
os.system(maven_command)
126+
127+
if __name__ == '__main__':
128+
main()

0 commit comments

Comments
 (0)