Improve dockerhub releases

This commit is contained in:
Svilen Markov 2024-08-27 05:19:35 +01:00
parent 303438834b
commit b484e32b08
3 changed files with 84 additions and 22 deletions

View File

@ -1099,7 +1099,7 @@ Whether to ignore invalid/self-signed certificates.
Whether to open the link in the same or a new tab. Whether to open the link in the same or a new tab.
### Releases ### Releases
Display a list of releases for specific repositories on Github. Draft releases and prereleases will not be shown. Display a list of latest releases for specific repositories on Github, GitLab or Docker Hub.
Example: Example:
@ -1138,6 +1138,24 @@ repositories:
- dockerhub:glanceapp/glance - dockerhub:glanceapp/glance
``` ```
Official images on Docker Hub can be specified by ommiting the owner:
```yaml
repositories:
- dockerhub:nginx
- dockerhub:node
- dockerhub:alpine
```
You can also specify specific tags for Docker Hub images:
```yaml
repositories:
- dockerhub:nginx:latest
- dockerhub:nginx:stable-alpine
```
##### `show-source-icon` ##### `show-source-icon`
Shows an icon of the source (GitHub/GitLab/Docker Hub) next to the repository name when set to `true`. Shows an icon of the source (GitHub/GitLab/Docker Hub) next to the repository name when set to `true`.

View File

@ -7,26 +7,40 @@ import (
) )
type dockerHubRepositoryTagsResponse struct { type dockerHubRepositoryTagsResponse struct {
Results []struct { Results []dockerHubRepositoryTagResponse `json:"results"`
Name string `json:"name"`
LastPushed string `json:"tag_last_pushed"`
} `json:"results"`
} }
const dockerHubReleaseNotesURLFormat = "https://hub.docker.com/r/%s/tags?name=%s" type dockerHubRepositoryTagResponse struct {
Name string `json:"name"`
LastPushed string `json:"tag_last_pushed"`
}
const dockerHubOfficialRepoTagURLFormat = "https://hub.docker.com/_/%s/tags?name=%s"
const dockerHubRepoTagURLFormat = "https://hub.docker.com/r/%s/tags?name=%s"
const dockerHubTagsURLFormat = "https://hub.docker.com/v2/namespaces/%s/repositories/%s/tags"
const dockerHubSpecificTagURLFormat = "https://hub.docker.com/v2/namespaces/%s/repositories/%s/tags/%s"
func fetchLatestDockerHubRelease(request *ReleaseRequest) (*AppRelease, error) { func fetchLatestDockerHubRelease(request *ReleaseRequest) (*AppRelease, error) {
parts := strings.Split(request.Repository, "/")
if len(parts) != 2 { nameParts := strings.Split(request.Repository, "/")
if len(nameParts) > 2 {
return nil, fmt.Errorf("invalid repository name: %s", request.Repository) return nil, fmt.Errorf("invalid repository name: %s", request.Repository)
} else if len(nameParts) == 1 {
nameParts = []string{"library", nameParts[0]}
} }
httpRequest, err := http.NewRequest( tagParts := strings.SplitN(nameParts[1], ":", 2)
"GET",
fmt.Sprintf("https://hub.docker.com/v2/namespaces/%s/repositories/%s/tags", parts[0], parts[1]), var requestURL string
nil,
) if len(tagParts) == 2 {
requestURL = fmt.Sprintf(dockerHubSpecificTagURLFormat, nameParts[0], tagParts[0], tagParts[1])
} else {
requestURL = fmt.Sprintf(dockerHubTagsURLFormat, nameParts[0], nameParts[1])
}
httpRequest, err := http.NewRequest("GET", requestURL, nil)
if err != nil { if err != nil {
return nil, err return nil, err
@ -36,22 +50,52 @@ func fetchLatestDockerHubRelease(request *ReleaseRequest) (*AppRelease, error) {
httpRequest.Header.Add("Authorization", "Bearer "+(*request.Token)) httpRequest.Header.Add("Authorization", "Bearer "+(*request.Token))
} }
response, err := decodeJsonFromRequest[dockerHubRepositoryTagsResponse](defaultClient, httpRequest) var tag *dockerHubRepositoryTagResponse
if err != nil { if len(tagParts) == 1 {
return nil, err response, err := decodeJsonFromRequest[dockerHubRepositoryTagsResponse](defaultClient, httpRequest)
if err != nil {
return nil, err
}
if len(response.Results) == 0 {
return nil, fmt.Errorf("no tags found for repository: %s", request.Repository)
}
tag = &response.Results[0]
} else {
response, err := decodeJsonFromRequest[dockerHubRepositoryTagResponse](defaultClient, httpRequest)
if err != nil {
return nil, err
}
tag = &response
} }
if len(response.Results) == 0 { var repo string
return nil, fmt.Errorf("no tags found for repository: %s", request.Repository) var displayName string
var notesURL string
if len(tagParts) == 1 {
repo = nameParts[1]
} else {
repo = tagParts[0]
} }
tag := response.Results[0] if nameParts[0] == "library" {
displayName = repo
notesURL = fmt.Sprintf(dockerHubOfficialRepoTagURLFormat, repo, tag.Name)
} else {
displayName = nameParts[0] + "/" + repo
notesURL = fmt.Sprintf(dockerHubRepoTagURLFormat, displayName, tag.Name)
}
return &AppRelease{ return &AppRelease{
Source: ReleaseSourceDockerHub, Source: ReleaseSourceDockerHub,
NotesUrl: fmt.Sprintf(dockerHubReleaseNotesURLFormat, request.Repository, tag.Name), NotesUrl: notesURL,
Name: request.Repository, Name: displayName,
Version: tag.Name, Version: tag.Name,
TimeReleased: parseRFC3339Time(tag.LastPushed), TimeReleased: parseRFC3339Time(tag.LastPushed),
}, nil }, nil

View File

@ -38,7 +38,7 @@ func (widget *Releases) Initialize() error {
var gitLabTokenAsString = widget.GitLabToken.String() var gitLabTokenAsString = widget.GitLabToken.String()
for _, repository := range widget.Repositories { for _, repository := range widget.Repositories {
parts := strings.Split(repository, ":") parts := strings.SplitN(repository, ":", 2)
var request *feed.ReleaseRequest var request *feed.ReleaseRequest
if len(parts) == 1 { if len(parts) == 1 {