Skip to content

Where people and agents ship software together. The open-source git platform for the whole job: issues, agents, checks and deploys to the edge.

Commit

Sessions read #N as every reader of references does

A session tied itself to what #N named with a scanner of its own: it took references inside code, ignored owner/name#N and workspace#N, and read seven digits where references have nine. It reads them with the shared reader now. The rules' notes name the TypeScript copy where it is, and say that #N names another repository's pull request only above the floor.

G1T-Session:
ses_01m56vxcstesp8b57jt5edge6y
syntaqxcommitted Parent221dfa6Browse files
4 files+77−150/4 viewed
+6−5
11 //! What `#N` in text names, the one set of rules every reader of references
22 //! follows: closing keywords in pull requests and commits (work), Markdown
3−//! on the site, chat and the CLI. `packages/contracts/src/refs.ts` mirrors
4−//! it.
3+//! on the site, chat and the CLI. `apps/web/app/lib/refs.ts` mirrors it.
54 //!
65 //! A reference is `#N`, `owner/name#N` (read in that repository's context)
76 //! or `workspace#N` (in that workspace's). Read in a repository R of
109 //! 1. a pull request of R numbered N;
1110 //! 2. a work item filed in R whose number there was N (an old issue);
1211 //! 3. the work item numbered N in W;
13−//! 4. a pull request numbered N in another repository of W (new pull
14−//! requests are numbered in the workspace, so this is unique).
12+//! 4. a pull request numbered N in another repository of W, when N is
13+//! above W's floor: new pull requests are numbered in the workspace, so
14+//! those are unique; the numbers its repositories used on their own
15+//! before collide, and name none of them from elsewhere.
1516 //!
1617 //! Read in a workspace alone, `#N` is the work item N in W, else a pull
17−//! request numbered N in W. The work service's `resolve_ref` does the
18+//! request numbered N in W, above its floor. The work service's `resolve_ref` does the
1819 //! lookups.
1920 //!
2021 //! What sits in code, a `span` or a fenced block, is no reference: it is
+34−7
247247 self.link(session_id, repo_id, LinkKind::Item, 0, item_id, via).await;
248248 }
249249
250− /// Ties a session to what `#N` in `text` names, read in its repository
251− /// (`refs`): one of its pull requests, or a work item of its workspace.
250+ /// Ties a session to what the references in `text` name, read in its
251+ /// repository as every reader of them reads them
252+ /// (`g1t_contracts::work::refs`, outside code): one of its workspace's
253+ /// pull requests, or work items.
252254 pub(crate) async fn link_refs(&self, session_id: &str, repo_id: &str, text: &str) -> Result<()> {
253255 let Some(workspace) = items::repo_workspace(self, repo_id).await? else {
254256 return Ok(());
255257 };
256− for number in refs_in(text).into_iter().take(MAX_REFS) {
257− match items::resolve(self, repo_id, &workspace, number).await? {
258− Some(Named::PullHere) => self.link_pull(session_id, repo_id, number, LinkVia::Ref).await,
259− Some(Named::Item(id)) => self.link_item(session_id, repo_id, &id, LinkVia::Ref).await,
260− _ => {}
258+ for reference in refs::refs_in_text(text).into_iter().take(MAX_REFS) {
259+ let Some((read_in, named)) = items::resolve_in(self, repo_id, &workspace, &reference).await? else { continue };
260+ match named {
261+ Named::PullHere => self.link_pull(session_id, &read_in, reference.number, LinkVia::Ref).await,
262+ Named::Item(id) => self.link_item(session_id, repo_id, &id, LinkVia::Ref).await,
263+ Named::PullThere(_) => {}
261264 }
262265 }
263266 Ok(())
753756 session.subagents = counts.get(&session.id).copied().unwrap_or_default();
754757 }
755758 }
759+
760+#[cfg(test)]
761+mod ref_tests {
762+ use g1t_contracts::work::refs::{self, Ref, RefScope};
763+
764+ #[test]
765+ fn a_session_reads_references_as_every_reader_does() {
766+ // What link_refs reads: never inside code, and owner/name#N and
767+ // workspace#N as what they name.
768+ let found = refs::refs_in_text("Fixing `#5` in acme/web#7, see acme#9 and #123456789");
769+ let scopes: Vec<(String, u32)> = found
770+ .iter()
771+ .map(|Ref { scope, number }| {
772+ let scope = match scope {
773+ RefScope::Here => "here".to_owned(),
774+ RefScope::Repo(path) => format!("{}/{}", path.namespace, path.name),
775+ RefScope::Workspace(slug) => slug.clone(),
776+ };
777+ (scope, *number)
778+ })
779+ .collect();
780+ assert_eq!(scopes, vec![("acme/web".to_owned(), 7), ("acme".to_owned(), 9), ("here".to_owned(), 123_456_789)]);
781+ }
782+}
+6−3
143143
144144 // --- References and landing ------------------------------------------------
145145
146−/// What `#number` names, read in repository `repo_id` of `workspace`.
147−pub(crate) async fn resolve(work: &Work, repo_id: &str, workspace: &str, number: u32) -> Result<Option<Named>> {
148− Ok(work.lookup_ref(Some(repo_id), workspace, number).await?.named(true))
146+/// What `reference` names, read in repository `repo_id` of `workspace`,
147+/// with the repository it is read in (another of the workspace's, for
148+/// `owner/name#N`): none for another workspace's, or a repository not
149+/// known.
150+pub(crate) async fn resolve_in(work: &Work, repo_id: &str, workspace: &str, reference: &Ref) -> Result<Option<(String, Named)>> {
151+ work.resolve_in(repo_id, workspace, reference).await
149152 }
150153
151154 /// The work item `reference` names, read in `repo`, by id: one of its
+31−0
219219 })
220220 }
221221
222+ /// What `reference` names read in `repo_id` of `workspace`, and the
223+ /// repository it is read in ([`super::resolve_in`]).
224+ pub(super) async fn resolve_in(&self, repo_id: &str, workspace: &str, reference: &Ref) -> Result<Option<(String, Named)>> {
225+ let read_in = match &reference.scope {
226+ RefScope::Here => Some(repo_id.to_owned()),
227+ RefScope::Workspace(named) => {
228+ if !named.eq_ignore_ascii_case(workspace) {
229+ return Ok(None);
230+ }
231+ None
232+ }
233+ RefScope::Repo(path) => {
234+ if !path.namespace.eq_ignore_ascii_case(workspace) {
235+ return Ok(None);
236+ }
237+ let known = self
238+ .db
239+ .prepare("SELECT repo_id AS value FROM repo_workspaces WHERE lower(path) = lower(?)")
240+ .bind(&[format!("{}/{}", path.namespace, path.name).into()])?
241+ .first::<ValueRow>(None)
242+ .await?;
243+ match known {
244+ Some(row) => Some(row.value),
245+ None => return Ok(None),
246+ }
247+ }
248+ };
249+ let found = self.lookup_ref(read_in.as_deref(), workspace, reference.number).await?;
250+ Ok(found.named(read_in.is_some()).map(|named| (read_in.unwrap_or_else(|| repo_id.to_owned()), named)))
251+ }
252+
222253 /// The work items `text`, written in `repo`, closes and is part of,
223254 /// with `own` (a pull request's own work item) closed first. Each of
224255 /// `who` (whoever wrote it, merges it or pushed it) must be able to

Comments

Sign in to comment.