Skip to content

GitHub — PR Comments

Pr-comments

Functions

postPRComment

async function postPRComment(config: PRCommentConfig, issues: DocumentationIssue[]): Promise<CommentResult>
TypeScript

Use postPRComment to automatically surface documentation issues as a GitHub PR review comment, so contributors see exactly what's missing before their code gets merged.

Reach for this in a CI pipeline or GitHub Action after running skrypt's analysis on a pull request. It's the last step in an automated doc-quality gate: scan the changed files, collect any DocumentationIssue objects, then call this to post them as a structured comment on the PR.

The function posts a single review comment to the GitHub Pull Requests API. If config.token is not provided, it falls back to the GITHUB_TOKEN environment variable — which is automatically available in GitHub Actions.

Parameters

NameTypeRequiredDescription
configPRCommentConfigYesGitHub connection details: repo owner, repo name, PR number, and optionally a personal access token with repo scope
config.tokenstringNoGitHub personal access token — falls back to GITHUB_TOKEN env var, so you can omit this in GitHub Actions
issuesDocumentationIssue[]YesThe documentation problems to report, typically the output of skrypt's analysis step. An empty array posts a ✅ all-clear comment

Returns

Returns a Promise<CommentResult> with the outcome of the API call — including the URL of the posted comment (result.commentUrl) so you can link to it in logs or downstream steps.

Heads up

  • The token needs repo scope for private repositories. For public repos, the default GITHUB_TOKEN in GitHub Actions is sufficient.
  • Calling this multiple times on the same PR creates multiple comments. If you're running this on every push, consider deleting or updating the previous comment to avoid noise.

Example:

type PRCommentConfig = {
  owner: string;
  repo: string;
  prNumber: number;
  token?: string;
};

type DocumentationIssue = {
  file: string;
  line: number;
  element: string;
  message: string;
  severity: "error" | "warning";
};

type CommentResult = {
  success: boolean;
  commentUrl: string;
  issueCount: number;
};

async function postPRComment(
  config: PRCommentConfig,
  issues: DocumentationIssue[]
): Promise<CommentResult> {
  const token = config.token || process.env.GITHUB_TOKEN;

  const body =
    issues.length === 0
      ? "✅ **skrypt**: All public API members are documented."
      : [
          `## 📄 Documentation Issues (${issues.length})`,
          "",
          "skrypt found the following documentation problems in this PR:",
          "",
          ...issues.map(
            (i) =>
              `- **${i.severity.toUpperCase()}** \`${i.file}:${i.line}\` — \`${i.element}\`: ${i.message}`
          ),
          "",
          "_Fix these before merging to keep your API docs complete._",
        ].join("\n");

  const response = await fetch(
    `https://api.github.com/repos/${config.owner}/${config.repo}/issues/${config.prNumber}/comments`,
    {
      method: "POST",
      headers: {
        Authorization: `Bearer ${token}`,
        "Content-Type": "application/json",
        Accept: "application/vnd.github+json",
      },
      body: JSON.stringify({ body }),
    }
  );

  if (!response.ok) {
    throw new Error(`GitHub API error: ${response.status} ${response.statusText}`);
  }

  const data = await response.json();

  return {
    success: true,
    commentUrl: data.html_url,
    issueCount: issues.length,
  };
}

// Example: post doc issues found on a PR in CI
const config: PRCommentConfig = {
  owner: "acme-corp",
  repo: "payments-sdk",
  prNumber: 142,
  // token omitted — reads from GITHUB_TOKEN in CI
};

const issues: DocumentationIssue[] = [
  {
    file: "src/client.ts",
    line: 34,
    element: "PaymentsClient.charge",
    message: "Missing @param description for `amount`",
    severity: "error",
  },
  {
    file: "src/webhooks.ts",
    line: 89,
    element: "verifySignature",
    message: "No return type documented",
    severity: "warning",
  },
];

try {
  const result = await postPRComment(config, issues);
  console.log(`Posted ${result.issueCount} issue(s) → ${result.commentUrl}`);
  // Posted 2 issue(s) → https://github.com/acme-corp/payments-sdk/pull/142#issuecomment-1984201337
} catch (err) {
  console.error("Failed to post PR comment:", err);
  process.exit(1);
}
TypeScript

postInlineComments

async function postInlineComments(config: PRCommentConfig, issues: DocumentationIssue[]): Promise<CommentResult[]>
TypeScript

Use postInlineComments to attach AI-generated documentation feedback directly to the lines of code that need it in a GitHub pull request review.

Reach for this after running skrypt's documentation analysis on a PR's changed files — it's the step that turns a list of documentation issues into actionable inline review comments that reviewers and authors see in the GitHub diff view.

Each issue in the issues array is mapped to a specific file path and line number, and posted as an inline comment on the PR. Authentication uses the token from config or falls back to the GITHUB_TOKEN environment variable, so it works out of the box in GitHub Actions.

Parameters

NameTypeRequiredDescription
configPRCommentConfigYesGitHub PR context and auth — includes the repo owner, repo name, PR number, and optionally a personal access token. If token is omitted, GITHUB_TOKEN must be set in the environment.
issuesDocumentationIssue[]YesDocumentation problems to post, each with a file path, line number, and message. An empty array is a no-op and returns [].

Returns

Returns a Promise<CommentResult[]> — one result per issue, each indicating whether the comment was successfully posted and the URL of the created comment. Use the results to surface failures (e.g., permission errors or invalid line numbers) without the entire batch silently dropping.

Heads up

  • Line numbers must correspond to lines in the PR diff, not the full file. Comments on lines outside the diff will fail silently or return an error result — validate line numbers against the diff before calling this.
  • Requires the GitHub token to have pull_requests: write permission. The default GITHUB_TOKEN in GitHub Actions has this, but fine-grained personal access tokens may not.

Example:

type PRCommentConfig = {
  token?: string;
  owner: string;
  repo: string;
  pullNumber: number;
  commitSha: string;
};

type DocumentationIssue = {
  path: string;
  line: number;
  message: string;
  severity: "error" | "warning" | "info";
};

type CommentResult = {
  success: boolean;
  issueIndex: number;
  commentUrl?: string;
  error?: string;
};

// Self-contained mock of postInlineComments
async function postInlineComments(
  config: PRCommentConfig,
  issues: DocumentationIssue[]
): Promise<CommentResult[]> {
  const token = config.token || process.env.GITHUB_TOKEN;
  if (!token) throw new Error("No GitHub token provided");

  const results: CommentResult[] = [];

  for (let i = 0; i < issues.length; i++) {
    const issue = issues[i];
    // Simulate GitHub API call
    const fakeCommentId = Math.floor(Math.random() * 900000000) + 100000000;
    results.push({
      success: true,
      issueIndex: i,
      commentUrl: `https://github.com/${config.owner}/${config.repo}/pull/${config.pullNumber}#discussion_r${fakeCommentId}`,
    });
  }

  return results;
}

const config: PRCommentConfig = {
  token: "ghp_A1B2C3D4E5F6G7H8I9J0K1L2M3N4O5P6Q7",
  owner: "acme-corp",
  repo: "payments-api",
  pullNumber: 142,
  commitSha: "a3f8c2e1d4b7690f2c5e8a1b3d6f9c2e4a7b0d3",
};

const issues: DocumentationIssue[] = [
  {
    path: "src/billing/invoice.ts",
    line: 34,
    message: "Missing @param documentation for `customerId` — callers won't know this expects a Stripe customer ID.",
    severity: "warning",
  },
  {
    path: "src/billing/invoice.ts",
    line: 61,
    message: "Return type is undocumented. Add @returns describing the shape of the invoice object.",
    severity: "error",
  },
  {
    path: "src/webhooks/handler.ts",
    line: 12,
    message: "Function has no JSDoc block. Add a description explaining which Stripe events this handles.",
    severity: "warning",
  },
];

async function main() {
  try {
    const results = await postInlineComments(config, issues);

    const succeeded = results.filter((r) => r.success);
    const failed = results.filter((r) => !r.success);

    console.log(`Posted ${succeeded.length}/${results.length} inline comments successfully.`);
    succeeded.forEach((r) => {
      console.log(`  ✓ Issue ${r.issueIndex}: ${r.commentUrl}`);
    });
    if (failed.length > 0) {
      console.warn(`  ✗ ${failed.length} comment(s) failed:`);
      failed.forEach((r) => console.warn(`    Issue ${r.issueIndex}: ${r.error}`));
    }
  } catch (err) {
    console.error("Failed to post comments:", err);
    process.exit(1);
  }
}

main();

// Expected output:
// Posted 3/3 inline comments successfully.
//   ✓ Issue 0: https://github.com/acme-corp/payments-api/pull/142#discussion_r583920471
//   ✓ Issue 1: https://github.com/acme-corp/payments-api/pull/142#discussion_r294817362
//   ✓ Issue 2: https://github.com/acme-corp/payments-api/pull/142#discussion_r748291053
TypeScript

analyzePRForDocs

async function analyzePRForDocs(config: PRCommentConfig, _options: { checkExamples?: boolean } = {}): Promise<DocumentationIssue[]>
TypeScript

Use analyzePRForDocs to scan a pull request and surface every function, class, or export that's missing or has incomplete documentation — before it merges.

Reach for this in a CI workflow or GitHub Action when you want to enforce documentation standards on new code. It pairs naturally with a PR comment bot: run it on each push, then post the returned issues as inline review comments so contributors know exactly what to fix.

It fetches the PR's changed files, parses the TypeScript AST, and compares exported symbols against their docstrings — flagging anything undocumented, missing parameter descriptions, or lacking a return type annotation.

Parameters

NameTypeRequiredDescription
configPRCommentConfigYesGitHub connection details and PR coordinates — includes token, owner, repo, and prNumber. The token needs pull_requests: read and contents: read permissions.
_options.checkExamplesbooleanNoWhen true, also flags documented symbols that have no @example block. Defaults to false, so example coverage is opt-in.

Returns

Returns a Promise<DocumentationIssue[]> — an array of issues, each describing a specific symbol and what's wrong with its docs. An empty array means the PR is clean. Pass the array to your comment formatter or fail the CI step if issues.length > 0.

Heads up

  • The _options parameter is reserved for future use — checkExamples is the only key currently respected, and behavior may expand in later versions.
  • The function reads from GitHub at call time, so it reflects the PR's state at that moment. Call it after the push event fires, not before the branch is updated.

Example:

type PRCommentConfig = {
  token: string;
  owner: string;
  repo: string;
  prNumber: number;
};

type DocumentationIssue = {
  symbol: string;
  file: string;
  line: number;
  issue: "missing_docstring" | "missing_param_docs" | "missing_return_doc" | "missing_example";
  message: string;
};

// Inline mock — replace with real analyzePRForDocs from autodocs
async function analyzePRForDocs(
  config: PRCommentConfig,
  _options: { checkExamples?: boolean } = {}
): Promise<DocumentationIssue[]> {
  console.log(
    `Scanning PR #${config.prNumber} on ${config.owner}/${config.repo}...`
  );

  // Simulated response from GitHub + AST analysis
  return [
    {
      symbol: "createPaymentIntent",
      file: "src/payments/intents.ts",
      line: 42,
      issue: "missing_param_docs",
      message: "Parameters 'amount' and 'currency' are undocumented.",
    },
    {
      symbol: "validateWebhook",
      file: "src/webhooks/validate.ts",
      line: 17,
      issue: "missing_return_doc",
      message: "Return type is undocumented.",
    },
  ];
}

async function main() {
  const config: PRCommentConfig = {
    token: "ghp_A1b2C3d4E5f6G7h8I9j0K1l2M3n4O5p6Q7",
    owner: "acme-corp",
    repo: "payments-sdk",
    prNumber: 284,
  };

  try {
    const issues = await analyzePRForDocs(config, { checkExamples: true });

    if (issues.length === 0) {
      console.log("✅ No documentation issues found.");
      process.exit(0);
    }

    console.log(`❌ Found ${issues.length} documentation issue(s):\n`);
    for (const issue of issues) {
      console.log(`  [${issue.symbol}] ${issue.file}:${issue.line}`);
      console.log(`  → ${issue.message}\n`);
    }

    // Fail CI if issues exist
    process.exit(1);
  } catch (err) {
    console.error("Failed to analyze PR:", err);
    process.exit(1);
  }
}

main();

// Expected output:
// Scanning PR #284 on acme-corp/payments-sdk...
// ❌ Found 2 documentation issue(s):
//
//   [createPaymentIntent] src/payments/intents.ts:42
//   → Parameters 'amount' and 'currency' are undocumented.
//
//   [validateWebhook] src/webhooks/validate.ts:17
//   → Return type is undocumented.
TypeScript
Was this helpful?