name: Labeler

on:
  pull_request_target:
    types: [opened, synchronize, reopened]
  issues:
    types: [opened]

permissions: {}

jobs:
  label:
    permissions:
      contents: read
      pull-requests: write
    runs-on: ubuntu-latest
    steps:
      - uses: actions/create-github-app-token@d72941d797fd3113feb6b93fd0dec494b13a2547 # v1
        id: app-token
        with:
          app-id: "2729701"
          private-key: ${{ secrets.GH_APP_PRIVATE_KEY }}
      - uses: actions/labeler@8558fd74291d67161a8a78ce36a881fa63b766a9 # v5
        with:
          configuration-path: .github/labeler.yml
          repo-token: ${{ steps.app-token.outputs.token }}
          sync-labels: true
      - name: Apply PR size label
        uses: actions/github-script@f28e40c7f34bde8b3046d885e986cb6290c5673b # v7
        with:
          github-token: ${{ steps.app-token.outputs.token }}
          script: |
            const pullRequest = context.payload.pull_request;
            if (!pullRequest) {
              return;
            }

            const sizeLabels = ["size: XS", "size: S", "size: M", "size: L", "size: XL"];
            const labelColor = "fbca04";

            for (const label of sizeLabels) {
              try {
                await github.rest.issues.getLabel({
                  owner: context.repo.owner,
                  repo: context.repo.repo,
                  name: label,
                });
              } catch (error) {
                if (error?.status !== 404) {
                  throw error;
                }
                await github.rest.issues.createLabel({
                  owner: context.repo.owner,
                  repo: context.repo.repo,
                  name: label,
                  color: labelColor,
                });
              }
            }

            const files = await github.paginate(github.rest.pulls.listFiles, {
              owner: context.repo.owner,
              repo: context.repo.repo,
              pull_number: pullRequest.number,
              per_page: 100,
            });

            const excludedLockfiles = new Set(["pnpm-lock.yaml", "package-lock.json", "yarn.lock", "bun.lockb"]);
            const totalChangedLines = files.reduce((total, file) => {
              const path = file.filename ?? "";
              if (path === "docs.acp.md" || path.startsWith("docs/") || excludedLockfiles.has(path)) {
                return total;
              }
              return total + (file.additions ?? 0) + (file.deletions ?? 0);
            }, 0);

            let targetSizeLabel = "size: XL";
            if (totalChangedLines < 50) {
              targetSizeLabel = "size: XS";
            } else if (totalChangedLines < 200) {
              targetSizeLabel = "size: S";
            } else if (totalChangedLines < 500) {
              targetSizeLabel = "size: M";
            } else if (totalChangedLines < 1000) {
              targetSizeLabel = "size: L";
            }

            const currentLabels = await github.paginate(github.rest.issues.listLabelsOnIssue, {
              owner: context.repo.owner,
              repo: context.repo.repo,
              issue_number: pullRequest.number,
              per_page: 100,
            });

            for (const label of currentLabels) {
              const name = label.name ?? "";
              if (!sizeLabels.includes(name)) {
                continue;
              }
              if (name === targetSizeLabel) {
                continue;
              }
              await github.rest.issues.removeLabel({
                owner: context.repo.owner,
                repo: context.repo.repo,
                issue_number: pullRequest.number,
                name,
              });
            }

            await github.rest.issues.addLabels({
              owner: context.repo.owner,
              repo: context.repo.repo,
              issue_number: pullRequest.number,
              labels: [targetSizeLabel],
            });
      - name: Apply maintainer label for org members
        uses: actions/github-script@f28e40c7f34bde8b3046d885e986cb6290c5673b # v7
        with:
          github-token: ${{ steps.app-token.outputs.token }}
          script: |
            const login = context.payload.pull_request?.user?.login;
            if (!login) {
              return;
            }

            let isMaintainer = false;
            try {
              const membership = await github.rest.teams.getMembershipForUserInOrg({
                org: context.repo.owner,
                team_slug: "maintainer",
                username: login,
              });
              isMaintainer = membership?.data?.state === "active";
            } catch (error) {
              if (error?.status !== 404) {
                throw error;
              }
            }

            if (!isMaintainer) {
              return;
            }

            await github.rest.issues.addLabels({
              ...context.repo,
              issue_number: context.payload.pull_request.number,
              labels: ["maintainer"],
            });

  label-issues:
    permissions:
      issues: write
    runs-on: ubuntu-latest
    steps:
      - uses: actions/create-github-app-token@d72941d797fd3113feb6b93fd0dec494b13a2547 # v1
        id: app-token
        with:
          app-id: "2729701"
          private-key: ${{ secrets.GH_APP_PRIVATE_KEY }}
      - name: Apply maintainer label for org members
        uses: actions/github-script@f28e40c7f34bde8b3046d885e986cb6290c5673b # v7
        with:
          github-token: ${{ steps.app-token.outputs.token }}
          script: |
            const login = context.payload.issue?.user?.login;
            if (!login) {
              return;
            }

            let isMaintainer = false;
            try {
              const membership = await github.rest.teams.getMembershipForUserInOrg({
                org: context.repo.owner,
                team_slug: "maintainer",
                username: login,
              });
              isMaintainer = membership?.data?.state === "active";
            } catch (error) {
              if (error?.status !== 404) {
                throw error;
              }
            }

            if (!isMaintainer) {
              return;
            }

            await github.rest.issues.addLabels({
              ...context.repo,
              issue_number: context.payload.issue.number,
              labels: ["maintainer"],
            });
