Skip to content

Commit 96628c6

Browse files
authored
Merge branch 'master' into bot/fix-usetable-isready-stale
2 parents dfcbc3d + 6d9cf69 commit 96628c6

48 files changed

Lines changed: 920 additions & 607 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/check-merge-labels.yml

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,17 +2,21 @@ name: Check merge labels
22

33
on:
44
pull_request:
5-
types: [labeled, unlabeled]
5+
types: [opened, reopened, labeled, unlabeled]
66
merge_group:
7+
78
permissions: read-all
89

910
jobs:
1011
label_checks:
12+
name: Check merge labels
1113
runs-on: ubuntu-latest
1214
steps:
13-
- id: manually_blocked
14-
if: |
15-
contains(github.event.pull_request.labels.*.name, 'do not merge')
15+
- if: github.event_name == 'pull_request' && contains(github.event.pull_request.labels.*.name, 'do not merge')
1616
run: |
1717
echo "This is labeled \"Do not merge\"."
1818
exit 1
19+
20+
# If we're in a merge queue, the PR has already passed checks these checks before being added to the queue.
21+
- if: github.event_name == 'merge_group'
22+
run: echo "Merge group run; skipping merge-label checks."

.github/workflows/ci.yml

Lines changed: 0 additions & 126 deletions
Original file line numberDiff line numberDiff line change
@@ -178,132 +178,6 @@ jobs:
178178
exit 1
179179
}
180180
181-
smoketests-python:
182-
needs: [lints]
183-
name: Smoketests (Python Legacy) (${{matrix.name}})
184-
strategy:
185-
matrix:
186-
include:
187-
- name: Linux
188-
runner: spacetimedb-new-runner-2
189-
smoketest_args: --docker
190-
- name: Windows
191-
runner: windows-latest
192-
smoketest_args: --no-build-cli
193-
runs-on: ${{ matrix.runner }}
194-
timeout-minutes: 120
195-
env:
196-
CARGO_TARGET_DIR: ${{ github.workspace }}/target
197-
steps:
198-
- name: Find Git ref
199-
env:
200-
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
201-
shell: bash
202-
run: |
203-
PR_NUMBER="${{ github.event.inputs.pr_number || null }}"
204-
if test -n "${PR_NUMBER}"; then
205-
GIT_REF="$( gh pr view --repo clockworklabs/SpacetimeDB $PR_NUMBER --json headRefName --jq .headRefName )"
206-
else
207-
GIT_REF="${{ github.ref }}"
208-
fi
209-
echo "GIT_REF=${GIT_REF}" >>"$GITHUB_ENV"
210-
- name: Checkout sources
211-
uses: actions/checkout@v4
212-
with:
213-
ref: ${{ env.GIT_REF }}
214-
- uses: dsherret/rust-toolchain-file@v1
215-
- name: Set default rust toolchain
216-
run: rustup default $(rustup show active-toolchain | cut -d' ' -f1)
217-
- name: Cache Rust dependencies
218-
uses: Swatinem/rust-cache@v2
219-
with:
220-
workspaces: ${{ github.workspace }}
221-
shared-key: spacetimedb
222-
cache-on-failure: false
223-
cache-all-crates: true
224-
cache-workspace-crates: true
225-
prefix-key: v1
226-
227-
# This step shouldn't be needed, but somehow we end up with caches that are missing librusty_v8.a.
228-
# ChatGPT suspects that this could be due to different build invocations using the same target dir,
229-
# and this makes sense to me because we only see it in this job where we mix `cargo build -p` with
230-
# `cargo build --manifest-path` (which apparently build different dependency trees).
231-
# However, we've been unable to fix it so... /shrug
232-
- name: Check v8 outputs
233-
shell: bash
234-
run: |
235-
find "${CARGO_TARGET_DIR}"/ -type f | grep '[/_]v8' || true
236-
if ! [ -f "${CARGO_TARGET_DIR}"/debug/gn_out/obj/librusty_v8.a ]; then
237-
echo "Could not find v8 output file librusty_v8.a; rebuilding manually."
238-
cargo clean -p v8 || true
239-
cargo build -p v8
240-
fi
241-
242-
- uses: actions/setup-dotnet@v4
243-
with:
244-
global-json-file: global.json
245-
246-
- name: Override NuGet packages
247-
shell: bash
248-
run: |
249-
dotnet pack -c Release crates/bindings-csharp/BSATN.Runtime
250-
dotnet pack -c Release crates/bindings-csharp/Runtime
251-
cd sdks/csharp
252-
./tools~/write-nuget-config.sh ../..
253-
254-
# nodejs and pnpm are required for the typescript quickstart smoketest
255-
- name: Set up Node.js
256-
uses: actions/setup-node@v4
257-
with:
258-
node-version: 22
259-
260-
- uses: pnpm/action-setup@v4
261-
with:
262-
run_install: true
263-
264-
- name: Install psql (Windows)
265-
if: runner.os == 'Windows'
266-
run: choco install psql -y --no-progress
267-
shell: powershell
268-
269-
- name: Build crates
270-
run: cargo build -p spacetimedb-cli -p spacetimedb-standalone -p spacetimedb-update
271-
272-
- name: Build and start database (Linux)
273-
if: runner.os == 'Linux'
274-
run: |
275-
# Our .dockerignore omits `target`, which our CI Dockerfile needs.
276-
rm .dockerignore
277-
docker compose -f .github/docker-compose.yml up -d
278-
279-
- name: Build and start database (Windows)
280-
if: runner.os == 'Windows'
281-
run: |
282-
# Fail properly if any individual command fails
283-
$ErrorActionPreference = 'Stop'
284-
$PSNativeCommandUseErrorActionPreference = $true
285-
286-
Start-Process target/debug/spacetimedb-cli.exe -ArgumentList 'start --pg-port 5432'
287-
cd modules
288-
# the sdk-manifests on windows-latest are messed up, so we need to update them
289-
dotnet workload config --update-mode manifests
290-
dotnet workload update
291-
292-
- uses: actions/setup-python@v5
293-
with: { python-version: "3.12" }
294-
if: runner.os == 'Windows'
295-
296-
- name: Install python deps
297-
run: python -m pip install -r smoketests/requirements.txt
298-
299-
- name: Run Python smoketests
300-
# Note: clear_database and replication only work in private
301-
run: python -m smoketests ${{ matrix.smoketest_args }} -x clear_database replication teams
302-
303-
- name: Stop containers (Linux)
304-
if: always() && runner.os == 'Linux'
305-
run: docker compose -f .github/docker-compose.yml down
306-
307181
test:
308182
needs: [lints]
309183
name: Test Suite
Lines changed: 93 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,45 +1,106 @@
1-
name: PR Approval Check
1+
name: Review Checks
22

33
on:
44
pull_request:
5-
types: [opened, synchronize, reopened, ready_for_review]
5+
types: [opened, synchronize, reopened]
66
pull_request_review:
7-
types: [submitted]
7+
types: [submitted, dismissed]
8+
merge_group:
89

910
permissions:
1011
contents: read
12+
pull-requests: read
13+
statuses: write
14+
15+
concurrency:
16+
group: pr-approval-check-${{ github.event.pull_request.number || github.sha }}
17+
cancel-in-progress: true
1118

1219
jobs:
13-
check-approvals:
20+
publish-approval-status:
21+
name: Set approval status
1422
runs-on: ubuntu-latest
15-
# Skip this check if PR is in draft state
16-
if: github.event.pull_request.draft == false
1723

1824
steps:
19-
- name: Checkout code
20-
uses: actions/checkout@v3
25+
- name: Evaluate and publish approval status
26+
uses: actions/github-script@v7
2127
with:
22-
fetch-depth: 0
23-
24-
- name: Check PR approvals
25-
env:
26-
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
27-
run: |
28-
# Check if PR author is clockwork-labs-bot
29-
if [[ "${{ github.event.pull_request.user.login }}" != "clockwork-labs-bot" ]]; then
30-
echo "PR opened by ${{ github.event.pull_request.user.login }}, not clockwork-labs-bot. Skipping check."
31-
exit 0
32-
fi
33-
34-
PR_NUMBER="${{ github.event.pull_request.number }}"
35-
# Get approval count
36-
APPROVALS=$(gh pr view $PR_NUMBER --json reviews -q '.reviews | map(select(.state == "APPROVED")) | length')
37-
38-
echo "PR has $APPROVALS approvals"
39-
40-
if [[ $APPROVALS -lt 2 ]]; then
41-
echo "Error: PRs from clockwork-labs-bot require at least 2 approvals"
42-
exit 1
43-
else
44-
echo "PR has the required number of approvals"
45-
fi
28+
github-token: ${{ secrets.GITHUB_TOKEN }}
29+
script: |
30+
const contextName = "PR approval check";
31+
32+
let targetSha;
33+
let state;
34+
let description;
35+
36+
if (context.eventName === "merge_group") {
37+
targetSha = process.env.GITHUB_SHA;
38+
state = "success";
39+
description = "Merge group entry; approvals already satisfied";
40+
} else {
41+
const pr = context.payload.pull_request;
42+
targetSha = pr.head.sha;
43+
44+
if (pr.user.login !== "clockwork-labs-bot") {
45+
state = "success";
46+
description = "PR author is not clockwork-labs-bot";
47+
} else {
48+
const result = await github.graphql(
49+
`
50+
query($owner: String!, $repo: String!, $number: Int!) {
51+
repository(owner: $owner, name: $repo) {
52+
pullRequest(number: $number) {
53+
latestOpinionatedReviews(first: 100, writersOnly: true) {
54+
nodes {
55+
state
56+
author {
57+
login
58+
}
59+
}
60+
}
61+
}
62+
}
63+
}
64+
`,
65+
{
66+
owner: context.repo.owner,
67+
repo: context.repo.repo,
68+
number: pr.number,
69+
}
70+
);
71+
72+
const effectiveApprovers =
73+
result.repository.pullRequest.latestOpinionatedReviews.nodes
74+
.filter((review) => review.state === "APPROVED")
75+
.map((review) => review.author?.login)
76+
.filter(Boolean);
77+
78+
core.info(
79+
`Latest effective approvers (${effectiveApprovers.length}): ${effectiveApprovers.join(", ")}`
80+
);
81+
82+
if (effectiveApprovers.length < 2) {
83+
state = "failure";
84+
description = "PRs from clockwork-labs-bot require at least 2 approvals";
85+
} else {
86+
state = "success";
87+
description = "PR has the required number of approvals";
88+
}
89+
}
90+
}
91+
92+
core.info(`Publishing status ${state} for ${targetSha}: ${description}`);
93+
94+
// We need to set a separate commit status for this, because it runs on both
95+
// pull_request and pull_request_review events. If we don't set an explicit context,
96+
// what happens is that there are sometimes two separate statuses on the same commit -
97+
// one from each event type. This leads to weird cases where one copy of the check is failed,
98+
// and the other is successful, and the failed one blocks the PR from merging.
99+
await github.rest.repos.createCommitStatus({
100+
owner: context.repo.owner,
101+
repo: context.repo.repo,
102+
sha: targetSha,
103+
state,
104+
context: contextName,
105+
description,
106+
});

crates/bindings/tests/ui/views.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -144,7 +144,6 @@ fn sched_table_view(_: &ViewContext, _args: ScheduledTable) -> Vec<PlayerInfo> {
144144
vec![]
145145
}
146146

147-
148147
#[table(accessor = player_info)]
149148
struct PlayerInfo {
150149
#[unique]

crates/bindings/tests/ui/views.stderr

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -61,20 +61,20 @@ error[E0425]: cannot find type `ScheduledTable` in this scope
6161
| ^^^^^^^^^^^^^^ not found in this scope
6262

6363
error[E0425]: cannot find type `T` in this scope
64-
--> tests/ui/views.rs:202:60
64+
--> tests/ui/views.rs:201:60
6565
|
66-
202 | fn view_nonexistent_table(ctx: &ViewContext) -> impl Query<T> {
66+
201 | fn view_nonexistent_table(ctx: &ViewContext) -> impl Query<T> {
6767
| ^ not found in this scope
6868
|
6969
help: you might be missing a type parameter
7070
|
71-
202 | fn view_nonexistent_table<T>(ctx: &ViewContext) -> impl Query<T> {
71+
201 | fn view_nonexistent_table<T>(ctx: &ViewContext) -> impl Query<T> {
7272
| +++
7373

7474
error[E0425]: cannot find type `T` in this scope
75-
--> tests/ui/views.rs:202:60
75+
--> tests/ui/views.rs:201:60
7676
|
77-
202 | fn view_nonexistent_table(ctx: &ViewContext) -> impl Query<T> {
77+
201 | fn view_nonexistent_table(ctx: &ViewContext) -> impl Query<T> {
7878
| ^ not found in this scope
7979

8080
error[E0277]: the trait bound `ViewKind<ReducerContext>: ViewKindTrait` is not satisfied
@@ -411,9 +411,9 @@ help: the trait `SpacetimeType` is not implemented for `NotSpacetimeType`
411411
= note: required for `Option<NotSpacetimeType>` to implement `SpacetimeType`
412412

413413
error[E0277]: the trait bound `{integer}: RHS<Player, spacetimedb::Identity>` is not satisfied
414-
--> tests/ui/views.rs:160:49
414+
--> tests/ui/views.rs:159:49
415415
|
416-
160 | ctx.from.player().r#where(|a| a.identity.eq(42)).build()
416+
159 | ctx.from.player().r#where(|a| a.identity.eq(42)).build()
417417
| -- ^^ the trait `RHS<Player, spacetimedb::Identity>` is not implemented for `{integer}`
418418
| |
419419
| required by a bound introduced by this call
@@ -435,9 +435,9 @@ note: required by a bound in `Col::<T, V>::eq`
435435
| ^^^^^^^^^ required by this bound in `Col::<T, V>::eq`
436436

437437
error[E0277]: the trait bound `u32: RHS<PlayerInfo, u8>` is not satisfied
438-
--> tests/ui/views.rs:166:49
438+
--> tests/ui/views.rs:165:49
439439
|
440-
166 | ctx.from.player_info().r#where(|a| a.age.eq(4200u32)).build()
440+
165 | ctx.from.player_info().r#where(|a| a.age.eq(4200u32)).build()
441441
| -- ^^^^^^^ the trait `RHS<PlayerInfo, u8>` is not implemented for `u32`
442442
| |
443443
| required by a bound introduced by this call
@@ -457,9 +457,9 @@ note: required by a bound in `Col::<T, V>::eq`
457457
= note: this error originates in the macro `impl_rhs` (in Nightly builds, run with -Z macro-backtrace for more info)
458458

459459
error[E0308]: mismatched types
460-
--> tests/ui/views.rs:175:62
460+
--> tests/ui/views.rs:174:62
461461
|
462-
175 | .left_semijoin(ctx.from.player(), |a, b| a.weight.eq(b.identity))
462+
174 | .left_semijoin(ctx.from.player(), |a, b| a.weight.eq(b.identity))
463463
| -- ^^^^^^^^^^ expected `IxCol<Player, u32>`, found `IxCol<Player, Identity>`
464464
| |
465465
| arguments to this method are incorrect
@@ -473,15 +473,15 @@ note: method defined here
473473
| ^^
474474

475475
error[E0609]: no field `age` on type `&PlayerInfoIxCols`
476-
--> tests/ui/views.rs:185:72
476+
--> tests/ui/views.rs:184:72
477477
|
478-
185 | .right_semijoin(ctx.from.player_info(), |a, b| a.identity.eq(b.age))
478+
184 | .right_semijoin(ctx.from.player_info(), |a, b| a.identity.eq(b.age))
479479
| ^^^ unknown field
480480
|
481481
= note: available fields are: `identity`, `weight`
482482

483483
error[E0599]: no method named `xyz` found for struct `QueryBuilder` in the current scope
484-
--> tests/ui/views.rs:203:14
484+
--> tests/ui/views.rs:202:14
485485
|
486-
203 | ctx.from.xyz().build()
486+
202 | ctx.from.xyz().build()
487487
| ^^^ method not found in `QueryBuilder`

crates/cli/src/subcommands/login.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@ pub async fn exec(mut config: Config, args: &ArgMatches) -> Result<(), anyhow::E
7171
Ok(identity) => println!("Logged in with identity {identity}"),
7272
Err(_) => println!("Token saved."),
7373
}
74+
return Ok(());
7475
}
7576

7677
if let Some(server) = server_issued_login {

0 commit comments

Comments
 (0)