Files
hunfabric/tools/duplicate-diff.py
Ludovico Magnocavallo 981e4581ee Add project-factory based data platform dataset to FAST project factory stage (#3957)
* dp rewrite stage 0, projects

* remove plan files

* generalize handling of basepath for projects in project-factory module

* central-0 ---> core-0

* add schemas, validate YAMLs, tags

* aspect types

* data catalog policy tag factory

* add support for data catalog taxonomy to project factory

* complete retrofit of old stage configuration, except networking

* shared vpc networking

* networking

* data platform as pf dataset

* docs

* test

* remove legacy dp stage, fix tests and links

* boilerplate

* tfdoc

* fix unrelated tfdoc

* schemas

* fix errors

* schema

* duplicate schemas

* yamllint

* Fix module naming convention for aspect-types

* Fix factories_config in vpcs.tf for net-vpc-factory compatibility

* Update schema documentation based on schema changes

* Fix false rename conflict in .config.yaml files

* Sync schemas and update documentation

* Fix path expansion for aspect-types and revert projects_input to master

* Restore path expansion for org_policies in projects-iam call

* Fix trailing newlines in schema duplicates to satisfy duplicate-diff

* Fix path expansion for data_catalog_taxonomy in taxonomies.tf

* Update inventory for data-platform test and clean up debug prints

* Add full values to data-platform inventory

* Align Stage 2 VPC Factory integration with Stage 0 and fix tests

TAG=agy

* Fix project factory context resolution and data platform datasets

- Update tag context keys in project factory to use file key without 'projects/' prefix.
- Fix tag reference in product-0.yaml.
- Fix shared_vpc_service_config in shared-0.yaml by moving service account to network_users.
- Set parent for domain-0 folder to data-platform.
- Mock net-dev-0 project ID in tests.
- Update inventories.

TAG=agy
CONV=4b37fa5b-bf59-4604-9e8f-b55353d967a0

* Fix project-level tag keys context resolution in project factory

* Fix commented out tag reference in domain-0 .config.yaml

* Fix merge() calls with empty arguments in project-factory and data-catalog-policy-tag

* Update Data Platform dataset README with prerequisites and customization guide

* Add Table of Contents to Data Platform dataset README

* docs: update Data Platform README with project templates tip

* Document data platform output files and linking sequence in README

* Update data platform README with VPC-SC and delegated IAM details

* Refactor data platform dataset and align stage defaults

* Update test inventory and variables for data platform with new prefix
2026-05-12 16:44:32 +02:00

213 lines
7.3 KiB
Python
Executable File

#!/usr/bin/env python3
# Copyright 2026 Google LLC
#
# 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.
#
import filecmp
import sys
import os
# List of folders and files that are expected to have same content
duplicates = [
# factory policies
[
"tests/modules/folder/factory/policies",
"tests/modules/organization/factory/policies",
"tests/modules/project/factory/policies",
],
# schemas
[
"fast/stages/1-vpcsc/schemas/access-level.schema.json",
"modules/vpc-sc/schemas/access-level.schema.json",
],
[
"modules/dataplex-aspect-types/schemas/aspect-type.schema.json",
"modules/project-factory/schemas/aspect-type.schema.json",
"fast/stages/2-project-factory/schemas/aspect-type.schema.json",
],
[
"modules/data-catalog-policy-tag/schemas/policy-tag.schema.json",
"modules/project-factory/schemas/taxonomy.schema.json",
],
[
"fast/stages/2-project-factory/schemas/budget.schema.json",
"fast/stages/0-org-setup/schemas/budget.schema.json",
"modules/billing-account/schemas/budget.schema.json",
"modules/project-factory/schemas/budget.schema.json",
],
[
"fast/stages/0-org-setup/schemas/custom-constraint.schema.json",
"modules/organization/schemas/org-policy-custom-constraint.schema.json",
],
[
"fast/stages/0-org-setup/schemas/custom-role.schema.json",
"modules/project/schemas/custom-role.schema.json",
"modules/organization/schemas/custom-role.schema.json",
],
[
"fast/stages/1-vpcsc/schemas/egress-policy.schema.json",
"modules/vpc-sc/schemas/egress-policy.schema.json",
],
[
"fast/stages/0-org-setup/schemas/firewall-rules.schema.json",
"fast/stages/2-networking/schemas/firewall-rules.schema.json",
"modules/net-vpc-factory/schemas/firewall-rules.schema.json",
"modules/net-vpc-firewall/schemas/firewall-rules.schema.json",
],
[
"modules/project-factory/schemas/folder.schema.json",
"fast/stages/0-org-setup/schemas/folder.schema.json",
"fast/stages/2-networking/schemas/folder.schema.json",
"fast/stages/2-project-factory/schemas/folder.schema.json",
"fast/stages/2-security/schemas/folder.schema.json",
],
[
"fast/stages/0-org-setup/schemas/observability.schema.json",
"modules/project/schemas/observability.schema.json",
],
[
"fast/stages/1-vpcsc/schemas/ingress-policy.schema.json",
"modules/vpc-sc/schemas/ingress-policy.schema.json",
],
[
"fast/stages/0-org-setup/schemas/org-policies.schema.json",
"modules/folder/schemas/org-policies.schema.json",
"modules/project/schemas/org-policies.schema.json",
"modules/organization/schemas/org-policies.schema.json",
],
[
"modules/folder/schemas/pam-entitlements.schema.json",
"modules/project/schemas/pam-entitlements.schema.json",
"modules/organization/schemas/pam-entitlements.schema.json",
],
[
"fast/stages/1-vpcsc/schemas/perimeter.schema.json",
"modules/vpc-sc/schemas/perimeter.schema.json",
],
[
"modules/project-factory/schemas/project.schema.json",
"fast/stages/0-org-setup/schemas/project.schema.json",
"fast/stages/2-networking/schemas/project.schema.json",
"fast/stages/2-project-factory/schemas/project.schema.json",
"fast/stages/2-security/schemas/project.schema.json",
],
[
"modules/folder/schemas/scc-sha-custom-modules.schema.json",
"modules/project/schemas/scc-sha-custom-modules.schema.json",
"modules/organization/schemas/scc-sha-custom-modules.schema.json",
],
[
"fast/stages/0-org-setup/schemas/subnet.schema.json",
"fast/stages/2-networking/schemas/subnet.schema.json",
"modules/net-vpc-factory/schemas/subnet.schema.json",
"modules/net-vpc/schemas/subnet.schema.json",
],
[
"fast/stages/0-org-setup/schemas/vpc-factory.schema.json",
"modules/net-vpc-factory/schemas/vpc-factory.schema.json",
],
[
"fast/stages/0-org-setup/schemas/tags.schema.json",
"modules/project/schemas/tags.schema.json",
"modules/organization/schemas/tags.schema.json",
"fast/stages/2-project-factory/schemas/tags.schema.json",
],
[
"modules/cloud-function-v1/bundle.tf",
"modules/cloud-function-v2/bundle.tf",
],
[
"modules/cloud-function-v1/serviceaccount.tf",
"modules/cloud-function-v2/serviceaccount.tf",
"modules/cloud-run-v2/serviceaccount.tf",
],
[
"modules/cloud-function-v1/variables-serviceaccount.tf",
"modules/cloud-function-v2/variables-serviceaccount.tf",
"modules/cloud-run-v2/variables-serviceaccount.tf",
],
[
"modules/cloud-function-v1/variables-vpcconnector.tf",
"modules/cloud-function-v2/variables-vpcconnector.tf",
"modules/cloud-run-v2/variables-vpcconnector.tf",
],
[
"modules/cloud-function-v1/vpcconnector.tf",
"modules/cloud-function-v2/vpcconnector.tf",
"modules/cloud-run-v2/vpcconnector.tf",
],
]
def check_dir_diff(dcmp):
"""
Recursively checks a filecmp.dircmp object for any differences.
Returns True if a difference is found, False otherwise.
"""
diff_found = False
if dcmp.left_only:
print(f"[DIFF] Only in {dcmp.left}: {dcmp.left_only}")
diff_found = True
if dcmp.right_only:
print(f"[DIFF] Only in {dcmp.right}: {dcmp.right_only}")
diff_found = True
if dcmp.diff_files:
print(f"[DIFF] Mismatched files: {dcmp.diff_files}")
diff_found = True
for sub_dcmp in dcmp.subdirs.values():
if check_dir_diff(sub_dcmp):
diff_found = True
return diff_found
has_diff = False
for group in duplicates:
first = group[0]
if not os.path.exists(first):
print(f"[ERROR] Path not found: {first}. Skipping group.")
has_diff = True
continue
is_dir = os.path.isdir(first)
for second in group[1:]:
if not os.path.exists(second):
print(f"[DIFF] Path not found: {second}")
has_diff = True
continue
if is_dir != os.path.isdir(second):
print(f"[DIFF] Type mismatch: {first} is {'DIR' if is_dir else 'FILE'}, "
f"but {second} is {'DIR' if os.path.isdir(second) else 'FILE'}.")
has_diff = True
continue
if is_dir:
dcmp = filecmp.dircmp(first, second)
if check_dir_diff(dcmp):
print(f"[DIFF] Found differences between directories {first} {second}")
has_diff = True
else:
if not filecmp.cmp(first, second, shallow=False):
print(f"[DIFF] Files are different: {first} {second}")
has_diff = True
if has_diff:
print("\nCheck finished: Found differences.")
sys.exit(1)