findutils 0.8.0

Rust implementation of GNU findutils
Documentation
on: [push, pull_request]

name: External-testsuites

jobs:
  gnu-tests:
    permissions:
      actions: read

    name: Run GNU findutils tests
    runs-on: ubuntu-latest
    steps:
      - name: Checkout findutils
        uses: actions/checkout@v4
        with:
          path: findutils
      - name: Checkout GNU findutils
        uses: actions/checkout@v4
        with:
          repository: gnu-mirror-unofficial/findutils
          path: findutils.gnu
          ref: 5768a03ddfb5e18b1682e339d6cdd24ff721c510
          submodules: false

      - name: Override submodule URL and initialize submodules
        # Use github instead of upstream git server
        run: |
          git submodule sync --recursive
          git config submodule.gnulib.url https://github.com/coreutils/gnulib.git
          git submodule update --init --recursive --depth 1
        working-directory: findutils.gnu
      - name: Install `rust` toolchain
        run: |
          ## Install `rust` toolchain
          rustup toolchain install stable --no-self-update -c rustfmt --profile minimal
          rustup default stable
      - name: Install dependencies
        shell: bash
        run: |
          # Enable sources & install dependencies
          sudo sed -i 's/^Types: deb$/Types: deb deb-src/' /etc/apt/sources.list.d/ubuntu.sources
          sudo apt-get update
          sudo apt-get build-dep findutils
      - name: Run GNU tests
        shell: bash
        run: |
          cd findutils
          bash util/build-gnu.sh ||:
      - name: Extract testing info
        shell: bash
        run: |

      - name: Upload gnu-test-report
        uses: actions/upload-artifact@v4
        with:
          name: gnu-test-report
          path: |
            findutils.gnu/find/testsuite/*.log
            findutils.gnu/xargs/testsuite/*.log
            findutils.gnu/tests/**/*.log
      - name: Upload gnu-result
        uses: actions/upload-artifact@v4
        with:
          name: gnu-result
          path: gnu-result.json
      - name: Download artifacts (gnu-result and gnu-test-report)
        uses: actions/github-script@v7
        with:
          script: |
            let fs = require('fs');
            fs.mkdirSync('${{ github.workspace }}/dl', { recursive: true });

            async function downloadArtifact(artifactName) {
              // List all artifacts from the workflow run
              let artifacts = await github.rest.actions.listWorkflowRunArtifacts({
                owner: context.repo.owner,
                repo: context.repo.repo,
                run_id: ${{ github.run_id }},
              });

              // Find the specified artifact
              let matchArtifact = artifacts.data.artifacts.find((artifact) => artifact.name === artifactName);
              if (!matchArtifact) {
                throw new Error(`Artifact "${artifactName}" not found.`);
              }

              // Download the artifact
              let download = await github.rest.actions.downloadArtifact({
                owner: context.repo.owner,
                repo: context.repo.repo,
                artifact_id: matchArtifact.id,
                archive_format: 'zip',
              });

              // Save the artifact to a file
              fs.writeFileSync(`${{ github.workspace }}/dl/${artifactName}.zip`, Buffer.from(download.data));
            }

            // Download the required artifacts
            await downloadArtifact("gnu-result");
            await downloadArtifact("gnu-test-report");

      - name: Compare failing tests against master
        shell: bash
        run: |
          ./findutils/util/diff-gnu.sh ./dl ./findutils.gnu
      - name: Compare against main results
        shell: bash
        run: |
          unzip dl/gnu-result.zip -d dl/
          unzip dl/gnu-test-report.zip -d dl/
          mv dl/gnu-result.json latest-gnu-result.json
          python findutils/util/compare_gnu_result.py

  bfs-tests:
    name: Run BFS tests
    runs-on: ubuntu-latest
    steps:
      - name: Checkout findutils
        uses: actions/checkout@v4
        with:
          path: findutils
      - name: Checkout BFS
        uses: actions/checkout@v4
        with:
          repository: tavianator/bfs
          path: bfs
          ref: "4.0"
      - name: Install `rust` toolchain
        run: |
          ## Install `rust` toolchain
          rustup toolchain install stable --no-self-update -c rustfmt --profile minimal
          rustup default stable
      - name: Install dependencies
        shell: bash
        run: |
          # Enable sources & install dependencies
          sudo sed -i 's/^Types: deb$/Types: deb deb-src/' /etc/apt/sources.list.d/ubuntu.sources
          sudo apt-get update
          sudo apt-get build-dep bfs
      - name: Run BFS tests
        shell: bash
        run: |
          cd findutils
          bash util/build-bfs.sh ||:
      - name: Upload bfs-test-report
        uses: actions/upload-artifact@v4
        with:
          name: bfs-test-report
          path: bfs/tests.log
      - name: Upload bfs-result
        uses: actions/upload-artifact@v4
        with:
          name: bfs-result
          path: bfs-result.json
      - name: Download artifacts (gnu-result and bfs-test-report)
        uses: actions/github-script@v7
        with:
          script: |
            let fs = require('fs');
            fs.mkdirSync('${{ github.workspace }}/dl', { recursive: true });

            async function downloadArtifact(artifactName) {
              // List all artifacts from the workflow run
              let artifacts = await github.rest.actions.listWorkflowRunArtifacts({
                owner: context.repo.owner,
                repo: context.repo.repo,
                run_id: ${{ github.run_id }},
              });

              // Find the specified artifact
              let matchArtifact = artifacts.data.artifacts.find((artifact) => artifact.name === artifactName);
              if (!matchArtifact) {
                throw new Error(`Artifact "${artifactName}" not found.`);
              }

              // Download the artifact
              let download = await github.rest.actions.downloadArtifact({
                owner: context.repo.owner,
                repo: context.repo.repo,
                artifact_id: matchArtifact.id,
                archive_format: 'zip',
              });

              // Save the artifact to a file
              fs.writeFileSync(`${{ github.workspace }}/dl/${artifactName}.zip`, Buffer.from(download.data));
            }

            // Download the required artifacts
            await downloadArtifact("bfs-result");
            await downloadArtifact("bfs-test-report");
      - name: Compare failing tests against main
        shell: bash
        run: |
          ./findutils/util/diff-bfs.sh dl/tests.log bfs/tests.log
      - name: Compare against main results
        shell: bash
        run: |
          unzip dl/bfs-result.zip -d dl/
          unzip dl/bfs-test-report.zip -d dl/
          mv dl/bfs-result.json latest-bfs-result.json
          python findutils/util/compare_bfs_result.py

  upload-annotations:
    name: Upload annotations
    runs-on: ubuntu-latest
    needs: [gnu-tests, bfs-tests]
    if: ${{ github.event_name == 'pull_request' }}

    steps:
      - name: List Annotations
        uses: actions/github-script@v7

        with:
          script: |
            let runs = await github.rest.checks.listForRef({
              owner: context.repo.owner,
              repo: context.repo.repo,
              ref: '${{ github.event.pull_request.head.sha }}'
            });

            let names = ['Run GNU findutils tests', 'Run BFS tests'];
            let results = [];
            runs.data.check_runs.filter(check => names.includes(check.name)).forEach(run => results.push(run));

            let annotations = { data: [], pull_request_number: '${{ github.event.number }}' };
            for (let result of results) {
              let run = await github.rest.checks.listAnnotations({
                owner: context.repo.owner,
                repo: context.repo.repo,
                check_run_id: result.id
              });

              run.data.forEach(data => {
                annotations.data.push({
                  run: result.name,
                  annotation: data
                });
              });
            }

            // Remove duplicate items.
            annotations.data = annotations.data.filter((value, index, self) =>
              self.findIndex(v => v.annotation.message === value.annotation.message) === index);

            let fs = require('fs');
            fs.writeFileSync('${{ github.workspace }}/annotations.json', JSON.stringify(annotations));

      - name: Upload annotations
        uses: actions/upload-artifact@v4
        with:
          name: comment
          path: annotations.json