diff --git a/assets/icons/ansible.svg b/assets/icons/ansible.svg new file mode 100644 index 00000000..afc3718d --- /dev/null +++ b/assets/icons/ansible.svg @@ -0,0 +1,2 @@ + + diff --git a/assets/js/fetch-repo.js b/assets/js/fetch-repo.js index 61bedfd0..0ea2bf67 100644 --- a/assets/js/fetch-repo.js +++ b/assets/js/fetch-repo.js @@ -12,6 +12,14 @@ } const platforms = { + "ansible-role": { + "results.0.download_count": "downloads", + "results.0.summary_fields.versions.0.name": "version", + }, + "ansible-collection": { + download_count: "downloads", + "highest_version.version": "version", + }, github: { full_name: "full_name", description: "description", @@ -49,12 +57,27 @@ }, }; + const formatThousands = (value) => + value == null ? value : Number(value).toLocaleString("en-US"); + const processors = { huggingface: { description: (value) => value?.replace(/Dataset Card for .+?\s+Dataset Summary\s+/, "").trim() || value, }, + "ansible-role": { + "results.0.download_count": formatThousands, + }, + "ansible-collection": { + download_count: formatThousands, + }, }; + const getNested = (obj, path) => + path.split(".").reduce((acc, key) => { + if (acc == null) return undefined; + return Array.isArray(acc) ? acc[Number(key)] : acc[key]; + }, obj); + const platform = Object.keys(platforms).find((p) => repoId.startsWith(p)) || "github"; const mapping = platforms[platform]; @@ -77,7 +100,7 @@ Object.entries(mapping).forEach(([dataField, elementSuffix]) => { const element = document.getElementById(`${repoId}-${elementSuffix}`); if (element) { - let value = data[dataField]; + let value = getNested(data, dataField); if (processors[platform]?.[dataField]) { value = processors[platform][dataField](value); } diff --git a/exampleSite/content/docs/shortcodes/index.md b/exampleSite/content/docs/shortcodes/index.md index 707deb26..af0a381e 100644 --- a/exampleSite/content/docs/shortcodes/index.md +++ b/exampleSite/content/docs/shortcodes/index.md @@ -187,6 +187,37 @@ The alert sign (`+` or `-`) is optional to control whether the admonition is fol


+## Ansible Galaxy Card + +`ansible` renders a card for an [Ansible Galaxy](https://galaxy.ansible.com/) entry, fetched at build time. It accepts either a `role` or a `collection` parameter, both in `namespace.name` form. + + +| Parameter | Description | +| ------------ | ------------------------------------------------------------------------------------ | +| `role` | [String] Galaxy role in the format `namespace.name`, e.g. `geerlingguy.docker` | +| `collection` | [String] Galaxy collection in the format `namespace.name`, e.g. `community.general` | + + +Set exactly one of `role` or `collection` per call. + +**Example 1: Role** + +```md +{{}} +``` + +{{< ansible role="geerlingguy.docker" >}} + +**Example 2: Collection** + +```md +{{}} +``` + +{{< ansible collection="community.general" >}} + +


+ ## Article `Article` will embed a single article into a markdown file. The `link` to the file should be the `.RelPermalink` of the file to be embedded. Note that the shortcode will not display anything if it's referencing it's parent. _Note: if you are running your website in a subfolder like Blowfish (i.e. /blowfish/) please include that path in the link._ diff --git a/layouts/shortcodes/ansible.html b/layouts/shortcodes/ansible.html new file mode 100644 index 00000000..99c5306a --- /dev/null +++ b/layouts/shortcodes/ansible.html @@ -0,0 +1,174 @@ +{{- $role := .Get "role" -}} +{{- $collection := .Get "collection" -}} +{{- $apiURL := "" -}} +{{- $repoLink := "" -}} +{{- $type := "" -}} +{{- $namespace := "" -}} +{{- $name := "" -}} + +{{- if $role -}} + {{- $parts := split $role "." -}} + {{- $namespace = index $parts 0 -}} + {{- $name = index $parts 1 -}} + {{- $apiURL = print "https://galaxy.ansible.com/api/v1/roles/?owner__username=" $namespace "&name=" $name -}} + {{- $repoLink = print "https://galaxy.ansible.com/ui/standalone/roles/" $namespace "/" $name "/" -}} + {{- $type = "role" -}} +{{- else if $collection -}} + {{- $parts := split $collection "." -}} + {{- $namespace = index $parts 0 -}} + {{- $name = index $parts 1 -}} + {{- $apiURL = print "https://galaxy.ansible.com/api/v3/plugin/ansible/content/published/collections/index/" $namespace "/" $name "/" -}} + {{- $repoLink = print "https://galaxy.ansible.com/ui/repo/published/" $namespace "/" $name "/" -}} + {{- $type = "collection" -}} +{{- end -}} + +{{ $id := delimit (slice "ansible" $type (partial "functions/uid.html" .)) "-" }} + +{{- $title := "" -}} +{{- $description := "" -}} +{{- $downloads := 0 -}} +{{- $version := "" -}} +{{- $tags := slice -}} +{{- $license := "" -}} +{{- $dataAvailable := false -}} + +{{- /* Formats an integer with comma thousand separators (lang.NumFmt is unavailable in this template context). */ -}} +{{- define "_format-int" -}} + {{- $n := printf "%d" (int .) -}} + {{- $out := "" -}} + {{- $len := len $n -}} + {{- range $i := seq $len -}} + {{- $idx := sub $i 1 -}} + {{- $c := substr $n $idx 1 -}} + {{- if and (gt $idx 0) (eq (mod (sub $len $idx) 3) 0) -}} + {{- $out = print $out "," $c -}} + {{- else -}} + {{- $out = print $out $c -}} + {{- end -}} + {{- end -}} + {{- $out -}} +{{- end -}} + +{{- with try (resources.GetRemote $apiURL) -}} + {{- with .Err -}} + {{- warnf "ansible shortcode: failed to fetch remote resource from %q: %s" $apiURL $.Position -}} + {{- else with .Value -}} + {{- $resp := . | transform.Unmarshal -}} + {{- if eq $type "role" -}} + {{- with index ($resp.results | default slice) 0 -}} + {{- $title = print $namespace "." .name -}} + {{- $description = .description -}} + {{- $downloads = .download_count -}} + {{- with .summary_fields -}} + {{- with index (.versions | default slice) 0 -}} + {{- $version = .name -}} + {{- end -}} + {{- $tags = .tags -}} + {{- end -}} + {{- $dataAvailable = true -}} + {{- end -}} + {{- else if eq $type "collection" -}} + {{- $title = print $namespace "." $name -}} + {{- $downloads = $resp.download_count -}} + {{- with $resp.highest_version -}} + {{- $version = .version -}} + {{- end -}} + {{- if $version -}} + {{- $versionURL := print $apiURL "versions/" $version "/" -}} + {{- with try (resources.GetRemote $versionURL) -}} + {{- with .Value -}} + {{- $verResp := . | transform.Unmarshal -}} + {{- with $verResp.metadata -}} + {{- $description = .description -}} + {{- $tags = .tags -}} + {{- with .license -}} + {{- $license = index . 0 -}} + {{- end -}} + {{- end -}} + {{- end -}} + {{- end -}} + {{- end -}} + {{- $dataAvailable = true -}} + {{- end -}} + {{- else -}} + {{- warnf "ansible shortcode: unable to get remote resource from %q: %s" $apiURL $.Position -}} + {{- end -}} +{{- end -}} + +{{- if $dataAvailable -}} +
+ +
+
+ + {{ partial "icon.html" "ansible" }} + +
+ {{ $title }} +
+
+ + {{- if $description }} +

+ {{ $description | markdownify }} +

+ {{- end }} + +
+ + {{ $type }} + + + + {{ partial "icon.html" "download" }} + +
+ {{ template "_format-int" $downloads }} +
+ + {{- if $version }} + + {{ partial "icon.html" "tag" }} + +
+ {{ $version }} +
+ {{- end }} + + {{- if $license }} + + {{ partial "icon.html" "scale-balanced" }} + +
+ {{ $license }} +
+ {{- end }} +
+ + {{- if $tags }} +
+ {{- range first 5 $tags }} + + {{ . }} + + {{- end }} +
+ {{- end }} +
+ {{ $fetchRepo := resources.Get "js/fetch-repo.js" }} + {{ $fetchRepo = $fetchRepo | resources.Minify | resources.Fingerprint ($.Site.Params.fingerprintAlgorithm | default "sha512") }} + +
+
+{{- else if $apiURL -}} + {{ warnf "ansible shortcode: unable to fetch %q: %s" $apiURL .Position }} +{{- end -}}