Skip to content

Commit e2ed271

Browse files
authored
Merge branch 'main' into features-checkmake-re-enable
2 parents 65aad9e + 4820eff commit e2ed271

File tree

252 files changed

+2544
-1067
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

252 files changed

+2544
-1067
lines changed

.automation/build.py

Lines changed: 150 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@
6161
IS_LATEST = "--latest" in sys.argv
6262
DELETE_DOCKERFILES = "--delete-dockerfiles" in sys.argv
6363
DELETE_TEST_CLASSES = "--delete-test-classes" in sys.argv
64+
CUSTOM_FLAVOR = "--custom-flavor" in sys.argv
6465

6566
# Release args management
6667
if RELEASE is True:
@@ -114,6 +115,7 @@
114115
f"{REPO_HOME}/megalinter/descriptors/schemas/megalinter-descriptor.jsonschema.json"
115116
)
116117
CONFIG_JSON_SCHEMA = f"{REPO_HOME}/megalinter/descriptors/schemas/megalinter-configuration.jsonschema.json"
118+
CUSTOM_FLAVOR_JSON_SCHEMA = f"{REPO_HOME}/megalinter/descriptors/schemas/megalinter-custom-flavor.jsonschema.json"
117119
OWN_MEGALINTER_CONFIG_FILE = f"{REPO_HOME}/.mega-linter.yml"
118120

119121
IDE_LIST = {
@@ -252,12 +254,13 @@ def generate_flavor(flavor, flavor_info):
252254
json.dump(flavor_info, outfile, indent=4, sort_keys=True)
253255
outfile.write("\n")
254256
# Write in global flavors files
255-
with open(GLOBAL_FLAVORS_FILE, "r", encoding="utf-8") as json_file:
256-
global_flavors = json.load(json_file)
257-
global_flavors[flavor] = flavor_info
258-
with open(GLOBAL_FLAVORS_FILE, "w", encoding="utf-8") as outfile:
259-
json.dump(global_flavors, outfile, indent=4, sort_keys=True)
260-
outfile.write("\n")
257+
if CUSTOM_FLAVOR is not True or os.path.isdir("/megalinter-builder"):
258+
with open(GLOBAL_FLAVORS_FILE, "r", encoding="utf-8") as json_file:
259+
global_flavors = json.load(json_file)
260+
global_flavors[flavor] = flavor_info
261+
with open(GLOBAL_FLAVORS_FILE, "w", encoding="utf-8") as outfile:
262+
json.dump(global_flavors, outfile, indent=4, sort_keys=True)
263+
outfile.write("\n")
261264
# Flavored dockerfile
262265
dockerfile = f"{FLAVORS_DIR}/{flavor}/Dockerfile"
263266
if not os.path.isdir(os.path.dirname(dockerfile)):
@@ -302,7 +305,27 @@ def generate_flavor(flavor, flavor_info):
302305
with open(flavor_action_yml, "w", encoding="utf-8") as file:
303306
file.write(action_yml)
304307
logging.info(f"Updated {flavor_action_yml}")
305-
extra_lines = [
308+
extra_lines = []
309+
if CUSTOM_FLAVOR is True:
310+
current_date_time_iso = datetime.now().isoformat()
311+
extra_lines += [
312+
"ENV CUSTOM_FLAVOR=true \\",
313+
f" BUILD_VERSION={os.getenv('BUILD_VERSION', 'local_build')} \\",
314+
f" BUILD_DATE={os.getenv('BUILD_DATE', 'local_build')} \\",
315+
f" BUILD_REVISION={os.getenv('BUILD_REVISION', 'local_build')} \\",
316+
f" CUSTOM_FLAVOR_BUILD_DATE={current_date_time_iso} \\",
317+
f" CUSTOM_FLAVOR_BUILD_REPO={os.getenv('CUSTOM_FLAVOR_BUILD_REPO', 'local_build')} \\",
318+
f" CUSTOM_FLAVOR_BUILD_REPO_URL={os.getenv('CUSTOM_FLAVOR_BUILD_REPO_URL', 'local_build')} \\",
319+
f" CUSTOM_FLAVOR_BUILD_USER={os.getenv('CUSTOM_FLAVOR_BUILD_USER', 'local_build')}",
320+
"",
321+
'LABEL com.github.actions.name="MegaLinter Custom Flavor" \\',
322+
f' maintainer="{os.getenv("CUSTOM_FLAVOR_BUILD_USER", "local_build")}" \\',
323+
f' org.opencontainers.image.source="{os.getenv("CUSTOM_FLAVOR_BUILD_REPO_URL", "local_build")}" \\',
324+
f' org.opencontainers.image.created="{os.getenv("BUILD_DATE", "local_build")}" \\',
325+
f' org.opencontainers.image.revision="{os.getenv("BUILD_REVISION", "local_build")}" \\',
326+
f' org.opencontainers.image.version="{os.getenv("BUILD_VERSION", "local_build")}"',
327+
]
328+
extra_lines += [
306329
"COPY entrypoint.sh /entrypoint.sh",
307330
"RUN chmod +x entrypoint.sh",
308331
'ENTRYPOINT ["/bin/bash", "/entrypoint.sh"]',
@@ -316,6 +339,7 @@ def generate_flavor(flavor, flavor_info):
316339
DEFAULT_DOCKERFILE_FLAVOR_ARGS.copy(),
317340
{"cargo": DEFAULT_DOCKERFILE_FLAVOR_CARGO_PACKAGES.copy()},
318341
)
342+
return dockerfile
319343

320344

321345
def build_dockerfile(
@@ -689,6 +713,20 @@ def match_flavor(item, flavor, flavor_info):
689713
return True
690714
else:
691715
return False
716+
# Custom flavor
717+
elif flavor == "CUSTOM":
718+
descriptors, linters_by_type = list_descriptors_for_build()
719+
# Item is a linter: check if present in the flavor
720+
if "linter_name" in item and item["name"] in flavor_info["linters"]:
721+
return True
722+
# Item is a descriptor and it contains one of the linters included in the flavor info
723+
if "linters" in item:
724+
for descriptor in descriptors:
725+
if item["descriptor_id"] == descriptor["descriptor_id"]:
726+
descriptor_linters = descriptor["linter_instances"]
727+
for descriptor_linter in descriptor_linters:
728+
if descriptor_linter.name in flavor_info["linters"]:
729+
return True
692730
# Other flavors
693731
elif "descriptor_flavors" in item:
694732
if flavor in item["descriptor_flavors"] or (
@@ -860,10 +898,11 @@ def list_descriptors_for_build():
860898
descriptors = []
861899
for descriptor_file in descriptor_files:
862900
descriptor = megalinter.linter_factory.build_descriptor_info(descriptor_file)
863-
descriptors += [descriptor]
864901
descriptor_linters = megalinter.linter_factory.build_descriptor_linters(
865902
descriptor_file, {"request_id": "build"}
866903
)
904+
descriptor["linter_instances"] = descriptor_linters
905+
descriptors += [descriptor]
867906
linters_by_type[descriptor_linters[0].descriptor_type] += descriptor_linters
868907
DESCRIPTORS_FOR_BUILD_CACHE = descriptors, linters_by_type
869908
return descriptors, linters_by_type
@@ -2855,6 +2894,15 @@ def generate_json_schema_enums():
28552894
with open(CONFIG_JSON_SCHEMA, "w", encoding="utf-8") as outfile:
28562895
json.dump(json_schema, outfile, indent=2, sort_keys=True)
28572896
outfile.write("\n")
2897+
# Also update megalinter custom flavor schema
2898+
with open(CUSTOM_FLAVOR_JSON_SCHEMA, "r", encoding="utf-8") as json_flavor_file:
2899+
json_flavor_schema = json.load(json_flavor_file)
2900+
json_flavor_schema["definitions"]["enum_linter_keys"]["enum"] = json_schema[
2901+
"definitions"
2902+
]["enum_linter_keys"]["enum"]
2903+
with open(CUSTOM_FLAVOR_JSON_SCHEMA, "w", encoding="utf-8") as outfile_flavor:
2904+
json.dump(json_flavor_schema, outfile_flavor, indent=2, sort_keys=True)
2905+
outfile_flavor.write("\n")
28582906

28592907

28602908
# Collect linters info from linter url, later used to build link preview card within linter documentation
@@ -3491,6 +3539,74 @@ def update_workflow_linters(file_path, linters):
34913539
f.write(file_content)
34923540

34933541

3542+
def generate_custom_flavor():
3543+
megalinter_dir = (
3544+
"/megalinter-builder"
3545+
if os.path.isdir("/megalinter-builder")
3546+
else f"{REPO_HOME}/.automation/test"
3547+
)
3548+
work_dir = (
3549+
"/github/workspace" if os.path.isdir("/github/workspace") else megalinter_dir
3550+
)
3551+
reports_dir = (
3552+
f"{work_dir}/megalinter-reports"
3553+
if work_dir == "/github/workspace"
3554+
else f"{REPO_HOME}/megalinter-reports"
3555+
)
3556+
flavor_file = f"{work_dir}/megalinter-custom-flavor.yml"
3557+
with open(flavor_file, "r", encoding="utf-8") as f:
3558+
flavor_info = yaml.safe_load(f)
3559+
flavor_info["strict"] = True
3560+
logging.info(f"Generating custom flavor from {flavor_file} in {megalinter_dir}")
3561+
dockerfile_tmp = generate_flavor("CUSTOM", flavor_info)
3562+
dockerfile = f"{megalinter_dir}/Dockerfile-megalinter-custom"
3563+
copyfile(dockerfile_tmp, dockerfile)
3564+
# Copy to reports dir
3565+
if not os.path.isdir(reports_dir):
3566+
os.makedirs(reports_dir, exist_ok=True)
3567+
shutil.copyfile(dockerfile, f"{reports_dir}/Dockerfile-megalinter-custom")
3568+
# Delete folder containing dockerfile if runned locally
3569+
dockerfile_tmp_dir = os.path.dirname(dockerfile_tmp)
3570+
if os.path.isdir(dockerfile_tmp_dir) and "/.automation/test" in work_dir:
3571+
logging.info(
3572+
f"Deleting folder {dockerfile_tmp_dir} containing custom flavor dockerfile"
3573+
)
3574+
shutil.rmtree(dockerfile_tmp_dir, ignore_errors=True)
3575+
# Display dockerfile content in log
3576+
with open(dockerfile, "r", encoding="utf-8") as f:
3577+
dockerfile_content = f.read()
3578+
logging.info(f"Generated custom flavor dockerfile:\n\n{dockerfile_content}\n")
3579+
return dockerfile
3580+
3581+
3582+
def build_custom_flavor(dockerfile):
3583+
logging.info("Building custom flavor docker image…")
3584+
work_dir = (
3585+
"/megalinter-builder" if os.path.isdir("/megalinter-builder") else REPO_HOME
3586+
)
3587+
tag_id = os.getenv("CUSTOM_FLAVOR_BUILD_REPO", "megalinter-custom").replace(
3588+
"/", "_"
3589+
)
3590+
command = [
3591+
"docker",
3592+
"build",
3593+
"-t",
3594+
tag_id,
3595+
"-f",
3596+
dockerfile,
3597+
work_dir,
3598+
]
3599+
logging.info("Running command: " + " ".join(command))
3600+
process = subprocess.run(
3601+
command,
3602+
stdout=subprocess.PIPE,
3603+
stderr=subprocess.STDOUT,
3604+
universal_newlines=True,
3605+
)
3606+
stdout = utils.clean_string(process.stdout)
3607+
logging.info(f"Build custom flavor results: ({process.returncode})\n" + stdout)
3608+
3609+
34943610
if __name__ == "__main__":
34953611
logging_format = (
34963612
"[%(levelname)s] %(message)s"
@@ -3511,25 +3627,29 @@ def update_workflow_linters(file_path, linters):
35113627
handlers=[logging.StreamHandler(sys.stdout)],
35123628
)
35133629
config.init_config("build")
3514-
# noinspection PyTypeChecker
3515-
collect_linter_previews()
3516-
generate_json_schema_enums()
3517-
validate_descriptors()
3518-
if UPDATE_DEPENDENTS is True:
3519-
update_dependents_info()
3520-
generate_all_flavors()
3521-
generate_linter_dockerfiles()
3522-
generate_linter_test_classes()
3523-
update_workflows_linters()
3524-
if UPDATE_DOC is True:
3525-
logging.info("Running documentation generators…")
3526-
# refresh_users_info() # deprecated since now we use github-dependents-info
3527-
generate_documentation()
3528-
generate_documentation_all_linters()
3529-
# generate_documentation_all_users() # deprecated since now we use github-dependents-info
3530-
generate_mkdocs_yml()
3531-
validate_own_megalinter_config()
3532-
manage_output_variables()
3533-
reformat_markdown_tables()
3534-
if RELEASE is True:
3535-
generate_version()
3630+
if CUSTOM_FLAVOR is True:
3631+
dockerfile = generate_custom_flavor()
3632+
build_custom_flavor(dockerfile)
3633+
else:
3634+
# noinspection PyTypeChecker
3635+
collect_linter_previews()
3636+
generate_json_schema_enums()
3637+
validate_descriptors()
3638+
if UPDATE_DEPENDENTS is True:
3639+
update_dependents_info()
3640+
generate_all_flavors()
3641+
generate_linter_dockerfiles()
3642+
generate_linter_test_classes()
3643+
update_workflows_linters()
3644+
if UPDATE_DOC is True:
3645+
logging.info("Running documentation generators…")
3646+
# refresh_users_info() # deprecated since now we use github-dependents-info
3647+
generate_documentation()
3648+
generate_documentation_all_linters()
3649+
# generate_documentation_all_users() # deprecated since now we use github-dependents-info
3650+
generate_mkdocs_yml()
3651+
validate_own_megalinter_config()
3652+
manage_output_variables()
3653+
reformat_markdown_tables()
3654+
if RELEASE is True:
3655+
generate_version()

0 commit comments

Comments
 (0)