diff --git a/.github/workflows/release-docker.yml b/.github/workflows/release-docker.yml index bd4ff1375..738992293 100644 --- a/.github/workflows/release-docker.yml +++ b/.github/workflows/release-docker.yml @@ -70,7 +70,7 @@ jobs: with: context: . build-args: | - VERSION:${{ needs.release.outputs.tag }} + VERSION=${{ needs.release.outputs.tag }} platforms: linux/amd64,linux/arm64 push: true tags: ${{ steps.tags.outputs.tags }} diff --git a/README.md b/README.md index e59da3dd7..326fb54d1 100644 --- a/README.md +++ b/README.md @@ -3,6 +3,7 @@ > A tool designed to test if an IPFS Gateway implementation complies with the [IPFS Gateway Specification](https://specs.ipfs.tech/http-gateways/) correctly. > Distributed as a Docker image, as well as a GitHub Action(s). +- [Dashboard](#dashboard) - [Commands](#commands) - [`test`](#test) - [Inputs](#inputs) @@ -17,12 +18,42 @@ - [Local Development](#local-development) - [Examples](#examples) - [APIs](#apis) -- [Dashboard](#dashboard) - - [Adding your gateway to the dashboard](#adding-your-gateway-to-the-dashboard) - - [Building the Dashboard](#building-the-dashboard) - [FAQ](#faq) - [In Development](#in-development) +## Dashboard + +The [Implementation Dashboard](https://ipfs.github.io/gateway-conformance/) is a view that showcases different implementations of IPFS Gateways. This dashboard aggregates results from many test runs and renders them on a static website. This'll give you more detailed insights and navigation options. + +### How it Works + +For every implementations that have been added to the `REPOSITORIES` file, our dashboard generation workflow loads the most recent `gateway-conformance` test results from their CI. You can try this locally with the `make website` command. + +### Adding your gateway to the dashboard + +The dashboard is hosted at [conformance.ipfs.tech](https://conformance.ipfs.tech/). It aggregates test outputs from various IPFS implementations and renders them on a static website. + +To add your gateway to the dashboard, you need to: + +- Ensure that your gateway's repository is public. +- Ensure your gateway generates generates the `output.json` file in a `gateway-conformance.yml` file. Check [kubo's workflow](https://github.com/ipfs/kubo/blob/master/.github/workflows/gateway-conformance.yml) for an example. +- Add your gateway to the list of repositories in the [REPOSITORIES](./REPOSITORIES) file. + +Once you join the dashboard, your test results will be picked up automatically and your implementation will show up on the dashboard. + +### Building the Dashboard + +- Set up a GitHub Token: Ensure you have a GitHub Token with `repo:read` scope. This is required to download artifacts. +- Run the Build Command: `GH_TOKEN=your_github_token make website` + +This command downloads the latest test artifacts from the repositories listed in the `./REPOSITORIES` file. Then it generates a static website with Hugo in the `www/public` directory. + +### How to work on the Dashboard + +- Use `make website` to generate all the assets required to build the static dashboard +- Use `cd ./www && hugo server` to start a local server with live-reload +- Use `cd ./www/themes/conformance && npm run build` to re-build the theme's styles + ## Commands ### test @@ -304,29 +335,6 @@ This templating is used almost everywhere in the test sugar, for example in requ Request().Path("ipfs/{{cid}}", myCid) // will use "ipfs/Qm...." ``` -## Dashboard - -The gateway conformance test suite includes a web dashboard. This dashboard aggregates results from many test runs and renders them on a static website. This'll give you more detailed insights and navigation options. - -### Adding your gateway to the dashboard - -The dashboard is hosted at [conformance.ipfs.tech](https://conformance.ipfs.tech/). It aggregates test outputs from various IPFS implementations and renders them on a static website. - -To add your gateway to the dashboard, you need to: - -- Ensure that your gateway's repository is public. -- Ensure your gateway generates generates the `output.json` file in a `gateway-conformance.yml` file. Check [kubo's workflow](https://github.com/ipfs/kubo/blob/master/.github/workflows/gateway-conformance.yml) for an example. -- Add your gateway to the list of repositories in the [REPOSITORIES](./REPOSITORIES) file. - -Once you join the dashboard, your test results will be picked up automatically and your implementation will show up on the dashboard. - -### Building the Dashboard - -- Set up a GitHub Token: Ensure you have a GitHub Token with `repo:read` scope. This is required to download artifacts. -- Run the Build Command: `GH_TOKEN=your_github_token make website` - -This command downloads the latest test artifacts from the repositories listed in the `./REPOSITORIES` file. Then it generates a static website with Hugo in the `www/public` directory. - ## FAQ ### How to generate XML, HTML and Markdown reports when using the tool as a Docker container? diff --git a/munge_aggregates.js b/munge_aggregates.js index 117a1000b..420a8ff50 100644 --- a/munge_aggregates.js +++ b/munge_aggregates.js @@ -63,6 +63,36 @@ const computeName = (u) => { }; }; +const getTestRunDetails = async (jobUrl) => { + if (!jobUrl) { + return {}; + } + + const match = jobUrl.match(/https:\/\/github\.com\/([^\/]+)\/([^\/]+)\/actions\/runs\/(\d+)/); + if (!match) { + console.warn('Invalid URL format:', jobUrl); + return {}; + } + + const [, owner, repo, run_id] = match; + + const apiUrl = `https://api.github.com/repos/${owner}/${repo}/actions/runs/${run_id}`; + + try { + // Required node18 + const result = await fetch(apiUrl, { + headers: { + 'Accept': 'application/vnd.github.v3+json' + } + }) + const { created_at, head_sha, head_branch, run_started_at } = await result.json() + return { created_at, head_sha, head_branch, run_started_at } + } catch (e) { + console.error(`Error fetch ${jobUrl} details:`, e); + return {} + } +} + const main = async () => { let db = new sqlite3.Database(dbFile, (err) => { if (err) { @@ -86,7 +116,9 @@ const main = async () => { if (!runs[id]) { runs[id] = {}; } - runs[id][version] = rest; + const testRunDetails = await getTestRunDetails(rest.job_url); + + runs[id][version] = { ...rest, ...testRunDetails }; } outputJSON("data/testruns.json", runs); diff --git a/www/themes/conformance/assets/style.css b/www/themes/conformance/assets/style.css index 92c14b41b..6b0d7b894 100644 --- a/www/themes/conformance/assets/style.css +++ b/www/themes/conformance/assets/style.css @@ -788,11 +788,6 @@ video { margin-bottom: 1.5rem; } -.my-auto { - margin-top: auto; - margin-bottom: auto; -} - .mb-3 { margin-bottom: 0.75rem; } @@ -801,8 +796,8 @@ video { margin-bottom: 1rem; } -.ml-4 { - margin-left: 1rem; +.mb-6 { + margin-bottom: 1.5rem; } .mr-2 { @@ -873,10 +868,18 @@ video { width: 1.25rem; } +.w-8 { + width: 2rem; +} + .w-auto { width: auto; } +.w-full { + width: 100%; +} + .min-w-full { min-width: 100%; } @@ -901,10 +904,6 @@ video { grid-template-columns: repeat(1, minmax(0, 1fr)); } -.flex-col { - flex-direction: column; -} - .items-center { align-items: center; } @@ -927,12 +926,6 @@ video { column-gap: 1.5rem; } -.space-x-4 > :not([hidden]) ~ :not([hidden]) { - --tw-space-x-reverse: 0; - margin-right: calc(1rem * var(--tw-space-x-reverse)); - margin-left: calc(1rem * calc(1 - var(--tw-space-x-reverse))); -} - .divide-y > :not([hidden]) ~ :not([hidden]) { --tw-divide-y-reverse: 0; border-top-width: calc(1px * calc(1 - var(--tw-divide-y-reverse))); @@ -1065,10 +1058,22 @@ video { padding-bottom: 0.5rem; } +.pb-4 { + padding-bottom: 1rem; +} + +.pr-4 { + padding-right: 1rem; +} + .pt-1 { padding-top: 0.25rem; } +.text-left { + text-align: left; +} + .text-center { text-align: center; } @@ -1124,6 +1129,11 @@ video { color: rgb(59 130 246 / var(--tw-text-opacity)); } +.text-blue-600 { + --tw-text-opacity: 1; + color: rgb(37 99 235 / var(--tw-text-opacity)); +} + .text-blue-700 { --tw-text-opacity: 1; color: rgb(29 78 216 / var(--tw-text-opacity)); @@ -1444,6 +1454,10 @@ article th { color: rgb(55 65 81 / var(--tw-text-opacity)); } +.hover\:underline:hover { + text-decoration-line: underline; +} + @media (min-width: 640px) { .sm\:px-6 { padding-left: 1.5rem; diff --git a/www/themes/conformance/layouts/partials/breadcrumbs.html b/www/themes/conformance/layouts/partials/breadcrumbs.html index bf6652897..d4885f72e 100644 --- a/www/themes/conformance/layouts/partials/breadcrumbs.html +++ b/www/themes/conformance/layouts/partials/breadcrumbs.html @@ -1,23 +1,21 @@ {{ define "breadcrumbitem" }} -
  • -
    {{ if (gt (len .Ancestors) 0) }} {{ .Title }} {{ else }} - + {{/* {{ .Title }} - + */}} {{ end }} -
    -
  • {{ end }} -
    - -
    +{{- range $i, $p := .Ancestors.Reverse }} + {{ template "breadcrumbitem" $p }} +{{ end }} +{{ template "breadcrumbitem" . }} diff --git a/www/themes/conformance/layouts/partials/header.html b/www/themes/conformance/layouts/partials/header.html index f163e6976..df9ceaaae 100644 --- a/www/themes/conformance/layouts/partials/header.html +++ b/www/themes/conformance/layouts/partials/header.html @@ -4,7 +4,7 @@ Logo - {{ if .Site.Menus.main }} + {{ if .Site.Menus.main }} {{ $currentPage := . }} {{ range .Site.Menus.main }} @@ -12,6 +12,10 @@ {{ end }} {{ end }} + + {{- block "breadcrumbs" . }} + {{ partial "breadcrumbs.html" . }} + {{- end -}} \ No newline at end of file diff --git a/www/themes/conformance/layouts/partials/result-table.html b/www/themes/conformance/layouts/partials/result-table.html index 7a6efb0f5..d04eb75ce 100644 --- a/www/themes/conformance/layouts/partials/result-table.html +++ b/www/themes/conformance/layouts/partials/result-table.html @@ -135,4 +135,4 @@ {{ end }} - \ No newline at end of file + diff --git a/www/themes/conformance/layouts/results/term.html b/www/themes/conformance/layouts/results/term.html index c96322f15..5da9971fa 100644 --- a/www/themes/conformance/layouts/results/term.html +++ b/www/themes/conformance/layouts/results/term.html @@ -10,6 +10,41 @@

    {{.Title}}

    {{.TableOfContents}} {{.Content}} +
    + {{ $implem := .Params.implementation_id }} + {{ $requestedVersion := .Params.version }} + + {{ with (index site.Data "testruns" .Params.implementation_id ) }} + {{ range $version, $details := . }} + {{ if (or (eq $requestedVersion nil) (eq $requestedVersion $version)) }} +
    +

    Metadata

    + + + + + + + + + + + + + + + + + +
    Conformance Version:{{ $version }}
    Implementation Version:{{ $details.head_branch }} ({{ $details.head_sha }})
    Results Generated At:{{ $details.created_at }}
    Job URL:{{ $details.job_url }}
    +
    + {{ end }} + {{ end }} + {{ end }} +
    + +

    Results

    +
    {{ partial "result-table.html" .Params }}
    @@ -50,4 +85,4 @@

    See Also

  • {{.Title}}
  • {{end}} -{{end}} {{end}} \ No newline at end of file +{{end}} {{end}}