Skip to content

Commit f534ec7

Browse files
committed
Keep readable workspace members' requires in Go selection
read_workspace dropped every main module when any `use` member was outside the root or unreadable, so a readable member requiring a higher version no longer marked a workspace zip pin inert and vex attested a replace go does not build (Bugbot, golang.rs:271). In a workspace the members' requires only ever prove a replace inert, so the readable ones still count when another member cannot be read. Co-Authored-By: Claude <noreply@anthropic.com>
1 parent 2beda00 commit f534ec7

1 file changed

Lines changed: 47 additions & 14 deletions

File tree

  • crates/socket-patch-core/src/vex/discover

‎crates/socket-patch-core/src/vex/discover/golang.rs‎

Lines changed: 47 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -165,7 +165,7 @@ async fn extract_with(ctx: &DiscoverCtx<'_>, out: &mut Discovery, workspaces: bo
165165
.any(|e| e.owner == Some(ReplaceOwner::Hosted));
166166
let mut graph = Graph {
167167
required,
168-
mains: Some(vec![MainModule::new(go_mod.as_deref().unwrap_or_default())]),
168+
mains: vec![MainModule::new(go_mod.as_deref().unwrap_or_default())],
169169
workspace: go_work.is_some(),
170170
};
171171
let mut sums = SumPins::default();
@@ -191,9 +191,8 @@ struct Graph {
191191
/// as a root-only reader can tell).
192192
required: HashMap<String, String>,
193193
/// The main modules: the root module, or every readable in-root
194-
/// `go.work` `use` member. `None` when a member is outside the root or
195-
/// unreadable.
196-
mains: Option<Vec<MainModule>>,
194+
/// `go.work` `use` member.
195+
mains: Vec<MainModule>,
197196
/// A `go.work` is in effect.
198197
workspace: bool,
199198
}
@@ -221,7 +220,7 @@ impl Graph {
221220
/// module past every `require` and sum line discovery reads. Only a
222221
/// higher version in that evidence proves the replace inert.
223222
fn select(&self, module: &str, version: &str, zips: &[&str]) -> Selection {
224-
let mains = self.mains.as_deref().unwrap_or_default();
223+
let mains = &self.mains;
225224
let required = mains
226225
.iter()
227226
.filter_map(|m| m.required.get(module).map(String::as_str))
@@ -241,19 +240,20 @@ impl Graph {
241240

242241
/// The `use` members of `go.work` as main modules, and the sum files go
243242
/// verifies against in workspace mode: `go.work.sum` and each member's
244-
/// `go.sum` (the root's only when `.` is a member). The main modules are
245-
/// `None` when a member's go.mod is outside the root or unreadable.
243+
/// `go.sum` (the root's only when `.` is a member). A member whose go.mod
244+
/// is outside the root or unreadable adds no main module; the others still
245+
/// count, since in a workspace their `require`s only ever prove a replace
246+
/// inert, never selected.
246247
async fn read_workspace(
247248
ctx: &DiscoverCtx<'_>,
248249
out: &mut Discovery,
249250
go_mod: Option<&str>,
250251
go_work: &str,
251-
) -> (Option<Vec<MainModule>>, Vec<String>) {
252-
let mut mains = Some(Vec::new());
252+
) -> (Vec<MainModule>, Vec<String>) {
253+
let mut mains = Vec::new();
253254
let mut files = vec![GO_WORK_SUM.to_string()];
254255
for dir in go_mod_edit::parse_use_dirs(go_work) {
255256
let Some(dir) = member_dir(&dir) else {
256-
mains = None;
257257
continue;
258258
};
259259
let text = if dir.is_empty() {
@@ -265,10 +265,8 @@ async fn read_workspace(
265265
None => None,
266266
}
267267
};
268-
match (text, mains.as_mut()) {
269-
(Some(text), Some(mains)) => mains.push(MainModule::new(&text)),
270-
(Some(_), None) => {}
271-
(None, _) => mains = None,
268+
if let Some(text) = text {
269+
mains.push(MainModule::new(&text));
272270
}
273271
let sum = member_file(&dir, GO_SUM);
274272
if !files.contains(&sum) {
@@ -1219,6 +1217,41 @@ mod tests {
12191217
}
12201218
}
12211219

1220+
/// A member that cannot be read (outside the root, or missing its
1221+
/// go.mod) does not hide another member's higher require.
1222+
#[tokio::test]
1223+
async fn workspace_unreadable_member_keeps_other_members_requires() {
1224+
let m = gopatch(UUID_A);
1225+
let sver = "v1.4.2-socketpatch.1";
1226+
for extra in ["../outside", "./missing"] {
1227+
let p = Project::new();
1228+
p.write("go.mod", BASE_GO_MOD)
1229+
.write(
1230+
"go.work",
1231+
format!(
1232+
"go 1.21\n\nuse (\n\t.\n\t{extra}\n\t./svc\n)\n\nreplace {MODULE} {VERSION} => {m} {sver}\n"
1233+
),
1234+
)
1235+
.write(
1236+
"go.work.sum",
1237+
format!("{m} {sver} {ZIP_H1}\n{m} {sver}/go.mod {MOD_H1}\n"),
1238+
)
1239+
.write(
1240+
"svc/go.mod",
1241+
format!("module example.com/svc\n\ngo 1.21\n\nrequire {MODULE} v1.5.0\n"),
1242+
);
1243+
let out = run(&p).await;
1244+
assert_refs(&out, &[]);
1245+
assert!(
1246+
out.diagnostics
1247+
.iter()
1248+
.any(|d| d.code == DIAG_REF_INVALID && d.detail.contains("selects v1.5.0")),
1249+
"{extra}: {:?}",
1250+
out.diagnostics
1251+
);
1252+
}
1253+
}
1254+
12221255
/// go verifies against the sum files of the mode it builds in: in
12231256
/// workspace mode `go.work.sum` and the members' go.sum (the root's only
12241257
/// when `.` is a member); under `GOWORK=off` the root go.sum alone, with

0 commit comments

Comments
 (0)