Pick any line to see why it is the way it is: the commit, the pull request and issue it came from, and what the agent was thinking.
| Running g1t yourself: the design, a docker compose proof, and a guide to what works today | 1 | #!/usr/bin/env bash |
| 2 | # End-to-end check of a self-hosted g1t: sign up, confirm the email, make a | |
| 3 | # workspace and a repository, push and clone over HTTP, open an issue, and | |
| Merge branch 'worktree-agent-aaf03bdceac799c89' | 4 | # read the code back through the site. Then the API on its own port (REST, |
| Self-hosting: RustFS for S3-compatible storage, buckets and the packs' lifecycle rule made with the AWS CLI | 5 | # OAuth metadata and MCP, with an access token), an npm package published to |
| 6 | # the installation's registry and installed back, pull requests from a branch | |
| Merge branch 'worktree-agent-aaf03bdceac799c89' | 7 | # and from a fork merged onto main, the merge queue taking a pull request |
| 8 | # and giving it back, and every cron handler the scheduler runs. | |
| Running g1t yourself: the design, a docker compose proof, and a guide to what works today | 9 | # |
| 10 | # ./smoke.sh # against the compose stack's defaults | |
| 11 | # G1T_URL=http://localhost:8787 MAIL_LOG=wrangler.log ./smoke.sh | |
| 12 | # | |
| 13 | # The confirmation link is read from Mailpit (MAILPIT_URL, the default) or, | |
| Merge branch 'worktree-agent-aaf03bdceac799c89' | 14 | # with MAIL_LOG set, from a log the mail Worker printed it to. API_URL and |
| 15 | # MCP_URL are where the API is (default: G1T_URL's host on port 8789). | |
| 16 | # SCHEDULER_ONCE is the command that runs every cron once (scheduler.mjs | |
| 17 | # --once, inside the g1t container); unset, that step is skipped: | |
| 18 | # | |
| 19 | # SCHEDULER_ONCE="docker compose -f deploy/self-host/docker-compose.yml exec -T g1t \ | |
| 20 | # node deploy/self-host/scheduler.mjs --once /data/generated/schedules.json" ./smoke.sh | |
| 21 | # | |
| 22 | # (In Git Bash on Windows, start the command with `env MSYS_NO_PATHCONV=1` | |
| 23 | # so /data is not rewritten into a Windows path.) | |
| 24 | # PACK_CACHE=off skips the check that a second clone is served from the | |
| Self-hosting: RustFS for S3-compatible storage, buckets and the packs' lifecycle rule made with the AWS CLI | 25 | # clone pack cache. PACKAGES=off skips publishing an npm package to the |
| 26 | # installation's registry and installing it back. | |
| Merge branch 'worktree-agent-aaf03bdceac799c89' | 27 | # |
| Self-hosting: RustFS for S3-compatible storage, buckets and the packs' lifecycle rule made with the AWS CLI | 28 | # Needs curl, git and node (to read JSON), and npm for the package. |
| Running g1t yourself: the design, a docker compose proof, and a guide to what works today | 29 | set -euo pipefail |
| 30 | ||
| 31 | G1T_URL="${G1T_URL:-http://localhost:8787}" | |
| Merge branch 'worktree-agent-aaf03bdceac799c89' | 32 | API_URL="${API_URL:-$(node -e 'const u = new URL(process.argv[1]); u.port = "8789"; console.log(u.origin)' "$G1T_URL")}" |
| 33 | MCP_URL="${MCP_URL:-$API_URL/mcp}" | |
| Running g1t yourself: the design, a docker compose proof, and a guide to what works today | 34 | MAILPIT_URL="${MAILPIT_URL:-http://localhost:8025}" |
| 35 | MAIL_LOG="${MAIL_LOG:-}" | |
| Merge branch 'worktree-agent-aaf03bdceac799c89' | 36 | SCHEDULER_ONCE="${SCHEDULER_ONCE:-}" |
| 37 | # off: this installation keeps no clone packs (no PACK_STORE), so a second | |
| 38 | # clone is not checked for a kept one. | |
| 39 | PACK_CACHE="${PACK_CACHE:-on}" | |
| Self-hosting: RustFS for S3-compatible storage, buckets and the packs' lifecycle rule made with the AWS CLI | 40 | # off: skip publishing and installing an npm package (which needs npm). |
| 41 | PACKAGES="${PACKAGES:-on}" | |
| Running g1t yourself: the design, a docker compose proof, and a guide to what works today | 42 | RUN="$(date +%s)" |
| 43 | USER_NAME="smoke${RUN}" | |
| 44 | EMAIL="${USER_NAME}@example.com" | |
| 45 | PASSWORD="correct-horse-${RUN}" | |
| 46 | WORKSPACE="ws${RUN}" | |
| 47 | REPO="hello" | |
| 48 | WORK="$(mktemp -d)" | |
| 49 | JAR="$WORK/cookies" | |
| 50 | trap 'rm -rf "$WORK"' EXIT | |
| 51 | ||
| 52 | step() { printf '\n== %s\n' "$*"; } | |
| 53 | fail() { printf 'FAILED: %s\n' "$*" >&2; exit 1; } | |
| 54 | ||
| 55 | # A form POST as a browser sends it, with the Origin the site checks. | |
| 56 | post() { | |
| 57 | local path="$1"; shift | |
| 58 | curl -sS -o "$WORK/body" -w '%{http_code} %{redirect_url}' -b "$JAR" -c "$JAR" \ | |
| 59 | -H "Origin: $G1T_URL" "$@" "$G1T_URL$path" | |
| 60 | } | |
| 61 | get() { | |
| 62 | curl -sS -o "$WORK/body" -w '%{http_code}' -b "$JAR" -c "$JAR" "$G1T_URL$1" | |
| 63 | } | |
| Merge branch 'worktree-agent-aaf03bdceac799c89' | 64 | # An API call with the access token: method, path, optional JSON body. The |
| 65 | # answer is in $WORK/api; the status is printed. | |
| 66 | api() { | |
| 67 | local method="$1" path="$2" body="${3:-}" | |
| 68 | local args=(-sS -o "$WORK/api" -w '%{http_code}' -X "$method" -H "Authorization: Bearer $TOKEN") | |
| 69 | [ -n "$body" ] && args+=(-H "content-type: application/json" --data "$body") | |
| 70 | curl "${args[@]}" "$API_URL$path" | |
| 71 | } | |
| 72 | # A field of the last API answer (or of FILE), by a JavaScript path: `json pull.number`. | |
| 73 | json() { | |
| 74 | node -e 'const v = process.argv[2].split(".").reduce((o, k) => o?.[k], JSON.parse(require("fs").readFileSync(process.argv[1], "utf8"))); console.log(typeof v === "object" ? JSON.stringify(v) : v ?? "")' "${2:-$WORK/api}" "$1" | |
| 75 | } | |
| 76 | # Waits for pull request $1 to have status $2. | |
| 77 | until_status() { | |
| 78 | local status="" | |
| 79 | for _ in $(seq 1 30); do | |
| 80 | [ "$(api GET "/repos/$WORKSPACE/$REPO/pulls/$1")" = 200 ] && status="$(json pull.status)" | |
| 81 | [ "$status" = "$2" ] && return 0 | |
| 82 | sleep 1 | |
| 83 | done | |
| 84 | fail "pull request #$1 is $status, not $2: $(head -c 400 "$WORK/api")" | |
| 85 | } | |
| 86 | # Whether main, cloned fresh, has a file. | |
| 87 | main_has() { | |
| 88 | rm -rf "$WORK/main" | |
| 89 | git -c credential.helper= clone -q "$G1T_URL/$WORKSPACE/$REPO.git" "$WORK/main" | |
| 90 | [ -f "$WORK/main/$1" ] | |
| 91 | } | |
| 92 | # A commit on a new branch of $1 (a clone), pushed to $2. | |
| 93 | commit_file() { | |
| 94 | local dir="$1" remote="$2" branch="$3" file="$4" | |
| 95 | ( | |
| 96 | cd "$dir" | |
| 97 | git config user.name "Smoke Test" | |
| 98 | git config user.email "$EMAIL" | |
| 99 | git config commit.gpgsign false | |
| 100 | git switch -q -c "$branch" 2>/dev/null || git switch -q "$branch" | |
| 101 | mkdir -p "$(dirname "$file")" | |
| 102 | printf 'Changed by smoke.sh on %s.\n' "$branch" > "$file" | |
| 103 | git add . && git commit -qm "Add $file" | |
| 104 | git -c credential.helper= push -q "$remote" "HEAD:$branch" | |
| 105 | ) | |
| 106 | } | |
| Running g1t yourself: the design, a docker compose proof, and a guide to what works today | 107 | |
| 108 | step "site answers at $G1T_URL" | |
| 109 | [ "$(get /)" = 200 ] || fail "GET / did not answer 200" | |
| 110 | ||
| 111 | step "sign up as $USER_NAME" | |
| 112 | out="$(post /register --data-urlencode "username=$USER_NAME" --data-urlencode "email=$EMAIL" --data-urlencode "password=$PASSWORD")" | |
| 113 | echo "$out" | |
| 114 | case "$out" in 30[23]*) ;; *) fail "register: $out $(head -c 300 "$WORK/body")" ;; esac | |
| 115 | # curl keeps Secure cookies only for https or localhost; carry it by hand. | |
| 116 | grep -q g1t_session "$JAR" || fail "no session cookie" | |
| 117 | ||
| 118 | step "confirm the email" | |
| 119 | link="" | |
| 120 | for _ in $(seq 1 20); do | |
| 121 | if [ -n "$MAIL_LOG" ]; then | |
| 122 | link="$(grep -ao "[a-z]*://[^ \"<]*/verify?token=[0-9a-zA-Z_-]*" "$MAIL_LOG" | tail -1 || true)" | |
| 123 | else | |
| 124 | id="$(curl -sS "$MAILPIT_URL/api/v1/search?query=to:$EMAIL" | sed -n 's/.*"ID":"\([^"]*\)".*/\1/p' | head -1)" | |
| 125 | [ -n "$id" ] && link="$(curl -sS "$MAILPIT_URL/api/v1/message/$id" | grep -ao '[a-z]*://[^ "<\\]*/verify?token=[0-9a-zA-Z_-]*' | head -1 || true)" | |
| 126 | fi | |
| 127 | [ -n "$link" ] && break | |
| 128 | sleep 1 | |
| 129 | done | |
| 130 | [ -n "$link" ] || fail "no confirmation email arrived" | |
| 131 | echo "$link" | |
| 132 | [ "$(get "/verify?${link#*\?}")" = 200 ] || fail "verify" | |
| 133 | grep -q "$USER_NAME" "$WORK/body" || fail "verify page does not name the account" | |
| 134 | ||
| 135 | step "create workspace $WORKSPACE" | |
| 136 | out="$(post /workspaces/new --data-urlencode "slug=$WORKSPACE" --data-urlencode "displayName=Smoke $RUN")" | |
| 137 | echo "$out" | |
| 138 | case "$out" in 30[23]*) ;; *) fail "workspace: $out $(head -c 300 "$WORK/body")" ;; esac | |
| 139 | ||
| 140 | step "create repository $WORKSPACE/$REPO" | |
| 141 | out="$(post /new --data-urlencode "workspace=$WORKSPACE" --data-urlencode "name=$REPO" --data-urlencode "description=Self-host smoke test" --data-urlencode "visibility=public" --data-urlencode "source=empty")" | |
| 142 | echo "$out" | |
| 143 | case "$out" in 30[23]*) ;; *) fail "repo: $out $(head -c 300 "$WORK/body")" ;; esac | |
| 144 | ||
| 145 | step "push over HTTP" | |
| 146 | remote="${G1T_URL/:\/\//://$USER_NAME:$PASSWORD@}/$WORKSPACE/$REPO.git" | |
| 147 | git init -q -b main "$WORK/src" | |
| 148 | ( | |
| 149 | cd "$WORK/src" | |
| 150 | git config user.name "Smoke Test" | |
| 151 | git config user.email "$EMAIL" | |
| 152 | # A throwaway commit: never signed, whatever the global config says. | |
| 153 | git config commit.gpgsign false | |
| 154 | printf '# hello\n\nPushed to a self-hosted g1t.\n' > README.md | |
| 155 | mkdir -p src && printf 'fn main() {\n println!("hello from g1t");\n}\n' > src/main.rs | |
| 156 | git add . && git commit -qm "First commit" | |
| 157 | git -c credential.helper= push -q "$remote" main | |
| 158 | ) | |
| 159 | echo "pushed $(git -C "$WORK/src" rev-parse --short HEAD)" | |
| 160 | ||
| 161 | step "clone over HTTP" | |
| 162 | git -c credential.helper= clone -q "$G1T_URL/$WORKSPACE/$REPO.git" "$WORK/clone" | |
| 163 | diff -q "$WORK/src/README.md" "$WORK/clone/README.md" || fail "clone differs" | |
| 164 | echo "clone matches" | |
| 165 | ||
| Merge branch 'worktree-agent-aaf03bdceac799c89' | 166 | if [ "$PACK_CACHE" != off ]; then |
| 167 | step "clone again: the pack comes from the cache" | |
| 168 | # The repos service says in Server-Timing whether the pack was kept. | |
| 169 | GIT_TRACE_CURL=1 GIT_TRACE_CURL_NO_DATA=1 git -c credential.helper= clone -q "$G1T_URL/$WORKSPACE/$REPO.git" "$WORK/again" 2> "$WORK/trace" | |
| 170 | grep -qi 'server-timing:.*pack;desc=hit' "$WORK/trace" || fail "the second clone's pack was not kept: $(grep -io 'pack;desc=[a-z]*' "$WORK/trace" | tr '\n' ' ')" | |
| 171 | diff -qr --exclude=.git "$WORK/clone" "$WORK/again" >/dev/null || fail "the kept pack differs" | |
| 172 | echo "hit" | |
| 173 | fi | |
| 174 | ||
| Running g1t yourself: the design, a docker compose proof, and a guide to what works today | 175 | step "open an issue" |
| 176 | out="$(post "/$WORKSPACE/$REPO/issues/new" --data-urlencode "title=It works" --data-urlencode "body=Opened by smoke.sh")" | |
| 177 | echo "$out" | |
| 178 | case "$out" in 30[23]*/issues/1) ;; *) fail "issue: $out $(head -c 300 "$WORK/body")" ;; esac | |
| 179 | [ "$(get "/$WORKSPACE/$REPO/issues/1")" = 200 ] || fail "issue page" | |
| 180 | grep -q "It works" "$WORK/body" || fail "issue page does not show the title" | |
| 181 | ||
| 182 | step "browse code in the site" | |
| 183 | [ "$(get "/$WORKSPACE/$REPO/code")" = 200 ] || fail "code page" | |
| 184 | grep -q "README.md" "$WORK/body" || fail "code page does not list README.md" | |
| 185 | [ "$(get "/$WORKSPACE/$REPO/blob/main/src/main.rs")" = 200 ] || fail "blob page" | |
| 186 | grep -q "hello from g1t" "$WORK/body" || fail "blob page does not show the file" | |
| 187 | [ "$(get "/$WORKSPACE/$REPO/commits")" = 200 ] || fail "commits page" | |
| 188 | grep -q "First commit" "$WORK/body" || fail "commits page does not show the commit" | |
| 189 | ||
| Merge branch 'worktree-agent-aaf03bdceac799c89' | 190 | step "make an access token" |
| 191 | out="$(post /settings/tokens --data-urlencode "intent=add-token" --data-urlencode "label=smoke" --data-urlencode "preset=full" --data-urlencode "expires=7")" | |
| 192 | echo "$out" | |
| 193 | TOKEN="$(grep -ao 'g1t_[0-9A-Za-z_-]*' "$WORK/body" | head -1 || true)" | |
| 194 | [ -n "$TOKEN" ] || fail "no token in the tokens page: $out" | |
| 195 | echo "token ${TOKEN:0:8}…" | |
| 196 | ||
| 197 | step "the API answers at $API_URL" | |
| 198 | [ "$(api GET /user)" = 200 ] || fail "GET /user: $(head -c 300 "$WORK/api")" | |
| 199 | [ "$(json username)" = "$USER_NAME" ] || fail "GET /user names $(json username), not $USER_NAME" | |
| 200 | [ "$(api GET /)" = 200 ] || fail "GET /" | |
| 201 | [ "$(json mcp_url)" = "$MCP_URL" ] || fail "the API's index names $(json mcp_url) as MCP, not $MCP_URL" | |
| 202 | [ "$(json git_url)" = "$G1T_URL/{owner}/{name}.git" ] || fail "git_url is $(json git_url)" | |
| 203 | curl -sS -o "$WORK/api" "$API_URL/.well-known/oauth-authorization-server" | |
| 204 | [ "$(json issuer)" = "$API_URL" ] || fail "the OAuth issuer is $(json issuer), not $API_URL" | |
| 205 | [ "$(json authorization_endpoint)" = "$G1T_URL/oauth/authorize" ] || fail "people approve at $(json authorization_endpoint)" | |
| 206 | echo "issuer $(json issuer)" | |
| 207 | code="$(curl -sS -o "$WORK/api" -D "$WORK/headers" -w '%{http_code}' -X POST -H "content-type: application/json" \ | |
| 208 | --data '{"jsonrpc":"2.0","id":1,"method":"tools/list"}' "$MCP_URL")" | |
| 209 | [ "$code" = 401 ] || fail "MCP without a token answered $code" | |
| 210 | grep -qi "resource_metadata=\"$API_URL/.well-known/oauth-protected-resource/mcp\"" "$WORK/headers" || fail "MCP's challenge: $(grep -i www-authenticate "$WORK/headers")" | |
| 211 | code="$(curl -sS -o "$WORK/api" -w '%{http_code}' -X POST -H "Authorization: Bearer $TOKEN" -H "content-type: application/json" \ | |
| 212 | -H "accept: application/json, text/event-stream" --data '{"jsonrpc":"2.0","id":1,"method":"tools/list"}' "$MCP_URL")" | |
| 213 | [ "$code" = 200 ] && grep -q '"tools"' "$WORK/api" || fail "MCP tools/list: $code $(head -c 300 "$WORK/api")" | |
| 214 | echo "MCP lists its tools at $MCP_URL" | |
| 215 | ||
| Self-hosting: RustFS for S3-compatible storage, buckets and the packs' lifecycle rule made with the AWS CLI | 216 | if [ "$PACKAGES" != off ]; then |
| 217 | step "publish an npm package and install it" | |
| 218 | # The tarball is kept in the packages store (S3), and read back from it. | |
| 219 | npmrc="@$WORKSPACE:registry=$G1T_URL/-/npm/ | |
| 220 | //${G1T_URL#*://}/-/npm/:_authToken=$TOKEN" | |
| 221 | mkdir -p "$WORK/pkg" "$WORK/app" | |
| 222 | printf '%s\n' "$npmrc" > "$WORK/pkg/.npmrc" | |
| 223 | printf '%s\n' "$npmrc" > "$WORK/app/.npmrc" | |
| 224 | printf '{"name":"@%s/%s","version":"1.0.0","repository":"%s/%s/%s","main":"index.js"}\n' \ | |
| 225 | "$WORKSPACE" "$REPO" "$G1T_URL" "$WORKSPACE" "$REPO" > "$WORK/pkg/package.json" | |
| 226 | printf 'module.exports = "published by smoke.sh %s";\n' "$RUN" > "$WORK/pkg/index.js" | |
| 227 | (cd "$WORK/pkg" && npm publish --silent) || fail "npm publish" | |
| 228 | (cd "$WORK/app" && npm init -y >/dev/null && npm install --silent --no-audit --no-fund "@$WORKSPACE/$REPO@1.0.0") || fail "npm install" | |
| 229 | got="$(cd "$WORK/app" && node -p "require('@$WORKSPACE/$REPO')")" | |
| 230 | [ "$got" = "published by smoke.sh $RUN" ] || fail "the installed package says: $got" | |
| 231 | echo "installed @$WORKSPACE/$REPO@1.0.0" | |
| 232 | fi | |
| 233 | ||
| Merge branch 'worktree-agent-aaf03bdceac799c89' | 234 | step "a pull request from a branch, merged" |
| 235 | git -C "$WORK/clone" config credential.helper "" | |
| 236 | commit_file "$WORK/clone" "$remote" from-branch docs/branch.md | |
| 237 | [ "$(api POST "/repos/$WORKSPACE/$REPO/pulls" '{"title":"From a branch","branch":"from-branch","body":"Opened by smoke.sh"}')" = 200 ] \ | |
| 238 | || fail "open from a branch: $(head -c 300 "$WORK/api")" | |
| 239 | BRANCH_PULL="$(json pull.number)" | |
| 240 | echo "pull request #$BRANCH_PULL ($(json pull.status))" | |
| 241 | [ "$(get "/$WORKSPACE/$REPO/pull/$BRANCH_PULL")" = 200 ] && grep -q "From a branch" "$WORK/body" || fail "pull request page" | |
| 242 | [ "$(api POST "/repos/$WORKSPACE/$REPO/pulls/$BRANCH_PULL/merge" '{}')" = 200 ] || fail "merge: $(head -c 300 "$WORK/api")" | |
| 243 | until_status "$BRANCH_PULL" merged | |
| 244 | main_has docs/branch.md || fail "main does not have the branch's change" | |
| 245 | echo "merged onto main" | |
| 246 | ||
| 247 | step "a pull request from a fork, merged" | |
| 248 | [ "$(api POST "/repos/$WORKSPACE/$REPO/pulls" '{"title":"From a fork","agent":"smoke"}')" = 200 ] \ | |
| 249 | || fail "open with a fork: $(head -c 300 "$WORK/api")" | |
| 250 | FORK_PULL="$(json pull.number)" | |
| 251 | fork_remote="$(json git.remote)" | |
| 252 | echo "pull request #$FORK_PULL ($(json pull.status)), fork $fork_remote" | |
| 253 | case "$fork_remote" in "$G1T_URL"/*) ;; *) fail "the fork's remote is not on $G1T_URL: $fork_remote" ;; esac | |
| 254 | [ "$fork_remote" != "$G1T_URL/$WORKSPACE/$REPO.git" ] || fail "no fork was made" | |
| 255 | authed_fork="${fork_remote/:\/\//://$USER_NAME:$TOKEN@}" | |
| 256 | git -c credential.helper= clone -q "$authed_fork" "$WORK/fork" | |
| 257 | commit_file "$WORK/fork" "$authed_fork" "$(git -C "$WORK/fork" branch --show-current)" docs/fork.md | |
| 258 | [ "$(api POST "/repos/$WORKSPACE/$REPO/pulls/$FORK_PULL/ready" '{"summary":"Adds docs/fork.md, from a fork."}')" = 200 ] \ | |
| 259 | || fail "ready: $(head -c 300 "$WORK/api")" | |
| 260 | [ "$(api POST "/repos/$WORKSPACE/$REPO/pulls/$FORK_PULL/merge" '{}')" = 200 ] || fail "merge: $(head -c 300 "$WORK/api")" | |
| 261 | until_status "$FORK_PULL" merged | |
| 262 | main_has docs/fork.md || fail "main does not have the fork's change" | |
| 263 | echo "merged onto main" | |
| 264 | ||
| 265 | step "the merge queue takes a pull request, and gives it back" | |
| 266 | [ "$(api PATCH "/repos/$WORKSPACE/$REPO/settings" '{"merge_queue":true}')" = 200 ] || fail "turn the queue on: $(head -c 300 "$WORK/api")" | |
| 267 | git -C "$WORK/clone" fetch -q "$G1T_URL/$WORKSPACE/$REPO.git" main | |
| 268 | git -C "$WORK/clone" switch -q -c queued FETCH_HEAD | |
| 269 | commit_file "$WORK/clone" "$remote" queued docs/queued.md | |
| 270 | [ "$(api POST "/repos/$WORKSPACE/$REPO/pulls" '{"title":"Through the queue","branch":"queued"}')" = 200 ] || fail "open: $(head -c 300 "$WORK/api")" | |
| 271 | QUEUE_PULL="$(json pull.number)" | |
| 272 | [ "$(api POST "/repos/$WORKSPACE/$REPO/pulls/$QUEUE_PULL/merge" '{}')" = 200 ] || fail "merge into the queue: $(head -c 300 "$WORK/api")" | |
| 273 | [ "$(api GET "/repos/$WORKSPACE/$REPO/queue")" = 200 ] || fail "queue: $(head -c 300 "$WORK/api")" | |
| 274 | [ "$(json enabled)" = true ] || fail "the queue is not on" | |
| 275 | node -e 'const q = JSON.parse(require("fs").readFileSync(process.argv[1], "utf8")); const e = q.active.find((e) => e.number === Number(process.argv[2])); if (!e) process.exit(1); console.log(`#${e.number} is ${e.state} in the queue`)' "$WORK/api" "$QUEUE_PULL" \ | |
| 276 | || fail "#$QUEUE_PULL is not in the queue: $(head -c 400 "$WORK/api")" | |
| 277 | [ "$(get "/$WORKSPACE/$REPO/queue")" = 200 ] && grep -q "Through the queue" "$WORK/body" || fail "queue page" | |
| 278 | # Testing a queued state needs a sandbox, and agents are off: take it out. | |
| 279 | out="$(post "/$WORKSPACE/$REPO/pull/$QUEUE_PULL" --data-urlencode "action=unqueue")" | |
| 280 | echo "unqueue: $out" | |
| 281 | [ "$(api GET "/repos/$WORKSPACE/$REPO/queue")" = 200 ] || fail "queue" | |
| 282 | node -e 'const q = JSON.parse(require("fs").readFileSync(process.argv[1], "utf8")); process.exit(q.active.some((e) => e.number === Number(process.argv[2])) ? 1 : 0)' "$WORK/api" "$QUEUE_PULL" \ | |
| 283 | || fail "#$QUEUE_PULL is still in the queue" | |
| 284 | [ "$(api PATCH "/repos/$WORKSPACE/$REPO/settings" '{"merge_queue":false}')" = 200 ] || fail "turn the queue off" | |
| 285 | [ "$(api POST "/repos/$WORKSPACE/$REPO/pulls/$QUEUE_PULL/merge" '{}')" = 200 ] || fail "merge: $(head -c 300 "$WORK/api")" | |
| 286 | until_status "$QUEUE_PULL" merged | |
| 287 | main_has docs/queued.md || fail "main does not have the change" | |
| 288 | echo "out of the queue, then merged onto main" | |
| 289 | ||
| 290 | if [ -n "$SCHEDULER_ONCE" ]; then | |
| 291 | step "every cron handler runs" | |
| 292 | $SCHEDULER_ONCE || fail "a cron handler failed" | |
| 293 | fi | |
| 294 | ||
| Running g1t yourself: the design, a docker compose proof, and a guide to what works today | 295 | printf '\nAll checks passed: %s/%s/%s\n' "$G1T_URL" "$WORKSPACE" "$REPO" |
This file's history is long; its oldest lines are credited to the oldest commit read.