ForgeFeed Specifications
A project refers to a peice of software which may be spread across multiple code repositories. For example a consider a fictious programming language which may be composed of several components such as a compiler, a standard library, example codebases, a marketing website, etc. When the architecture of such a project spans multiple repositories then it is likely they should be represented as a project.
Sometimes however the scope of a project is much smaller such that it is entirely contained within one single repository, alternatively a large project might choose to version it's code all in one logical repository. If your forge supports it you MAY present a single repository as both an identifiable project and also a repository.
A project URI identifies a software project and optionally the host that is resides on. The value serves to contain enough information such that a client with a simple URL parser may easily parse the identifier. A project URI MUST be a valid RFC7565 URI. The slug and hostname parts MUST match the URI path specification as defined in RFC3986-3.3 while the hostname, if specified, must match RFC3986-3.2.2.
project-uri = prefix slug hostname
prefix = "project://"
slug = rfc3986-path
hostname = [@ rfc3986-hostname]
The Slug represents a unique string that identifies a project at a particular code forge.
If the hostname part is missing then the address of the server receiving the query is assumed. For example the following two queries are equivalent:
https://example.org/.well-known/webfinger?resource=project://spartacus
https://example.org/.well-known/webfinger?resource=project://spartacus@example.org
An example parser written in the Python programming language. Any programming language which implements a valid RFC7565 parser should be sufficent for reading a project URI.
from urllib.parse import urlparse
def parse_project(text):
url = urlparse(text)
if url.scheme != "project": # schema must be repository://
raise Exception("Wrong scheme, should be project://")
if not url.path:
raise Exception("Missing slug part")
split = url.path.split("@", 1)
if len(split) == 2:
domain = urlparse(f"ignore://{split[1]}")
return (split[0], domain.netloc)
return (split[0], None)
The following Relation Types are available for use within a project resource.
http://forge-feed.org/rel/avatar
http://forge-feed.org/rel/chatroom
http://forge-feed.org/rel/description
http://forge-feed.org/rel/label
http://forge-feed.org/rel/homepage
http://forge-feed.org/rel/repository
http://forge-feed.org/rel/mailing-list
http://forge-feed.org/rel/ticketing-system
http://forge-feed.org/rel/avatarForges that allow users to configure a logo can expose this information as an avatar for use in other applications.
{
"rel": "http://webfinger.net/rel/avatar",
"href": "https://example.org/stylized-logo.png"
}
http://feed-forge.org/rel/chatroomA chatroom refers to an interactive chat environment for real time collaboration among project contributors.
{
"rel": "http://webfinger.net/rel/chatroom",
"href": "xmpp://spartacus@chat.example.org"
}
http://forge-feed.org/rel/descriptionA brief textual description which tells you something about the project.
{
"rel": "http://example.org/rel/description",
"titles": {
"en-us": "A Text Adventure Written in FORTRAN 77",
"es": "Una Aventura de Texto Escrita en FORTRAN 77"
}
}
http://forge-feed.org/rel/labelA short text based category which can be used for searching.
{
"rel": "http://forge-feed.org/rel/label",
"properties": {
"http://feed-forge.org/ns/label": "text-adventure"
}
}
http://forge-feed.org/rel/homepageLink to an HTTP representation of the project homepage.
{
"rel": "http://feed-forge.org/rel/homepage",
"href": "https://example.org/example/spartacus"
}
http://forge-feed.org/rel/mailing-listLinks to associated mailing lists, forms, etc.
{
"rel": "http://feed-forge.org/rel/mailing-list",
"href": "mailto://list-name@mail.example.org",
"properties": {
"http://feed-forge.org/ns/mailing-list-subscribe": "mailto://subscribe+list-name@mail.example.org",
"http://feed-forge.org/ns/mailing-list-unsubscribe": "mailto://unsubscribe+list-name@mail.example.org"
}
}
http://forge-feed.org/rel/ticketing-systemLinks to issue tracking systems.
{
"ref": "http://forge-feed.org/rel/ticketing-system",
"href": "https://example.org/bugs",
}
http://forge-feed.org/rel/repositoryReference to a VCS managed code repository.
{
"rel": "http://webfinger.net/rel/repository",
"href": "https://code.example.org/spartacus/spartan-engine",
"properties": {
"http://forge-feed.org/ns/repository-uri": "repository:spartacus/spartan-engine",
"http://forge-feed.org/ns/vcs-type": "git"
}
}
The following property identifiers are available for use within a project resource.
http://forge-feed.org/ns/label
http://forge-feed.org/ns/repository-uri
http://forge-feed.org/ns/vcs-type
http://forge-feed.org/ns/mailing-list-subscribe
http://forge-feed.org/ns/mailing-list-unsubscribe
http://forge-feed.org/ns/labelA short text based category which can be used for searching.
http://forge-feed.org/ns/repository-uriA Repository URI as described by the Repository URI specification.
http://forge-feed.org/ns/vcs-typeIdentifies VCS types, valid strings are:
bzr (GNU Bazaar) bazaar.canonical.com
darcs (Darcs) darcs.net
fossil (Fossil) fossil-scm.org
git (Git) git-scm.com
hg (Mercurial) mercurial-scm.org
pijul (Pijul) pijul.org
svn (Apache Subversion) subversion.apache.org
http://forge-feed.org/ns/mailing-list-subscribeMailto link for subscribing from a mailing list.
http://forge-feed.org/ns/mailing-list-unsubscribeMailto link for unsubscribing from a mailing list.
A WebFinger query may be used to identify detailed information about a public project at a particular forge. Here is an example response about a fictitious project which has two code repositories associated with it as well as chat links, and a bug tracking system.
GET https://example.org/.well-known/webfinger?resource=project:spartacus
{
"subject": "project:spartacus",
"aliases": [
"https://example.org"
],
"links": [
{
"rel": "http://webfinger.net/rel/avatar",
"href": "https://example.org/stylized-logo.png"
},
{
"rel": "http://feed-forge.org/rel/homepage",
"href": "https://code.example.org/spartacus"
},
{
"rel": "http://forge-feed.org/rel/description",
"titles": {
"en-us": "A Text Adventure Written in FORTRAN 77",
"es": "Una Aventura de Texto Escrita en FORTRAN 77"
}
},
{
"rel": "http://forge-feed.org/rel/chatroom",
"href": "ircs://irc.libera.chat/#spartacus-game",
"properties": {
"http://feed-forge.org/ns/chatroom": "irc"
}
},
{
"rel": "http://forge-feed.org/rel/ticketing-system",
"href": "https://example.org/bugs"
},
{
"rel": "http://forge-feed.org/rel/label",
"properties": {
"http://feed-forge.org/ns/label": "fortran"
}
},
{
"rel": "http://forge-feed.org/rel/label",
"properties": {
"http://feed-forge.org/ns/label": "text-adventure"
}
},
{
"rel": "http://forge-feed.org/rel/repository",
"href": "https://code.example.org/spartacus/spartan-engine",
"titles": {
"en-us": "The Spartan Game Engine"
},
"properties": {
"http://forge-feed.org/rel/repository-uri": "repository:spartacus/game-engine"
}
},
{
"rel": "http://forge-feed.org/rel/repository",
"href": "https://code.example.org/spartacus/game",
"titles": {
"en-us": "Implementation of the Spartacus Text Adventure game"
},
"properties": {
"http://forge-feed.org/ns/repository-uri": "repository:spartacus/game",
"http://forge-feed.org/ns/vcs-type": "git"
}
},
{
"rel": "http://forge-feed.org/rel/repository",
"href": "https://code.example.org/spartacus/game",
"titles": {
"en-us": "Promotional Website for the Spartacus Game"
},
"properties": {
"http://forge-feed.org/ns/repository-uri": "repository:spartacus/www",
"http://forge-feed.org/ns/vcs-type": "git"
}
}
]
}
Here is an example of a project with only a single repository associated with it.
{
"subject": "project:fuu/bar",
"links": [
{
"rel": "http://forge-feed.org/rel/repository",
"href": "https://code.example.org/fuu/bar",
"titles": {
"en-us": "Baz Qux"
},
"properties": {
"http://forge-feed.org/rel/repository-uri": "repository:fuu/bar",
"http://forge-feed.org/rel/vcs-type": "git"
}
}
]
}
Projects which are not publicly available should not be identifiable by making webfinger queries at all. A project which is private MUST return the same response as a repository which does not exist when making a webfinger request.
GET https://example.org/.well-known/webfinger?resource=project:example/spartacus
200
GET https://example.org/.well-known/webfinger?resource=project:example/private-project
404
GET https://example.org/.well-known/webfinger?resource=project:example/non-existent-project
404