11# Copyright (c) 2025 Airbyte, Inc., all rights reserved.
22"""Manifest related commands.
33
4- Coming soon.
5-
6- This module is planned to provide a command line interface (CLI) for validating
4+ This module provides a command line interface (CLI) for validating and migrating
75Airbyte CDK manifests.
86"""
97
8+ import sys
9+ from importlib import metadata
10+ from pathlib import Path
11+ from typing import Any , Dict
12+
1013import rich_click as click
14+ import yaml
15+ from jsonschema .exceptions import ValidationError
16+ from jsonschema .validators import validate
17+
18+ from airbyte_cdk .manifest_migrations .migration_handler import ManifestMigrationHandler
19+ from airbyte_cdk .sources .declarative .manifest_declarative_source import (
20+ _get_declarative_component_schema ,
21+ )
1122
1223
1324@click .group (
@@ -19,6 +30,145 @@ def manifest_cli_group() -> None:
1930 pass
2031
2132
33+ @manifest_cli_group .command ("validate" )
34+ @click .option (
35+ "--manifest-path" ,
36+ type = click .Path (exists = True , path_type = Path ),
37+ default = "manifest.yaml" ,
38+ help = "Path to the manifest file to validate (default: manifest.yaml)" ,
39+ )
40+ def validate_manifest (manifest_path : Path ) -> None :
41+ """Validate a manifest file against the declarative component schema.
42+
43+ This command validates the manifest file and checks version compatibility.
44+ If validation fails, it will suggest running the migrate command if needed.
45+ """
46+ try :
47+ with open (manifest_path , "r" ) as f :
48+ manifest_dict = yaml .safe_load (f )
49+
50+ if not isinstance (manifest_dict , dict ):
51+ click .echo (
52+ f"❌ Error: Manifest file { manifest_path } does not contain a valid YAML dictionary" ,
53+ err = True ,
54+ )
55+ sys .exit (1 )
56+
57+ schema = _get_declarative_component_schema ()
58+
59+ validate (manifest_dict , schema )
60+
61+ migration_handler = ManifestMigrationHandler (manifest_dict )
62+ migrated_manifest = migration_handler .apply_migrations ()
63+
64+ if migrated_manifest != manifest_dict :
65+ click .echo (
66+ f"⚠️ Manifest { manifest_path } is valid but could benefit from migration to the latest version." ,
67+ err = True ,
68+ )
69+ click .echo (
70+ "Run 'airbyte-cdk manifest migrate' to apply available migrations." , err = True
71+ )
72+ sys .exit (1 )
73+
74+ click .echo (f"✅ Manifest { manifest_path } is valid and up to date." )
75+
76+ except FileNotFoundError :
77+ click .echo (f"❌ Error: Manifest file { manifest_path } not found" , err = True )
78+ sys .exit (1 )
79+ except yaml .YAMLError as e :
80+ click .echo (f"❌ Error: Invalid YAML in { manifest_path } : { e } " , err = True )
81+ sys .exit (1 )
82+ except ValidationError as e :
83+ click .echo (f"❌ Validation failed for { manifest_path } :" , err = True )
84+ click .echo (f" { e .message } " , err = True )
85+ click .echo (
86+ "Run 'airbyte-cdk manifest migrate' to apply available migrations that might fix this issue." ,
87+ err = True ,
88+ )
89+ sys .exit (1 )
90+ except Exception as e :
91+ click .echo (f"❌ Unexpected error validating { manifest_path } : { e } " , err = True )
92+ sys .exit (1 )
93+
94+
95+ @manifest_cli_group .command ("migrate" )
96+ @click .option (
97+ "--manifest-path" ,
98+ type = click .Path (exists = True , path_type = Path ),
99+ default = "manifest.yaml" ,
100+ help = "Path to the manifest file to migrate (default: manifest.yaml)" ,
101+ )
102+ @click .option (
103+ "--dry-run" ,
104+ is_flag = True ,
105+ help = "Show what changes would be made without actually modifying the file" ,
106+ )
107+ def migrate_manifest (manifest_path : Path , dry_run : bool ) -> None :
108+ """Apply migrations to make a manifest file compatible with the latest version.
109+
110+ This command applies all necessary migrations to update the manifest file
111+ to be compatible with the latest CDK version.
112+ """
113+ try :
114+ with open (manifest_path , "r" ) as f :
115+ original_manifest = yaml .safe_load (f )
116+
117+ if not isinstance (original_manifest , dict ):
118+ click .echo (
119+ f"❌ Error: Manifest file { manifest_path } does not contain a valid YAML dictionary" ,
120+ err = True ,
121+ )
122+ sys .exit (1 )
123+
124+ migration_handler = ManifestMigrationHandler (original_manifest )
125+ migrated_manifest = migration_handler .apply_migrations ()
126+
127+ if migrated_manifest == original_manifest :
128+ click .echo (f"✅ Manifest { manifest_path } is already up to date - no migrations needed." )
129+ return
130+
131+ if dry_run :
132+ click .echo (f"🔍 Dry run - changes that would be made to { manifest_path } :" )
133+ click .echo (
134+ " Migrations would be applied to update the manifest to the latest version."
135+ )
136+ click .echo (" Run without --dry-run to apply the changes." )
137+ return
138+
139+ current_cdk_version = metadata .version ("airbyte_cdk" )
140+ migrated_manifest ["version" ] = current_cdk_version
141+
142+ with open (manifest_path , "w" ) as f :
143+ yaml .dump (migrated_manifest , f , default_flow_style = False , sort_keys = False )
144+
145+ click .echo (
146+ f"✅ Successfully migrated { manifest_path } to the latest version ({ current_cdk_version } )."
147+ )
148+
149+ try :
150+ schema = _get_declarative_component_schema ()
151+ validate (migrated_manifest , schema )
152+ click .echo (f"✅ Migrated manifest { manifest_path } passes validation." )
153+ except ValidationError as e :
154+ click .echo (
155+ f"⚠️ Warning: Migrated manifest { manifest_path } still has validation issues:" ,
156+ err = True ,
157+ )
158+ click .echo (f" { e .message } " , err = True )
159+ click .echo (" Manual fixes may be required." , err = True )
160+
161+ except FileNotFoundError :
162+ click .echo (f"❌ Error: Manifest file { manifest_path } not found" , err = True )
163+ sys .exit (1 )
164+ except yaml .YAMLError as e :
165+ click .echo (f"❌ Error: Invalid YAML in { manifest_path } : { e } " , err = True )
166+ sys .exit (1 )
167+ except Exception as e :
168+ click .echo (f"❌ Unexpected error migrating { manifest_path } : { e } " , err = True )
169+ sys .exit (1 )
170+
171+
22172__all__ = [
23173 "manifest_cli_group" ,
24174]
0 commit comments