@recaptime-dev's working patches + fork for Phorge, a community fork of Phabricator. (Upstream dev and stable branches are at upstream/main and upstream/stable respectively.) hq.recaptime.dev/wiki/Phorge
phorge phabricator

Allow saving lint errors to database

Summary: This saves lint errors to the path change of current commit. It requires pushed revision. It doesn't save difference from previous commit mentioned in T2038#comment-4 - I don't plan doing it after all, everything would be much more complicated and the amount of data saved with this approach isn't that bad.

Test Plan: Applied patch, ran script, verified DB.

Reviewers: epriestley

Reviewed By: epriestley

CC: aran, Korvin

Maniphest Tasks: T2038

Differential Revision: https://secure.phabricator.com/D3899

vrana 23a046b3 d91305e5

+143
+24
resources/sql/patches/repository-lint.sql
··· 1 + CREATE TABLE {$NAMESPACE}_repository.repository_branch ( 2 + id int unsigned NOT NULL AUTO_INCREMENT, 3 + repositoryID int unsigned NOT NULL, 4 + name varchar(255) NOT NULL, 5 + lintCommit varchar(40), 6 + dateCreated int unsigned NOT NULL, 7 + dateModified int unsigned NOT NULL, 8 + UNIQUE (repositoryID, name), 9 + PRIMARY KEY (id) 10 + ); 11 + 12 + CREATE TABLE {$NAMESPACE}_repository.repository_lintmessage ( 13 + id int unsigned NOT NULL AUTO_INCREMENT, 14 + branchID int unsigned NOT NULL, 15 + path varchar(512) NOT NULL, 16 + line int unsigned NOT NULL, 17 + code varchar(32) NOT NULL, 18 + severity varchar(16) NOT NULL, 19 + name varchar(255) NOT NULL, 20 + description text NOT NULL, 21 + INDEX (branchID, path(64)), 22 + INDEX (branchID, code, path(64)), 23 + PRIMARY KEY (id) 24 + );
+103
scripts/repository/save_lint.php
··· 1 + #!/usr/bin/env php 2 + <?php 3 + 4 + require_once dirname(__FILE__).'/../__init_script__.php'; 5 + 6 + if (function_exists('posix_isatty') && posix_isatty(STDIN)) { 7 + $command = 'xargs -0 arc lint --output json | '.__FILE__; 8 + echo "Usage: git ls-files -z | {$command}\n"; 9 + echo "Usage: git diff --name-only -z | {$command}\n"; // TODO: Handle deletes. 10 + echo "Purpose: Save all lint errors to database.\n"; 11 + exit(1); 12 + } 13 + 14 + $working_copy = ArcanistWorkingCopyIdentity::newFromPath('.'); 15 + $api = ArcanistRepositoryAPI::newAPIFromWorkingCopyIdentity($working_copy); 16 + $svn_root = id(new PhutilURI($api->getSourceControlPath()))->getPath(); 17 + 18 + $project_id = $working_copy->getProjectID(); 19 + $project = id(new PhabricatorRepositoryArcanistProject()) 20 + ->loadOneWhere('name = %s', $project_id); 21 + if (!$project || !$project->getRepositoryID()) { 22 + throw new Exception("Couldn't find repository for {$project_id}."); 23 + } 24 + 25 + $branch_name = $api->getBranchName(); 26 + $branch = id(new PhabricatorRepositoryBranch())->loadOneWhere( 27 + 'repositoryID = %d AND name = %s', 28 + $project->getRepositoryID(), 29 + $branch_name); 30 + if (!$branch) { 31 + $branch = id(new PhabricatorRepositoryBranch()) 32 + ->setRepositoryID($project->getRepositoryID()) 33 + ->setName($branch_name); 34 + } 35 + $branch->setLintCommit($api->getWorkingCopyRevision()); 36 + $branch->save(); 37 + $conn = $branch->establishConnection('w'); 38 + 39 + $inserts = array(); 40 + 41 + while ($json = fgets(STDIN)) { 42 + $paths = json_decode(rtrim($json, "\n"), true); 43 + if (!is_array($paths)) { 44 + throw new Exception("Invalid JSON: {$json}"); 45 + } 46 + 47 + if (!$paths) { 48 + continue; 49 + } 50 + 51 + $conn->openTransaction(); 52 + 53 + foreach (array_chunk(array_keys($paths), 1024) as $some_paths) { 54 + $full_paths = array(); 55 + foreach ($some_paths as $path) { 56 + $full_paths[] = $svn_root.'/'.$path; 57 + } 58 + queryfx( 59 + $conn, 60 + 'DELETE FROM %T WHERE branchID = %d AND path IN (%Ls)', 61 + PhabricatorRepository::TABLE_LINTMESSAGE, 62 + $branch->getID(), 63 + $full_paths); 64 + } 65 + 66 + foreach ($paths as $path => $messages) { 67 + // TODO: Handle multiple $json for a single path. Don't save duplicates. 68 + 69 + foreach ($messages as $message) { 70 + $inserts[] = qsprintf( 71 + $conn, 72 + '(%d, %s, %d, %s, %s, %s, %s)', 73 + $branch->getID(), 74 + $svn_root.'/'.$path, 75 + idx($message, 'line', 0), 76 + idx($message, 'code', ''), 77 + idx($message, 'severity', ''), 78 + idx($message, 'name', ''), 79 + idx($message, 'description', '')); 80 + 81 + if (count($inserts) >= 256) { 82 + save_lint_messages($conn, $inserts); 83 + $inserts = array(); 84 + } 85 + } 86 + } 87 + 88 + $conn->saveTransaction(); 89 + } 90 + 91 + save_lint_messages($conn, $inserts); 92 + 93 + function save_lint_messages($conn, array $inserts) { 94 + if ($inserts) { 95 + queryfx( 96 + $conn, 97 + 'INSERT INTO %T 98 + (branchID, path, line, code, severity, name, description) 99 + VALUES %Q', 100 + PhabricatorRepository::TABLE_LINTMESSAGE, 101 + implode(', ', $inserts)); 102 + } 103 + }
+2
src/__phutil_library_map__.php
··· 992 992 'PhabricatorRepositoryArcanistProjectDeleteController' => 'applications/repository/controller/PhabricatorRepositoryArcanistProjectDeleteController.php', 993 993 'PhabricatorRepositoryArcanistProjectEditController' => 'applications/repository/controller/PhabricatorRepositoryArcanistProjectEditController.php', 994 994 'PhabricatorRepositoryAuditRequest' => 'applications/repository/storage/PhabricatorRepositoryAuditRequest.php', 995 + 'PhabricatorRepositoryBranch' => 'applications/repository/storage/PhabricatorRepositoryBranch.php', 995 996 'PhabricatorRepositoryCommit' => 'applications/repository/storage/PhabricatorRepositoryCommit.php', 996 997 'PhabricatorRepositoryCommitChangeParserWorker' => 'applications/repository/worker/commitchangeparser/PhabricatorRepositoryCommitChangeParserWorker.php', 997 998 'PhabricatorRepositoryCommitData' => 'applications/repository/storage/PhabricatorRepositoryCommitData.php', ··· 2175 2176 'PhabricatorRepositoryArcanistProjectDeleteController' => 'PhabricatorRepositoryController', 2176 2177 'PhabricatorRepositoryArcanistProjectEditController' => 'PhabricatorRepositoryController', 2177 2178 'PhabricatorRepositoryAuditRequest' => 'PhabricatorRepositoryDAO', 2179 + 'PhabricatorRepositoryBranch' => 'PhabricatorRepositoryDAO', 2178 2180 'PhabricatorRepositoryCommit' => 'PhabricatorRepositoryDAO', 2179 2181 'PhabricatorRepositoryCommitChangeParserWorker' => 'PhabricatorRepositoryCommitParserWorker', 2180 2182 'PhabricatorRepositoryCommitData' => 'PhabricatorRepositoryDAO',
+1
src/applications/repository/storage/PhabricatorRepository.php
··· 10 10 const TABLE_FILESYSTEM = 'repository_filesystem'; 11 11 const TABLE_SUMMARY = 'repository_summary'; 12 12 const TABLE_BADCOMMIT = 'repository_badcommit'; 13 + const TABLE_LINTMESSAGE = 'repository_lintmessage'; 13 14 14 15 protected $phid; 15 16 protected $name;
+9
src/applications/repository/storage/PhabricatorRepositoryBranch.php
··· 1 + <?php 2 + 3 + final class PhabricatorRepositoryBranch extends PhabricatorRepositoryDAO { 4 + 5 + protected $repositoryID; 6 + protected $name; 7 + protected $lintCommit; 8 + 9 + }
+4
src/infrastructure/storage/patch/PhabricatorBuiltinPatchList.php
··· 1024 1024 'type' => 'sql', 1025 1025 'name' => $this->getPatchPath('dropfileproxyimage.sql'), 1026 1026 ), 1027 + 'repository-lint.sql' => array( 1028 + 'type' => 'sql', 1029 + 'name' => $this->getPatchPath('repository-lint.sql'), 1030 + ), 1027 1031 ); 1028 1032 } 1029 1033