Releases Page MVC
<!-- triage-serverless v2 PLEASE DO NOT REMOVE THIS SECTION -->
*The following page may contain information related to upcoming products, features and functionality.
It is important to note that the information presented is for informational purposes only, so please do not rely on the information for purchasing or planning purposes.
Just like with all projects, the items mentioned on the page are subject to change or delay, and the development, release, and timing of any products, features, or functionality remain at the sole discretion of GitLab Inc.*
<!-- triage-serverless v2 PLEASE DO NOT REMOVE THIS SECTION -->
## Problem to Solve
Projects regularly publish released code, but we don't currently have a first-class way to do that within GitLab. Many teams are using artifacts to do this, but this is beyond their intention (which was primarily a way to pass dependencies between jobs/stages within a pipeline.)
## MVC Solution
### Backend specifications:
We need the ability to distribute project release downloads properly within GitLab. As MVC we will introduce a read-only releases page which will allow you to find and download releases, and add the ability via API to add/update them.
1. Implement dedicated __read-only__ releases list page separate from tags located at `Project > Releases`
1. Releases will become a first class citizen and will have a dedicated release handling REST API similar to [GH](https://developer.github.com/v3/repos/releases/#create-a-release).
- Releases will depend on a tag (required metadata), but will not be an extension of a tag as they are now
- ~~`POST /projects/:id/repository/tags/:tag_name/release`~~ => `POST /api/v4/projects/:id/releases`
- Deprecate releases as release notes upon tags: ~~`POST /projects/:id/repository/tags/:tag_name/release`~~
- Old release api table info will be reused in new api. This means old release info will be available in new release list
1. Users will be able to provide links to released assets
### Backend API
#### A release
```json
{
"name": "Bionic Beaver",
"tag_name": "18.04"
"description": "## changelog\n\n* line 1\n* line2",
"description_html": "<div><h2>changelog</h2><ul><li>line1</li<li>line 2</li></ul></div>",
"created_at": "2012-05-28T05:00:00-07:00"
"commit": {
"id": "2695effb5807a22ff3d138d593fd856244e155e7",
"short_id": "2695effb",
"title": "Initial commit",
"created_at": "2017-07-26T11:08:53.000+02:00",
"parent_ids": [
"2a4b78934375d7f53875269ffd4f45fd83a84ebe"
],
"message": "Initial commit",
"author_name": "John Smith",
"author_email": "john@example.com",
"authored_date": "2012-05-28T04:42:42-07:00",
"committer_name": "Jack Smith",
"committer_email": "jack@example.com",
"committed_date": "2012-05-28T04:42:42-07:00"
},
"author": {
"id": 1,
"name": "Administrator",
"username": "root",
"state": "active",
"avatar_url": "http://localhost:3000/uploads/-/system/user/avatar/1/avatar.png",
"web_url": "http://localhost:3000/root"
},
"assets": {
"count": 6,
"sources": [
{
"format": "zip",
"url": "https://gitlab.com/gitlab-org/gitlab-ce/-/archive/v11.3.12/gitlab-ce-v11.3.12.zip"
},
{
"format": "tar.gz",
"url": "https://gitlab.com/gitlab-org/gitlab-ce/-/archive/v11.3.12/gitlab-ce-v11.3.12.tar.gz"
},
{
"format": "tar.bz2",
"url": "https://gitlab.com/gitlab-org/gitlab-ce/-/archive/v11.3.12/gitlab-ce-v11.3.12.tar.bz2"
},
{
"format": "tar",
"url": "https://gitlab.com/gitlab-org/gitlab-ce/-/archive/v11.3.12/gitlab-ce-v11.3.12.tar"
}
],
"links": [
{
"name": "release-18.04.dmg",
"url": "https://my-external-hosting.example.com/scrambled-url/",
"external": true
},
{
"name": "binary-linux-amd64",
"url": "https://gitlab.com/gitlab-org/gitlab-ce/-/jobs/artifacts/v11.6.0-rc4/download?job=rspec-mysql+41%2F50",
"external": false
}
]
}
}
```
#### Release creation
`POST /projects/:id/releases`
*request body*
```json
{
"name": "Bionic Beaver",
"tag_name": "18.04",
"description": "## changelog\n\n* line 1\n* line2",
"ref": "stable-18-04",
"assets": {
"links": [
{
"name": "release-18.04.dmg",
"url": "https://my-external-hosting.example.com/scrambled-url/"
},
{
"name": "binary-linux-amd64",
"url": "https://gitlab.com/gitlab-org/gitlab-ce/-/jobs/artifacts/v11.6.0-rc4/download?job=rspec-mysql+41%2F50"
}
]
}
}
```
* `name`: mandatory - release name
* `tag_name`: mandatory - the tag where we must create a release
* `description`: optional - a markdown description of the release
* `ref`: optional - if `tag_name` doesn't exists in the repository then it will be created on `ref`. It can be a commit SHA, another tag name, or branch name
* `assets`: mandatory
* `links`: mandatory - an array of asset links
* `name`: mandatory - the name of the asset
* `url`: mandatory - the url of the asset
*response*
a release object
Other API endpoints:
* `GET /projects/:id/releases` => paginated list of relases, sorted by `created_at`
* `GET /projects/:id/release/:tag_name` => a release for the given tag
* `DELETE /projects/:id/release/:tag_name` => delete a release
* `PUT /projects/:id/release/:tag_name` => update a release
**note**: Deleting a release will not delete the associated tag.
### How to edit and update asset links
- Users **cannot** edit nor delete asset links in `PUT /projects/:id/release/:tag_name`. Instead, we're going to introduce explicit API calls for it
- `GET /projects/:id/release/:tag_name/links` ... Get asset links of a release
- `POST /projects/:id/release/:tag_name/links` ... Create an asset link of a release
- `PUT /projects/:id/release/:tag_name/links/:link_id` ... Update an asset link of a release
- `DELETE /projects/:id/release/:tag_name/links/:link_id` ... Remove an asset link from a release
### Frontend
Frontend will make a GET request using REST API
### API Response
See above *Backend API > A release*
### Plan
We (@nolith and @filipa) will be splitting the work in several iterations (MRs):
- [x] Create an MR with the route + index page + menu entry behind a feature flag: https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/23687
- [ ] Create an MR with the project's page change behind the same feature flag
- Backend:
- [x] expand current relese data structure https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/23763
- [x] prepare new API endpoints behind the same feature flag gitlab-org/gitlab-ce!23795
- [x] implements assets (both links and source archives(read-only)) https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/24056
- [x] Support CURD operation for individual asset links in Release API https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/24100
- Frontend
- [x] Create a Vue component to render the release block - https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/23697
- [x] Create the Vuex store with REST API request: https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/23796
- [ ] Remove the feature flag
- [ ] Add feature spec for Release page
- [ ] Write ~Documentation gitlab-org/gitlab-ce!23901
### Mockups
**Releases page (read-only):**
Features:
- Release list (ordered by creation date, newest at the top)
- commit (anchor + Ttooltip: `commit title`)
- tag (anchor + Tooltip: `tag`)
- creation data (Tooltip: `time`)
- release author (anchor + Tooltip stating name)
- ~~edited date (Tooltip: `time`)~~ This is considered out of scope for now https://gitlab.com/gitlab-org/gitlab-ce/issues/41766#note_124034247
- release name
- Asset source archives expandable anchor (Dropdown: `zip, tar.gz, tar.bz2, tar` download options, Icon: `package`)
- Asset packages anchors (Tooltip: `Download asset`, Icon: `doc-code`)
- Links can be provided to outside sources as a type of asset other than packages (packages can be done in a separate iteration this way)
- If the link is not of the same base URL as the GitLab instance, `(external source)` is appended to the anchor
- Markdown description
- Loading will for now happen with a centered spinner => follow up Skeleton loading https://gitlab.com/gitlab-org/gitlab-ce/issues/55242
- When the page is empty we will have an empty state detailed below
[__FE Specs__](https://gitlab-org.gitlab.io/gitlab-design/hosted/dimitrie/ce%2341766-releases-page-spec-previews/)

[desktop-big-descriptiom](/uploads/ab57382b698cc89bc4bd3834508586f7/_768-big-descriptiom.png)
[mobile](/uploads/b1e9c99e855303f303b022c5c4034896/_768.png)
[mobile-big-description](/uploads/97fa16681fa9553d6d90ef25078f04de/_768-big-description.png)
[Tooltips + dropdowns](/uploads/0e24afe177a49c42c36bdff340097129/Tooltips.png)
[external link](/uploads/0687c79137c83fedd24d3c9a4ff0aacf/image.png)
> Note: Only sources have a dropdown because is the same content in different archives, links should point to different resources (i.e. a linux binary, a windows installer, a macOS package). So in that sense links will be listed individually, while sources are rendered as a dropdown.
- Link assets should have the same distance towards each other as towards "source code" expandable anchor
[multiple links example](/uploads/4185640dbdd044e3e2eb39045a8ed479/_768_copy.png)
__Change towards project homepage:__
Changes:
- `Tags` will be swapped out with `Releases`

__Empty state__
[Empty state mockup](/uploads/7c073ea3f77e7bad83fae1fca06edf18/image.png)
- `Getting started with releases`
- `Releases mark specific points in a project's development history, communicate information about the type of change, and deliver on prepared, often compiled, versions of the software to be reused elsewhere. Currently, releases can only be created through the API.`
- `Open documentation`
- Illustration through https://gitlab.com/gitlab-org/gitlab-svgs/merge_requests/181
- Illustration: `releases`
### Links / references
* #23553
* #25533
* #5894
* #41083
* #40368
* #39457
There is open source, self-hosted, forge-like software that also offers this kind of feature:
- https://github.com/shumatech/BOSSA/releases
- FusionForge : https://fusionforge.org/
- Tuleap : https://tuleap.net/
### Success Measures
We should measure the number of created releases over time to ensure we're seeing this feature used.
issue