فهرست منبع

Improve dockerhub releases

Svilen Markov 10 ماه پیش
والد
کامیت
b484e32b08
3فایلهای تغییر یافته به همراه84 افزوده شده و 22 حذف شده
  1. 19 1
      docs/configuration.md
  2. 64 20
      internal/feed/dockerhub.go
  3. 1 1
      internal/widget/releases.go

+ 19 - 1
docs/configuration.md

@@ -1099,7 +1099,7 @@ Whether to ignore invalid/self-signed certificates.
 Whether to open the link in the same or a new tab.
 
 ### 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:
 
@@ -1138,6 +1138,24 @@ repositories:
   - 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`
 Shows an icon of the source (GitHub/GitLab/Docker Hub) next to the repository name when set to `true`.
 

+ 64 - 20
internal/feed/dockerhub.go

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

+ 1 - 1
internal/widget/releases.go

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