Error during initial deploy when dry-run and create-change-history-table set to true
Describe the bug
Hello,
This is the error in question:
File "/opt/hostedtoolcache/Python/3.13.2/x64/lib/python3.13/site-packages/schemachange/cli.py", line 71, in main
deploy(config=config, session=session)
~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/opt/hostedtoolcache/Python/3.13.2/x64/lib/python3.13/site-packages/schemachange/deploy.py", line 102, in deploy
script_metadata = versioned_scripts.get(script.name)
^^^^^^^^^^^^^^^^^^^^^
AttributeError: 'NoneType' object has no attribute 'get'
I took a quick peek at the code. It looks like if dry-run and create-change-history-table are both set to true, with CHANGE_HISTORY table not yet created, the code errors when attempting to find a versioned script entry in a dictionary set to None.
To Reproduce
Run schemachange command and make sure:
dry-runis set totruecreate-change-history-tableis set to trueCHANGE_HISTORYtable does not yet exist
Expected behavior
This was caught because of how we have our pipeline set up - where a dry-run deploy runs first, then the true deploy after manual approval.
If an initial "true" deploy should be done prior to doing the dry-run, then the documentation should probably include a disclaimer for dry-run option (unless I missed it).
Otherwise, I'm thinking the fix would be:
Return an empty dictionary for already-applied versioned scripts only if:
dry-runis set totruecreate-change-history-tableis set to trueCHANGE_HISTORYtable does not yet exist
Schemachange
- Version: 4.0.1
Also getting this one 👍
Also experiencing issues with this.
We found out on our end if schemas and tables do not exist in Snowflake, dry-run will fail. First of all, ensure that you have them ready, so then dry-run would work
here is a work around.
if you remove the --create-change-history param, and manually run this sql (more or less) on your snowflake, you'll be good. reference the CHANGE_HISTORY DDL on the main doc page.
CREATE SCHEMA IF NOT EXISTS DEV_INTEGRATION.SCHEMACHANGE;
USE SCHEMA DEV_INTEGRATION.SCHEMACHANGE;
CREATE TABLE IF NOT EXISTS "SCHEMACHANGE"."CHANGE_HISTORY"
(
VERSION VARCHAR,
DESCRIPTION VARCHAR,
SCRIPT VARCHAR,
SCRIPT_TYPE VARCHAR,
CHECKSUM VARCHAR,
EXECUTION_TIME NUMBER,
STATUS VARCHAR,
INSTALLED_BY VARCHAR,
INSTALLED_ON TIMESTAMP_LTZ
);
and be sure to point schemachange at the custom path to
"--change-history-table DEV_INTEGRATION.SCHEMACHANGE.CHANGE_HISTORY"
The problem is in the get_script_metadata function inside the SnowflakeSession.py
When in --dry_run and the change table does not exists there
change_history_table_exists = self.change_history_table_exists(
create_change_history_table=create_change_history_table,
dry_run=dry_run,
)
if not change_history_table_exists:
return None, None, None
This returns None as versioned_scripts when initialization occurs in the deploy.py and fails when calling get method on None object.
(
versioned_scripts,
r_scripts_checksum,
max_published_version,
) = session.get_script_metadata(
create_change_history_table=config.create_change_history_table,
dry_run=config.dry_run,
)
A quick fix would be return defaultdict(dict)
change_history_table_exists = self.change_history_table_exists(
create_change_history_table=create_change_history_table,
dry_run=dry_run,
)
if not change_history_table_exists:
return defaultdict(dict), None, None
This will return empty dictionary for versioned scripts and --dry_run will behave normally.
For dry-run on initial deployment, use --create-change-history-table to create the table if missing.
schemachange deploy --dry-run --create-change-history-table
Fixed for 4.2.0 (mid-December). Give it a test when it's available to verify it handles your scenario.