Skip to content

Deploy from a repository

Start by installing the CLI and signing in. Then pick the path that matches what you have.

Two commands do different things, and it is worth knowing which one you are running:

  • A single folder’s push — ronja wf push, ronja app push and the others — sends the folder to your own draft. Nobody else sees it until you publish it. ronja automation push is the exception: an automation has no draft, so its push changes the live automation at once.
  • ronja sync apply pushes and publishes every folder under the directory it runs in. What it deploys is live as soon as it finishes.

For a quick change to one workflow, App, module or Feature’s tables, with no repository set up:

  1. Copy it into a folder: ronja wf clone <workflow ID>, then go into the folder it names.
  2. Edit the files in your own editor.
  3. Run ronja wf push to send them to your draft.
  4. Run ronja wf test to run the draft and see its result.
  5. Run ronja wf publish to take it live.

Apps work the same way with ronja app. Modules (ronja module clone <module ID>) and a Feature’s tables (ronja pipeline clone <Feature ID>) use clone, push and publish, with no test step. See Work on Ronja from your editor.

Adopt a repository you already deploy from

Section titled “Adopt a repository you already deploy from”

If you already push folders from a repository, let Ronja keep the record of what each one deploys, so a build server needs nothing committed by hand. Each folder must already name the stack in ronja.json, with its Feature’s ID as featureID; a folder that does not is reported no_feature and left unchanged.

  1. Run ronja sync adopt --stack prod at the top of the repository.
  2. Commit the changed ronja.json files.
  3. Run ronja sync apply --stack prod --dry-run to see what a deploy would do, then ronja sync apply --stack prod.

Once adopted, a folder writes and runs only inside its stack’s Feature. A workflow that writes a table in another Feature, or runs a workflow or Saved Agent there, is refused (writes_outside_target, runs_outside_target) until that dependency is declared in ronja.json with "write": true or "run": true and set in the stack’s bind map.

Running ronja sync adopt again is safe. To stop a folder keeping its records in Ronja, run ronja sync unmanage.

To start a repository from what a Feature already holds:

Terminal window
mkdir sales && cd sales && git init
ronja import feature Sales # the Feature's folders, on stack "main"
git add -A && git commit -m "Import Sales"
ronja sync status --stack main # clean: the tree holds what is live
# edit files, commit, then:
ronja sync apply --stack main --dry-run # what the deploy would change
ronja sync apply --stack main # push and publish every changed folder

In the dry run, everything that already matches what is live is listed as unchanged — a workflow, App or module folder, and each table, metric and automation file — and the deploy changes nothing for it. (If Ronja has no record yet of a row the folder’s ronja.lock.json names, the dry run says the deploy adds that record; that changes nothing you deployed.) If someone changes something in Ronja that the repository deploys, the next deploy stops and names it; run ronja <kind> pull to take the change into the folder, and commit it.

An import names what each folder reads by the folder that builds it where it can, so the same repository can deploy elsewhere. It leaves two kinds of ID in place and lists them: a table a workflow’s code replaces by its ID, and IDs written into an App’s source. Before deploying to a second stack, change each tools.replaceTable(df, "table-…") it lists to tools.replaceTable(df, {{ write('<name>') }}) with the name it gives, and the App’s IDs by hand. Letting Ronja keep the records of tables and metrics needs an Admin, so anyone else’s import writes no pipeline folder and lists the tables and metrics it left out.

A second stack — a test Feature next to production, say — deploys the same repository somewhere else. Two limits shape how you do it, so read them first:

  • Use a separate checkout for each stack. A checkout remembers what it last deployed per organization, not per stack, so deploying a second stack of the same organization from the checkout that deployed the first can be refused as drift, because it is compared with the first stack’s record. Clone the repository again for the second stack. A build server that starts from a fresh checkout every run is not affected.
  • An organization has one copy of each module. A module’s name is unique in the organization, so every stack deploys a module to the Feature it already lives in, and deploying any stack publishes that one copy. Each workflow keeps running the module version it was last published with until it is published again.

Then, in the new checkout:

  1. Add the stack to every folder’s ronja.json, next to main: the same url and tenantID, and the second Feature’s ID as its featureID (for a module folder, the Feature the module already lives in).

  2. Run ronja bind --stack <name> in each folder to choose what that stack reads. It never fills in what the code writes ("write": true) or a workflow or Saved Agent it runs ("run": true), because the match it would find is production’s: set each of those by hand in that stack’s bind map in ronja.json, to a row in the new Feature. A workflow’s own output ("output": true) needs nothing: its first run on the new stack makes it in the new Feature.

    A table one of the repository’s own workflows writes is not something to look up by name either: name it by that workflow’s folder, so each stack reads its own copy. An import already writes it that way. In the reading folder’s ronja.json, from is the workflow folder’s path and address is the name the workflow gives the table, and the folder needs "formatVersion": 7:

    "dependencies": {
    "weekly_revenue": {"kind": "table", "from": "../../workflows/compute-weekly-revenue", "address": "weekly_revenue"}
    }

    A table a pipeline folder builds is named the same way, with its .sql file as address.

  3. Run ronja sync apply --stack <name> --allow-create. Without --allow-create, sync apply only updates what already exists and refuses to create anything. A folder that reads a workflow’s output is refused until that workflow has run once on the new stack: run it (ronja wf run --stack <name> in its folder), then apply again.

Take a change made in Ronja into the repository

Section titled “Take a change made in Ronja into the repository”

Anyone can still change something a repository deploys — in Ronja, by asking Ronja, or from a folder of their own — and it is marked Managed in git while they do. The repository’s next deploy stops on the change. To keep it:

  1. Run ronja <kind> pull in the folder: ronja wf pull, ronja app pull, ronja module pull, ronja pipeline pull or ronja automation pull.
  2. Read the diff it prints. The folder’s files now hold what is live.
  3. Commit the changed files.

The next ronja sync apply writes nothing for that folder. --dry-run shows the diff and changes nothing.

A pull reads only what is live, never a draft, and never replaces a change of your own that has not been deployed: it stops and names your files. Deploy your change first and combine the two by hand, or pass --force to replace your change with what is live. It also stops on changes you have not committed. Each refusal says why and what to do next.