Skip to content

Set up Flight in your repo

Everything that has to be in your repository for Flight to build and publish it, and nothing that does not.

Flight builds your repository the way you would build it locally, so most repositories need exactly one new file. This page is what goes in it, plus the handful of things about the build machine that change how you write your Makefile.

What your repository needs#

  • your-repothe repository root
    • .ceagle-flightrequired, at the root
    • makefileor whatever your build command runs
    • src
      • main.c
    • bincreated by the build, gitignored

Only .ceagle-flight is new. Everything else is however your project already builds.

The minimum manifest#

.ceagle-flight
[program]
name = "Snake"
version = "1.0.0"

[build]
output = "bin/SNAKE.8xp"

That builds. Everything else has a default: the command defaults to make, the timeout to ten minutes, the categories to other, and submodules are off.

A realistic manifest#

.ceagle-flight
[program]
name = "Snake"
version = "1.2.0"
summary = "The classic, on your calculator."
description = """
Eat the pixels. Do not eat yourself.

Hold [2nd] to sprint.
"""
categories = ["games"]
tags = ["arcade", "classic"]
author = "Ada Lovelace"
depends = ["graphx-helpers"]

[build]
command = "make"
output = "bin/SNAKE.8xp"
submodules = false
timeout = "10m"
Manifest reference

Every key, its default, its limit, and the error you get when it is wrong.

Read on

Getting the output path right#

output is the one field that fails most first builds. It is a path relative to the repository root, and it has to match exactly one regular file after the build finishes.

  1. Find what your Makefile is called

    The CE C toolchain's standard makefile writes into bin/, named after the NAME variable:

    makefile
    NAME = SNAKE
    ICON = icon.png
    DESCRIPTION = "Snake"
    COMPRESSED = NO
    
    include $(shell cedev-config --makefile)

    With NAME = SNAKE the artifact is bin/SNAKE.8xp.

  2. Write that path, or a glob that matches it

    output = "bin/SNAKE.8xp"

    A glob is fine when you would rather not repeat the name:

    output = "bin/*.8xp"
  3. Make sure only one file matches

    A glob that matches two files fails with the output pattern matched more than one file. That happens most often when a previous build left something in bin/, or when the repository ships a prebuilt binary. Add bin/ to .gitignore.

Rules on the output path
relativeRequired

It must stay inside the repository. Absolute paths, backslashes and any .. segment are rejected before the build runs.

one matchRequired

Zero matches and two matches are both failures, with different errors.

a regular fileRequired

A symlink is refused rather than followed, even if it points somewhere legitimate.

sizeat most 8 MiB

And the variable body itself has to fit in a calculator variable.

Writing a Makefile that works here#

The build machine is not your machine. Four differences matter.

  1. There is no network

    The container runs with networking disabled. A Makefile that downloads a dependency, clones something, or runs a package manager fails.

    Everything a build needs has to be in the repository, or a git submodule, or already in the image.

  2. The toolchain is already installed

    The CE C toolchain is at /opt/CEdev, CEDEV is set, and /opt/CEdev/bin is on the PATH. Do not try to install it.

    include $(shell cedev-config --makefile)

    works as-is.

  3. Submodules are off by default

    If your build needs them, say so:

    [build]
    submodules = true

    They are cloned with the same protocol allow-list as the repository, so only HTTPS submodules resolve.

  4. The command runs through a login shell

    The build runs bash -lc with your command, in the directory holding your manifest, as an unprivileged user. CEAGLE_FLIGHT=1 is set, so a Makefile can branch on it:

    ifdef CEAGLE_FLIGHT
    COMPRESSED = YES
    endif
The build environment

The exact image, the toolchain version, the environment variables and the limits.

Read on

Connect it in the console#

  1. Install the GitHub App

    From the project's Flight tab. Grant it the repository. It asks to read metadata, and to write deployments and commit statuses so a build shows up on the commit.

  2. Pick the repository and branch

    Only public repositories are eligible. The branch defaults to the repository default.

  3. Leave build on push enabled

    A push to the tracked branch then starts a build on its own.

Test the manifest before you push#

There is no offline validator, but the console serves a known-good example for any language and mode, which is useful to diff against:

curl -s "https://roost.ceagle.cc/api/v1/manifest?language=asm"
curl -s "https://roost.ceagle.cc/api/v1/manifest?language=lib&mode=libify"
curl -s "https://roost.ceagle.cc/api/v1/manifest?language=lib&mode=custom"

A repository that backs two projects#

A repository may back as many projects as it has manifests. Each project is connected with its own manifest path, and no two projects may name the same manifest in the same repository.

The usual shape is a monorepo holding a library and the application that uses it:

  • your-repothe repository root
    • libone project
      • .ceagle-flight
      • makefile
    • appanother project
      • .ceagle-flight
      • makefile

Create two projects, then connect each one to the same repository and give it its own path. The path is the directory a project builds from, so lib and app here. Flight appends the manifest name for you, and lib/.ceagle-flight means the same thing if you would rather be explicit.

Two manifests in one directory work too, when a single tree produces two artifacts from one build system. Name the second one with a suffix, .ceagle-flight.app, and give that as the path.

The whole repository is checked out for every build, so a project in a subdirectory can still read what sits beside it. A Makefile in app/ may include headers from ../lib. Only the paths the manifest names are confined to the project's own directory.

Each project keeps its own address, its own listing, its own release history and its own build queue. A push to the tracked branch builds every project connected to that repository, not only the one whose files changed, because a change in a library is exactly when the application that links it needs rebuilding.

If what you have is a library and its consumer, consider publishing the library as a LibLoad library and declaring it as a dependency of the application. That works whether or not they share a repository.

Next#

CEagle documentation