Commit fd260f75bb

fd260f75bbf4cb2c5a1c09b6039427f25a2fa7db

parent: f8856437fb

Verified · cmc

cmc <hello@cleberg.net> · 2026-09-20 01:23 UTC

Move the live suite's fixtures off krz/gitbay-ios

The issue and merge-request fixtures now live in ios-smoke/ui-smoke-edit,
alongside the file the edit flow commits to. The app repository no longer
accumulates smoke issues and closed merge requests, and no longer needs a
ui-smoke branch.

smoke-account.sh seeds ui-smoke divergent from main in the fixture repo,
which the merge-request flows need in both directions, and reruns now
reach that step on an existing repo. The milestone the issue flow assigns
is created by the suite, as the API can make one.

Closes #9

Layout: unified · split

gitbayUITests/LiveSmokeUITests.swift +41 −23
@@ -11,9 +11,10 @@ import XCTest
1111/// -only-testing:gitbayUITests ...
1212///
1313/// They run as the `ios-smoke` account, a krz admin that owns the
14/// scratch and fixture repositories (smoke-account.sh provisions it), and
15/// assume branch `ui-smoke` exists on krz/gitbay-ios. A signed-out device
16/// is signed in at setUp from TEST_RUNNER_GITBAY_UITEST_TOKEN.
14/// scratch and fixture repositories (smoke-account.sh provisions it).
15/// Everything they write goes to those, never to krz/gitbay-ios. A
16/// signed-out device is signed in at setUp from
17/// TEST_RUNNER_GITBAY_UITEST_TOKEN.
1718final class LiveSmokeUITests: XCTestCase {
1819
1920 private var app: XCUIApplication!
@@ -32,7 +33,11 @@ final class LiveSmokeUITests: XCTestCase {
3233 static let smokeUser = "ios-smoke"
3334 static let smokeProfileDescription = "Live UI smoke account for gitbay-ios"
3435 static let smokePGPEmail = "ios-smoke+pgp@gitbay.org"
35 static let editRepo = "\(smokeUser)/ui-smoke-edit"
36
37 /// The repository the write flows work in: the fixture issue and
38 /// merge requests, and the file testBlameAndEditFlows edits.
39 /// smoke-account.sh seeds it, with `main` and `ui-smoke` divergent.
40 static let fixtureRepo = "\(smokeUser)/ui-smoke-edit"
3641
3742 override func setUpWithError() throws {
3843 try XCTSkipUnless(
@@ -56,6 +61,8 @@ final class LiveSmokeUITests: XCTestCase {
5661 deleteScratchRepo()
5762 }
5863 if name.contains("testCreationAndEditingFlows") {
64 try requireFixtureRepo()
65 ensureFixtureMilestone()
5966 ensureFixtureIssue()
6067 try requireFixtureBranch()
6168 }
@@ -69,6 +76,7 @@ final class LiveSmokeUITests: XCTestCase {
6976 ensureOrgFixtures()
7077 }
7178 if name.contains("testCloseInFavourFlow") {
79 try requireFixtureRepo()
7280 try requireFixtureBranch()
7381 closeSmokeMergeRequests()
7482 try openSupersedeFixtures()
@@ -143,7 +151,7 @@ final class LiveSmokeUITests: XCTestCase {
143151 "--title", Self.successorTitle])
144152 let open = openSmokeMergeRequests().map { $0.title }
145153 try XCTSkipUnless(open.contains(Self.supersededTitle) && open.contains(Self.successorTitle), """
146 could not open both fixture merge requests on krz/gitbay-ios \
154 could not open both fixture merge requests on \(Self.fixtureRepo) \
147155 (have \(open)); the ui-smoke branch may be level with main.
148156 """)
149157 }
@@ -175,6 +183,19 @@ final class LiveSmokeUITests: XCTestCase {
175183 _ = runCommand(["repo", "delete", Self.scratchRepo + "-2", "--yes"])
176184 }
177185
186 /// The milestone the editing flow assigns. Created rather than
187 /// required: unlike a branch, the API can make one.
188 static let fixtureMilestone = "v1.0.0"
189
190 private func ensureFixtureMilestone() {
191 guard let data = readCommand(["milestone", "list", Self.fixtureRepo, "--state", "all"]),
192 let envelope = try? JSONSerialization.jsonObject(with: data) as? [String: Any]
193 else { return }
194 let rows = envelope["data"] as? [[String: Any]] ?? []
195 if rows.contains(where: { $0["title"] as? String == Self.fixtureMilestone }) { return }
196 _ = runCommand(["milestone", "create", Self.fixtureRepo, Self.fixtureMilestone])
197 }
198
178199 /// The issue the editing flow works on. It is a fixture, not a real
179200 /// issue: pinning the test to whatever issue happened to be open put
180201 /// it at the mercy of the project moving on, and it duly broke when
@@ -200,8 +221,6 @@ final class LiveSmokeUITests: XCTestCase {
200221 )
201222 }
202223
203 static let fixtureRepo = "krz/gitbay-ios"
204
205224 /// The MR flow needs a source branch carrying a commit main does not
206225 /// have. Nothing in the app or the API can create a branch — that is
207226 /// a push — so this only checks, and says so plainly rather than
@@ -214,9 +233,9 @@ final class LiveSmokeUITests: XCTestCase {
214233 else { return } // no token, or the instance is unreachable
215234 let names = branches.compactMap { $0["name"] as? String }
216235 try XCTSkipUnless(names.contains("ui-smoke"), """
217 krz/gitbay-ios has no ui-smoke branch. The MR flow opens a \
218 merge request from it; recreate it with a commit main does \
219 not have (see .gitbay/ui-smoke.md on that branch).
236 \(Self.fixtureRepo) has no ui-smoke branch. The MR flows open \
237 one merge request each way between it and main, so each side \
238 needs a commit the other lacks; smoke-account.sh seeds both.
220239 """)
221240 }
222241
@@ -265,9 +284,9 @@ final class LiveSmokeUITests: XCTestCase {
265284 /// MR create, MR close. One test so the flows share navigation and
266285 /// the writes happen exactly once.
267286 func testCreationAndEditingFlows() throws {
268 openRepo("krz/gitbay-ios")
287 openRepo(Self.fixtureRepo)
269288
270 // --- the fixture issue: milestone picker assigns v1.0.0 ---
289 // --- the fixture issue: milestone picker assigns the fixture ---
271290 app.staticTexts["Issues"].firstMatch.tap()
272291 let issueRow = app.staticTexts
273292 .containing(NSPredicate(format: "label CONTAINS 'ui-smoke fixture'")).firstMatch
@@ -280,11 +299,11 @@ final class LiveSmokeUITests: XCTestCase {
280299 XCTAssertTrue(milestoneMenu.waitForExistence(timeout: 10))
281300 milestoneMenu.tap()
282301 let milestoneChoice = app.buttons
283 .containing(NSPredicate(format: "label BEGINSWITH 'v1.0.0'")).firstMatch
302 .containing(NSPredicate(format: "label BEGINSWITH %@", Self.fixtureMilestone)).firstMatch
284303 XCTAssertTrue(milestoneChoice.waitForExistence(timeout: 5), "milestone menu did not open")
285304 milestoneChoice.tap()
286305 // The reload renders the assigned milestone in the header row.
287 XCTAssertTrue(app.staticTexts["v1.0.0"].firstMatch
306 XCTAssertTrue(app.staticTexts[Self.fixtureMilestone].firstMatch
288307 .waitForExistence(timeout: 10), "milestone not shown after assign")
289308
290309 // --- the fixture issue: edit sheet saves (content unchanged) ---
@@ -415,18 +434,17 @@ final class LiveSmokeUITests: XCTestCase {
415434 keys.tap()
416435 }
417436
418 /// The edit flow saves a change to a real file. Seeding a
419 /// repository's first commit is a push, which no test can make, so
420 /// this only checks — and says why, rather than failing later at
421 /// "ios-smoke/ui-smoke-edit not in the repo list".
437 /// Seeding a repository's first commit is a push, which no test can
438 /// make, so this only checks — and says why, rather than failing
439 /// later at "ios-smoke/ui-smoke-edit not in the repo list".
422440 private func requireFixtureRepo() throws {
423 guard let data = readCommand(["repo", "show", Self.editRepo]),
441 guard let data = readCommand(["repo", "show", Self.fixtureRepo]),
424442 let envelope = try? JSONSerialization.jsonObject(with: data) as? [String: Any]
425443 else { return } // no token, or the instance is unreachable
426444 try XCTSkipUnless(envelope["data"] != nil, """
427 \(Self.editRepo) is missing. The edit flow saves a change to \
428 notes.txt in it; gitbayUITests/smoke-account.sh seeds it (or \
429 push it by hand, see that script) and run again.
445 \(Self.fixtureRepo) is missing. The write flows work in it; \
446 gitbayUITests/smoke-account.sh seeds it (or push it by hand, \
447 see that script) and run again.
430448 """)
431449 }
432450
@@ -1186,7 +1204,7 @@ extension LiveSmokeUITests {
11861204 // previous query, and clearing it from the harness is unreliable.
11871205 app.terminate()
11881206 app.launch()
1189 openRepo(Self.editRepo)
1207 openRepo(Self.fixtureRepo)
11901208 app.staticTexts["Files"].firstMatch.tap()
11911209 let notes = app.staticTexts["notes.txt"].firstMatch
11921210 XCTAssertTrue(notes.waitForExistence(timeout: 15), "notes.txt not in the tree")
gitbayUITests/smoke-account.sh +53 −16
@@ -4,7 +4,9 @@
44# what already exists, so a failed run is rerun as is. It creates the
55# account with a fresh SSH key (~/.ssh/gitbay-ios-smoke), makes it a krz
66# admin, sets its profile description, registers a PGP key, and pushes
7# the ios-smoke/ui-smoke-edit fixture that testBlameAndEditFlows edits.
7# the ios-smoke/ui-smoke-edit fixture the write flows work in: notes.txt
8# for testBlameAndEditFlows, and a ui-smoke branch divergent from main
9# for the merge-request flows.
810# LiveSmokeUITests asserts on the same values, so keep the two in step.
911set -eu
1012
@@ -39,37 +41,72 @@ if ! as_smoke pgp list --json | grep -q "$pgp_email"; then
3941 rm -rf "$gnupg"
4042fi
4143
42if as_smoke repo show "$user/ui-smoke-edit" --json > /dev/null 2>&1; then
43 echo "$user/ui-smoke-edit exists"
44 exit 0
45fi
46as_smoke repo create "$user/ui-smoke-edit"
44repo=$user/ui-smoke-edit
45url=ssh://git@gitbay.org/$repo.git
4746work=$(mktemp -d)
48git -C "$work" init -q -b main
49cat > "$work/README.md" <<'EOF'
47trap 'rm -rf "$work"' EXIT
48
49commit_in_work() {
50 git -C "$work" add -A
51 git -C "$work" -c user.name="$user" -c user.email="$user@gitbay.org" \
52 -c commit.gpgsign=false commit -q -m "$1"
53}
54
55push_work() {
56 GIT_SSH_COMMAND="$smoke_ssh" git -C "$work" push -q "$url" "$1"
57}
58
59if as_smoke repo show "$repo" --json > /dev/null 2>&1; then
60 echo "$repo exists"
61 GIT_SSH_COMMAND="$smoke_ssh" git clone -q "$url" "$work"
62else
63 as_smoke repo create "$repo"
64 git -C "$work" init -q -b main
65 cat > "$work/README.md" <<'EOF'
5066# ui-smoke-edit
5167
5268A fixture repository for the gitbay-ios live UI smoke suite. `notes.txt`
53is edited by `testBlameAndEditFlows` on every run.
69is edited by `testBlameAndEditFlows` on every run, and the `ui-smoke`
70branch is what the merge-request flows open merge requests from.
5471
5572Nothing in the app or the JSON API can seed a repository's first commit
5673(that is a push), so the suite only checks that this repo exists and
5774skips when it does not. `gitbayUITests/smoke-account.sh` in krz/gitbay-ios
5875is what created it.
5976EOF
60cat > "$work/notes.txt" <<'EOF'
77 cat > "$work/notes.txt" <<'EOF'
6178Scratch content for the live UI smoke suite.
6279
6380testBlameAndEditFlows opens this file and saves an edit through the app,
6481which is how the file-editing path is verified end to end. The text does
6582not matter; the file existing does.
6683EOF
67git -C "$work" add -A
68git -C "$work" -c user.name="$user" -c user.email="$user@gitbay.org" -c commit.gpgsign=false \
69 commit -q -m 'fixture repo for the live smoke suite'
70GIT_SSH_COMMAND="$smoke_ssh" \
71 git -C "$work" push -q "ssh://git@gitbay.org/$user/ui-smoke-edit.git" main
72rm -rf "$work"
84 commit_in_work 'fixture repo for the live smoke suite'
85 push_work main
86fi
87
88# The MR flows open one merge request each way between ui-smoke and
89# main, so each side needs a commit the other lacks. Only a push can
90# make a branch, which is why this lives here and not in the suite.
91if ! as_smoke repo refs "$repo" --json | grep -q '"ui-smoke"'; then
92 git -C "$work" checkout -q -b ui-smoke
93 cat > "$work/ui-smoke.md" <<'EOF'
94This branch exists so the live UI smoke suite has a merge request to
95open. It is never merged: the suite opens merge requests both ways
96between it and main, and closes them again.
97EOF
98 commit_in_work 'ui-smoke: a commit main does not have'
99 push_work ui-smoke
100
101 git -C "$work" checkout -q main
102 cat > "$work/main.md" <<'EOF'
103The counterpart of ui-smoke.md: a commit on main that the ui-smoke
104branch does not have, so a merge request from main to ui-smoke has
105something to carry.
106EOF
107 commit_in_work 'main: a commit ui-smoke does not have'
108 push_work main
109fi
73110
74111echo "Mint the suite's token with:"
75112echo " $smoke_ssh git@gitbay.org token create --name ui-smoke --scope full --ttl 30d"