Skip to main content

Repository groups

A repository group links repositories of your workspace that depend on each other, such as an API and the website that calls it. Group them here, and Gryndel knows they belong together. This page explains how to create and change groups, what disabled means, how Gryndel shows the repositories are related, and what groups do today.

What groups do today​

A group does two things:

  • It shows how its repositories are related: which endpoints, packages, database tables, messages and files each one uses from the others, worked out from what Gryndel learned about each repository (see How they are related).
  • Reviews check changes against the other repositories. When a merge or pull request changes something another repository in the group relies on, the review reports what breaks there on the changed line (see What reviews check).

Open the page​

In the sidebar, under KNOWLEDGE, click Repository groups. Everyone in the workspace can see the groups. Only workspace admins can change them; viewers see a note saying so. See Members for the roles.

The groups are listed in a table with their description, how many repositories they hold (and how many of those are active, when some are disabled), who created them and when. Search finds a group by its name, description, creator or any of its repositories. Click a group's name to open its configuration in a popup: its repositories, the buttons to change it, and how its repositories are related. A repository can be in several groups.

Create a group​

  1. Click New group.
  2. Enter a name. It must be different from the other groups in the workspace; upper and lower case don't count as a difference.
  3. Optionally add a description, for example what the repositories do together.
  4. Choose the repositories, then save. The new group opens.

A workspace can have up to 50 groups, and a group up to 50 repositories.

A repository is missing from the list​

The choices come from the workspace's Repositories list, not from the code host directly. When a repository you expect isn't offered, go to Repositories and refresh the list there first (see Refresh the project list), then come back.

Change a group​

Click the group's name, then in its popup:

  • Rename changes its name and description.
  • Add repositories adds more. Repositories already in the group aren't offered.

Saving, or closing the form, returns to the group.

  • Delete group deletes the group and its list of repositories. The repositories themselves are not changed. You are asked to confirm.

Disable or remove a repository​

Each repository in a group has two buttons.

ActionWhat happensGood for
DisableThe repository stays in the group, shown as Disabled and greyed on the map, but is left out of the group's checks. Enable puts it back.A repository you want to keep listed but not count for now, such as one being rewritten
RemoveThe repository leaves the group. You are asked to confirm.A repository that no longer belongs with the others

Neither action touches the repository's code, its settings or its reviews. You can add a removed repository to the group again later.

"Left the workspace"​

A repository that was in a group but is no longer in the workspace's repository list (for example deleted, moved, or no longer visible to Gryndel) is shown as Left the workspace. Remove it from the group, or leave it in case it comes back.

A group's popup shows how its repositories depend on each other. It is worked out from each repository's .gryndel/contracts.yaml: the endpoints, packages, tables, messages and files it provides and uses, which Gryndel writes when it learns the repository. Gryndel reads the file from each repository's default branch, so a learn counts once its merge or pull request is merged.

Contracts and Last learned​

The table of repositories has two more columns:

ContractsMeans
LearnedThe default branch has the file, and none of the files it names (the first 20) has a later commit on the default branch.
Possibly out of dateA file the contracts point at changed after the contracts did (the note names it, or how many). Learn the repository again and merge the proposal. To keep it learned, see Learn again after every merge.
Not merged yetGryndel learned the repository, but its proposal isn't merged, so the default branch has no contracts file yet.
Not learnedThe repository has no contracts file. It takes no part in the map until it is learned and merged.
Cannot readGryndel could not read the repository on the code host; the note says what the host answered.

Last learned shows when Gryndel last learned the repository, linked to its proposal. Admins see Learn or Learn again, which starts a learn as on the repository's Configure panel; it takes a few minutes, and the proposal then waits for you to merge it.

The map​

Each repository is a box. An arrow goes from a repository to one whose endpoints, packages, tables, messages or files it uses, labelled with the first one and how many more there are. A disabled repository and its arrows are greyed and dashed. Hover a label to see every route.

Repositories are placed in columns in the direction of use, and each column is ordered to keep arrows from crossing. Arrows run at right angles in lanes of their own, around the boxes rather than through them, and each label has room of its own, on its arrow wherever there is space. Nothing on the map overlaps. Two repositories that use each other (a loop) sit in neighbouring columns, with one arrow going back.

Open the map on its own page​

For a large group, click Open map above the map. It opens in a new tab with nothing but the map, the search and the details, so it can fill the window:

  • Zoom with + and - (or the buttons), Ctrl or ⌘ with the scroll wheel (or pinch on a trackpad), and 0 or Fit to see the whole map. Click the percentage to go back to actual size. Drag the background to move around; the scroll bars work too.
  • Search (press /) finds repositories, endpoints, packages, tables, topics, files and fields, and file paths such as billing/sync.py. Everything the search matches stays lit and the rest fades. Click a result, or press Enter for the first, to go to it.
  • Click a repository to light it and its arrows and list what it uses and what uses it. Click an arrow for every use it stands for, with the file and line on both sides and the fields. Click the background or press Escape to let go.
  • All kinds shows one kind of relation at a time; the boxes stay where they are.
  • Check again reads every repository again, as in the group's popup.

The page uses the workspace the group is in, and the same sign-in. It works on a phone too: the map comes first and the details below it.

Relations​

The table under the map has one row per use: which repository uses what from which, with the file and line on both sides, linked to the code host. Fields shows the response fields it reads and the request fields it sends (the package symbols, table columns, message fields or file fields it uses), and warns about any the other side's contracts don't list, such as Not in the response: price or Not a column: status. Choose a kind (HTTP, Packages, Tables, Messages, Files) to see only that kind.

How calls are matched:

  • Routes are compared without regard to how parameters are written ({id}, :id, ${id}) or to a base URL in front, and a call without a method matches any method.
  • When two repositories serve the same route, the one whose name matches the service the code names (INVENTORY_API_URL and inventory-api) is taken.
  • Package names match ignoring case and -, _ and ..
  • A table, view, stored procedure or function (kind Database) relates the repository whose schema creates it (it owns it) and each repository that reads, writes or calls it. Names match ignoring case, quotes and brackets, part by part: items matches inventory.items, and server2.shop.dbo.items (or [shop].[dbo].[items], shop..items, Oracle's items@server2) matches dbo.items. A schema or database both names give must agree, so shop.dbo.items doesn't match archive.dbo.items. The server in a four-part name (server2.shop.dbo.items, Oracle's items@server2) names a link, which means something only on the server that defines it: Gryndel follows the link of the server where the query runs to the server it points at (see linked servers). Tables in a database repository carry the server and database of their folder, and an application's tables those of the connection its code uses. Two tables placed on a server and database match only when both agree, so two orders tables on different servers are two tables. When either side can't be placed (no connection learned, or a host no database repository lists), the match is shown as a possible match: marked in the table, drawn as a dotted arrow on the map, and passed to reviews as possible. A placed match replaces possible ones for the same use. One no repository in the group creates isn't shown.
  • A message topic or queue relates the repository that publishes to it and each one that subscribes to it; a file, the repository that writes it and each one that reads it. A saved query (a .sql file that creates nothing, such as queries/low_stock.sql) relates the repository that keeps it and each one whose code names it; a path matches the same file under a longer path.

Calls no member serves​

Endpoints a repository calls that no repository in the group serves are listed under the table. They are other systems, or a repository missing from the group. Calls to an address held whole in a variable (such as GET {image_url}) are not listed, since no endpoint can be named. Dependencies on packages nobody in the group publishes are not listed either, since most are public libraries.

Databases​

In a group with database repositories, the card lists the servers and databases they describe, as checkboxes, all ticked. Untick a database the group should ignore, such as a staging copy or a database no member uses, then Save databases: its tables take no part in this group's map, and reviews leave it out when every group the reviewed repository is in leaves it out. Unticking a server unticks all its databases. Only admins can change them.

A database two repositories claim (both have its server and database folder) is marked "claimed by 2 repositories, so not used": neither repository's tables are matched until one of them stops claiming it.

Not placed​

Also in a group with database repositories, the card and the map page list names Gryndel could not place on a server or database, so tables used through them match only as possible:

  • "DATABASE_URL in src/inventory-worker isn't mapped to a database": its host is not one of the servers' names. Add the host to the server's also_known_as, or say where it points under declared: connections: in the application's .gryndel/contracts.yaml.
  • "src/cron uses tables through no connection Gryndel knows": no configuration file sets one. Declare it the same way.
  • "far, linked from odd-cluster, isn't mapped to a server", or "NOWHERE, used on odd-cluster, isn't defined there": name the link's server under linked: in server.yaml (see linked servers).
  • "orders on orders-cluster is claimed by" two repositories.

Answer one on the page. Admins see a list of the group's databases next to each connection or link: pick where it points and Propose. Gryndel opens a merge request on the repository it belongs to, as itself, adding one entry to declared: connections: in the application's .gryndel/contracts.yaml, or to linked: in the server's server.yaml (or under the server in .gryndel/databases.yaml). It changes nothing else in the file, comments included, and further answers while it is open are added to the same merge request. Review and merge it: a connection applies at once (after Check again), a link once the database repository is learned again. A database claimed twice has no answer here: remove the claim from one of the repositories.

Once the answers are merged, the list is empty.

Check again​

Gryndel keeps what it read for ten minutes. Check again reads every repository again, for example after merging a learn's proposal; a repository read in the last minute is not read again.

What reviews check​

Each review of a repository in a group (and active there) also checks the change against every other active repository of its groups. It uses the same contracts as the map: the changed repository's .gryndel/contracts.yaml from the merge or pull request's target branch, so a change can't rewrite its own, and each other repository's from its default branch.

  1. Gryndel finds the endpoints, packages, tables, messages and files the change touches: lines changed in the code that serves, makes, creates, publishes or reads them, or changed lines that name a field, column or message field the other repository uses (for example a migration that drops a column another repository reads).
  2. For each, it reads the other repository's code where it uses it, and asks the model whether the change breaks it, for example a field removed that the site still reads.
  3. Code search covers what the contracts don't. Gryndel lists the routes and the distinctive names (such as price_cents or getItem, not plain words like price) that the change removes and adds back nowhere. It searches each other repository's default branch for those its contracts don't name, including repositories that aren't learned. Each place found in code (not tests, docs or comments) is checked the same way.
  4. A break is posted like any finding, on the changed line, with category cross-repo. It names the other repository and the file and line that break. It never quotes that repository's code, which people on this merge or pull request may not be allowed to see.

Findings below the repository's Min. severity to publish are withheld, and Fail commit status on counts them like any other finding. The review's summary says what was checked, for example:

Related repositories: checked src/inventory-web from their contracts and src/shop by code search only (2 shared uses touched by this change, 1 broken; 1 code search).

The summary saysMeans
checked … from their contractsBoth sides are learned; the numbers say how many shared uses the change touched (or a search found) and how many break.
… by code search onlyThe other repository has no contracts, or this one has none: only a code search for what the change removes was used. Learn both for a full check.
… not learned, so not checkedThe other repository has no contracts file on its default branch, and nothing was searched there: the change removes nothing to search for, or the code host can't search. Learn it and merge the proposal.
… is not on the target branch, so only code was searchedThis repository isn't learned yet; its changes were checked by code search only.
not checked, because .gryndel/contracts.yaml is not on the target branchThis repository isn't learned yet, and nothing could be searched.
Code search of … failedThe code host refused the search, for example over its rate limit; the reason follows. The review still finishes.
could not read …Gryndel couldn't read the other repository; the reason follows. The review still finishes.
… could not be judgedThe model call failed; the review still finishes without those checks.

No line appears when the repository is in no group, or when Related repositories is turned off in its settings (Reviews tab).

Limits today:

  • Code search looks only for what the change removes: a new call the change adds to an endpoint the other repository doesn't serve isn't caught until the contracts list it.
  • A changed type or meaning behind a name that stays the same is caught only when the contracts list the use.
  • At most 6 names and routes are searched, in 12 searches per review, 3 files per search.
  • On GitHub, code search covers default branches only and is rate limited; a refused search is named in the summary.
  • A disabled repository is left out in both directions.
  • It adds one model call per eight touched or found uses, and none when the change touches nothing shared.

See a repository's groups​

Open Repositories, click Configure on a repository and choose the Groups tab. It lists the groups the repository is in and whether it is active or disabled there. It is read-only: change membership on the Repository groups page. A repository in no group shows a link to that page.