This document describes the rules and guidelines for representing version control and project management related objects as linked data, using the ForgeFed vocabulary, ActivityStreams 2, and other related vocabularies.
The ForgeFed modeling specification is a set of rules and guidelines which describe version control repository and project management related objects and properties, and specify how to represent them as JSON-LD objects (and linked data in general) using the ForgeFed vocabulary and related vocabularies and ontologies. Using these modeling rules consistently across implementations and instances allows to have a common language spoken across networks of software forges, project management apps and more.
The ForgeFed vocabulary specification defines a dedicated vocabulary of forge-related terms, and the modeling specification uses these terms, along with terms that already exist in ActivityPub or elsewhere and can be reused for forge federation.
The ForgeFed behavior specification provides instructions for using Activities, and which Activities and properties to use, to represent forge events, and describes the side-effects these Activities should have. The objects used as inputs and outputs of behavior descriptions there are defined here in the modeling specification.
To represent a named set of changes committed into a repository's history, use the ForgeFed Commit type. Such a committed change set is called e.g. a commit in Git, and a patch in Darcs.
Properties:
mailto
URImailto
URImediaType
SHOULD be "text/plain" and content
is the commit's possibly-multi-line description; if the commit title and
description are a single commit message string, then the description is
everything after the 1st line of the commit message (possibly with leading
whitespace stripped)Example:
{
"@context": [
"https://www.w3.org/ns/activitystreams",
"https://forgefed.peers.community/ns"
],
"id": "https://example.dev/alice/myrepo/commits/109ec9a09c7df7fec775d2ba0b9d466e5643ec8c",
"type": "Commit",
"context": "https://example.dev/alice/myrepo",
"attributedTo": "https://example.dev/bob",
"created": "2019-07-11T12:34:56Z",
"committedBy": "https://example.dev/alice",
"committed": "2019-07-26T23:45:01Z",
"hash": "109ec9a09c7df7fec775d2ba0b9d466e5643ec8c",
"summary": "Add an installation script, fixes issue #89",
"description": {
"mediaType": "text/plain",
"content": "It's about time people can install it on their computers!"
}
}
To represent a repository branch, use the ForgeFed Branch type. It can be a real built-in version control system branch (such as a Git branch) or a copy of the repo used as a branch (e.g. in Darcs, which doesn't implement branches, and the way to have branches is to keep multiple versions of the repo).
Properties:
Example:
{
"@context": [
"https://www.w3.org/ns/activitystreams",
"https://forgefed.peers.community/ns"
],
"id": "https://example.dev/luke/myrepo/branches/master",
"type": "Branch",
"context": "https://example.dev/luke/myrepo",
"name": "master",
"ref": "refs/heads/master"
}
To represent a version control repository, use the ForgeFed Repository type.
Properties:
<p>A command-line tool that does cool things</p>
"Example:
{
"@context": [
"https://www.w3.org/ns/activitystreams",
"https://w3id.org/security/v1",
"https://forgefed.peers.community/ns"
],
"id": "https://dev.example/aviva/treesim",
"type": "Repository",
"publicKey": {
"id": "https://dev.example/aviva/treesim#main-key",
"owner": "https://dev.example/aviva/treesim",
"publicKeyPem": "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhki....."
},
"inbox": "https://dev.example/aviva/treesim/inbox",
"outbox": "https://dev.example/aviva/treesim/outbox",
"followers": "https://dev.example/aviva/treesim/followers",
"team": "https://dev.example/aviva/treesim/team",
"ticketsTrackedBy": "https://dev.example/aviva/treesim",
"sendPatchesTo": "https://dev.example/aviva/treesim",
"name": "Tree Growth 3D Simulation",
"attributedTo": "https://example.dev/bob",
"summary": "<p>Tree growth 3D simulator for my nature exploration game</p>"
}
To represent an event of Commits being pushed to a Repository, use a ForgeFed Push activity.
Properties:
Example:
{
"@context": [
"https://www.w3.org/ns/activitystreams",
"https://forgefed.peers.community/ns"
],
"id": "https://dev.example/aviva/outbox/E26bE",
"type": "Push",
"actor": "https://dev.example/aviva",
"to": [
"https://dev.example/aviva/followers",
"https://dev.example/aviva/game-of-life",
"https://dev.example/aviva/game-of-life/team",
"https://dev.example/aviva/game-of-life/followers"
],
"context": "https://dev.example/aviva/game-of-life",
"target": "https://dev.example/aviva/game-of-life/branches/master",
"hashBefore": "017cbb00bc20d1cae85f46d638684898d095f0ae",
"hashAfter": "be9f48a341c4bb5cd79ae7ab85fbf0c05d2837bb",
"object": {
"totalItems": 2,
"type": "OrderedCollection",
"orderedItems": [
{
"id": "https://dev.example/aviva/game-of-life/commits/be9f48a341c4bb5cd79ae7ab85fbf0c05d2837bb",
"type": "Commit",
"attributedTo": "https://dev.example/aviva",
"context": "https://dev.example/aviva/game-of-life",
"hash": "be9f48a341c4bb5cd79ae7ab85fbf0c05d2837bb",
"created": "2019-12-02T16:07:32Z",
"summary": "Add widget to alter simulation speed"
},
{
"id": "https://dev.example/aviva/game-of-life/commits/fa37fe100a8b1e69933889c5bf3caf95cd3ae1e6",
"type": "Commit",
"attributedTo": "https://dev.example/aviva",
"context": "https://dev.example/aviva/game-of-life",
"hash": "fa37fe100a8b1e69933889c5bf3caf95cd3ae1e6",
"created": "2019-12-02T15:51:52Z",
"summary": "Set window title correctly, fixes issue #7"
}
]
}
}
To represent a work item in a project, use the ForgeFed Ticket type.
TODO decide on ticket categories/subtypes and update below
TODO decide on property for titles, update below
TODO properly document history
or remove it from example
Properties:
Example:
{
"@context": [
"https://www.w3.org/ns/activitystreams",
"https://forgefed.peers.community/ns"
],
"id": "https://dev.example/aviva/game-of-life/issues/107",
"type": "Ticket",
"context": "https://dev.example/aviva/game-of-life",
"attributedTo": "https://forge.example/luke",
"summary": "Window title is empty",
"content": "<p>When I start the simulation, window title disappears suddenly</p>",
"mediaType": "text/html",
"source": {
"mediaType": "text/markdown; variant=Commonmark",
"content": "When I start the simulation, window title disappears suddenly",
},
"published": "2019-11-04T07:00:04.465807Z",
"followers": "https://dev.example/aviva/game-of-life/issues/107/followers",
"team": "https://dev.example/aviva/game-of-life/issues/107/team",
"replies": "https://dev.example/aviva/game-of-life/issues/107/discussion",
"history": "https://dev.example/aviva/game-of-life/issues/107/activity",
"dependants": "https://dev.example/aviva/game-of-life/issues/107/rdeps",
"dependencies": "https://dev.example/aviva/game-of-life/issues/107/deps",
"isResolved": true,
"resolvedBy": "https://code.example/martin",
"resolved": "2020-02-07T06:45:03.281314Z"
}
To represent a comment, e.g. a comment on a ticket or a merge request, use the ActivityPub Note type.
Properties:
Example:
{
"@context": "https://www.w3.org/ns/activitystreams",
"id": "https://forge.example/luke/comments/rD05r",
"type": "Note",
"attributedTo": "https://forge.example/luke",
"context": "https://dev.example/aviva/game-of-life/merge-requests/19",
"inReplyTo": "https://dev.example/aviva/comments/E9AGE",
"mediaType": "text/html",
"content": "<p>Thank you for the review! I'll submit a correction ASAP</p>",
"source": {
"mediaType": "text/markdown; variant=Commonmark",
"content": "Thank you for the review! I'll submit a correction ASAP"
},
"published": "2019-11-06T20:49:05.604488Z"
}