Understanding CI Syntax:
A Complete Documentation
%202.png)





We initially created the CI as a cheaper and freer alternative for CircleCI, Github Actions and Heroku since we were using them heavily in our workflow. Because of that, you would find some of our syntax aligns with CircleCi and Github Actions syntax because we are inspired by them.
In our CI we value the value of composition, mix-ins so there are 2 file type you would need to know:
<workflow-file-type>.yml
<module-file-type>.yml
We would organize <module-file-type>.yml
into a special mods
folder and in other.yml
files, you can compile them to use. This should enable a large multitude of custom logic and help organize your deployment code logic neatly by reducing repeated codes.
Anatomy of
<workflow-file-type>.yml
- version
- name
- on.<action-type>
- on.<action-type>.branches.<branch>
- on.<action-type>.tags.<tag>
- env
- jobs
- jobs.<jobId>
- jobs.<jobId>.builder
- jobs.<jobId>.requires
- jobs.<jobId>.steps
- jobs.<jobId>.steps[*].uses
- jobs.<jobId>.steps[*].run
- jobs.<jobId>.steps[*].name
Anatomy of
<module-file-type>.yml
- modules
- modules.<moduleId>.steps
- modules.<moduleId>.steps[*].uses
- modules.<moduleId>.steps[*].run
- modules.<moduleId>.steps[*].name
Here is the folder structure:
.tvtci/
mods/
module-1.yml
module-2.yml
module-3.yml
workflow-id-1.yml
workflow-id-2.yml
Version
The version of the configuration file, right now we are at our first release so version 1
is expected. You can also removed this option and we would default to the latest version.
Name
The name of the current flow, if you do not specify a workflow, we would use the file’s name. It would be ugly…but hey… at least you don’t need to spend time thinking about it too much.
on.<action-type>
We are currently supporting these <action-type>:
- push - When a branch is received a push, we would trigger the CI on the branch that received the new codes.
- pull_request - For platform that supports creating pull requests, otherwise you can safely ignore this.
on.<action-type>.branches.<branch>
For filtering action type to specific branches only. We accept glob patterns, wild cards to match branches easier.
Example:
on:
push:
branches:
- production
- test
- staging
- 'features/**'
- 'fix/*'
Environment
A list of possible environment, right now we haven’t supported the ability to separate run time env and bundled app env yet. You would need to write logic to add desired env to your app’s env file. You can have 2 types of env:
- Hard-coded env
- Secrets env
Hard-coded environment
We supported these primitive types:
- boolean
- string
- number
Secrets environment
You can reference configurable env from the dashboard using ${{ secrets.<name> }}
syntax. We actually inspired this way of reference variable from Github syntax. As it leaves lots of great room for extending variable in the future. Kudos to the engineer who though of this.
Example:
env:
HARD_CODE_ENV: "well-you-should-not-hard-code-anything"
CONFIGRABLE_SECRETS: ${{ secrets.CONFIGRABLE_SECRETS }}
And just before you ask, all the configurable secrets is shared across environments. We do have plan to make them separate in the foreseeable future. So stay tune!
jobs
This is where you define your workflows, by default we would let things run in parallel because honestly, time is just too precious to be wasted. You can ask children jobs for wait for is parents using requires
keywords (details docs below).
jobs.<jobId>
Must be a string with no special character. In theory, you have unlimited amount of jobs but don’t over run it because we would use kill switch on jobs that occupied a space for too long. The current threshold is 1 hour
and can be changed in the future.
Example:
jobs:
myAwesomeJobThatIsTooCoolToHandleIthink:
steps:
- runs: echo "foo"
jobs.<jobId>.builder
Right now we support a variety of tag combination. You can provider builder
as:
- string
- array
We support the following keywords for OS:
- linux - coming soon
- ubuntu
- macos - We are using a fleet of MacOS Sonoma, in the future we would add more granular control over how you can specify the OS version
Each OS keywords would be compatible with specific keywords:
macOS
tag would be compatible with:
x64
,sonoma
xcode16
ubuntu
tag would be compatible with:
node
,nodejs
,nvm
,golang
Example:
jobs:
myAwesomeJobThatIsTooCoolToHandleIthink:
builder:
- macOS
- x64
jobs.<jobId>.requires
Because by default our jobs is running in parallel, you would need this keywords to create an order in your jobs:
jobs:
myAwesomeJobThatIsTooCoolToHandleIthink:
builder:
- macos
mySecondAwesomeJobThatIsTooCoolToHandleIthink:
requires:
- myAwesomeJobThatIsTooCoolToHandleIthink
builder:
- linux
jobs.<jobId>.steps
These are the steps that would be execute in order inside of each jobs. Run whatever you want, just make sure to stay with in the moral ground and be happy.
jobs.<jobId>.steps[*].uses
This is where you would declare which part you would want to re-use from your modules. When compiling the scripts, we would read the id in here and execute the scripts accordingly.
By default, we create the function:
- checkout - to clone and checkout code from the current interacted branch in your repository.
Example:
jobs:
myAwesomeJobThatIsTooCoolToHandleIthink:
builder:
- macos
steps:
- uses: checkout
- uses: otherPrecompliedModule
jobs.<jobId>.steps[*].run
This is where you specify your command. Remember that each run
is a different process, so if you have process specific variables, you can place them in a single run
Example 1:
- name: Install Bun dependencies
run: bun install
Example 2:
- name: Install and build because why no
run: bun install && bun run build
jobs.<jobId>.steps[*].name
Well everyone needs a name, you can skip it if you don’t want to name your spiritual child. I, we don’t judge.
jobs.<jobId>.steps[*].working-directory
This is a place where you want to run your command.
Example 1:
- name: Install Bun dependencies
run: bun install
working-directory: ./app
modules
This is where you compose re-usable commands across files.
modules.<moduleId>.steps
The way to define is similar to jobs.<jobId>.steps
you can read how to define steps here CI Syntax.