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
- Click New group.
- Enter a name. It must be different from the other groups in the workspace; upper and lower case don't count as a difference.
- Optionally add a description, for example what the repositories do together.
- 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.
| Action | What happens | Good for |
|---|---|---|
| Disable | The 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 |
| Remove | The 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.
How they are related
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:
| Contracts | Means |
|---|---|
| Learned | The 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 date | A 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 yet | Gryndel learned the repository, but its proposal isn't merged, so the default branch has no contracts file yet. |
| Not learned | The repository has no contracts file. It takes no part in the map until it is learned and merged. |
| Cannot read | Gryndel 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_URLandinventory-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:
itemsmatchesinventory.items, andserver2.shop.dbo.items(or[shop].[dbo].[items],shop..items, Oracle'sitems@server2) matchesdbo.items. A schema or database both names give must agree, soshop.dbo.itemsdoesn't matcharchive.dbo.items. The server in a four-part name (server2.shop.dbo.items, Oracle'sitems@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 twoorderstables 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
.sqlfile that creates nothing, such asqueries/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_URLin src/inventory-worker isn't mapped to a database": its host is not one of the servers' names. Add the host to the server'salso_known_as, or say where it points underdeclared: 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 underlinked:inserver.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.
- 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).
- 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.
- Code search covers what the contracts don't. Gryndel lists the routes and the
distinctive names (such as
price_centsorgetItem, not plain words likeprice) 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. - 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-webfrom their contracts andsrc/shopby code search only (2 shared uses touched by this change, 1 broken; 1 code search).
| The summary says | Means |
|---|---|
| checked … from their contracts | Both sides are learned; the numbers say how many shared uses the change touched (or a search found) and how many break. |
| … by code search only | The 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 checked | The 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 searched | This repository isn't learned yet; its changes were checked by code search only. |
not checked, because .gryndel/contracts.yaml is not on the target branch | This repository isn't learned yet, and nothing could be searched. |
| Code search of … failed | The 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 judged | The 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.