diff --git a/.github/actions/extract-fixtures/action.yml b/.github/actions/extract-fixtures/action.yml index c96a54ddb..1d349b991 100644 --- a/.github/actions/extract-fixtures/action.yml +++ b/.github/actions/extract-fixtures/action.yml @@ -22,6 +22,6 @@ runs: MERGED: ${{ inputs.merged }} with: repository: ${{ steps.github.outputs.action_repository }} - ref: ${{ steps.github.outputs.action_ref }} + ref: ${{ steps.github.outputs.action_sha || steps.github.outputs.action_ref }} dockerfile: Dockerfile args: extract-fixtures --directory="$OUTPUT" --merged="$MERGED" diff --git a/.github/actions/test/action.yml b/.github/actions/test/action.yml index 2d5d088ab..89664cc25 100644 --- a/.github/actions/test/action.yml +++ b/.github/actions/test/action.yml @@ -42,7 +42,7 @@ runs: SPECS: ${{ inputs.specs }} with: repository: ${{ steps.github.outputs.action_repository }} - ref: ${{ steps.github.outputs.action_ref }} + ref: ${{ steps.github.outputs.action_sha || steps.github.outputs.action_ref }} dockerfile: Dockerfile opts: --network=host args: test --url="$URL" --json="$JSON" --specs="$SPECS" --subdomain-url="$SUBDOMAIN" -- ${{ inputs.args }} diff --git a/.github/workflows/test-dev-e2e.yml b/.github/workflows/test-dev-e2e.yml new file mode 100644 index 000000000..13614bfce --- /dev/null +++ b/.github/workflows/test-dev-e2e.yml @@ -0,0 +1,54 @@ +name: Test Dev (e2e) + +on: + workflow_dispatch: + push: + branches: + - main + pull_request: + +jobs: + bifrost-gateway: + uses: singulargarden/bifrost-gateway2/.github/workflows/gateway-conformance.yml@main + with: + artifact_json_name: conformance-bifrost-gateway.json + kubo-gateway: + uses: singulargarden/kubo/.github/workflows/gateway-conformance.yml@master + with: + artifact_json_name: conformance-kubo-gateway.json + aggregate: + runs-on: "ubuntu-latest" + needs: [bifrost-gateway, kubo-gateway] + # the tests might have failed + if: always() + defaults: + run: + shell: bash + steps: + - uses: actions/checkout@v3 + with: + path: "gateway-conformance" + - name: Download Artifacts + uses: actions/download-artifact@v3 + with: + path: artifacts + - name: Aggregate results + working-directory: ./artifacts + run: | + set -e + set -o pipefail + mkdir ./aggregates + + # download-artifact downloads artifacts in a directory named after the artifact + # details: https://github.com/actions/download-artifact#download-all-artifacts + for folder in ./conformance-*.json; do + file="${folder}/output.json" + new_file="aggregates/${folder#conformance-}" + jq -ns 'inputs' "$file" | node ../gateway-conformance/aggregate.js 1 > "${new_file}" + done + + node ../gateway-conformance/aggregate-into-table.js ./aggregates/*.json > /tmp/table.md + node ../gateway-conformance/aggregate-update-names.js ../gateway-conformance/names.json /tmp/table.md > ./table.md + - name: Set summary + if: (failure() || success()) + run: cat ./artifacts/table.md >> $GITHUB_STEP_SUMMARY \ No newline at end of file diff --git a/.github/workflows/test-prod-e2e.yml b/.github/workflows/test-prod-e2e.yml index 8819deec2..fd5e48e1e 100644 --- a/.github/workflows/test-prod-e2e.yml +++ b/.github/workflows/test-prod-e2e.yml @@ -110,6 +110,7 @@ jobs: done node ../gateway-conformance/aggregate-into-table.js ./aggregates/*.json > ./table.md + node ../gateway-conformance/aggregate-update-names.js ../gateway-conformance/names.json ./table.md > ./table.md - name: Set summary if: (failure() || success()) run: cat ./artifacts/table.md >> $GITHUB_STEP_SUMMARY \ No newline at end of file diff --git a/.github/workflows/update-badge.yml b/.github/workflows/update-badge.yml index 4c647c439..d67720858 100644 --- a/.github/workflows/update-badge.yml +++ b/.github/workflows/update-badge.yml @@ -9,6 +9,7 @@ on: workflow_run: workflows: - Test Production (e2e) + - Test Dev (e2e) types: - completed branches: @@ -23,41 +24,67 @@ concurrency: cancel-in-progress: true jobs: - update-badge: + update-badge-prod: runs-on: ubuntu-latest steps: - uses: pl-strflt/job-summary-url-action@v1 id: metadata with: - workflow: test-prod-e2e.yml # ${{ github.event.workflow.path }} + workflow: ${{ github.event.workflow.path }} run_id: ${{ github.event.workflow_run.id }} run_attempt: ${{ github.event.workflow_run.run_attempt }} job: aggregate - uses: actions/checkout@v3 + - id: update + uses: actions/github-script@v6 + env: + WORKFLOW_PATH: ${{ github.event.workflow.path }} + BADGE_URL: ${{ github.event.workflow.badge_url }} + SUMMARY_URL: ${{ steps.metadata.outputs.job_summary_url }} + with: + script: | + const fs = require('fs') + + const workflowPath = process.env.WORKFLOW_PATH + const badgeURL = process.env.BADGE_URL + const refName = process.env.GITHUB_REF_NAME + const summaryURL = process.env.SUMMARY_URL + + console.log(` + workflowPath: ${workflowPath} + badgeURL: ${badgeURL} + refName: ${refName} + summaryURL: ${summaryURL} + `) + + function escapeRegExp(string) { + return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); + } + + const searchValue = new RegExp(`\\[!\\[([^\\]]+)\\]\\(.*${escapeRegExp(badgeURL)}.*\\)\\]\\(.*\\)`, 'g') + const replaceValue = `[![$1](${badgeURL}?branch=${refName})](${summaryURL})` + + console.log(`Searching for: ${searchValue}`) + console.log(`To replace it with: ${replaceValue}`) + + const readme = fs.readFileSync('README.md').toString() + const updatedReadme = readme.replace(searchValue, replaceValue) + + if (readme !== updatedReadme) { + console.log('Updating README') + fs.writeFileSync('README.md', updatedReadme) + return true + } else { + console.log('README does not need to be updated') + return false + } # https://github.com/orgs/community/discussions/26560 - - run: | + - if: steps.update.outputs.result == 'true' + run: | git config user.email "41898282+github-actions[bot]@users.noreply.github.com" git config user.name "github-actions[bot]" - - run: | - echo GITHUB_JOB_SUMMARY_URL=${GITHUB_JOB_SUMMARY_URL} - IN='[![Conformance Production Dashboard](https://github.com/ipfs/gateway-conformance/actions/workflows/test-prod-e2e.yml/badge.svg?branch=master)](.*)' - ESCAPED_IN=$(printf '%s\n' "$IN" | sed -e 's/[][\/!&]/\\&/g') - - OUT="[![Conformance Production Dashboard](https://github.com/ipfs/gateway-conformance/actions/workflows/test-prod-e2e.yml/badge.svg?branch=master)](${GITHUB_JOB_SUMMARY_URL})" - - sed -i "s;${ESCAPED_IN};${OUT};" README.md - env: - GITHUB_JOB_SUMMARY_URL: ${{ steps.metadata.outputs.job_summary_url }} - REPOSITORY: ${{ github.repository }} - - id: git - run: | - if [[ -n $(git diff --shortstat 2> /dev/null | tail -n1) ]]; then - echo "dirty=1" >> $GITHUB_OUTPUT - else - echo "dirty=0" >> $GITHUB_OUTPUT - fi - - if: steps.git.outputs.dirty == '1' + - if: steps.update.outputs.result == 'true' run: | git add README.md - git commit -m 'chore: update the link to the dashboard [skip ci]' - git push + git commit -m 'chore: update the link to the interop dashboard [skip ci]' + git push \ No newline at end of file diff --git a/README.md b/README.md index c0db0ba61..0f7623626 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,9 @@ `gateway-conformance` is a tool designed to test if an IPFS Gateway implementation complies with the IPFS Gateway Specification correctly. The tool is distributed as a Docker image, as well as a GitHub Action(s). -[![Conformance Production Dashboard](https://github.com/ipfs/gateway-conformance/actions/workflows/test-prod-e2e.yml/badge.svg?branch=master)]() +[![Conformance Production Dashboard](https://github.com/singulargarden/gateway-conformance/workflows/Test%20Dev%20(e2e)/badge.svg?branch=main)]() + +[![Conformance Dev Dashboard](https://github.com/singulargarden/gateway-conformance/workflows/Test%20Production%20(e2e)/badge.svg?branch=main)]() ## Table of Contents diff --git a/aggregate-update-names.js b/aggregate-update-names.js new file mode 100644 index 000000000..67d0b6a46 --- /dev/null +++ b/aggregate-update-names.js @@ -0,0 +1,27 @@ +const fs = require('fs'); + +const jsonFilePath = process.argv[2]; +const markdownFilePath = process.argv[3]; + +// Check if file paths are provided +if (!jsonFilePath || !markdownFilePath) { + console.error('Both a JSON file path and a Markdown file path must be provided.'); + process.exit(1); +} + +const jsonData = JSON.parse(fs.readFileSync(jsonFilePath, 'utf8')); +const sortedKeys = Object.keys(jsonData).sort((a, b) => b.length - a.length); + +let markdown = fs.readFileSync(markdownFilePath, 'utf8'); + +for (const key of sortedKeys) { + const newName = jsonData[key][1] + ? `[${jsonData[key][0]}](${jsonData[key][1]})` + : jsonData[key][0]; + + const regex = new RegExp(key, 'g'); + markdown = markdown.replace(regex, newName); +} + +// output the new markdown to stdout +fs.writeFileSync(1, markdown); \ No newline at end of file diff --git a/names.json b/names.json new file mode 100644 index 000000000..bc9a948f8 --- /dev/null +++ b/names.json @@ -0,0 +1,122 @@ +{ + "Cors": [ + "Cross-Origin Resource Sharing", + null + ], + "DagPbConversion": [ + "DAG-PB Conversion to DAG-CBOR/JSON", + "https://ipld.io/specs/codecs/dag-pb/spec/#logical-format" + ], + "DNSLinkGateway": [ + "DNSLink Gateway", + "https://specs.ipfs.tech/http-gateways/dnslink-gateway/" + ], + "DNSLinkGatewayUnixFSDirectoryListing": [ + "Generated UnixFS Directory Listing for DNSLink", + "https://specs.ipfs.tech/http-gateways/dnslink-gateway/" + ], + "GatewayBlock": [ + "Gateway Block", + null + ], + "GatewayCache": [ + "HTTP Caching", + null + ], + "GatewayCacheWithIPNS": [ + "HTTP Caching with IPNS", + null + ], + "GatewayIPNSRecord": [ + "Signed IPNS Record", + null + ], + "GatewayJSONCborAndIPNS": [ + "[DAG-]CBOR/JSON on IPNS", + null + ], + "GatewayJsonCbor": [ + "[DAG-]CBOR/JSON", + "https://specs.ipfs.tech/http-gateways/path-gateway/#traversing-through-dag-json-and-dag-cbor" + ], + "GatewaySubdomainAndIPNS": [ + "Subdomain Gateway with IPNS", + "https://specs.ipfs.tech/http-gateways/subdomain-gateway/" + ], + "GatewaySubdomains": [ + "Subdomain Gateway", + "https://specs.ipfs.tech/http-gateways/subdomain-gateway/" + ], + "GatewaySymlink": [ + "UnixFS Symlink", + null + ], + "NativeDag": [ + "Native DAG-CBOR/JSON", + null + ], + "Web Pathing": [ + "Pathing", + "https://specs.ipfs.tech/http-gateways/path-gateway/#content-resolution" + ], + "PlainCodec": [ + "Plain CBOR/JSON", + null + ], + "RedirectsFileSupport": [ + "_redirects File Support", + "https://specs.ipfs.tech/http-gateways/web-redirects-file/" + ], + "RedirectsFileSupportWithDNSLink": [ + "_redirects File Support with DNSLink", + "https://specs.ipfs.tech/http-gateways/web-redirects-file/" + ], + "SubdomainGatewayDNSLinkInlining": [ + "Subdomain Gateway DNSLink Inlining", + "https://specs.ipfs.tech/http-gateways/subdomain-gateway/#host-request-header" + ], + "Tar": [ + "TAR Responses", + null + ], + "TrustlessCarDagScopeAll": [ + "CAR with dag-scope=all", + "https://specs.ipfs.tech/http-gateways/trustless-gateway/#dag-scope-request-query-parameter" + ], + "TrustlessCarDagScopeBlock": [ + "CAR with dag-scope=block", + "https://specs.ipfs.tech/http-gateways/trustless-gateway/#dag-scope-request-query-parameter" + ], + "TrustlessCarDagScopeEntity": [ + "CAR with dag-scope=entity", + "https://specs.ipfs.tech/http-gateways/trustless-gateway/#dag-scope-request-query-parameter" + ], + "TrustlessCarEntityBytes": [ + "CAR with entity-bytes", + "https://specs.ipfs.tech/http-gateways/trustless-gateway/#entity-bytes-request-query-parameter" + ], + "TrustlessCarPathing": [ + "Trustless CAR with Web Pathing", + "https://specs.ipfs.tech/http-gateways/trustless-gateway/" + ], + "TrustlessRaw": [ + "Trustless Raw Block (application/vnd.ipld.raw)", + "https://specs.ipfs.tech/http-gateways/trustless-gateway/" + ], + "UnixFSDirectoryListing": [ + "UnixFS Directory Listing", + null + ], + "UnixFSDirectoryListingOnSubdomainGateway": [ + "UnixFS Directory Listing on Subdomain Gateway", + null + ], + "conformance-bifrost-gateway": [ + "ipfs/bifrost-gateway", + "https://github.com/ipfs/bifrost-gateway" + ], + "conformance-kubo-gateway": [ + "ipfs/kubo", + "https://github.com/ipfs/kubo" + ] +} \ No newline at end of file