1import minimatch from 'minimatch';
2import path from 'path';
3import prettyBytes from 'pretty-bytes';
4
5import Git from '../../Git';
6import logger from '../../Logger';
7import { ReviewInput, ReviewOutput, ReviewStatus } from '../types';
8
9const FILE_SIZE_LIMIT = 5 * 1000 * 1000; // 5MB
10const PRETTY_FILE_SIZE_LIMIT = prettyBytes(FILE_SIZE_LIMIT);
11
12const IGNORED_PATHS = ['android/versioned-abis/**/*.aar'];
13
14export default async function ({ pullRequest, diff }: ReviewInput): Promise<ReviewOutput | null> {
15  if (!pullRequest.head) {
16    logger.warn('Detached PR, we cannot asses the state of files!', pullRequest);
17    return null;
18  }
19
20  const listTree = await Git.listTreeAsync(
21    pullRequest.head.sha,
22    diff.filter((file) => !file.deleted).map((file) => file.path)
23  );
24
25  const fileReports = listTree
26    .map((file) => {
27      const logs: string[] = [];
28
29      // We may ignore some paths where the files are allowed to be bigger (e.g. versioned .aar files).
30      if (IGNORED_PATHS.some((pattern) => minimatch(file.path, pattern))) {
31        return null;
32      }
33
34      const extname = path.extname(file.path).substr(1).toLowerCase();
35      if (extname === 'gif') {
36        logs.push(`**GIF** files are forbidden, please consider using **MP4** instead`);
37      }
38
39      if (file.size > FILE_SIZE_LIMIT) {
40        const prettySize = prettyBytes(file.size);
41        logs.push(`File size **${prettySize}** exceeds the limit of **${PRETTY_FILE_SIZE_LIMIT}**`);
42      }
43
44      if (logs.length === 0) {
45        return null;
46      }
47      return `- ${linkToFile(pullRequest.head, file.path)}\n  - ${logs.join('\n  - ')}`;
48    })
49    .filter(Boolean);
50
51  if (fileReports.length === 0) {
52    return null;
53  }
54
55  return {
56    status: ReviewStatus.ERROR,
57    title: 'Forbidden file size or format',
58    body: fileReports.join('\n'),
59  };
60}
61
62function linkToFile(head: ReviewInput['pullRequest']['head'], path: string): string {
63  return `[${path}](${head.repo?.html_url}/blob/${head.ref}/${encodeURIComponent(path)})`;
64}
65