Hooks¶
A hook is a Python function. A step in a hooks file runs it before or after a workspace deploys: run a notebook, refresh a model, publish a warehouse's schema. fab deploy publishes item definitions and nothing else; hooks do the rest.
Hooks run on every deploy, including a rollback, so a step must be safe to repeat (CREATE TABLE IF NOT EXISTS, MERGE).
Most hooks are for one item type; the For column says which.
| Hook | For | Ships in | Does |
|---|---|---|---|
run_notebook |
Notebook | allez | Runs a notebook and waits for it to finish. |
run_pipeline |
Data pipeline | allez | Runs a data pipeline and waits for it to finish. |
run_item |
Any runnable item | allez | Runs any runnable item and waits for it to finish. |
refresh_semanticmodel |
Semantic model | allez | Refreshes a semantic model and waits for it. With a request, an enhanced refresh that reports each table and the attempts. |
query_semanticmodel |
Semantic model | allez | Runs a DAX query and prints the rows it returns in the deploy log. |
fab_api |
Any endpoint | allez | Calls any Fabric or Power BI REST endpoint. |
publish_sqlproj |
SQL database, Warehouse | allez | Publishes a SQL database or a warehouse from its item folder through Fabric's definition API. |
Every hook allez ships talks to Fabric through fab alone.
What a deploy does not carry¶
fab deploy publishes item definitions, for the item types fabric-cicd supports. Fabric decides what a definition holds, per type:
| Item | In the definition | Not carried |
|---|---|---|
| Warehouse | The item only: an empty warehouse with the committed collation. | The schema, without a publish_sqlproj step. Rows. SQL permissions and security. |
| SQL database | The item only: an empty database. | The schema, saved queries and the scripts marked in the editor, without a publish_sqlproj step. SQL permissions and security. |
| Lakehouse | Metadata, shortcuts, OneLake data-access roles (what is tracked). | Tables, files, data. |
| Semantic model | The model. | Its data (refresh_semanticmodel) and its refresh schedule (fab_api). |
| dbt job | dbt-content.json and the whole project under Code/. |
Run output under Output/. Runs: the item's own schedule. |
| Notebook, data pipeline, … | The definition and its schedules (.schedules; a parameter.yml rule adjusts them per environment). |
Credentials, connections. |
Data arrives through a post-deploy step: a notebook that is safe to run again, or a SQL database's post-deployment script.
Using a hook¶
Name it as a step's action in a hooks file, with the hook's keys beside it, and name that file in the dag (hooks files has the file format and an example). A step's keys are checked against the hook when the file loads: a misspelt or missing key stops the deploy before any fab call. allez deploy --plan prints each step and where its hook comes from: Would run run_notebook (library) item=<Name>.Notebook timeout_seconds=900.
Every step also takes on_error. fail, the default, stops the deploy at that step. continue logs the failure and runs the next step, then the rest of the deploy. Use continue for a step whose failure should not block the release, such as a read-back or a take-over that fails on an empty workspace (Steps).
Where allez finds a hook¶
.allez/hooks/<action>.py: your own, in the.allez/folder that sits besidefabric/(not in it).- The library: the hooks allez ships, versioned with the tag you install. Nothing to copy.
Your folder first, then allez's. A file in .allez/hooks/ with a library hook's name replaces it.
.
├── 📁 .allez/ # everything allez keeps in your repo
│ ├── 📁 hooks/ # only what is yours; committed; may not exist
│ │ └── 📄 my_hook.py
│ └── 📁 cache/ # workspace ids for --plan; git-ignored
└── 📁 fabric/
Shared pipelines, one hooks folder per solution¶
allez finds .allez/hooks/ from the solution on disk: the parent of the folder that holds the root allez.yml. It does not look in the working directory, in the pipeline's checkout, or in any other repository. So when pipeline templates live in one repo (a hub) and each solution repo (a spoke) carries thin pipelines that extend them, the hooks still live in the spoke, beside fabric/.
The reason is where the hooks are loaded. Every verb loads a hooks file and checks each step against its hook's signature before any fab call, and --plan does the same on a laptop with no pipeline in sight. A hook that exists only where the pipeline can see it makes the solution unloadable everywhere else, and a hook is code that runs with the deploy's identity, so it belongs in the pull request that changes the solution it runs for. Both reasons are why allez never reads hooks from a pipeline checkout.
Writing your own¶
A hook is one file, .allez/hooks/<action>.py, defining run with the context first and the step's keys after it:
from allez.hooks import Context, job_params
def run(ctx: Context, table: str, rows: int = 100) -> None:
ctx.fab.run_job(ctx.workspace, "Seed", "Notebook",
params=job_params({"table": table, "rows": rows}), console=ctx.console)
That is action: seed_table with table: and optional rows:. Files starting with _ are never hooks; use them for shared helpers.
ctx. |
Is |
|---|---|
env |
The environment being deployed. |
workspace, workspace_id |
The workspace this dag node deploys to. |
fab |
allez's fab wrapper; every Fabric call goes through it (api, run_job, find_item, …). |
console |
Where to print. |
folder |
The sub-folder, to read or rewrite definitions about to be published. |
allez.hooks also exports split_item ("<Name>.SemanticModel" → ("<Name>", "SemanticModel")) and job_params ({rows: 100} → ["rows:int=100"], the shape fab job run -P takes).
To change a library hook, copy it from src/allez/library_hooks/ in the allez repo into .allez/hooks/ and edit it; the imports are the same.