.gitbay/wiki/CI.org

7a667c7b40578f9e76675c36ac11f236a882d711
gitbay/.gitbay/wiki/CI.org rendered · source · history · blame · raw

115 lines · 5755 bytes

  1#+title: CI: what a push queues
  2
  3Three mechanisms decide what a push does to CI, and they interact:
  4
  5- *Dedupe.* A job's result is a property of the commit's tree. A commit
  6  that already has a passed, queued or running build for a job is not
  7  queued again; a commit whose tree already passed a job gets that
  8  result as its status, naming the build it came from (#177). A failed,
  9  cancelled or abandoned build does not count: that commit runs again.
 10- *Path filters.* =paths= and =paths-ignore= on a job are evaluated
 11  against the files the push changed. The diff base is the old tip when
 12  it is an ancestor of the new one, and the merge base with the default
 13  branch otherwise: a new branch, or a force push after a rebase (#176).
 14  A filter that cannot be evaluated, because there is no diff base or
 15  the diff fails, runs the job rather than skipping it. A filter that
 16  excludes the push records a =skipped= status, which =require-checks=
 17  accepts (#172).
 18- *The reaper.* A build a runner claimed and never reported is failed by
 19  the scheduler's tick: two minutes after its log stream ended, or at
 20  the build deadline if no stream was ever seen (#179). Its status reads
 21  =build abandoned=.
 22
 23Which runner takes a build is the fourth: a build is claimed only by a
 24runner attached to its repository (or one polling with a full-scope
 25admin key), and an untrusted build only by one started with
 26=-untrusted=. A repository with no runner attached queues builds
 27nothing claims. See the Users page. Among what a runner may claim it
 28takes the oldest pending build; per-repository rotation when one
 29runner serves several is krz/gitbay#207. There is no cap on how many
 30builds an account queues or how often a schedule fires; that is
 31krz/gitbay#206.
 32
 33Scheduled jobs run on their cron against the default branch, never on
 34push; a default-branch push registers or updates them. Tag jobs run on
 35a matching tag push and nothing else.
 36
 37* The table
 38
 39One =ci.yml= with five jobs, each isolating one rule:
 40
 41#+begin_src yaml
 42jobs:
 43  plain:
 44    steps: [echo plain]
 45  onapp:
 46    paths: [app/**]
 47    steps: [echo onapp]
 48  notapp:
 49    paths-ignore: [app/**]
 50    steps: [echo notapp]
 51  nightly:
 52    schedule: "0 3 * * *"
 53    steps: [echo nightly]
 54  release:
 55    tags: "v*"
 56    steps: [echo release]
 57#+end_src
 58
 59Every push below changes =app/x= and nothing else, so a push whose
 60filters are evaluated queues =onapp= and skips =notapp=, and a push
 61whose filters cannot be evaluated queues both. Each cell is what the
 62push produced for that job; the commit's =ci/<job>= status follows:
 63
 64- =queued=: a build, and a =pending= status until the runner reports.
 65  =queued, untrusted= is a build without the repository's secrets.
 66- =skipped=: no build, and a =skipped= status naming the filter.
 67- =reused=: no build, and a =success= status naming the earlier build
 68  with the same tree.
 69- =registered=: no build; the job's schedule is (re)registered.
 70- =abandoned=: the build failed and the status reads =build abandoned=.
 71- =—=: nothing new. A status the commit already had stands.
 72
 73| push | plain | onapp | notapp | nightly | release | ci/config |
 74|---+---+---+---+---+---+---|
 75| first push of the default branch | queued | queued | queued | registered | — | — |
 76| push to the default branch | queued | queued | skipped | registered | — | — |
 77| push to another branch | queued | queued | skipped | — | — | — |
 78| a new branch, no old sha | queued | queued | skipped | — | — | — |
 79| rebase onto a moved default branch, old not an ancestor | queued | queued | skipped | — | — | — |
 80| rewritten commit, same tree as a passed build | reused | reused | skipped | — | — | — |
 81| fast-forward of a commit built on another branch | — | — | — | registered | — | — |
 82| a commit whose earlier build failed, on a new branch | queued | queued | — | — | — | — |
 83| merge request head from a fork | queued, untrusted | queued, untrusted | queued, untrusted | — | — | — |
 84| tag push | — | — | — | — | queued | — |
 85| schedule tick on the default branch | — | — | — | queued | — | — |
 86| claimed builds whose runner vanished | abandoned | abandoned | — | — | — | — |
 87| push to the default branch with an old sha that cannot be diffed | queued | queued | queued | registered | — | — |
 88| push with a broken ci.yml | — | — | — | — | — | failure |
 89| push with no ci.yml | — | — | — | — | — | — |
 90
 91Rows worth a second look:
 92
 93- The first push of the default branch has no diff base at all: the
 94  merge base of the tip with itself is the tip. Every filtered job
 95  runs. The same holds when the old sha cannot be diffed on the default
 96  branch; on any other branch the merge base takes over and the filters
 97  apply.
 98- A rewritten commit with the same tree reuses =plain= and =onapp=
 99  because the tree check comes before the filter. =notapp= never had a
100  passed build to reuse, and the push changed nothing, so the filter
101  skips it again.
102- A fast-forward of a commit built elsewhere queues nothing: the
103  builds belong to the commit, not the branch. The default-branch push
104  still registers the schedule.
105- A failed build does not stand for its commit. The same commit pushed
106  to another branch runs again; =notapp= keeps its skipped status.
107- A merge request head from a fork has no diff base and, unlike a
108  branch push, no merge-base fallback: every job runs, without secrets.
109  Filtering a head down to no jobs would make it unmergeable under
110  =require-checks= (#172).
111
112=TestPushShapes= in =internal/hookd= runs every row against real git
113and the store, and =TestPushShapesTableOnWiki= checks that this page
114carries each row as the code has it. A row that changes fails there
115first.