Activities for project actor

Introduced in GitLab 16.5 with two flags named activity_pub and activity_pub_project. Disabled by default. This feature is an Experiment.

On self-managed GitLab, by default this feature is not available. To make it available, an administrator can enable the feature flags named activity_pub and activity_pub_project. On GitLab.com, this feature is not available. The feature is not ready for production use.

This feature requires two feature flags:

  • activity_pub: Enables or disables all ActivityPub-related features.
  • activity_pub_project: Enables and disable ActivityPub features specific to projects. Requires the activity_pub flag to also be enabled.

Profile

{
  "@context": "https://www.w3.org/ns/activitystreams",
  "id": PROJECT_URL,
  "type": "Application",
  "name": PROJECT_NAME,
  "summary": PROJECT_DESCRIPTION,
  "url": PROJECT_URL,
  "outbox": PROJECT_OUTBOX_URL,
  "inbox": null,
}

Outbox

For a project, we can map the events happening on the project activity timeline on GitLab, when a user:

There’s also a Design tab in the project activities, but it’s just empty in all projects I follow and I don’t see anything related to it in my projects sidebar. Maybe it’s a premium feature? If so, it’s of no concern to us for public following through ActivityPub.

User creates the repository

{
  "id": PROJECT_OUTBOX_URL#event_id,
  "type": "Create",
  "to": [
    "https://www.w3.org/ns/activitystreams#Public"
  ],
  "actor": {
    "id": USER_PROFILE_URL,
    "type": "Person",
    "name": USER_NAME,
    "url": USER_PROFILE_URL,
  },
  "object": {
    "id": PROJECT_URL,
    "type": "Application",
    "name": PROJECT_NAME,
    "summary": PROJECT_DESCRIPTION,
    "url": PROJECT_URL,
  }
}

User pushes commits

{
  "id": PROJECT_OUTBOX_URL#event_id,
  "type": "Update",
  "actor": {
    "id": USER_PROFILE_URL,
    "type": "Person",
    "name": USER_NAME,
    "url": USER_PROFILE_URL,
  },
  "object": {
    "id": PROJECT_URL,
    "type": "Application",
    "name": PROJECT_NAME,
    "summary": PROJECT_DESCRIPTION,
    "url": PROJECT_URL,
  },
  "result": COMMITS_DIFF_URL,
}

User pushes a tag

{
  "id": PROJECT_OUTBOX_URL#event_id,
  "type": "Update",
  "actor": {
    "id": USER_PROFILE_URL,
    "type": "Person",
    "name": USER_NAME,
    "url": USER_PROFILE_URL,
  },
  "object": {
    "id": PROJECT_URL,
    "type": "Application",
    "name": PROJECT_NAME,
    "summary": PROJECT_DESCRIPTION,
    "url": PROJECT_URL,
  },
  "name": TAG_NAME,
  "result": COMMIT_URL,
}

User opens a merge request

{
  "id": PROJECT_OUTBOX_URL#event_id,
  "type": "Add",
  "to": [
    "https://www.w3.org/ns/activitystreams#Public"
  ],
  "actor": {
    "id": USER_PROFILE_URL,
    "type": "Person",
    "name": USER_NAME,
    "url": USER_PROFILE_URL,
  },
  "object": {
    "id": MERGE_REQUEST_URL,
    "type": "Application",
    "name": MERGE_REQUEST_TITLE,
    "url": MERGE_REQUEST_URL,
    "context": {
      "id": PROJECT_URL,
      "type": "Application",
      "name": PROJECT_NAME,
      "summary": PROJECT_DESCRIPTION,
      "url": PROJECT_URL,
    },
  },
  "target": {
    "id": PROJECT_URL,
    "type": "Application",
    "name": PROJECT_NAME,
    "summary": PROJECT_DESCRIPTION,
    "url": PROJECT_URL,
  },
}

User accepts a merge request

{
  "id": PROJECT_OUTBOX_URL#event_id,
  "type": "Accept",
  "to": [
    "https://www.w3.org/ns/activitystreams#Public"
  ],
  "actor": {
    "id": USER_PROFILE_URL,
    "type": "Person",
    "name": USER_NAME,
    "url": USER_PROFILE_URL,
  },
  "object": {
    "id": MERGE_REQUEST_URL,
    "type": "Application",
    "name": MERGE_REQUEST_TITLE,
    "url": MERGE_REQUEST_URL,
    "context": {
      "id": PROJECT_URL,
      "type": "Application",
      "name": PROJECT_NAME,
      "summary": PROJECT_DESCRIPTION,
      "url": PROJECT_URL,
    },
  },
  "target": {
    "id": PROJECT_URL,
    "type": "Application",
    "name": PROJECT_NAME,
    "summary": PROJECT_DESCRIPTION,
    "url": PROJECT_URL,
  },
}

User closes a merge request

{
  "id": PROJECT_OUTBOX_URL#event_id,
  "type": "Remove",
  "to": [
    "https://www.w3.org/ns/activitystreams#Public"
  ],
  "actor": {
    "id": USER_PROFILE_URL,
    "type": "Person",
    "name": USER_NAME,
    "url": USER_PROFILE_URL,
  },
  "object": {
    "id": MERGE_REQUEST_URL,
    "type": "Application",
    "name": MERGE_REQUEST_TITLE,
    "url": MERGE_REQUEST_URL,
    "context": {
      "id": PROJECT_URL,
      "type": "Application",
      "name": PROJECT_NAME,
      "summary": PROJECT_DESCRIPTION,
      "url": PROJECT_URL,
    },
  },
  "origin": {
    "id": PROJECT_URL,
    "type": "Application",
    "name": PROJECT_NAME,
    "summary": PROJECT_DESCRIPTION,
    "url": PROJECT_URL,
  },
}

User opens an issue

{
  "id": PROJECT_OUTBOX_URL#event_id,
  "type": "Add",
  "to": [
    "https://www.w3.org/ns/activitystreams#Public"
  ],
  "actor": {
    "id": USER_PROFILE_URL,
    "type": "Person",
    "name": USER_NAME,
    "url": USER_PROFILE_URL,
  },
  "object": {
    "id": ISSUE_URL,
    "type": "Page",
    "name": ISSUE_TITLE,
    "url": ISSUE_URL,
    "context": {
      "id": PROJECT_URL,
      "type": "Application",
      "name": PROJECT_NAME,
      "summary": PROJECT_DESCRIPTION,
      "url": PROJECT_URL,
    }
  },
  "target": {
    "id": PROJECT_URL,
    "type": "Application",
    "name": PROJECT_NAME,
    "summary": PROJECT_DESCRIPTION,
    "url": PROJECT_URL,
  }
}

Why to add the project both as object.context and target? For multiple consistency reasons:

  • The Add activity is more commonly used with a target.
  • The Remove activity used to close the issue is more commonly used with an origin.
  • The Update activity used to reopen an issue specifies that target and origin have no specific meaning, making context better suited for that.
  • We could use context only with Update, but merge requests must be taken into consideration.

Merge requests are very similar to issues, so we want their activities to be similar. While the best type for issues is page, the type chosen for merge request is application, both to distinguish it from issues and because they contain code.

To distinguish merge requests from projects (which are also application), merge requests are an application with another application (the project) as context. Given the merge request will have a context even with the Add and Remove activities, the same is done with issues for consistency.

An alternative that was considered, but dismissed: instead of Add for issues, use Create. That would have allowed us to always use context, but it creates more problems that it solves. Accept and Reject could work quite well for closing merge requests, but what would we use to close issues? Delete is incorrect, as the issue is not deleted, just closed. Reopening the issue later would require an Update after a Delete.

Using Create for opening issues and Remove for closing issues would be asymmetrical:

  • Create is mirrored by Delete.
  • Add is mirrored by Remove.

To minimize pain for those who will build on top of those resources, it’s best to duplicate the project information as context and target / origin.

User closes an issue

{
  "id": PROJECT_OUTBOX_URL#event_id,
  "type": "Remove",
  "to": [
    "https://www.w3.org/ns/activitystreams#Public"
  ],
  "actor": {
    "id": USER_PROFILE_URL,
    "type": "Person",
    "name": USER_NAME,
    "url": USER_PROFILE_URL,
  },
  "object": {
    "id": ISSUE_URL,
    "type": "Page",
    "name": ISSUE_TITLE,
    "url": ISSUE_URL,
    "context": {
      "id": PROJECT_URL,
      "type": "Application",
      "name": PROJECT_NAME,
      "summary": PROJECT_DESCRIPTION,
      "url": PROJECT_URL,
    },
  },
  "origin": {
    "id": PROJECT_URL,
    "type": "Application",
    "name": PROJECT_NAME,
    "summary": PROJECT_DESCRIPTION,
    "url": PROJECT_URL,
  },
}

User reopens an issue

{
  "id": PROJECT_OUTBOX_URL#event_id,
  "type": "Update",
  "to": [
    "https://www.w3.org/ns/activitystreams#Public"
  ],
  "actor": {
    "id": USER_PROFILE_URL,
    "type": "Person",
    "name": USER_NAME,
    "url": USER_PROFILE_URL,
  },
  "object": {
    "id": ISSUE_URL,
    "type": "Page",
    "name": ISSUE_TITLE,
    "url": ISSUE_URL,
    "context": {
      "id": PROJECT_URL,
      "type": "Application",
      "name": PROJECT_NAME,
      "summary": PROJECT_DESCRIPTION,
      "url": PROJECT_URL,
    },
  },
}

User comments on a merge request

{
  "id": PROJECT_OUTBOX_URL#event_id,
  "type": "Add",
  "to": [
    "https://www.w3.org/ns/activitystreams#Public"
  ],
  "actor": {
    "id": USER_PROFILE_URL,
    "type": "Person",
    "name": USER_NAME,
    "url": USER_PROFILE_URL,
  },
  "object": {
    "id": NOTE_URL,
    "type": "Note",
    "content": NOTE_NOTE,
  },
  "target": {
    "id": MERGE_REQUEST_URL,
    "type": "Application",
    "name": MERGE_REQUEST_TITLE,
    "url": MERGE_REQUEST_URL,
    "context": {
      "id": PROJECT_URL,
      "type": "Application",
      "name": PROJECT_NAME,
      "summary": PROJECT_DESCRIPTION,
      "url": PROJECT_URL,
    },
  },
}

User comments on an issue

{
  "id": PROJECT_URL#event_id,
  "type": "Add",
  "to": [
    "https://www.w3.org/ns/activitystreams#Public"
  ],
  "actor": {
    "id": USER_PROFILE_URL,
    "type": "Person",
    "name": USER_NAME,
    "url": USER_PROFILE_URL,
  },
  "object": {
    "id": NOTE_URL,
    "type": "Note",
    "content": NOTE_NOTE,
  },
  "target": {
    "id": ISSUE_URL,
    "type": "Page",
    "name": ISSUE_TITLE,
    "url": ISSUE_URL,
    "context": {
      "id": PROJECT_URL,
      "type": "Application",
      "name": PROJECT_NAME,
      "summary": PROJECT_DESCRIPTION,
      "url": PROJECT_URL,
    },
  },
}

User creates a wiki page

{
  "id": PROJECT_OUTBOX_URL#event_id,
  "type": "Create",
  "to": [
    "https://www.w3.org/ns/activitystreams#Public"
  ],
  "actor": {
    "id": USER_PROFILE_URL,
    "type": "Person",
    "name": USER_NAME,
    "url": USER_PROFILE_URL,
  },
  "object": {
    "id": WIKI_PAGE_URL,
    "type": "Page",
    "name": WIKI_PAGE_HUMAN_TITLE,
    "url": WIKI_PAGE_URL,
  }
}

User updates a wiki page

{
  "id": PROJECT_OUTBOX_URL#event_id,
  "type": "Update",
  "to": [
    "https://www.w3.org/ns/activitystreams#Public"
  ],
  "actor": {
    "id": USER_PROFILE_URL,
    "type": "Person",
    "name": USER_NAME,
    "url": USER_PROFILE_URL,
  },
  "object": {
    "id": WIKI_PAGE_URL,
    "type": "Page",
    "name": WIKI_PAGE_HUMAN_TITLE,
    "url": WIKI_PAGE_URL,
  }
}

User destroys a wiki page

{
  "id": PROJECT_OUTBOX_URL#event_id,
  "type": "Delete",
  "to": [
    "https://www.w3.org/ns/activitystreams#Public"
  ],
  "actor": {
    "id": USER_PROFILE_URL,
    "type": "Person",
    "name": USER_NAME,
    "url": USER_PROFILE_URL,
  },
  "object": {
    "id": WIKI_PAGE_URL,
    "type": "Page",
    "name": WIKI_PAGE_HUMAN_TITLE,
    "url": WIKI_PAGE_URL,
  }
}

User joins the project

{
  "id": PROJECT_OUTBOX_URL#event_id,
  "type": "Add",
  "to": [
    "https://www.w3.org/ns/activitystreams#Public"
  ],
  "actor": {
    "id": USER_PROFILE_URL,
    "type": "Person",
    "name": USER_NAME,
    "url": USER_PROFILE_URL,
  },
  "object": {
    "id": USER_PROFILE_URL,
    "type": "Person",
    "name": USER_NAME,
    "url": USER_PROFILE_URL,
  },
  "target": {
    "id": PROJECT_URL,
    "type": "Application",
    "name": PROJECT_NAME,
    "summary": PROJECT_DESCRIPTION,
    "url": PROJECT_URL,
  },
}

The GitLab project timeline does not mention who added a member to the project, so this does the same. However, the Add activity requires an Actor. For that reason, we use the same person as actor and object.

In the Members page of a project contains a source attribute. While there is sometimes mention of who added the user, this is used mainly to distinguish if the user is a member attached to the project directly, or through a group. It would not be a good “actor” (that would rather be an origin for the membership).

User leaves the project

{
  "id": PROJECT_OUTBOX_URL#event_id,
  "type": "Remove",
  "to": [
    "https://www.w3.org/ns/activitystreams#Public"
  ],
  "actor": {
    "id": USER_PROFILE_URL,
    "type": "Person",
    "name": USER_NAME,
    "url": USER_PROFILE_URL,
  },
  "object": {
    "id": USER_PROFILE_URL,
    "type": "Person",
    "name": USER_NAME,
    "url": USER_PROFILE_URL,
  },
  "target": {
    "id": PROJECT_URL,
    "type": "Application",
    "name": PROJECT_NAME,
    "summary": PROJECT_DESCRIPTION,
    "url": PROJECT_URL,
  },
}

See User joined the project.

User deletes the repository

{
  "id": PROJECT_OUTBOX_URL#event_id,
  "type": "Delete",
  "to": [
    "https://www.w3.org/ns/activitystreams#Public"
  ],
  "actor": {
    "id": USER_PROFILE_URL,
    "type": "Person",
    "name": USER_NAME,
    "url": USER_PROFILE_URL,
  },
  "object": {
    "id": PROJECT_URL,
    "type": "Application",
    "name": PROJECT_NAME,
    "summary": PROJECT_DESCRIPTION,
    "url": PROJECT_URL,
  }
}