diff --git a/conf/default.conf.php b/conf/default.conf.php
index 9d79cbd2be..7578ee2e40 100644
--- a/conf/default.conf.php
+++ b/conf/default.conf.php
@@ -1,643 +1,637 @@
null,
// If you have multiple environments, provide the production environment URI
// here so that emails, etc., generated in development/sandbox environments
// contain the right links.
'phabricator.production-uri' => null,
// Setting this to 'true' will invoke a special setup mode which helps guide
// you through setting up Phabricator.
'phabricator.setup' => false,
// The default PHID for users who haven't uploaded a profile image. It should
// be 50x50px.
'user.default-profile-image-phid' => 'PHID-FILE-4d61229816cfe6f2b2a3',
// -- IMPORTANT! Security! -------------------------------------------------- //
// IMPORTANT: By default, Phabricator serves files from the same domain the
// application lives on. This is convenient but not secure: it creates
// a vulnerability where an external attacker can:
//
// - Convince a privileged user to upload a file which appears to be an
// image or some other inoccuous type of file (the file is actually both
// a JAR and an image); and
// - convince the user to give them the URI for the image; and
// - convince the user to click a link to a site which embeds the "image"
// using an tag. This steals the user's credentials.
//
// If the attacker is internal, they can execute the first two steps
// themselves and need only convince another user to click a link in order to
// steal their credentials.
//
// To avoid this, you should configure a second domain in the same way you
// have the primary domain configured (e.g., point it at the same machine and
// set up the same vhost rules) and provide it here. For instance, if your
// primary install is on "http://www.phabricator-example.com/", you could
// configure "http://www.phabricator-files.com/" and specify the entire
// domain (with protocol) here. This will enforce that viewable files are
// served only from the alternate domain. Ideally, you should use a completely
// separate domain name rather than just a different subdomain.
//
// It is STRONGLY RECOMMENDED that you configure this. Phabricator makes this
// attack difficult, but it is viable unless you isolate the file domain.
'security.alternate-file-domain' => null,
// -- DarkConsole ----------------------------------------------------------- //
// DarkConsole is a administrative debugging/profiling tool built into
// Phabricator. You can leave it disabled unless you're developing against
// Phabricator.
// Determines whether or not DarkConsole is available. DarkConsole exposes
// some data like queries and stack traces, so you should be careful about
// turning it on in production (although users can not normally see it, even
// if the deployment configuration enables it).
'darkconsole.enabled' => false,
// Always enable DarkConsole, even for logged out users. This potentially
// exposes sensitive information to users, so make sure untrusted users can
// not access an install running in this mode. You should definitely leave
// this off in production. It is only really useful for using DarkConsole
// utilties to debug or profile logged-out pages. You must set
// 'darkconsole.enabled' to use this option.
'darkconsole.always-on' => false,
// Allows you to mask certain configuration values from appearing in the
// "Config" tab of DarkConsole.
'darkconsole.config-mask' => array(
'mysql.pass',
'amazon-ses.secret-key',
'recaptcha.private-key',
'phabricator.csrf-key',
'facebook.application-secret',
'github.application-secret',
),
// -- MySQL --------------------------------------------------------------- //
// The username to use when connecting to MySQL.
'mysql.user' => 'root',
// The password to use when connecting to MySQL.
'mysql.pass' => '',
// The MySQL server to connect to. If you want to connect to a different
// port than the default (which is 3306), specify it in the hostname
// (e.g., db.example.com:1234).
'mysql.host' => 'localhost',
// -- Email ----------------------------------------------------------------- //
// Some Phabricator tools send email notifications, e.g. when Differential
// revisions are updated or Maniphest tasks are changed. These options allow
// you to configure how email is delivered.
// You can test your mail setup by going to "MetaMTA" in the web interface,
// clicking "Send New Message", and then composing a message.
// Default address to send mail "From".
'metamta.default-address' => 'noreply@example.com',
// Domain used to generate Message-IDs.
'metamta.domain' => 'example.com',
// When a user takes an action which generates an email notification (like
// commenting on a Differential revision), Phabricator can either send that
// mail "From" the user's email address (like "alincoln@logcabin.com") or
// "From" the 'metamta.default-address' address. The user experience is
// generally better if Phabricator uses the user's real address as the "From"
// since the messages are easier to organize when they appear in mail clients,
// but this will only work if the server is authorized to send email on behalf
// of the "From" domain. Practically, this means:
// - If you are doing an install for Example Corp and all the users will
// have corporate @corp.example.com addresses and any hosts Phabricator
// is running on are authorized to send email from corp.example.com,
// you can enable this to make the user experience a little better.
// - If you are doing an install for an open source project and your
// users will be registering via Facebook and using personal email
// addresses, you MUST NOT enable this or virtually all of your outgoing
// email will vanish into SFP blackholes.
// - If your install is anything else, you're much safer leaving this
// off since the risk in turning it on is that your outgoing mail will
// mostly never arrive.
'metamta.can-send-as-user' => false,
// Adapter class to use to transmit mail to the MTA. The default uses
// PHPMailerLite, which will invoke "sendmail". This is appropriate
// if sendmail actually works on your host, but if you haven't configured mail
// it may not be so great. You can also use Amazon SES, by changing this to
// 'PhabricatorMailImplementationAmazonSESAdapter', signing up for SES, and
// filling in your 'amazon-ses.access-key' and 'amazon-ses.secret-key' below.
'metamta.mail-adapter' =>
'PhabricatorMailImplementationPHPMailerLiteAdapter',
// When email is sent, try to hand it off to the MTA immediately. This may
// be worth disabling if your MTA infrastructure is slow or unreliable. If you
// disable this option, you must run the 'metamta_mta.php' daemon or mail
// won't be handed off to the MTA. If you're using Amazon SES it can be a
// little slugish sometimes so it may be worth disabling this and moving to
// the daemon after you've got your install up and running. If you have a
// properly configured local MTA it should not be necessary to disable this.
'metamta.send-immediately' => true,
// If you're using Amazon SES to send email, provide your AWS access key
// and AWS secret key here. To set up Amazon SES with Phabricator, you need
// to:
// - Make sure 'metamta.mail-adapter' is set to:
// "PhabricatorMailImplementationAmazonSESAdapter"
// - Make sure 'metamta.can-send-as-user' is false.
// - Make sure 'metamta.default-address' is configured to something sensible.
// - Make sure 'metamta.default-address' is a validated SES "From" address.
'amazon-ses.access-key' => null,
'amazon-ses.secret-key' => null,
// If you're using Sendgrid to send email, provide your access credentials
// here. This will use the REST API. You can also use Sendgrid as a normal
// SMTP service.
'sendgrid.api-user' => null,
'sendgrid.api-key' => null,
// You can configure a reply handler domain so that email sent from Maniphest
// will have a special "Reply To" address like "T123+82+af19f@example.com"
// that allows recipients to reply by email and interact with tasks. For
// instructions on configurating reply handlers, see the article
// "Configuring Inbound Email" in the Phabricator documentation. By default,
// this is set to 'null' and Phabricator will use a generic 'noreply@' address
// or the address of the acting user instead of a special reply handler
// address (see 'metamta.default-address'). If you set a domain here,
// Phabricator will begin generating private reply handler addresses. See
// also 'metamta.maniphest.reply-handler' to further configure behavior.
// This key should be set to the domain part after the @, like "example.com".
'metamta.maniphest.reply-handler-domain' => null,
// You can follow the instructions in "Configuring Inbound Email" in the
// Phabricator documentation and set 'metamta.maniphest.reply-handler-domain'
// to support updating Maniphest tasks by email. If you want more advanced
// customization than this provides, you can override the reply handler
// class with an implementation of your own. This will allow you to do things
// like have a single public reply handler or change how private reply
// handlers are generated and validated.
// This key should be set to a loadable subclass of
// PhabricatorMailReplyHandler (and possibly of ManiphestReplyHandler).
'metamta.maniphest.reply-handler' => 'ManiphestReplyHandler',
// Prefix prepended to mail sent by Maniphest. You can change this to
// distinguish between testing and development installs, for example.
'metamta.maniphest.subject-prefix' => '[Maniphest]',
// See 'metamta.maniphest.reply-handler-domain'. This does the same thing,
// but allows email replies via Differential.
'metamta.differential.reply-handler-domain' => null,
// See 'metamta.maniphest.reply-handler'. This does the same thing, but
// affects Differential.
'metamta.differential.reply-handler' => 'DifferentialReplyHandler',
// Prefix prepended to mail sent by Differential.
'metamta.differential.subject-prefix' => '[Differential]',
// By default, Phabricator generates unique reply-to addresses and sends a
// separate email to each recipient when you enable reply handling. This is
// more secure than using "From" to establish user identity, but can mean
// users may receive multiple emails when they are on mailing lists. Instead,
// you can use a single, non-unique reply to address and authenticate users
// based on the "From" address by setting this to 'true'. This trades away
// a little bit of security for convenience, but it's reasonable in many
// installs. Object interactions are still protected using hashes in the
// single public email address, so objects can not be replied to blindly.
'metamta.public-replies' => false,
// You can configure an email address like "bugs@phabricator.example.com"
// which will automatically create Maniphest tasks when users send email
// to it. This relies on the "From" address to authenticate users, so it is
// is not completely secure. To set this up, enter a complete email
// address like "bugs@phabricator.example.com" and then configure mail to
// that address so it routed to Phabricator (if you've already configured
// reply handlers, you're probably already done). See "Configuring Inbound
// Email" in the documentation for more information.
'metamta.maniphest.public-create-email' => null,
// -- Auth ------------------------------------------------------------------ //
// Can users login with a username/password, or by following the link from
// a password reset email? You can disable this and configure one or more
// OAuth providers instead.
'auth.password-auth-enabled' => true,
// Maximum number of simultaneous web sessions each user is permitted to have.
// Setting this to "1" will prevent a user from logging in on more than one
// browser at the same time.
'auth.sessions.web' => 5,
// Maximum number of simultaneous Conduit sessions each user is permitted
// to have.
'auth.sessions.conduit' => 3,
// Set this true to enable the Settings -> SSH Public Keys panel, which will
// allow users to associated SSH public keys with their accounts. This is only
// really useful if you're setting up services over SSH and want to use
// Phabricator for authentication; in most situations you can leave this
// disabled.
'auth.sshkeys.enabled' => false,
// -- Accounts -------------------------------------------------------------- //
// Is basic account information (email, real name, profile picture) editable?
// If you set up Phabricator to automatically synchronize account information
// from some other authoritative system, you can disable this to ensure
// information remains consistent across both systems.
'account.editable' => true,
// -- Facebook ------------------------------------------------------------ //
// Can users use Facebook credentials to login to Phabricator?
'facebook.auth-enabled' => false,
// Can users use Facebook credentials to create new Phabricator accounts?
'facebook.registration-enabled' => true,
// Are Facebook accounts permanently linked to Phabricator accounts, or can
// the user unlink them?
'facebook.auth-permanent' => false,
// The Facebook "Application ID" to use for Facebook API access.
'facebook.application-id' => null,
// The Facebook "Application Secret" to use for Facebook API access.
'facebook.application-secret' => null,
// -- Github ---------------------------------------------------------------- //
// Can users use Github credentials to login to Phabricator?
'github.auth-enabled' => false,
// Can users use Github credentials to create new Phabricator accounts?
'github.registration-enabled' => true,
// Are Github accounts permanently linked to Phabricator accounts, or can
// the user unlink them?
'github.auth-permanent' => false,
// The Github "Client ID" to use for Github API access.
'github.application-id' => null,
// The Github "Secret" to use for Github API access.
'github.application-secret' => null,
// -- Recaptcha ------------------------------------------------------------- //
// Is Recaptcha enabled? If disabled, captchas will not appear.
'recaptcha.enabled' => false,
// Your Recaptcha public key, obtained from Recaptcha.
'recaptcha.public-key' => null,
// Your Recaptcha private key, obtained from Recaptcha.
'recaptcha.private-key' => null,
// -- Misc ------------------------------------------------------------------ //
// This is hashed with other inputs to generate CSRF tokens. If you want, you
// can change it to some other string which is unique to your install. This
// will make your install more secure in a vague, mostly theoretical way. But
// it will take you like 3 seconds of mashing on your keyboard to set it up so
// you might as well.
'phabricator.csrf-key' => '0b7ec0592e0a2829d8b71df2fa269b2c6172eca3',
// This is hashed with other inputs to generate mail tokens. If you want, you
// can change it to some other string which is unique to your install. In
// particular, you will want to do this if you accidentally send a bunch of
// mail somewhere you shouldn't have, to invalidate all old reply-to
// addresses.
'phabricator.mail-key' => '5ce3e7e8787f6e40dfae861da315a5cdf1018f12',
// This is hashed with other inputs to generate file secret keys. Changing
// it will invalidate all file URIs if you have an alternate file domain
// configured (see 'security.alternate-file-domain').
'phabricator.file-key' => 'ade8dadc8b4382067069a4d4798112191af8a190',
// Version string displayed in the footer. You probably should leave this
// alone.
'phabricator.version' => 'UNSTABLE',
// PHP requires that you set a timezone in your php.ini before using date
// functions, or it will emit a warning. If this isn't possible (for instance,
// because you are using HPHP) you can set some valid constant for
// date_default_timezone_set() here and Phabricator will set it on your
// behalf, silencing the warning.
'phabricator.timezone' => null,
// When unhandled exceptions occur, stack traces are hidden by default.
// You can enable traces for development to make it easier to debug problems.
'phabricator.show-stack-traces' => false,
// -- Files ----------------------------------------------------------------- //
// Lists which uploaded file types may be viewed in the browser. If a file
// has a mime type which does not appear in this list, it will always be
// downloaded instead of displayed. This is a security consideration: if a
// user uploads a file of type "text/html" and it is displayed as
// "text/html", they can easily execute XSS attacks. This is also a usability
// consideration, since browsers tend to freak out when viewing enormous
// binary files.
//
// The keys in this array are viewable mime types; the values are the mime
// types they will be delivered as when they are viewed in the browser.
//
// IMPORTANT: Making any file types viewable is a security vulnerability if
// you do not configure 'security.alternate-file-domain' above.
'files.viewable-mime-types' => array(
'image/jpeg' => 'image/jpeg',
'image/jpg' => 'image/jpg',
'image/png' => 'image/png',
'image/gif' => 'image/gif',
'text/plain' => 'text/plain; charset=utf-8',
),
// Phabricator can proxy images from other servers so you can paste the URI
// to a funny picture of a cat into the comment box and have it show up as an
// image. However, this means the webserver Phabricator is running on will
// make HTTP requests to arbitrary URIs. If the server has access to internal
// resources, this could be a security risk. You should only enable it if you
// are installed entirely a VPN and VPN access is required to access
// Phabricator, or if the webserver has no special access to anything. If
// unsure, it is safer to leave this disabled.
'files.enable-proxy' => false,
// -- Storage --------------------------------------------------------------- //
// Phabricator allows users to upload files, and can keep them in various
// storage engines. This section allows you to configure which engines
// Phabricator will use, and how it will use them.
// The largest filesize Phabricator will store in the MySQL BLOB storage
// engine, which just uses a database table to store files. While this isn't a
// best practice, it's really easy to set up. This is hard-limited by the
// value of 'max_allowed_packet' in MySQL (since this often defaults to 1MB,
// the default here is slightly smaller than 1MB). Set this to 0 to disable
// use of the MySQL blob engine.
'storage.mysql-engine.max-size' => 1000000,
// Phabricator provides a local disk storage engine, which just writes files
// to some directory on local disk. The webserver must have read/write
// permissions on this directory. This is straightforward and suitable for
// most installs, but will not scale past one web frontend unless the path
// is actually an NFS mount, since you'll end up with some of the files
// written to each web frontend and no way for them to share. To use the
// local disk storage engine, specify the path to a directory here. To
// disable it, specify null.
'storage.local-disk.path' => null,
// If you want to store files in Amazon S3, specify an AWS access and secret
// key here and a bucket name below.
'amazon-s3.access-key' => null,
'amazon-s3.secret-key' => null,
// Set this to a valid Amazon S3 bucket to store files there. You must also
// configure S3 access keys above.
'storage.s3.bucket' => null,
// Phabricator uses a storage engine selector to choose which storage engine
// to use when writing file data. If you add new storage engines or want to
// provide very custom rules (e.g., write images to one storage engine and
// other files to a different one), you can provide an alternate
// implementation here. The default engine will use choose MySQL, Local Disk,
// and S3, in that order, if they have valid configurations above and a file
// fits within configured limits.
'storage.engine-selector' => 'PhabricatorDefaultFileStorageEngineSelector',
// -- Search ---------------------------------------------------------------- //
// Phabricator uses a search engine selector to choose which search engine
// to use when indexing and reconstructing documents, and when executing
// queries. You can override the engine selector to provide a new selector
// class which can select some custom engine you implement, if you want to
// store your documents in some search engine which does not have default
// support.
'search.engine-selector' => 'PhabricatorDefaultSearchEngineSelector',
// -- Differential ---------------------------------------------------------- //
'differential.revision-custom-detail-renderer' => null,
// Array for custom remarkup rules. The array should have a list of
// class names of classes that extend PhutilRemarkupRule
'differential.custom-remarkup-rules' => null,
// Array for custom remarkup block rules. The array should have a list of
// class names of classes that extend PhutilRemarkupEngineBlockRule
'differential.custom-remarkup-block-rules' => null,
// Set display word-wrap widths for Differential. Specify a dictionary of
// regular expressions mapping to column widths. The filename will be matched
// against each regexp in order until one matches. The default configuration
// uses a width of 100 for Java and 80 for other languages. Note that 80 is
// the greatest column width of all time. Changes here will not be immediately
// reflected in old revisions unless you purge the render cache.
'differential.wordwrap' => array(
'/\.java$/' => 100,
'/.*/' => 80,
),
- // Class for appending custom fields to be included in the commit
- // messages generated by "arc amend". Should inherit
- // DifferentialCommitMessageModifier
- 'differential.modify-commit-message-class' => null,
-
// List of file regexps were whitespace is meaningful and should not
// use 'ignore-all' by default
'differential.whitespace-matters' => array(
'/\.py$/',
),
-
'differential.field-selector' => 'DifferentialDefaultFieldSelector',
// -- Maniphest ------------------------------------------------------------- //
'maniphest.enabled' => true,
// Array of custom fields for Maniphest tasks. For details on adding custom
// fields to Maniphest, see "Maniphest User Guide: Adding Custom Fields".
'maniphest.custom-fields' => array(),
// Class which drives custom field construction. See "Maniphest User Guide:
// Adding Custom Fields" in the documentation for more information.
'maniphest.custom-task-extensions-class' => 'ManiphestDefaultTaskExtensions',
// -- Remarkup -------------------------------------------------------------- //
// If you enable this, linked YouTube videos will be embeded inline. This has
// mild security implications (you'll leak referrers to YouTube) and is pretty
// silly (but sort of awesome).
'remarkup.enable-embedded-youtube' => false,
// -- Garbage Collection ---------------------------------------------------- //
// Phabricator generates various logs and caches in the database which can
// be garbage collected after a while to make the total data size more
// manageable. To run garbage collection, launch a
// PhabricatorGarbageCollector daemon.
// Since the GC daemon can issue large writes and table scans, you may want to
// run it only during off hours or make sure it is scheduled so it doesn't
// overlap with backups. This determines when the daemon can start running
// each day.
'gcdaemon.run-at' => '12 AM',
// How many seconds after 'gcdaemon.run-at' the daemon may collect garbage
// for. By default it runs continuously, but you can set it to run for a
// limited period of time. For instance, if you do backups at 3 AM, you might
// run garbage collection for an hour beforehand. This is not a high-precision
// limit so you may want to leave some room for the GC to actually stop, and
// if you set it to something like 3 seconds you're on your own.
'gcdaemon.run-for' => 24 * 60 * 60,
// These 'ttl' keys configure how much old data the GC daemon keeps around.
// Objects older than the ttl will be collected. Set any value to 0 to store
// data indefinitely.
'gcdaemon.ttl.herald-transcripts' => 30 * (24 * 60 * 60),
'gcdaemon.ttl.daemon-logs' => 7 * (24 * 60 * 60),
'gcdaemon.ttl.differential-parse-cache' => 14 * (24 * 60 * 60),
// -- Feed ------------------------------------------------------------------ //
// If you set this to true, you can embed Phabricator activity feeds in other
// pages using iframes. These feeds are completely public, and a login is not
// required to view them! This is intended for things like open source
// projects that want to expose an activity feed on the project homepage.
'feed.public' => false,
// -- Customization --------------------------------------------------------- //
// Paths to additional phutil libraries to load.
'load-libraries' => array(),
'aphront.default-application-configuration-class' =>
'AphrontDefaultApplicationConfiguration',
'controller.oauth-registration' =>
'PhabricatorOAuthDefaultRegistrationController',
// Directory that phd (the Phabricator daemon control script) should use to
// track running daemons.
'phd.pid-directory' => '/var/tmp/phd',
// This value is an input to the hash function when building resource hashes.
// It has no security value, but if you accidentally poison user caches (by
// pushing a bad patch or having something go wrong with a CDN, e.g.) you can
// change this to something else and rebuild the Celerity map to break user
// caches. Unless you are doing Celerity development, it is exceptionally
// unlikely that you need to modify this.
'celerity.resource-hash' => 'd9455ea150622ee044f7931dabfa52aa',
// In a development environment, it is desirable to force static resources
// (CSS and JS) to be read from disk on every request, so that edits to them
// appear when you reload the page even if you haven't updated the resource
// maps. This setting ensures requests will be verified against the state on
// disk. Generally, you should leave this off in production (caching behavior
// and performance improve with it off) but turn it on in development. (These
// settings are the defaults.)
'celerity.force-disk-reads' => false,
// -- Pygments ------------------------------------------------------------ //
// Phabricator can highlight PHP by default, but if you want syntax
// highlighting for other languages you should install the python package
// 'Pygments', make sure the 'pygmentize' script is available in the
// $PATH of the webserver, and then enable this.
'pygments.enabled' => false,
// In places that we display a dropdown to syntax-highlight code,
// this is where that list is defined.
// Syntax is 'lexer-name' => 'Display Name',
'pygments.dropdown-choices' => array(
'apacheconf' => 'Apache Configuration',
'bash' => 'Bash Scripting',
'brainfuck' => 'Brainf*ck',
'c' => 'C',
'cpp' => 'C++',
'css' => 'CSS',
'diff' => 'Diff',
'django' => 'Django Templating',
'erb' => 'Embedded Ruby/ERB',
'erlang' => 'Erlang',
'html' => 'HTML',
'infer' => 'Infer from title (extension)',
'java' => 'Java',
'js' => 'Javascript',
'mysql' => 'MySQL',
'perl' => 'Perl',
'php' => 'PHP',
'text' => 'Plain Text',
'python' => 'Python',
'rainbow' => 'Rainbow',
'remarkup' => 'Remarkup',
'ruby' => 'Ruby',
'xml' => 'XML',
),
'pygments.dropdown-default' => 'infer',
// This is an override list of regular expressions which allows you to choose
// what language files are highlighted as. If your projects have certain rules
// about filenames or use unusual or ambiguous language extensions, you can
// create a mapping here. This is an ordered dictionary of regular expressions
// which will be tested against the filename. They should map to either an
// explicit language as a string value, or a numeric index into the captured
// groups as an integer.
'syntax.filemap' => array(
// Example: Treat all '*.xyz' files as PHP.
// '@\\.xyz$@' => 'php',
// Example: Treat 'httpd.conf' as 'apacheconf'.
// '@/httpd\\.conf$@' => 'apacheconf',
// Example: Treat all '*.x.bak' file as '.x'. NOTE: we map to capturing
// group 1 by specifying the mapping as "1".
// '@\\.([^.]+)\\.bak$@' => 1,
),
);
diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php
index 3e2e54abe6..3647f3116f 100644
--- a/src/__phutil_library_map__.php
+++ b/src/__phutil_library_map__.php
@@ -1,1241 +1,1238 @@
array(
'Aphront304Response' => 'aphront/response/304',
'Aphront400Response' => 'aphront/response/400',
'Aphront404Response' => 'aphront/response/404',
'AphrontAjaxResponse' => 'aphront/response/ajax',
'AphrontApplicationConfiguration' => 'aphront/applicationconfiguration',
'AphrontAttachedFileView' => 'view/control/attachedfile',
'AphrontCSRFException' => 'aphront/exception/csrf',
'AphrontCalendarMonthView' => 'applications/calendar/view/month',
'AphrontContextBarView' => 'view/layout/contextbar',
'AphrontController' => 'aphront/controller',
'AphrontCrumbsView' => 'view/layout/crumbs',
'AphrontDatabaseConnection' => 'storage/connection/base',
'AphrontDefaultApplicationConfiguration' => 'aphront/default/configuration',
'AphrontDefaultApplicationController' => 'aphront/default/controller',
'AphrontDialogResponse' => 'aphront/response/dialog',
'AphrontDialogView' => 'view/dialog',
'AphrontErrorView' => 'view/form/error',
'AphrontException' => 'aphront/exception/base',
'AphrontFilePreviewView' => 'view/layout/filepreview',
'AphrontFileResponse' => 'aphront/response/file',
'AphrontFormCheckboxControl' => 'view/form/control/checkbox',
'AphrontFormControl' => 'view/form/control/base',
'AphrontFormDividerControl' => 'view/form/control/divider',
'AphrontFormDragAndDropUploadControl' => 'view/form/control/draganddropupload',
'AphrontFormFileControl' => 'view/form/control/file',
'AphrontFormLayoutView' => 'view/form/layout',
'AphrontFormMarkupControl' => 'view/form/control/markup',
'AphrontFormPasswordControl' => 'view/form/control/password',
'AphrontFormRecaptchaControl' => 'view/form/control/recaptcha',
'AphrontFormSelectControl' => 'view/form/control/select',
'AphrontFormStaticControl' => 'view/form/control/static',
'AphrontFormSubmitControl' => 'view/form/control/submit',
'AphrontFormTextAreaControl' => 'view/form/control/textarea',
'AphrontFormTextControl' => 'view/form/control/text',
'AphrontFormToggleButtonsControl' => 'view/form/control/togglebuttons',
'AphrontFormTokenizerControl' => 'view/form/control/tokenizer',
'AphrontFormView' => 'view/form/base',
'AphrontHeadsupActionListView' => 'view/layout/headsup/actionlist',
'AphrontHeadsupActionView' => 'view/layout/headsup/action',
'AphrontIsolatedDatabaseConnection' => 'storage/connection/isolated',
'AphrontIsolatedDatabaseConnectionTestCase' => 'storage/connection/isolated/__tests__',
'AphrontKeyboardShortcutsAvailableView' => 'view/widget/keyboardshortcuts',
'AphrontListFilterView' => 'view/layout/listfilter',
'AphrontMySQLDatabaseConnection' => 'storage/connection/mysql',
'AphrontNullView' => 'view/null',
'AphrontPageView' => 'view/page/base',
'AphrontPagerView' => 'view/control/pager',
'AphrontPanelView' => 'view/layout/panel',
'AphrontQueryAccessDeniedException' => 'storage/exception/accessdenied',
'AphrontQueryConnectionException' => 'storage/exception/connection',
'AphrontQueryConnectionLostException' => 'storage/exception/connectionlost',
'AphrontQueryCountException' => 'storage/exception/count',
'AphrontQueryDuplicateKeyException' => 'storage/exception/duplicatekey',
'AphrontQueryException' => 'storage/exception/base',
'AphrontQueryObjectMissingException' => 'storage/exception/objectmissing',
'AphrontQueryParameterException' => 'storage/exception/parameter',
'AphrontQueryRecoverableException' => 'storage/exception/recoverable',
'AphrontRedirectException' => 'aphront/exception/redirect',
'AphrontRedirectResponse' => 'aphront/response/redirect',
'AphrontReloadResponse' => 'aphront/response/reload',
'AphrontRequest' => 'aphront/request',
'AphrontRequestFailureView' => 'view/page/failure',
'AphrontResponse' => 'aphront/response/base',
'AphrontScopedUnguardedWriteCapability' => 'aphront/writeguard/scopeguard',
'AphrontSideNavView' => 'view/layout/sidenav',
'AphrontTableView' => 'view/control/table',
'AphrontTokenizerTemplateView' => 'view/control/tokenizer',
'AphrontTypeaheadTemplateView' => 'view/control/typeahead',
'AphrontURIMapper' => 'aphront/mapper',
'AphrontView' => 'view/base',
'AphrontWebpageResponse' => 'aphront/response/webpage',
'AphrontWriteGuard' => 'aphront/writeguard',
'CelerityAPI' => 'infrastructure/celerity/api',
'CelerityResourceController' => 'infrastructure/celerity/controller',
'CelerityResourceMap' => 'infrastructure/celerity/map',
'CelerityStaticResourceResponse' => 'infrastructure/celerity/response',
'ConduitAPIMethod' => 'applications/conduit/method/base',
'ConduitAPIRequest' => 'applications/conduit/protocol/request',
'ConduitAPI_conduit_connect_Method' => 'applications/conduit/method/conduit/connect',
'ConduitAPI_conduit_getcertificate_Method' => 'applications/conduit/method/conduit/getcertificate',
'ConduitAPI_conduit_ping_Method' => 'applications/conduit/method/conduit/ping',
'ConduitAPI_daemon_launched_Method' => 'applications/conduit/method/daemon/launched',
'ConduitAPI_daemon_log_Method' => 'applications/conduit/method/daemon/log',
'ConduitAPI_differential_creatediff_Method' => 'applications/conduit/method/differential/creatediff',
'ConduitAPI_differential_createrevision_Method' => 'applications/conduit/method/differential/createrevision',
'ConduitAPI_differential_find_Method' => 'applications/conduit/method/differential/find',
'ConduitAPI_differential_getalldiffs_Method' => 'applications/conduit/method/differential/getalldiffs',
'ConduitAPI_differential_getcommitmessage_Method' => 'applications/conduit/method/differential/getcommitmessage',
'ConduitAPI_differential_getcommitpaths_Method' => 'applications/conduit/method/differential/getcommitpaths',
'ConduitAPI_differential_getdiff_Method' => 'applications/conduit/method/differential/getdiff',
'ConduitAPI_differential_getrevision_Method' => 'applications/conduit/method/differential/getrevision',
'ConduitAPI_differential_getrevisionfeedback_Method' => 'applications/conduit/method/differential/getrevisionfeedback',
'ConduitAPI_differential_markcommitted_Method' => 'applications/conduit/method/differential/markcommitted',
'ConduitAPI_differential_parsecommitmessage_Method' => 'applications/conduit/method/differential/parsecommitmessage',
'ConduitAPI_differential_setdiffproperty_Method' => 'applications/conduit/method/differential/setdiffproperty',
'ConduitAPI_differential_updaterevision_Method' => 'applications/conduit/method/differential/updaterevision',
'ConduitAPI_differential_updatetaskrevisionassoc_Method' => 'applications/conduit/method/differential/updatetaskrevisionassoc',
'ConduitAPI_differential_updateunitresults_Method' => 'applications/conduit/method/differential/updateunitresults',
'ConduitAPI_diffusion_getcommits_Method' => 'applications/conduit/method/diffusion/getcommits',
'ConduitAPI_diffusion_getrecentcommitsbypath_Method' => 'applications/conduit/method/diffusion/getrecentcommitsbypath',
'ConduitAPI_feed_publish_Method' => 'applications/conduit/method/feed/publish',
'ConduitAPI_file_download_Method' => 'applications/conduit/method/file/download',
'ConduitAPI_file_info_Method' => 'applications/conduit/method/file/info',
'ConduitAPI_file_upload_Method' => 'applications/conduit/method/file/upload',
'ConduitAPI_maniphest_info_Method' => 'applications/conduit/method/maniphest/info',
'ConduitAPI_paste_Method' => 'applications/conduit/method/paste/base',
'ConduitAPI_paste_create_Method' => 'applications/conduit/method/paste/create',
'ConduitAPI_paste_info_Method' => 'applications/conduit/method/paste/info',
'ConduitAPI_path_getowners_Method' => 'applications/conduit/method/path/getowners',
'ConduitAPI_slowvote_info_Method' => 'applications/conduit/method/slowvote/info',
'ConduitAPI_user_find_Method' => 'applications/conduit/method/user/find',
'ConduitAPI_user_whoami_Method' => 'applications/conduit/method/user/whoami',
'ConduitException' => 'applications/conduit/protocol/exception',
'DarkConsole' => 'aphront/console/api',
'DarkConsoleConfigPlugin' => 'aphront/console/plugin/config',
'DarkConsoleController' => 'aphront/console/controller',
'DarkConsoleCore' => 'aphront/console/core',
'DarkConsoleErrorLogPlugin' => 'aphront/console/plugin/errorlog',
'DarkConsoleErrorLogPluginAPI' => 'aphront/console/plugin/errorlog/api',
'DarkConsolePlugin' => 'aphront/console/plugin/base',
'DarkConsoleRequestPlugin' => 'aphront/console/plugin/request',
'DarkConsoleServicesPlugin' => 'aphront/console/plugin/services',
'DarkConsoleXHProfPlugin' => 'aphront/console/plugin/xhprof',
'DarkConsoleXHProfPluginAPI' => 'aphront/console/plugin/xhprof/api',
'DatabaseConfigurationProvider' => 'applications/base/storage/configuration',
'DifferentialAction' => 'applications/differential/constants/action',
'DifferentialAddCommentView' => 'applications/differential/view/addcomment',
'DifferentialApplyPatchFieldSpecification' => 'applications/differential/field/specification/applypatch',
'DifferentialArcanistProjectFieldSpecification' => 'applications/differential/field/specification/arcanistproject',
'DifferentialAuthorFieldSpecification' => 'applications/differential/field/specification/author',
'DifferentialAuxiliaryField' => 'applications/differential/storage/auxiliaryfield',
'DifferentialBlameRevisionFieldSpecification' => 'applications/differential/field/specification/blamerev',
'DifferentialCCWelcomeMail' => 'applications/differential/mail/ccwelcome',
'DifferentialCCsFieldSpecification' => 'applications/differential/field/specification/ccs',
'DifferentialChangeType' => 'applications/differential/constants/changetype',
'DifferentialChangeset' => 'applications/differential/storage/changeset',
'DifferentialChangesetDetailView' => 'applications/differential/view/changesetdetailview',
'DifferentialChangesetListView' => 'applications/differential/view/changesetlistview',
'DifferentialChangesetParser' => 'applications/differential/parser/changeset',
'DifferentialChangesetViewController' => 'applications/differential/controller/changesetview',
'DifferentialComment' => 'applications/differential/storage/comment',
'DifferentialCommentEditor' => 'applications/differential/editor/comment',
'DifferentialCommentMail' => 'applications/differential/mail/comment',
'DifferentialCommentPreviewController' => 'applications/differential/controller/commentpreview',
'DifferentialCommentSaveController' => 'applications/differential/controller/commentsave',
'DifferentialCommitMessage' => 'applications/differential/parser/commitmessage',
- 'DifferentialCommitMessageData' => 'applications/differential/data/commitmessage',
- 'DifferentialCommitMessageField' => 'applications/differential/data/commitmessage',
- 'DifferentialCommitMessageModifier' => 'applications/differential/data/commitmessage',
'DifferentialCommitMessageParserException' => 'applications/differential/parser/commitmessage/exception',
'DifferentialCommitsFieldSpecification' => 'applications/differential/field/specification/commits',
'DifferentialController' => 'applications/differential/controller/base',
'DifferentialDAO' => 'applications/differential/storage/base',
'DifferentialDefaultFieldSelector' => 'applications/differential/field/selector/default',
'DifferentialDependenciesFieldSpecification' => 'applications/differential/field/specification/dependencies',
'DifferentialDiff' => 'applications/differential/storage/diff',
'DifferentialDiffContentMail' => 'applications/differential/mail/diffcontent',
'DifferentialDiffCreateController' => 'applications/differential/controller/diffcreate',
'DifferentialDiffProperty' => 'applications/differential/storage/diffproperty',
'DifferentialDiffTableOfContentsView' => 'applications/differential/view/difftableofcontents',
'DifferentialDiffViewController' => 'applications/differential/controller/diffview',
'DifferentialExceptionMail' => 'applications/differential/mail/exception',
'DifferentialExportPatchFieldSpecification' => 'applications/differential/field/specification/exportpatch',
'DifferentialFieldDataNotAvailableException' => 'applications/differential/field/exception/notavailable',
'DifferentialFieldSelector' => 'applications/differential/field/selector/base',
'DifferentialFieldSpecification' => 'applications/differential/field/specification/base',
'DifferentialFieldSpecificationIncompleteException' => 'applications/differential/field/exception/incomplete',
'DifferentialFieldValidationException' => 'applications/differential/field/exception/validation',
'DifferentialGitSVNIDFieldSpecification' => 'applications/differential/field/specification/gitsvnid',
'DifferentialHostFieldSpecification' => 'applications/differential/field/specification/host',
'DifferentialHunk' => 'applications/differential/storage/hunk',
'DifferentialInlineComment' => 'applications/differential/storage/inlinecomment',
'DifferentialInlineCommentEditController' => 'applications/differential/controller/inlinecommentedit',
'DifferentialInlineCommentPreviewController' => 'applications/differential/controller/inlinecommentpreview',
'DifferentialInlineCommentView' => 'applications/differential/view/inlinecomment',
'DifferentialLinesFieldSpecification' => 'applications/differential/field/specification/lines',
'DifferentialLintFieldSpecification' => 'applications/differential/field/specification/lint',
'DifferentialLintStatus' => 'applications/differential/constants/lintstatus',
'DifferentialMail' => 'applications/differential/mail/base',
'DifferentialManiphestTasksFieldSpecification' => 'applications/differential/field/specification/maniphesttasks',
'DifferentialNewDiffMail' => 'applications/differential/mail/newdiff',
'DifferentialPathFieldSpecification' => 'applications/differential/field/specification/path',
'DifferentialPrimaryPaneView' => 'applications/differential/view/primarypane',
'DifferentialReplyHandler' => 'applications/differential/replyhandler',
'DifferentialRevertPlanFieldSpecification' => 'applications/differential/field/specification/revertplan',
'DifferentialReviewRequestMail' => 'applications/differential/mail/reviewrequest',
'DifferentialReviewedByFieldSpecification' => 'applications/differential/field/specification/reviewedby',
'DifferentialReviewersFieldSpecification' => 'applications/differential/field/specification/reviewers',
'DifferentialRevision' => 'applications/differential/storage/revision',
'DifferentialRevisionCommentListView' => 'applications/differential/view/revisioncommentlist',
'DifferentialRevisionCommentView' => 'applications/differential/view/revisioncomment',
'DifferentialRevisionControlSystem' => 'applications/differential/constants/revisioncontrolsystem',
'DifferentialRevisionDetailRenderer' => 'applications/differential/controller/customrenderer',
'DifferentialRevisionDetailView' => 'applications/differential/view/revisiondetail',
'DifferentialRevisionEditController' => 'applications/differential/controller/revisionedit',
'DifferentialRevisionEditor' => 'applications/differential/editor/revision',
'DifferentialRevisionIDFieldSpecification' => 'applications/differential/field/specification/revisionid',
'DifferentialRevisionListController' => 'applications/differential/controller/revisionlist',
'DifferentialRevisionListData' => 'applications/differential/data/revisionlist',
'DifferentialRevisionStatus' => 'applications/differential/constants/revisionstatus',
'DifferentialRevisionStatusFieldSpecification' => 'applications/differential/field/specification/revisionstatus',
'DifferentialRevisionUpdateHistoryView' => 'applications/differential/view/revisionupdatehistory',
'DifferentialRevisionViewController' => 'applications/differential/controller/revisionview',
'DifferentialSubscribeController' => 'applications/differential/controller/subscribe',
'DifferentialSummaryFieldSpecification' => 'applications/differential/field/specification/summary',
'DifferentialTasksAttacher' => 'applications/differential/tasks',
'DifferentialTestPlanFieldSpecification' => 'applications/differential/field/specification/testplan',
'DifferentialTitleFieldSpecification' => 'applications/differential/field/specification/title',
'DifferentialUnitFieldSpecification' => 'applications/differential/field/specification/unit',
'DifferentialUnitStatus' => 'applications/differential/constants/unitstatus',
'DifferentialUnitTestResult' => 'applications/differential/constants/unittestresult',
'DifferentialViewTime' => 'applications/differential/storage/viewtime',
'DiffusionBranchInformation' => 'applications/diffusion/data/branch',
'DiffusionBranchQuery' => 'applications/diffusion/query/branch/base',
'DiffusionBranchTableView' => 'applications/diffusion/view/branchtable',
'DiffusionBrowseController' => 'applications/diffusion/controller/browse',
'DiffusionBrowseFileController' => 'applications/diffusion/controller/file',
'DiffusionBrowseQuery' => 'applications/diffusion/query/browse/base',
'DiffusionBrowseTableView' => 'applications/diffusion/view/browsetable',
'DiffusionChangeController' => 'applications/diffusion/controller/change',
'DiffusionCommitChangeTableView' => 'applications/diffusion/view/commitchangetable',
'DiffusionCommitController' => 'applications/diffusion/controller/commit',
'DiffusionCommitListController' => 'applications/diffusion/controller/commitlist',
'DiffusionController' => 'applications/diffusion/controller/base',
'DiffusionDiffController' => 'applications/diffusion/controller/diff',
'DiffusionDiffQuery' => 'applications/diffusion/query/diff/base',
'DiffusionFileContent' => 'applications/diffusion/data/filecontent',
'DiffusionFileContentQuery' => 'applications/diffusion/query/filecontent/base',
'DiffusionGitBranchQuery' => 'applications/diffusion/query/branch/git',
'DiffusionGitBrowseQuery' => 'applications/diffusion/query/browse/git',
'DiffusionGitDiffQuery' => 'applications/diffusion/query/diff/git',
'DiffusionGitFileContentQuery' => 'applications/diffusion/query/filecontent/git',
'DiffusionGitHistoryQuery' => 'applications/diffusion/query/history/git',
'DiffusionGitLastModifiedQuery' => 'applications/diffusion/query/lastmodified/git',
'DiffusionGitPathIDQuery' => 'applications/diffusion/query/pathid/base',
'DiffusionGitRequest' => 'applications/diffusion/request/git',
'DiffusionHistoryController' => 'applications/diffusion/controller/history',
'DiffusionHistoryQuery' => 'applications/diffusion/query/history/base',
'DiffusionHistoryTableView' => 'applications/diffusion/view/historytable',
'DiffusionHomeController' => 'applications/diffusion/controller/home',
'DiffusionLastModifiedController' => 'applications/diffusion/controller/lastmodified',
'DiffusionLastModifiedQuery' => 'applications/diffusion/query/lastmodified/base',
'DiffusionPathChange' => 'applications/diffusion/data/pathchange',
'DiffusionPathChangeQuery' => 'applications/diffusion/query/pathchange/base',
'DiffusionPathCompleteController' => 'applications/diffusion/controller/pathcomplete',
'DiffusionPathValidateController' => 'applications/diffusion/controller/pathvalidate',
'DiffusionRepositoryController' => 'applications/diffusion/controller/repository',
'DiffusionRepositoryPath' => 'applications/diffusion/data/repositorypath',
'DiffusionRequest' => 'applications/diffusion/request/base',
'DiffusionSvnBrowseQuery' => 'applications/diffusion/query/browse/svn',
'DiffusionSvnDiffQuery' => 'applications/diffusion/query/diff/svn',
'DiffusionSvnFileContentQuery' => 'applications/diffusion/query/filecontent/svn',
'DiffusionSvnHistoryQuery' => 'applications/diffusion/query/history/svn',
'DiffusionSvnLastModifiedQuery' => 'applications/diffusion/query/lastmodified/svn',
'DiffusionSvnRequest' => 'applications/diffusion/request/svn',
'DiffusionView' => 'applications/diffusion/view/base',
'HeraldAction' => 'applications/herald/storage/action',
'HeraldActionConfig' => 'applications/herald/config/action',
'HeraldApplyTranscript' => 'applications/herald/storage/transcript/apply',
'HeraldCommitAdapter' => 'applications/herald/adapter/commit',
'HeraldCondition' => 'applications/herald/storage/condition',
'HeraldConditionConfig' => 'applications/herald/config/condition',
'HeraldConditionTranscript' => 'applications/herald/storage/transcript/condition',
'HeraldContentTypeConfig' => 'applications/herald/config/contenttype',
'HeraldController' => 'applications/herald/controller/base',
'HeraldDAO' => 'applications/herald/storage/base',
'HeraldDeleteController' => 'applications/herald/controller/delete',
'HeraldDifferentialRevisionAdapter' => 'applications/herald/adapter/differential',
'HeraldDryRunAdapter' => 'applications/herald/adapter/dryrun',
'HeraldEffect' => 'applications/herald/engine/effect',
'HeraldEngine' => 'applications/herald/engine/engine',
'HeraldFieldConfig' => 'applications/herald/config/field',
'HeraldHomeController' => 'applications/herald/controller/home',
'HeraldInvalidConditionException' => 'applications/herald/engine/engine/exception',
'HeraldInvalidFieldException' => 'applications/herald/engine/engine/exception',
'HeraldNewController' => 'applications/herald/controller/new',
'HeraldObjectAdapter' => 'applications/herald/adapter/base',
'HeraldObjectTranscript' => 'applications/herald/storage/transcript/object',
'HeraldRecursiveConditionsException' => 'applications/herald/engine/engine/exception',
'HeraldRepetitionPolicyConfig' => 'applications/herald/config/repetitionpolicy',
'HeraldRule' => 'applications/herald/storage/rule',
'HeraldRuleController' => 'applications/herald/controller/rule',
'HeraldRuleTranscript' => 'applications/herald/storage/transcript/rule',
'HeraldTestConsoleController' => 'applications/herald/controller/test',
'HeraldTranscript' => 'applications/herald/storage/transcript/base',
'HeraldTranscriptController' => 'applications/herald/controller/transcript',
'HeraldTranscriptListController' => 'applications/herald/controller/transcriptlist',
'HeraldValueTypeConfig' => 'applications/herald/config/valuetype',
'Javelin' => 'infrastructure/javelin/api',
'LiskDAO' => 'storage/lisk/dao',
'LiskIsolationTestCase' => 'storage/lisk/dao/__tests__',
'LiskIsolationTestDAO' => 'storage/lisk/dao/__tests__',
'LiskIsolationTestDAOException' => 'storage/lisk/dao/__tests__',
'ManiphestAuxiliaryFieldDefaultSpecification' => 'applications/maniphest/auxiliaryfield/default',
'ManiphestAuxiliaryFieldSpecification' => 'applications/maniphest/auxiliaryfield/base',
'ManiphestAuxiliaryFieldTypeException' => 'applications/maniphest/auxiliaryfield/typeexception',
'ManiphestAuxiliaryFieldValidationException' => 'applications/maniphest/auxiliaryfield/validationexception',
'ManiphestConstants' => 'applications/maniphest/constants/base',
'ManiphestController' => 'applications/maniphest/controller/base',
'ManiphestDAO' => 'applications/maniphest/storage/base',
'ManiphestDefaultTaskExtensions' => 'applications/maniphest/extensions/task',
'ManiphestReplyHandler' => 'applications/maniphest/replyhandler',
'ManiphestTask' => 'applications/maniphest/storage/task',
'ManiphestTaskAuxiliaryStorage' => 'applications/maniphest/storage/auxiliary',
'ManiphestTaskDescriptionChangeController' => 'applications/maniphest/controller/descriptionchange',
'ManiphestTaskDetailController' => 'applications/maniphest/controller/taskdetail',
'ManiphestTaskEditController' => 'applications/maniphest/controller/taskedit',
'ManiphestTaskExtensions' => 'applications/maniphest/extensions/base',
'ManiphestTaskListController' => 'applications/maniphest/controller/tasklist',
'ManiphestTaskListView' => 'applications/maniphest/view/tasklist',
'ManiphestTaskOwner' => 'applications/maniphest/constants/owner',
'ManiphestTaskPriority' => 'applications/maniphest/constants/priority',
'ManiphestTaskProject' => 'applications/maniphest/storage/taskproject',
'ManiphestTaskQuery' => 'applications/maniphest/query',
'ManiphestTaskStatus' => 'applications/maniphest/constants/status',
'ManiphestTaskSubscriber' => 'applications/maniphest/storage/subscriber',
'ManiphestTaskSummaryView' => 'applications/maniphest/view/tasksummary',
'ManiphestTransaction' => 'applications/maniphest/storage/transaction',
'ManiphestTransactionDetailView' => 'applications/maniphest/view/transactiondetail',
'ManiphestTransactionEditor' => 'applications/maniphest/editor/transaction',
'ManiphestTransactionListView' => 'applications/maniphest/view/transactionlist',
'ManiphestTransactionPreviewController' => 'applications/maniphest/controller/transactionpreview',
'ManiphestTransactionSaveController' => 'applications/maniphest/controller/transactionsave',
'ManiphestTransactionType' => 'applications/maniphest/constants/transactiontype',
'ManiphestView' => 'applications/maniphest/view/base',
'Phabricator404Controller' => 'applications/base/controller/404',
'PhabricatorAuthController' => 'applications/auth/controller/base',
'PhabricatorCalendarBrowseController' => 'applications/calendar/controller/browse',
'PhabricatorCalendarController' => 'applications/calendar/controller/base',
'PhabricatorConduitAPIController' => 'applications/conduit/controller/api',
'PhabricatorConduitCertificateToken' => 'applications/conduit/storage/token',
'PhabricatorConduitConnectionLog' => 'applications/conduit/storage/connectionlog',
'PhabricatorConduitConsoleController' => 'applications/conduit/controller/console',
'PhabricatorConduitController' => 'applications/conduit/controller/base',
'PhabricatorConduitDAO' => 'applications/conduit/storage/base',
'PhabricatorConduitLogController' => 'applications/conduit/controller/log',
'PhabricatorConduitMethodCallLog' => 'applications/conduit/storage/methodcalllog',
'PhabricatorConduitTokenController' => 'applications/conduit/controller/token',
'PhabricatorController' => 'applications/base/controller/base',
'PhabricatorCountdownController' => 'applications/countdown/controller/base',
'PhabricatorCountdownDAO' => 'applications/countdown/storage/base',
'PhabricatorCountdownDeleteController' => 'applications/countdown/controller/delete',
'PhabricatorCountdownEditController' => 'applications/countdown/controller/edit',
'PhabricatorCountdownListController' => 'applications/countdown/controller/list',
'PhabricatorCountdownViewController' => 'applications/countdown/controller/view',
'PhabricatorDaemon' => 'infrastructure/daemon/base',
'PhabricatorDaemonCombinedLogController' => 'applications/daemon/controller/combined',
'PhabricatorDaemonConsoleController' => 'applications/daemon/controller/console',
'PhabricatorDaemonControl' => 'infrastructure/daemon/control',
'PhabricatorDaemonController' => 'applications/daemon/controller/base',
'PhabricatorDaemonDAO' => 'infrastructure/daemon/storage/base',
'PhabricatorDaemonLog' => 'infrastructure/daemon/storage/log',
'PhabricatorDaemonLogEvent' => 'infrastructure/daemon/storage/event',
'PhabricatorDaemonLogEventsView' => 'applications/daemon/view/daemonlogevents',
'PhabricatorDaemonLogListController' => 'applications/daemon/controller/loglist',
'PhabricatorDaemonLogListView' => 'applications/daemon/view/daemonloglist',
'PhabricatorDaemonLogViewController' => 'applications/daemon/controller/logview',
'PhabricatorDaemonReference' => 'infrastructure/daemon/control/reference',
'PhabricatorDaemonTimelineConsoleController' => 'applications/daemon/controller/timeline',
'PhabricatorDaemonTimelineEventController' => 'applications/daemon/controller/timelineevent',
'PhabricatorDefaultFileStorageEngineSelector' => 'applications/files/engineselector/default',
'PhabricatorDefaultSearchEngineSelector' => 'applications/search/selector/default',
'PhabricatorDifferenceEngine' => 'infrastructure/diff/engine',
'PhabricatorDirectoryCategory' => 'applications/directory/storage/category',
'PhabricatorDirectoryCategoryDeleteController' => 'applications/directory/controller/categorydelete',
'PhabricatorDirectoryCategoryEditController' => 'applications/directory/controller/categoryedit',
'PhabricatorDirectoryCategoryListController' => 'applications/directory/controller/categorylist',
'PhabricatorDirectoryController' => 'applications/directory/controller/base',
'PhabricatorDirectoryDAO' => 'applications/directory/storage/base',
'PhabricatorDirectoryItem' => 'applications/directory/storage/item',
'PhabricatorDirectoryItemDeleteController' => 'applications/directory/controller/itemdelete',
'PhabricatorDirectoryItemEditController' => 'applications/directory/controller/itemedit',
'PhabricatorDirectoryItemListController' => 'applications/directory/controller/itemlist',
'PhabricatorDirectoryMainController' => 'applications/directory/controller/main',
'PhabricatorDisabledUserController' => 'applications/auth/controller/disabled',
'PhabricatorDraft' => 'applications/draft/storage/draft',
'PhabricatorDraftDAO' => 'applications/draft/storage/base',
'PhabricatorEmailLoginController' => 'applications/auth/controller/email',
'PhabricatorEmailTokenController' => 'applications/auth/controller/emailtoken',
'PhabricatorEnv' => 'infrastructure/env',
'PhabricatorFeedConstants' => 'applications/feed/constants/base',
'PhabricatorFeedController' => 'applications/feed/controller/base',
'PhabricatorFeedDAO' => 'applications/feed/storage/base',
'PhabricatorFeedPublicStreamController' => 'applications/feed/controller/publicstream',
'PhabricatorFeedQuery' => 'applications/feed/query',
'PhabricatorFeedStory' => 'applications/feed/story/base',
'PhabricatorFeedStoryData' => 'applications/feed/storage/story',
'PhabricatorFeedStoryDifferential' => 'applications/feed/story/differential',
'PhabricatorFeedStoryPhriction' => 'applications/feed/story/phriction',
'PhabricatorFeedStoryPublisher' => 'applications/feed/publisher',
'PhabricatorFeedStoryReference' => 'applications/feed/storage/storyreference',
'PhabricatorFeedStoryStatus' => 'applications/feed/story/status',
'PhabricatorFeedStoryTypeConstants' => 'applications/feed/constants/story',
'PhabricatorFeedStoryUnknown' => 'applications/feed/story/unknown',
'PhabricatorFeedStoryView' => 'applications/feed/view/story',
'PhabricatorFeedStreamController' => 'applications/feed/controller/stream',
'PhabricatorFeedView' => 'applications/feed/view/base',
'PhabricatorFile' => 'applications/files/storage/file',
'PhabricatorFileAltViewController' => 'applications/files/controller/altview',
'PhabricatorFileController' => 'applications/files/controller/base',
'PhabricatorFileDAO' => 'applications/files/storage/base',
'PhabricatorFileDropUploadController' => 'applications/files/controller/dropupload',
'PhabricatorFileImageMacro' => 'applications/files/storage/imagemacro',
'PhabricatorFileListController' => 'applications/files/controller/list',
'PhabricatorFileMacroDeleteController' => 'applications/files/controller/macrodelete',
'PhabricatorFileMacroEditController' => 'applications/files/controller/macroedit',
'PhabricatorFileMacroListController' => 'applications/files/controller/macrolist',
'PhabricatorFileProxyController' => 'applications/files/controller/proxy',
'PhabricatorFileProxyImage' => 'applications/files/storage/proxyimage',
'PhabricatorFileStorageBlob' => 'applications/files/storage/storageblob',
'PhabricatorFileStorageEngine' => 'applications/files/engine/base',
'PhabricatorFileStorageEngineSelector' => 'applications/files/engineselector/base',
'PhabricatorFileTransformController' => 'applications/files/controller/transform',
'PhabricatorFileURI' => 'applications/files/uri',
'PhabricatorFileUploadController' => 'applications/files/controller/upload',
'PhabricatorFileUploadException' => 'applications/files/exception/upload',
'PhabricatorFileViewController' => 'applications/files/controller/view',
'PhabricatorGarbageCollectorDaemon' => 'infrastructure/daemon/garbagecollector',
'PhabricatorGoodForNothingWorker' => 'infrastructure/daemon/workers/worker/goodfornothing',
'PhabricatorHandleObjectSelectorDataView' => 'applications/phid/handle/view/selector',
'PhabricatorHelpController' => 'applications/help/controller/base',
'PhabricatorHelpKeyboardShortcutController' => 'applications/help/controller/keyboardshortcut',
'PhabricatorIRCBot' => 'infrastructure/daemon/irc/bot',
'PhabricatorIRCHandler' => 'infrastructure/daemon/irc/handler/base',
'PhabricatorIRCMessage' => 'infrastructure/daemon/irc/message',
'PhabricatorIRCObjectNameHandler' => 'infrastructure/daemon/irc/handler/objectname',
'PhabricatorIRCProtocolHandler' => 'infrastructure/daemon/irc/handler/protocol',
'PhabricatorImageTransformer' => 'applications/files/transform',
'PhabricatorJavelinLinter' => 'infrastructure/lint/linter/javelin',
'PhabricatorLintEngine' => 'infrastructure/lint/engine',
'PhabricatorLiskDAO' => 'applications/base/storage/lisk',
'PhabricatorLocalDiskFileStorageEngine' => 'applications/files/engine/localdisk',
'PhabricatorLoginController' => 'applications/auth/controller/login',
'PhabricatorLogoutController' => 'applications/auth/controller/logout',
'PhabricatorMailImplementationAdapter' => 'applications/metamta/adapter/base',
'PhabricatorMailImplementationAmazonSESAdapter' => 'applications/metamta/adapter/amazonses',
'PhabricatorMailImplementationPHPMailerLiteAdapter' => 'applications/metamta/adapter/phpmailerlite',
'PhabricatorMailImplementationSendGridAdapter' => 'applications/metamta/adapter/sendgrid',
'PhabricatorMailImplementationTestAdapter' => 'applications/metamta/adapter/test',
'PhabricatorMailReplyHandler' => 'applications/metamta/replyhandler/base',
'PhabricatorMarkupEngine' => 'applications/markup/engine',
'PhabricatorMetaMTAController' => 'applications/metamta/controller/base',
'PhabricatorMetaMTADAO' => 'applications/metamta/storage/base',
'PhabricatorMetaMTADaemon' => 'applications/metamta/daemon/mta',
'PhabricatorMetaMTAEmailBodyParser' => 'applications/metamta/parser',
'PhabricatorMetaMTAEmailBodyParserTestCase' => 'applications/metamta/parser/__tests__',
'PhabricatorMetaMTAListController' => 'applications/metamta/controller/list',
'PhabricatorMetaMTAMail' => 'applications/metamta/storage/mail',
'PhabricatorMetaMTAMailTestCase' => 'applications/metamta/storage/mail/__tests__',
'PhabricatorMetaMTAMailingList' => 'applications/metamta/storage/mailinglist',
'PhabricatorMetaMTAMailingListEditController' => 'applications/metamta/controller/mailinglistedit',
'PhabricatorMetaMTAMailingListsController' => 'applications/metamta/controller/mailinglists',
'PhabricatorMetaMTAReceiveController' => 'applications/metamta/controller/receive',
'PhabricatorMetaMTAReceivedListController' => 'applications/metamta/controller/receivedlist',
'PhabricatorMetaMTAReceivedMail' => 'applications/metamta/storage/receivedmail',
'PhabricatorMetaMTASendController' => 'applications/metamta/controller/send',
'PhabricatorMetaMTASendGridReceiveController' => 'applications/metamta/controller/sendgridreceive',
'PhabricatorMetaMTAViewController' => 'applications/metamta/controller/view',
'PhabricatorMySQLFileStorageEngine' => 'applications/files/engine/mysql',
'PhabricatorOAuthDefaultRegistrationController' => 'applications/auth/controller/oauthregistration/default',
'PhabricatorOAuthDiagnosticsController' => 'applications/auth/controller/oauthdiagnostics',
'PhabricatorOAuthFailureView' => 'applications/auth/view/oauthfailure',
'PhabricatorOAuthLoginController' => 'applications/auth/controller/oauth',
'PhabricatorOAuthProvider' => 'applications/auth/oauth/provider/base',
'PhabricatorOAuthProviderFacebook' => 'applications/auth/oauth/provider/facebook',
'PhabricatorOAuthProviderGithub' => 'applications/auth/oauth/provider/github',
'PhabricatorOAuthRegistrationController' => 'applications/auth/controller/oauthregistration/base',
'PhabricatorOAuthUnlinkController' => 'applications/auth/controller/unlink',
'PhabricatorObjectGraph' => 'applications/phid/graph',
'PhabricatorObjectHandle' => 'applications/phid/handle',
'PhabricatorObjectHandleConstants' => 'applications/phid/handle/const/base',
'PhabricatorObjectHandleData' => 'applications/phid/handle/data',
'PhabricatorObjectHandleStatus' => 'applications/phid/handle/const/status',
'PhabricatorObjectSelectorDialog' => 'view/control/objectselector',
'PhabricatorOwnersController' => 'applications/owners/controller/base',
'PhabricatorOwnersDAO' => 'applications/owners/storage/base',
'PhabricatorOwnersDeleteController' => 'applications/owners/controller/delete',
'PhabricatorOwnersDetailController' => 'applications/owners/controller/detail',
'PhabricatorOwnersEditController' => 'applications/owners/controller/edit',
'PhabricatorOwnersListController' => 'applications/owners/controller/list',
'PhabricatorOwnersOwner' => 'applications/owners/storage/owner',
'PhabricatorOwnersPackage' => 'applications/owners/storage/package',
'PhabricatorOwnersPath' => 'applications/owners/storage/path',
'PhabricatorPHID' => 'applications/phid/storage/phid',
'PhabricatorPHIDConstants' => 'applications/phid/constants',
'PhabricatorPHIDController' => 'applications/phid/controller/base',
'PhabricatorPHIDDAO' => 'applications/phid/storage/base',
'PhabricatorPHIDListController' => 'applications/phid/controller/list',
'PhabricatorPHIDLookupController' => 'applications/phid/controller/lookup',
'PhabricatorPaste' => 'applications/paste/storage/paste',
'PhabricatorPasteController' => 'applications/paste/controller/base',
'PhabricatorPasteCreateController' => 'applications/paste/controller/create',
'PhabricatorPasteDAO' => 'applications/paste/storage/base',
'PhabricatorPasteListController' => 'applications/paste/controller/list',
'PhabricatorPasteViewController' => 'applications/paste/controller/view',
'PhabricatorPeopleController' => 'applications/people/controller/base',
'PhabricatorPeopleEditController' => 'applications/people/controller/edit',
'PhabricatorPeopleListController' => 'applications/people/controller/list',
'PhabricatorPeopleLogsController' => 'applications/people/controller/logs',
'PhabricatorPeopleProfileController' => 'applications/people/controller/profile',
'PhabricatorProfileView' => 'view/layout/profile',
'PhabricatorProject' => 'applications/project/storage/project',
'PhabricatorProjectAffiliation' => 'applications/project/storage/affiliation',
'PhabricatorProjectAffiliationEditController' => 'applications/project/controller/editaffiliation',
'PhabricatorProjectController' => 'applications/project/controller/base',
'PhabricatorProjectCreateController' => 'applications/project/controller/create',
'PhabricatorProjectDAO' => 'applications/project/storage/base',
'PhabricatorProjectListController' => 'applications/project/controller/list',
'PhabricatorProjectProfile' => 'applications/project/storage/profile',
'PhabricatorProjectProfileController' => 'applications/project/controller/profile',
'PhabricatorProjectProfileEditController' => 'applications/project/controller/profileedit',
'PhabricatorProjectStatus' => 'applications/project/constants/status',
'PhabricatorProjectSubproject' => 'applications/project/storage/subproject',
'PhabricatorRedirectController' => 'applications/base/controller/redirect',
'PhabricatorRefreshCSRFController' => 'applications/auth/controller/refresh',
'PhabricatorRemarkupRuleDifferential' => 'infrastructure/markup/remarkup/markuprule/differential',
'PhabricatorRemarkupRuleDifferentialHandle' => 'infrastructure/markup/remarkup/markuprule/handle/differential',
'PhabricatorRemarkupRuleDiffusion' => 'infrastructure/markup/remarkup/markuprule/diffusion',
'PhabricatorRemarkupRuleEmbedFile' => 'infrastructure/markup/remarkup/markuprule/embedobject',
'PhabricatorRemarkupRuleImageMacro' => 'infrastructure/markup/remarkup/markuprule/imagemacro',
'PhabricatorRemarkupRuleManiphest' => 'infrastructure/markup/remarkup/markuprule/maniphest',
'PhabricatorRemarkupRuleManiphestHandle' => 'infrastructure/markup/remarkup/markuprule/handle/maniphest',
'PhabricatorRemarkupRuleMention' => 'infrastructure/markup/remarkup/markuprule/mention',
'PhabricatorRemarkupRuleObjectHandle' => 'infrastructure/markup/remarkup/markuprule/handle',
'PhabricatorRemarkupRuleObjectName' => 'infrastructure/markup/remarkup/markuprule/objectname',
'PhabricatorRemarkupRulePaste' => 'infrastructure/markup/remarkup/markuprule/paste',
'PhabricatorRemarkupRulePhriction' => 'infrastructure/markup/remarkup/markuprule/phriction',
'PhabricatorRemarkupRuleProxyImage' => 'infrastructure/markup/remarkup/markuprule/proxyimage',
'PhabricatorRemarkupRuleYoutube' => 'infrastructure/markup/remarkup/markuprule/youtube',
'PhabricatorRepository' => 'applications/repository/storage/repository',
'PhabricatorRepositoryArcanistProject' => 'applications/repository/storage/arcanistproject',
'PhabricatorRepositoryArcanistProjectEditController' => 'applications/repository/controller/arcansistprojectedit',
'PhabricatorRepositoryCommit' => 'applications/repository/storage/commit',
'PhabricatorRepositoryCommitChangeParserWorker' => 'applications/repository/worker/commitchangeparser/base',
'PhabricatorRepositoryCommitData' => 'applications/repository/storage/commitdata',
'PhabricatorRepositoryCommitDiscoveryDaemon' => 'applications/repository/daemon/commitdiscovery/base',
'PhabricatorRepositoryCommitHeraldWorker' => 'applications/repository/worker/herald',
'PhabricatorRepositoryCommitMessageDetailParser' => 'applications/repository/parser/base',
'PhabricatorRepositoryCommitMessageParserWorker' => 'applications/repository/worker/commitmessageparser/base',
'PhabricatorRepositoryCommitParserWorker' => 'applications/repository/worker/base',
'PhabricatorRepositoryCommitTaskDaemon' => 'applications/repository/daemon/committask',
'PhabricatorRepositoryController' => 'applications/repository/controller/base',
'PhabricatorRepositoryCreateController' => 'applications/repository/controller/create',
'PhabricatorRepositoryDAO' => 'applications/repository/storage/base',
'PhabricatorRepositoryDaemon' => 'applications/repository/daemon/base',
'PhabricatorRepositoryDefaultCommitMessageDetailParser' => 'applications/repository/parser/default',
'PhabricatorRepositoryDeleteController' => 'applications/repository/controller/delete',
'PhabricatorRepositoryEditController' => 'applications/repository/controller/edit',
'PhabricatorRepositoryGitCommitChangeParserWorker' => 'applications/repository/worker/commitchangeparser/git',
'PhabricatorRepositoryGitCommitDiscoveryDaemon' => 'applications/repository/daemon/commitdiscovery/git',
'PhabricatorRepositoryGitCommitMessageParserWorker' => 'applications/repository/worker/commitmessageparser/git',
'PhabricatorRepositoryGitFetchDaemon' => 'applications/repository/daemon/gitfetch',
'PhabricatorRepositoryGitHubNotification' => 'applications/repository/storage/githubnotification',
'PhabricatorRepositoryGitHubPostReceiveController' => 'applications/repository/controller/github-post-receive',
'PhabricatorRepositoryListController' => 'applications/repository/controller/list',
'PhabricatorRepositoryShortcut' => 'applications/repository/storage/shortcut',
'PhabricatorRepositorySvnCommitChangeParserWorker' => 'applications/repository/worker/commitchangeparser/svn',
'PhabricatorRepositorySvnCommitDiscoveryDaemon' => 'applications/repository/daemon/commitdiscovery/svn',
'PhabricatorRepositorySvnCommitMessageParserWorker' => 'applications/repository/worker/commitmessageparser/svn',
'PhabricatorRepositoryType' => 'applications/repository/constants/repositorytype',
'PhabricatorS3FileStorageEngine' => 'applications/files/engine/s3',
'PhabricatorSQLPatchList' => 'infrastructure/setup/sql',
'PhabricatorSearchAbstractDocument' => 'applications/search/index/abstractdocument',
'PhabricatorSearchAttachController' => 'applications/search/controller/attach',
'PhabricatorSearchBaseController' => 'applications/search/controller/base',
'PhabricatorSearchCommitIndexer' => 'applications/search/index/indexer/repository',
'PhabricatorSearchController' => 'applications/search/controller/search',
'PhabricatorSearchDAO' => 'applications/search/storage/base',
'PhabricatorSearchDifferentialIndexer' => 'applications/search/index/indexer/differential',
'PhabricatorSearchDocument' => 'applications/search/storage/document/document',
'PhabricatorSearchDocumentField' => 'applications/search/storage/document/field',
'PhabricatorSearchDocumentIndexer' => 'applications/search/index/indexer/base',
'PhabricatorSearchDocumentRelationship' => 'applications/search/storage/document/relationship',
'PhabricatorSearchEngine' => 'applications/search/engine/base',
'PhabricatorSearchEngineMySQL' => 'applications/search/engine/mysql',
'PhabricatorSearchEngineSelector' => 'applications/search/selector/base',
'PhabricatorSearchField' => 'applications/search/constants/field',
'PhabricatorSearchIndexController' => 'applications/search/controller/index',
'PhabricatorSearchManiphestIndexer' => 'applications/search/index/indexer/maniphest',
'PhabricatorSearchPhrictionIndexer' => 'applications/search/index/indexer/phriction',
'PhabricatorSearchQuery' => 'applications/search/storage/query',
'PhabricatorSearchRelationship' => 'applications/search/constants/relationship',
'PhabricatorSearchResultView' => 'applications/search/view/searchresult',
'PhabricatorSearchSelectController' => 'applications/search/controller/select',
'PhabricatorSearchUserIndexer' => 'applications/search/index/indexer/user',
'PhabricatorSetup' => 'infrastructure/setup',
'PhabricatorSlowvoteChoice' => 'applications/slowvote/storage/choice',
'PhabricatorSlowvoteComment' => 'applications/slowvote/storage/comment',
'PhabricatorSlowvoteController' => 'applications/slowvote/controller/base',
'PhabricatorSlowvoteCreateController' => 'applications/slowvote/controller/create',
'PhabricatorSlowvoteDAO' => 'applications/slowvote/storage/base',
'PhabricatorSlowvoteListController' => 'applications/slowvote/controller/list',
'PhabricatorSlowvoteOption' => 'applications/slowvote/storage/option',
'PhabricatorSlowvotePoll' => 'applications/slowvote/storage/poll',
'PhabricatorSlowvotePollController' => 'applications/slowvote/controller/poll',
'PhabricatorStandardPageView' => 'view/page/standard',
'PhabricatorStatusController' => 'applications/status/base',
'PhabricatorSyntaxHighlighter' => 'applications/markup/syntax',
'PhabricatorTaskmasterDaemon' => 'infrastructure/daemon/workers/taskmaster',
'PhabricatorTestCase' => 'infrastructure/testing/testcase',
'PhabricatorTimelineCursor' => 'infrastructure/daemon/timeline/storage/cursor',
'PhabricatorTimelineDAO' => 'infrastructure/daemon/timeline/storage/base',
'PhabricatorTimelineEvent' => 'infrastructure/daemon/timeline/storage/event',
'PhabricatorTimelineEventData' => 'infrastructure/daemon/timeline/storage/eventdata',
'PhabricatorTimelineIterator' => 'infrastructure/daemon/timeline/cursor/iterator',
'PhabricatorTimer' => 'applications/countdown/storage/timer',
'PhabricatorTransformedFile' => 'applications/files/storage/transformed',
'PhabricatorTrivialTestCase' => 'infrastructure/testing/testcase/__tests__',
'PhabricatorTypeaheadCommonDatasourceController' => 'applications/typeahead/controller/common',
'PhabricatorTypeaheadDatasourceController' => 'applications/typeahead/controller/base',
'PhabricatorUIExample' => 'applications/uiexample/examples/base',
'PhabricatorUIExampleController' => 'applications/uiexample/controller/base',
'PhabricatorUIExampleRenderController' => 'applications/uiexample/controller/render',
'PhabricatorUIListFilterExample' => 'applications/uiexample/examples/listfilter',
'PhabricatorUIPagerExample' => 'applications/uiexample/examples/pager',
'PhabricatorUser' => 'applications/people/storage/user',
'PhabricatorUserAccountSettingsPanelController' => 'applications/people/controller/settings/panels/account',
'PhabricatorUserConduitSettingsPanelController' => 'applications/people/controller/settings/panels/conduit',
'PhabricatorUserDAO' => 'applications/people/storage/base',
'PhabricatorUserEmailSettingsPanelController' => 'applications/people/controller/settings/panels/email',
'PhabricatorUserLog' => 'applications/people/storage/log',
'PhabricatorUserOAuthInfo' => 'applications/people/storage/useroauthinfo',
'PhabricatorUserOAuthSettingsPanelController' => 'applications/people/controller/settings/panels/oauth',
'PhabricatorUserPreferenceSettingsPanelController' => 'applications/people/controller/settings/panels/preferences',
'PhabricatorUserPreferences' => 'applications/people/storage/preferences',
'PhabricatorUserProfile' => 'applications/people/storage/profile',
'PhabricatorUserProfileSettingsPanelController' => 'applications/people/controller/settings/panels/profile',
'PhabricatorUserSSHKey' => 'applications/people/storage/usersshkey',
'PhabricatorUserSSHKeysSettingsPanelController' => 'applications/people/controller/settings/panels/sshkeys',
'PhabricatorUserSettingsController' => 'applications/people/controller/settings',
'PhabricatorUserSettingsPanelController' => 'applications/people/controller/settings/panels/base',
'PhabricatorWorker' => 'infrastructure/daemon/workers/worker',
'PhabricatorWorkerDAO' => 'infrastructure/daemon/workers/storage/base',
'PhabricatorWorkerTask' => 'infrastructure/daemon/workers/storage/task',
'PhabricatorWorkerTaskData' => 'infrastructure/daemon/workers/storage/taskdata',
'PhabricatorWorkerTaskDetailController' => 'applications/daemon/controller/workertaskdetail',
'PhabricatorXHPASTViewController' => 'applications/xhpastview/controller/base',
'PhabricatorXHPASTViewDAO' => 'applications/xhpastview/storage/base',
'PhabricatorXHPASTViewFrameController' => 'applications/xhpastview/controller/viewframe',
'PhabricatorXHPASTViewFramesetController' => 'applications/xhpastview/controller/viewframeset',
'PhabricatorXHPASTViewInputController' => 'applications/xhpastview/controller/viewinput',
'PhabricatorXHPASTViewPanelController' => 'applications/xhpastview/controller/viewpanel',
'PhabricatorXHPASTViewParseTree' => 'applications/xhpastview/storage/parsetree',
'PhabricatorXHPASTViewRunController' => 'applications/xhpastview/controller/run',
'PhabricatorXHPASTViewStreamController' => 'applications/xhpastview/controller/viewstream',
'PhabricatorXHPASTViewTreeController' => 'applications/xhpastview/controller/viewtree',
'PhabricatorXHProfController' => 'applications/xhprof/controller/base',
'PhabricatorXHProfProfileController' => 'applications/xhprof/controller/profile',
'PhabricatorXHProfProfileSymbolView' => 'applications/xhprof/view/symbol',
'PhabricatorXHProfProfileTopLevelView' => 'applications/xhprof/view/toplevel',
'PhrictionActionConstants' => 'applications/phriction/constants/action',
'PhrictionConstants' => 'applications/phriction/constants/base',
'PhrictionContent' => 'applications/phriction/storage/content',
'PhrictionController' => 'applications/phriction/controller/base',
'PhrictionDAO' => 'applications/phriction/storage/base',
'PhrictionDiffController' => 'applications/phriction/controller/diff',
'PhrictionDocument' => 'applications/phriction/storage/document',
'PhrictionDocumentController' => 'applications/phriction/controller/document',
'PhrictionDocumentPreviewController' => 'applications/phriction/controller/documentpreview',
'PhrictionDocumentTestCase' => 'applications/phriction/storage/document/__tests__',
'PhrictionEditController' => 'applications/phriction/controller/edit',
'PhrictionHistoryController' => 'applications/phriction/controller/history',
'PhrictionListController' => 'applications/phriction/controller/list',
),
'function' =>
array(
'_qsprintf_check_scalar_type' => 'storage/qsprintf',
'_qsprintf_check_type' => 'storage/qsprintf',
'celerity_generate_unique_node_id' => 'infrastructure/celerity/api',
'celerity_register_resource_map' => 'infrastructure/celerity/map',
'javelin_render_tag' => 'infrastructure/javelin/markup',
'phabricator_date' => 'view/utils',
'phabricator_datetime' => 'view/utils',
'phabricator_format_relative_time' => 'view/utils',
'phabricator_format_timestamp' => 'view/utils',
'phabricator_format_units_generic' => 'view/utils',
'phabricator_render_form' => 'infrastructure/javelin/markup',
'phabricator_time' => 'view/utils',
'qsprintf' => 'storage/qsprintf',
'queryfx' => 'storage/queryfx',
'queryfx_all' => 'storage/queryfx',
'queryfx_one' => 'storage/queryfx',
'require_celerity_resource' => 'infrastructure/celerity/api',
'vqsprintf' => 'storage/qsprintf',
'vqueryfx' => 'storage/queryfx',
'vqueryfx_all' => 'storage/queryfx',
'xsprintf_query' => 'storage/qsprintf',
),
'requires_class' =>
array(
'Aphront304Response' => 'AphrontResponse',
'Aphront400Response' => 'AphrontResponse',
'Aphront404Response' => 'AphrontResponse',
'AphrontAjaxResponse' => 'AphrontResponse',
'AphrontAttachedFileView' => 'AphrontView',
'AphrontCSRFException' => 'AphrontException',
'AphrontCalendarMonthView' => 'AphrontView',
'AphrontContextBarView' => 'AphrontView',
'AphrontCrumbsView' => 'AphrontView',
'AphrontDefaultApplicationConfiguration' => 'AphrontApplicationConfiguration',
'AphrontDefaultApplicationController' => 'AphrontController',
'AphrontDialogResponse' => 'AphrontResponse',
'AphrontDialogView' => 'AphrontView',
'AphrontErrorView' => 'AphrontView',
'AphrontFilePreviewView' => 'AphrontView',
'AphrontFileResponse' => 'AphrontResponse',
'AphrontFormCheckboxControl' => 'AphrontFormControl',
'AphrontFormControl' => 'AphrontView',
'AphrontFormDividerControl' => 'AphrontFormControl',
'AphrontFormDragAndDropUploadControl' => 'AphrontFormControl',
'AphrontFormFileControl' => 'AphrontFormControl',
'AphrontFormLayoutView' => 'AphrontView',
'AphrontFormMarkupControl' => 'AphrontFormControl',
'AphrontFormPasswordControl' => 'AphrontFormControl',
'AphrontFormRecaptchaControl' => 'AphrontFormControl',
'AphrontFormSelectControl' => 'AphrontFormControl',
'AphrontFormStaticControl' => 'AphrontFormControl',
'AphrontFormSubmitControl' => 'AphrontFormControl',
'AphrontFormTextAreaControl' => 'AphrontFormControl',
'AphrontFormTextControl' => 'AphrontFormControl',
'AphrontFormToggleButtonsControl' => 'AphrontFormControl',
'AphrontFormTokenizerControl' => 'AphrontFormControl',
'AphrontFormView' => 'AphrontView',
'AphrontHeadsupActionListView' => 'AphrontView',
'AphrontHeadsupActionView' => 'AphrontView',
'AphrontIsolatedDatabaseConnection' => 'AphrontDatabaseConnection',
'AphrontIsolatedDatabaseConnectionTestCase' => 'PhabricatorTestCase',
'AphrontKeyboardShortcutsAvailableView' => 'AphrontView',
'AphrontListFilterView' => 'AphrontView',
'AphrontMySQLDatabaseConnection' => 'AphrontDatabaseConnection',
'AphrontNullView' => 'AphrontView',
'AphrontPageView' => 'AphrontView',
'AphrontPagerView' => 'AphrontView',
'AphrontPanelView' => 'AphrontView',
'AphrontQueryAccessDeniedException' => 'AphrontQueryRecoverableException',
'AphrontQueryConnectionException' => 'AphrontQueryException',
'AphrontQueryConnectionLostException' => 'AphrontQueryRecoverableException',
'AphrontQueryCountException' => 'AphrontQueryException',
'AphrontQueryDuplicateKeyException' => 'AphrontQueryException',
'AphrontQueryObjectMissingException' => 'AphrontQueryException',
'AphrontQueryParameterException' => 'AphrontQueryException',
'AphrontQueryRecoverableException' => 'AphrontQueryException',
'AphrontRedirectException' => 'AphrontException',
'AphrontRedirectResponse' => 'AphrontResponse',
'AphrontReloadResponse' => 'AphrontRedirectResponse',
'AphrontRequestFailureView' => 'AphrontView',
'AphrontSideNavView' => 'AphrontView',
'AphrontTableView' => 'AphrontView',
'AphrontTokenizerTemplateView' => 'AphrontView',
'AphrontTypeaheadTemplateView' => 'AphrontView',
'AphrontWebpageResponse' => 'AphrontResponse',
'CelerityResourceController' => 'AphrontController',
'ConduitAPI_conduit_connect_Method' => 'ConduitAPIMethod',
'ConduitAPI_conduit_getcertificate_Method' => 'ConduitAPIMethod',
'ConduitAPI_conduit_ping_Method' => 'ConduitAPIMethod',
'ConduitAPI_daemon_launched_Method' => 'ConduitAPIMethod',
'ConduitAPI_daemon_log_Method' => 'ConduitAPIMethod',
'ConduitAPI_differential_creatediff_Method' => 'ConduitAPIMethod',
'ConduitAPI_differential_createrevision_Method' => 'ConduitAPIMethod',
'ConduitAPI_differential_find_Method' => 'ConduitAPIMethod',
'ConduitAPI_differential_getalldiffs_Method' => 'ConduitAPIMethod',
'ConduitAPI_differential_getcommitmessage_Method' => 'ConduitAPIMethod',
'ConduitAPI_differential_getcommitpaths_Method' => 'ConduitAPIMethod',
'ConduitAPI_differential_getdiff_Method' => 'ConduitAPIMethod',
'ConduitAPI_differential_getrevision_Method' => 'ConduitAPIMethod',
'ConduitAPI_differential_getrevisionfeedback_Method' => 'ConduitAPIMethod',
'ConduitAPI_differential_markcommitted_Method' => 'ConduitAPIMethod',
'ConduitAPI_differential_parsecommitmessage_Method' => 'ConduitAPIMethod',
'ConduitAPI_differential_setdiffproperty_Method' => 'ConduitAPIMethod',
'ConduitAPI_differential_updaterevision_Method' => 'ConduitAPIMethod',
'ConduitAPI_differential_updatetaskrevisionassoc_Method' => 'ConduitAPIMethod',
'ConduitAPI_differential_updateunitresults_Method' => 'ConduitAPIMethod',
'ConduitAPI_diffusion_getcommits_Method' => 'ConduitAPIMethod',
'ConduitAPI_diffusion_getrecentcommitsbypath_Method' => 'ConduitAPIMethod',
'ConduitAPI_feed_publish_Method' => 'ConduitAPIMethod',
'ConduitAPI_file_download_Method' => 'ConduitAPIMethod',
'ConduitAPI_file_info_Method' => 'ConduitAPIMethod',
'ConduitAPI_file_upload_Method' => 'ConduitAPIMethod',
'ConduitAPI_maniphest_info_Method' => 'ConduitAPIMethod',
'ConduitAPI_paste_Method' => 'ConduitAPIMethod',
'ConduitAPI_paste_create_Method' => 'ConduitAPI_paste_Method',
'ConduitAPI_paste_info_Method' => 'ConduitAPI_paste_Method',
'ConduitAPI_path_getowners_Method' => 'ConduitAPIMethod',
'ConduitAPI_slowvote_info_Method' => 'ConduitAPIMethod',
'ConduitAPI_user_find_Method' => 'ConduitAPIMethod',
'ConduitAPI_user_whoami_Method' => 'ConduitAPIMethod',
'DarkConsoleConfigPlugin' => 'DarkConsolePlugin',
'DarkConsoleController' => 'PhabricatorController',
'DarkConsoleErrorLogPlugin' => 'DarkConsolePlugin',
'DarkConsoleRequestPlugin' => 'DarkConsolePlugin',
'DarkConsoleServicesPlugin' => 'DarkConsolePlugin',
'DarkConsoleXHProfPlugin' => 'DarkConsolePlugin',
'DifferentialAddCommentView' => 'AphrontView',
'DifferentialApplyPatchFieldSpecification' => 'DifferentialFieldSpecification',
'DifferentialArcanistProjectFieldSpecification' => 'DifferentialFieldSpecification',
'DifferentialAuthorFieldSpecification' => 'DifferentialFieldSpecification',
'DifferentialAuxiliaryField' => 'DifferentialDAO',
'DifferentialBlameRevisionFieldSpecification' => 'DifferentialFieldSpecification',
'DifferentialCCWelcomeMail' => 'DifferentialReviewRequestMail',
'DifferentialCCsFieldSpecification' => 'DifferentialFieldSpecification',
'DifferentialChangeset' => 'DifferentialDAO',
'DifferentialChangesetDetailView' => 'AphrontView',
'DifferentialChangesetListView' => 'AphrontView',
'DifferentialChangesetViewController' => 'DifferentialController',
'DifferentialComment' => 'DifferentialDAO',
'DifferentialCommentMail' => 'DifferentialMail',
'DifferentialCommentPreviewController' => 'DifferentialController',
'DifferentialCommentSaveController' => 'DifferentialController',
'DifferentialCommitsFieldSpecification' => 'DifferentialFieldSpecification',
'DifferentialController' => 'PhabricatorController',
'DifferentialDAO' => 'PhabricatorLiskDAO',
'DifferentialDefaultFieldSelector' => 'DifferentialFieldSelector',
'DifferentialDependenciesFieldSpecification' => 'DifferentialFieldSpecification',
'DifferentialDiff' => 'DifferentialDAO',
'DifferentialDiffContentMail' => 'DifferentialMail',
'DifferentialDiffCreateController' => 'DifferentialController',
'DifferentialDiffProperty' => 'DifferentialDAO',
'DifferentialDiffTableOfContentsView' => 'AphrontView',
'DifferentialDiffViewController' => 'DifferentialController',
'DifferentialExceptionMail' => 'DifferentialMail',
'DifferentialExportPatchFieldSpecification' => 'DifferentialFieldSpecification',
'DifferentialGitSVNIDFieldSpecification' => 'DifferentialFieldSpecification',
'DifferentialHostFieldSpecification' => 'DifferentialFieldSpecification',
'DifferentialHunk' => 'DifferentialDAO',
'DifferentialInlineComment' => 'DifferentialDAO',
'DifferentialInlineCommentEditController' => 'DifferentialController',
'DifferentialInlineCommentPreviewController' => 'DifferentialController',
'DifferentialInlineCommentView' => 'AphrontView',
'DifferentialLinesFieldSpecification' => 'DifferentialFieldSpecification',
'DifferentialLintFieldSpecification' => 'DifferentialFieldSpecification',
'DifferentialManiphestTasksFieldSpecification' => 'DifferentialFieldSpecification',
'DifferentialNewDiffMail' => 'DifferentialReviewRequestMail',
'DifferentialPathFieldSpecification' => 'DifferentialFieldSpecification',
'DifferentialPrimaryPaneView' => 'AphrontView',
'DifferentialReplyHandler' => 'PhabricatorMailReplyHandler',
'DifferentialRevertPlanFieldSpecification' => 'DifferentialFieldSpecification',
'DifferentialReviewRequestMail' => 'DifferentialMail',
'DifferentialReviewedByFieldSpecification' => 'DifferentialFieldSpecification',
'DifferentialReviewersFieldSpecification' => 'DifferentialFieldSpecification',
'DifferentialRevision' => 'DifferentialDAO',
'DifferentialRevisionCommentListView' => 'AphrontView',
'DifferentialRevisionCommentView' => 'AphrontView',
'DifferentialRevisionDetailView' => 'AphrontView',
'DifferentialRevisionEditController' => 'DifferentialController',
'DifferentialRevisionIDFieldSpecification' => 'DifferentialFieldSpecification',
'DifferentialRevisionListController' => 'DifferentialController',
'DifferentialRevisionStatusFieldSpecification' => 'DifferentialFieldSpecification',
'DifferentialRevisionUpdateHistoryView' => 'AphrontView',
'DifferentialRevisionViewController' => 'DifferentialController',
'DifferentialSubscribeController' => 'DifferentialController',
'DifferentialSummaryFieldSpecification' => 'DifferentialFieldSpecification',
'DifferentialTestPlanFieldSpecification' => 'DifferentialFieldSpecification',
'DifferentialTitleFieldSpecification' => 'DifferentialFieldSpecification',
'DifferentialUnitFieldSpecification' => 'DifferentialFieldSpecification',
'DifferentialViewTime' => 'DifferentialDAO',
'DiffusionBranchTableView' => 'DiffusionView',
'DiffusionBrowseController' => 'DiffusionController',
'DiffusionBrowseFileController' => 'DiffusionController',
'DiffusionBrowseTableView' => 'DiffusionView',
'DiffusionChangeController' => 'DiffusionController',
'DiffusionCommitChangeTableView' => 'DiffusionView',
'DiffusionCommitController' => 'DiffusionController',
'DiffusionCommitListController' => 'DiffusionController',
'DiffusionController' => 'PhabricatorController',
'DiffusionDiffController' => 'DiffusionController',
'DiffusionGitBranchQuery' => 'DiffusionBranchQuery',
'DiffusionGitBrowseQuery' => 'DiffusionBrowseQuery',
'DiffusionGitDiffQuery' => 'DiffusionDiffQuery',
'DiffusionGitFileContentQuery' => 'DiffusionFileContentQuery',
'DiffusionGitHistoryQuery' => 'DiffusionHistoryQuery',
'DiffusionGitLastModifiedQuery' => 'DiffusionLastModifiedQuery',
'DiffusionGitRequest' => 'DiffusionRequest',
'DiffusionHistoryController' => 'DiffusionController',
'DiffusionHistoryTableView' => 'DiffusionView',
'DiffusionHomeController' => 'DiffusionController',
'DiffusionLastModifiedController' => 'DiffusionController',
'DiffusionPathCompleteController' => 'DiffusionController',
'DiffusionPathValidateController' => 'DiffusionController',
'DiffusionRepositoryController' => 'DiffusionController',
'DiffusionSvnBrowseQuery' => 'DiffusionBrowseQuery',
'DiffusionSvnDiffQuery' => 'DiffusionDiffQuery',
'DiffusionSvnFileContentQuery' => 'DiffusionFileContentQuery',
'DiffusionSvnHistoryQuery' => 'DiffusionHistoryQuery',
'DiffusionSvnLastModifiedQuery' => 'DiffusionLastModifiedQuery',
'DiffusionSvnRequest' => 'DiffusionRequest',
'DiffusionView' => 'AphrontView',
'HeraldAction' => 'HeraldDAO',
'HeraldApplyTranscript' => 'HeraldDAO',
'HeraldCommitAdapter' => 'HeraldObjectAdapter',
'HeraldCondition' => 'HeraldDAO',
'HeraldController' => 'PhabricatorController',
'HeraldDAO' => 'PhabricatorLiskDAO',
'HeraldDeleteController' => 'HeraldController',
'HeraldDifferentialRevisionAdapter' => 'HeraldObjectAdapter',
'HeraldDryRunAdapter' => 'HeraldObjectAdapter',
'HeraldHomeController' => 'HeraldController',
'HeraldNewController' => 'HeraldController',
'HeraldRule' => 'HeraldDAO',
'HeraldRuleController' => 'HeraldController',
'HeraldTestConsoleController' => 'HeraldController',
'HeraldTranscript' => 'HeraldDAO',
'HeraldTranscriptController' => 'HeraldController',
'HeraldTranscriptListController' => 'HeraldController',
'LiskIsolationTestCase' => 'PhabricatorTestCase',
'LiskIsolationTestDAO' => 'LiskDAO',
'ManiphestAuxiliaryFieldDefaultSpecification' => 'ManiphestAuxiliaryFieldSpecification',
'ManiphestController' => 'PhabricatorController',
'ManiphestDAO' => 'PhabricatorLiskDAO',
'ManiphestDefaultTaskExtensions' => 'ManiphestTaskExtensions',
'ManiphestReplyHandler' => 'PhabricatorMailReplyHandler',
'ManiphestTask' => 'ManiphestDAO',
'ManiphestTaskAuxiliaryStorage' => 'ManiphestDAO',
'ManiphestTaskDescriptionChangeController' => 'ManiphestController',
'ManiphestTaskDetailController' => 'ManiphestController',
'ManiphestTaskEditController' => 'ManiphestController',
'ManiphestTaskListController' => 'ManiphestController',
'ManiphestTaskListView' => 'ManiphestView',
'ManiphestTaskOwner' => 'ManiphestConstants',
'ManiphestTaskPriority' => 'ManiphestConstants',
'ManiphestTaskProject' => 'ManiphestDAO',
'ManiphestTaskStatus' => 'ManiphestConstants',
'ManiphestTaskSubscriber' => 'ManiphestDAO',
'ManiphestTaskSummaryView' => 'ManiphestView',
'ManiphestTransaction' => 'ManiphestDAO',
'ManiphestTransactionDetailView' => 'ManiphestView',
'ManiphestTransactionListView' => 'ManiphestView',
'ManiphestTransactionPreviewController' => 'ManiphestController',
'ManiphestTransactionSaveController' => 'ManiphestController',
'ManiphestTransactionType' => 'ManiphestConstants',
'ManiphestView' => 'AphrontView',
'Phabricator404Controller' => 'PhabricatorController',
'PhabricatorAuthController' => 'PhabricatorController',
'PhabricatorCalendarBrowseController' => 'PhabricatorCalendarController',
'PhabricatorCalendarController' => 'PhabricatorController',
'PhabricatorConduitAPIController' => 'PhabricatorConduitController',
'PhabricatorConduitCertificateToken' => 'PhabricatorConduitDAO',
'PhabricatorConduitConnectionLog' => 'PhabricatorConduitDAO',
'PhabricatorConduitConsoleController' => 'PhabricatorConduitController',
'PhabricatorConduitController' => 'PhabricatorController',
'PhabricatorConduitDAO' => 'PhabricatorLiskDAO',
'PhabricatorConduitLogController' => 'PhabricatorConduitController',
'PhabricatorConduitMethodCallLog' => 'PhabricatorConduitDAO',
'PhabricatorConduitTokenController' => 'PhabricatorConduitController',
'PhabricatorController' => 'AphrontController',
'PhabricatorCountdownController' => 'PhabricatorController',
'PhabricatorCountdownDAO' => 'PhabricatorLiskDAO',
'PhabricatorCountdownDeleteController' => 'PhabricatorCountdownController',
'PhabricatorCountdownEditController' => 'PhabricatorCountdownController',
'PhabricatorCountdownListController' => 'PhabricatorCountdownController',
'PhabricatorCountdownViewController' => 'PhabricatorCountdownController',
'PhabricatorDaemon' => 'PhutilDaemon',
'PhabricatorDaemonCombinedLogController' => 'PhabricatorDaemonController',
'PhabricatorDaemonConsoleController' => 'PhabricatorDaemonController',
'PhabricatorDaemonController' => 'PhabricatorController',
'PhabricatorDaemonDAO' => 'PhabricatorLiskDAO',
'PhabricatorDaemonLog' => 'PhabricatorDaemonDAO',
'PhabricatorDaemonLogEvent' => 'PhabricatorDaemonDAO',
'PhabricatorDaemonLogEventsView' => 'AphrontView',
'PhabricatorDaemonLogListController' => 'PhabricatorDaemonController',
'PhabricatorDaemonLogListView' => 'AphrontView',
'PhabricatorDaemonLogViewController' => 'PhabricatorDaemonController',
'PhabricatorDaemonTimelineConsoleController' => 'PhabricatorDaemonController',
'PhabricatorDaemonTimelineEventController' => 'PhabricatorDaemonController',
'PhabricatorDefaultFileStorageEngineSelector' => 'PhabricatorFileStorageEngineSelector',
'PhabricatorDefaultSearchEngineSelector' => 'PhabricatorSearchEngineSelector',
'PhabricatorDirectoryCategory' => 'PhabricatorDirectoryDAO',
'PhabricatorDirectoryCategoryDeleteController' => 'PhabricatorDirectoryController',
'PhabricatorDirectoryCategoryEditController' => 'PhabricatorDirectoryController',
'PhabricatorDirectoryCategoryListController' => 'PhabricatorDirectoryController',
'PhabricatorDirectoryController' => 'PhabricatorController',
'PhabricatorDirectoryDAO' => 'PhabricatorLiskDAO',
'PhabricatorDirectoryItem' => 'PhabricatorDirectoryDAO',
'PhabricatorDirectoryItemDeleteController' => 'PhabricatorDirectoryController',
'PhabricatorDirectoryItemEditController' => 'PhabricatorDirectoryController',
'PhabricatorDirectoryItemListController' => 'PhabricatorDirectoryController',
'PhabricatorDirectoryMainController' => 'PhabricatorDirectoryController',
'PhabricatorDisabledUserController' => 'PhabricatorAuthController',
'PhabricatorDraft' => 'PhabricatorDraftDAO',
'PhabricatorDraftDAO' => 'PhabricatorLiskDAO',
'PhabricatorEmailLoginController' => 'PhabricatorAuthController',
'PhabricatorEmailTokenController' => 'PhabricatorAuthController',
'PhabricatorFeedController' => 'PhabricatorController',
'PhabricatorFeedDAO' => 'PhabricatorLiskDAO',
'PhabricatorFeedPublicStreamController' => 'PhabricatorFeedController',
'PhabricatorFeedStoryData' => 'PhabricatorFeedDAO',
'PhabricatorFeedStoryDifferential' => 'PhabricatorFeedStory',
'PhabricatorFeedStoryPhriction' => 'PhabricatorFeedStory',
'PhabricatorFeedStoryReference' => 'PhabricatorFeedDAO',
'PhabricatorFeedStoryStatus' => 'PhabricatorFeedStory',
'PhabricatorFeedStoryTypeConstants' => 'PhabricatorFeedConstants',
'PhabricatorFeedStoryUnknown' => 'PhabricatorFeedStory',
'PhabricatorFeedStoryView' => 'PhabricatorFeedView',
'PhabricatorFeedStreamController' => 'PhabricatorFeedController',
'PhabricatorFeedView' => 'AphrontView',
'PhabricatorFile' => 'PhabricatorFileDAO',
'PhabricatorFileAltViewController' => 'PhabricatorFileController',
'PhabricatorFileController' => 'PhabricatorController',
'PhabricatorFileDAO' => 'PhabricatorLiskDAO',
'PhabricatorFileDropUploadController' => 'PhabricatorFileController',
'PhabricatorFileImageMacro' => 'PhabricatorFileDAO',
'PhabricatorFileListController' => 'PhabricatorFileController',
'PhabricatorFileMacroDeleteController' => 'PhabricatorFileController',
'PhabricatorFileMacroEditController' => 'PhabricatorFileController',
'PhabricatorFileMacroListController' => 'PhabricatorFileController',
'PhabricatorFileProxyController' => 'PhabricatorFileController',
'PhabricatorFileProxyImage' => 'PhabricatorFileDAO',
'PhabricatorFileStorageBlob' => 'PhabricatorFileDAO',
'PhabricatorFileTransformController' => 'PhabricatorFileController',
'PhabricatorFileUploadController' => 'PhabricatorFileController',
'PhabricatorFileViewController' => 'PhabricatorFileController',
'PhabricatorGarbageCollectorDaemon' => 'PhabricatorDaemon',
'PhabricatorGoodForNothingWorker' => 'PhabricatorWorker',
'PhabricatorHelpController' => 'PhabricatorController',
'PhabricatorHelpKeyboardShortcutController' => 'PhabricatorHelpController',
'PhabricatorIRCBot' => 'PhabricatorDaemon',
'PhabricatorIRCObjectNameHandler' => 'PhabricatorIRCHandler',
'PhabricatorIRCProtocolHandler' => 'PhabricatorIRCHandler',
'PhabricatorJavelinLinter' => 'ArcanistLinter',
'PhabricatorLintEngine' => 'PhutilLintEngine',
'PhabricatorLiskDAO' => 'LiskDAO',
'PhabricatorLocalDiskFileStorageEngine' => 'PhabricatorFileStorageEngine',
'PhabricatorLoginController' => 'PhabricatorAuthController',
'PhabricatorLogoutController' => 'PhabricatorAuthController',
'PhabricatorMailImplementationAmazonSESAdapter' => 'PhabricatorMailImplementationPHPMailerLiteAdapter',
'PhabricatorMailImplementationPHPMailerLiteAdapter' => 'PhabricatorMailImplementationAdapter',
'PhabricatorMailImplementationSendGridAdapter' => 'PhabricatorMailImplementationAdapter',
'PhabricatorMailImplementationTestAdapter' => 'PhabricatorMailImplementationAdapter',
'PhabricatorMetaMTAController' => 'PhabricatorController',
'PhabricatorMetaMTADAO' => 'PhabricatorLiskDAO',
'PhabricatorMetaMTADaemon' => 'PhabricatorDaemon',
'PhabricatorMetaMTAEmailBodyParserTestCase' => 'PhabricatorTestCase',
'PhabricatorMetaMTAListController' => 'PhabricatorMetaMTAController',
'PhabricatorMetaMTAMail' => 'PhabricatorMetaMTADAO',
'PhabricatorMetaMTAMailTestCase' => 'PhabricatorTestCase',
'PhabricatorMetaMTAMailingList' => 'PhabricatorMetaMTADAO',
'PhabricatorMetaMTAMailingListEditController' => 'PhabricatorMetaMTAController',
'PhabricatorMetaMTAMailingListsController' => 'PhabricatorMetaMTAController',
'PhabricatorMetaMTAReceiveController' => 'PhabricatorMetaMTAController',
'PhabricatorMetaMTAReceivedListController' => 'PhabricatorMetaMTAController',
'PhabricatorMetaMTAReceivedMail' => 'PhabricatorMetaMTADAO',
'PhabricatorMetaMTASendController' => 'PhabricatorMetaMTAController',
'PhabricatorMetaMTASendGridReceiveController' => 'PhabricatorMetaMTAController',
'PhabricatorMetaMTAViewController' => 'PhabricatorMetaMTAController',
'PhabricatorMySQLFileStorageEngine' => 'PhabricatorFileStorageEngine',
'PhabricatorOAuthDefaultRegistrationController' => 'PhabricatorOAuthRegistrationController',
'PhabricatorOAuthDiagnosticsController' => 'PhabricatorAuthController',
'PhabricatorOAuthFailureView' => 'AphrontView',
'PhabricatorOAuthLoginController' => 'PhabricatorAuthController',
'PhabricatorOAuthProviderFacebook' => 'PhabricatorOAuthProvider',
'PhabricatorOAuthProviderGithub' => 'PhabricatorOAuthProvider',
'PhabricatorOAuthRegistrationController' => 'PhabricatorAuthController',
'PhabricatorOAuthUnlinkController' => 'PhabricatorAuthController',
'PhabricatorObjectGraph' => 'AbstractDirectedGraph',
'PhabricatorObjectHandleStatus' => 'PhabricatorObjectHandleConstants',
'PhabricatorOwnersController' => 'PhabricatorController',
'PhabricatorOwnersDAO' => 'PhabricatorLiskDAO',
'PhabricatorOwnersDeleteController' => 'PhabricatorOwnersController',
'PhabricatorOwnersDetailController' => 'PhabricatorOwnersController',
'PhabricatorOwnersEditController' => 'PhabricatorOwnersController',
'PhabricatorOwnersListController' => 'PhabricatorOwnersController',
'PhabricatorOwnersOwner' => 'PhabricatorOwnersDAO',
'PhabricatorOwnersPackage' => 'PhabricatorOwnersDAO',
'PhabricatorOwnersPath' => 'PhabricatorOwnersDAO',
'PhabricatorPHID' => 'PhabricatorPHIDDAO',
'PhabricatorPHIDController' => 'PhabricatorController',
'PhabricatorPHIDDAO' => 'PhabricatorLiskDAO',
'PhabricatorPHIDListController' => 'PhabricatorPHIDController',
'PhabricatorPHIDLookupController' => 'PhabricatorPHIDController',
'PhabricatorPaste' => 'PhabricatorPasteDAO',
'PhabricatorPasteController' => 'PhabricatorController',
'PhabricatorPasteCreateController' => 'PhabricatorPasteController',
'PhabricatorPasteDAO' => 'PhabricatorLiskDAO',
'PhabricatorPasteListController' => 'PhabricatorPasteController',
'PhabricatorPasteViewController' => 'PhabricatorPasteController',
'PhabricatorPeopleController' => 'PhabricatorController',
'PhabricatorPeopleEditController' => 'PhabricatorPeopleController',
'PhabricatorPeopleListController' => 'PhabricatorPeopleController',
'PhabricatorPeopleLogsController' => 'PhabricatorPeopleController',
'PhabricatorPeopleProfileController' => 'PhabricatorPeopleController',
'PhabricatorProfileView' => 'AphrontView',
'PhabricatorProject' => 'PhabricatorProjectDAO',
'PhabricatorProjectAffiliation' => 'PhabricatorProjectDAO',
'PhabricatorProjectAffiliationEditController' => 'PhabricatorProjectController',
'PhabricatorProjectController' => 'PhabricatorController',
'PhabricatorProjectCreateController' => 'PhabricatorProjectController',
'PhabricatorProjectDAO' => 'PhabricatorLiskDAO',
'PhabricatorProjectListController' => 'PhabricatorProjectController',
'PhabricatorProjectProfile' => 'PhabricatorProjectDAO',
'PhabricatorProjectProfileController' => 'PhabricatorProjectController',
'PhabricatorProjectProfileEditController' => 'PhabricatorProjectController',
'PhabricatorProjectSubproject' => 'PhabricatorProjectDAO',
'PhabricatorRedirectController' => 'PhabricatorController',
'PhabricatorRefreshCSRFController' => 'PhabricatorAuthController',
'PhabricatorRemarkupRuleDifferential' => 'PhabricatorRemarkupRuleObjectName',
'PhabricatorRemarkupRuleDifferentialHandle' => 'PhabricatorRemarkupRuleObjectHandle',
'PhabricatorRemarkupRuleDiffusion' => 'PhutilRemarkupRule',
'PhabricatorRemarkupRuleEmbedFile' => 'PhutilRemarkupRule',
'PhabricatorRemarkupRuleImageMacro' => 'PhutilRemarkupRule',
'PhabricatorRemarkupRuleManiphest' => 'PhabricatorRemarkupRuleObjectName',
'PhabricatorRemarkupRuleManiphestHandle' => 'PhabricatorRemarkupRuleObjectHandle',
'PhabricatorRemarkupRuleMention' => 'PhutilRemarkupRule',
'PhabricatorRemarkupRuleObjectHandle' => 'PhutilRemarkupRule',
'PhabricatorRemarkupRuleObjectName' => 'PhutilRemarkupRule',
'PhabricatorRemarkupRulePaste' => 'PhabricatorRemarkupRuleObjectName',
'PhabricatorRemarkupRulePhriction' => 'PhutilRemarkupRule',
'PhabricatorRemarkupRuleProxyImage' => 'PhutilRemarkupRule',
'PhabricatorRemarkupRuleYoutube' => 'PhutilRemarkupRule',
'PhabricatorRepository' => 'PhabricatorRepositoryDAO',
'PhabricatorRepositoryArcanistProject' => 'PhabricatorRepositoryDAO',
'PhabricatorRepositoryArcanistProjectEditController' => 'PhabricatorRepositoryController',
'PhabricatorRepositoryCommit' => 'PhabricatorRepositoryDAO',
'PhabricatorRepositoryCommitChangeParserWorker' => 'PhabricatorRepositoryCommitParserWorker',
'PhabricatorRepositoryCommitData' => 'PhabricatorRepositoryDAO',
'PhabricatorRepositoryCommitDiscoveryDaemon' => 'PhabricatorRepositoryDaemon',
'PhabricatorRepositoryCommitHeraldWorker' => 'PhabricatorRepositoryCommitParserWorker',
'PhabricatorRepositoryCommitMessageParserWorker' => 'PhabricatorRepositoryCommitParserWorker',
'PhabricatorRepositoryCommitParserWorker' => 'PhabricatorWorker',
'PhabricatorRepositoryCommitTaskDaemon' => 'PhabricatorRepositoryDaemon',
'PhabricatorRepositoryController' => 'PhabricatorController',
'PhabricatorRepositoryCreateController' => 'PhabricatorRepositoryController',
'PhabricatorRepositoryDAO' => 'PhabricatorLiskDAO',
'PhabricatorRepositoryDaemon' => 'PhabricatorDaemon',
'PhabricatorRepositoryDefaultCommitMessageDetailParser' => 'PhabricatorRepositoryCommitMessageDetailParser',
'PhabricatorRepositoryDeleteController' => 'PhabricatorRepositoryController',
'PhabricatorRepositoryEditController' => 'PhabricatorRepositoryController',
'PhabricatorRepositoryGitCommitChangeParserWorker' => 'PhabricatorRepositoryCommitChangeParserWorker',
'PhabricatorRepositoryGitCommitDiscoveryDaemon' => 'PhabricatorRepositoryCommitDiscoveryDaemon',
'PhabricatorRepositoryGitCommitMessageParserWorker' => 'PhabricatorRepositoryCommitMessageParserWorker',
'PhabricatorRepositoryGitFetchDaemon' => 'PhabricatorRepositoryDaemon',
'PhabricatorRepositoryGitHubNotification' => 'PhabricatorRepositoryDAO',
'PhabricatorRepositoryGitHubPostReceiveController' => 'PhabricatorRepositoryController',
'PhabricatorRepositoryListController' => 'PhabricatorRepositoryController',
'PhabricatorRepositoryShortcut' => 'PhabricatorRepositoryDAO',
'PhabricatorRepositorySvnCommitChangeParserWorker' => 'PhabricatorRepositoryCommitChangeParserWorker',
'PhabricatorRepositorySvnCommitDiscoveryDaemon' => 'PhabricatorRepositoryCommitDiscoveryDaemon',
'PhabricatorRepositorySvnCommitMessageParserWorker' => 'PhabricatorRepositoryCommitMessageParserWorker',
'PhabricatorS3FileStorageEngine' => 'PhabricatorFileStorageEngine',
'PhabricatorSearchAttachController' => 'PhabricatorSearchController',
'PhabricatorSearchBaseController' => 'PhabricatorController',
'PhabricatorSearchCommitIndexer' => 'PhabricatorSearchDocumentIndexer',
'PhabricatorSearchController' => 'PhabricatorSearchBaseController',
'PhabricatorSearchDAO' => 'PhabricatorLiskDAO',
'PhabricatorSearchDifferentialIndexer' => 'PhabricatorSearchDocumentIndexer',
'PhabricatorSearchDocument' => 'PhabricatorSearchDAO',
'PhabricatorSearchDocumentField' => 'PhabricatorSearchDAO',
'PhabricatorSearchDocumentRelationship' => 'PhabricatorSearchDAO',
'PhabricatorSearchEngineMySQL' => 'PhabricatorSearchEngine',
'PhabricatorSearchIndexController' => 'PhabricatorSearchBaseController',
'PhabricatorSearchManiphestIndexer' => 'PhabricatorSearchDocumentIndexer',
'PhabricatorSearchPhrictionIndexer' => 'PhabricatorSearchDocumentIndexer',
'PhabricatorSearchQuery' => 'PhabricatorSearchDAO',
'PhabricatorSearchResultView' => 'AphrontView',
'PhabricatorSearchSelectController' => 'PhabricatorSearchController',
'PhabricatorSearchUserIndexer' => 'PhabricatorSearchDocumentIndexer',
'PhabricatorSlowvoteChoice' => 'PhabricatorSlowvoteDAO',
'PhabricatorSlowvoteComment' => 'PhabricatorSlowvoteDAO',
'PhabricatorSlowvoteController' => 'PhabricatorController',
'PhabricatorSlowvoteCreateController' => 'PhabricatorSlowvoteController',
'PhabricatorSlowvoteDAO' => 'PhabricatorLiskDAO',
'PhabricatorSlowvoteListController' => 'PhabricatorSlowvoteController',
'PhabricatorSlowvoteOption' => 'PhabricatorSlowvoteDAO',
'PhabricatorSlowvotePoll' => 'PhabricatorSlowvoteDAO',
'PhabricatorSlowvotePollController' => 'PhabricatorSlowvoteController',
'PhabricatorStandardPageView' => 'AphrontPageView',
'PhabricatorStatusController' => 'PhabricatorController',
'PhabricatorTaskmasterDaemon' => 'PhabricatorDaemon',
'PhabricatorTestCase' => 'ArcanistPhutilTestCase',
'PhabricatorTimelineCursor' => 'PhabricatorTimelineDAO',
'PhabricatorTimelineDAO' => 'PhabricatorLiskDAO',
'PhabricatorTimelineEvent' => 'PhabricatorTimelineDAO',
'PhabricatorTimelineEventData' => 'PhabricatorTimelineDAO',
'PhabricatorTimer' => 'PhabricatorCountdownDAO',
'PhabricatorTransformedFile' => 'PhabricatorFileDAO',
'PhabricatorTrivialTestCase' => 'PhabricatorTestCase',
'PhabricatorTypeaheadCommonDatasourceController' => 'PhabricatorTypeaheadDatasourceController',
'PhabricatorTypeaheadDatasourceController' => 'PhabricatorController',
'PhabricatorUIExampleController' => 'PhabricatorController',
'PhabricatorUIExampleRenderController' => 'PhabricatorUIExampleController',
'PhabricatorUIListFilterExample' => 'PhabricatorUIExample',
'PhabricatorUIPagerExample' => 'PhabricatorUIExample',
'PhabricatorUser' => 'PhabricatorUserDAO',
'PhabricatorUserAccountSettingsPanelController' => 'PhabricatorUserSettingsPanelController',
'PhabricatorUserConduitSettingsPanelController' => 'PhabricatorUserSettingsPanelController',
'PhabricatorUserDAO' => 'PhabricatorLiskDAO',
'PhabricatorUserEmailSettingsPanelController' => 'PhabricatorUserSettingsPanelController',
'PhabricatorUserLog' => 'PhabricatorUserDAO',
'PhabricatorUserOAuthInfo' => 'PhabricatorUserDAO',
'PhabricatorUserOAuthSettingsPanelController' => 'PhabricatorUserSettingsPanelController',
'PhabricatorUserPreferenceSettingsPanelController' => 'PhabricatorUserSettingsPanelController',
'PhabricatorUserPreferences' => 'PhabricatorUserDAO',
'PhabricatorUserProfile' => 'PhabricatorUserDAO',
'PhabricatorUserProfileSettingsPanelController' => 'PhabricatorUserSettingsPanelController',
'PhabricatorUserSSHKey' => 'PhabricatorUserDAO',
'PhabricatorUserSSHKeysSettingsPanelController' => 'PhabricatorUserSettingsPanelController',
'PhabricatorUserSettingsController' => 'PhabricatorPeopleController',
'PhabricatorUserSettingsPanelController' => 'PhabricatorPeopleController',
'PhabricatorWorkerDAO' => 'PhabricatorLiskDAO',
'PhabricatorWorkerTask' => 'PhabricatorWorkerDAO',
'PhabricatorWorkerTaskData' => 'PhabricatorWorkerDAO',
'PhabricatorWorkerTaskDetailController' => 'PhabricatorDaemonController',
'PhabricatorXHPASTViewController' => 'PhabricatorController',
'PhabricatorXHPASTViewDAO' => 'PhabricatorLiskDAO',
'PhabricatorXHPASTViewFrameController' => 'PhabricatorXHPASTViewController',
'PhabricatorXHPASTViewFramesetController' => 'PhabricatorXHPASTViewController',
'PhabricatorXHPASTViewInputController' => 'PhabricatorXHPASTViewPanelController',
'PhabricatorXHPASTViewPanelController' => 'PhabricatorXHPASTViewController',
'PhabricatorXHPASTViewParseTree' => 'PhabricatorXHPASTViewDAO',
'PhabricatorXHPASTViewRunController' => 'PhabricatorXHPASTViewController',
'PhabricatorXHPASTViewStreamController' => 'PhabricatorXHPASTViewPanelController',
'PhabricatorXHPASTViewTreeController' => 'PhabricatorXHPASTViewPanelController',
'PhabricatorXHProfController' => 'PhabricatorController',
'PhabricatorXHProfProfileController' => 'PhabricatorXHProfController',
'PhabricatorXHProfProfileSymbolView' => 'AphrontView',
'PhabricatorXHProfProfileTopLevelView' => 'AphrontView',
'PhrictionActionConstants' => 'PhrictionConstants',
'PhrictionContent' => 'PhrictionDAO',
'PhrictionController' => 'PhabricatorController',
'PhrictionDAO' => 'PhabricatorLiskDAO',
'PhrictionDiffController' => 'PhrictionController',
'PhrictionDocument' => 'PhrictionDAO',
'PhrictionDocumentController' => 'PhrictionController',
'PhrictionDocumentPreviewController' => 'PhrictionController',
'PhrictionDocumentTestCase' => 'PhabricatorTestCase',
'PhrictionEditController' => 'PhrictionController',
'PhrictionHistoryController' => 'PhrictionController',
'PhrictionListController' => 'PhrictionController',
),
'requires_interface' =>
array(
),
));
diff --git a/src/applications/conduit/method/differential/getcommitmessage/ConduitAPI_differential_getcommitmessage_Method.php b/src/applications/conduit/method/differential/getcommitmessage/ConduitAPI_differential_getcommitmessage_Method.php
index c24d901635..f2685128cb 100644
--- a/src/applications/conduit/method/differential/getcommitmessage/ConduitAPI_differential_getcommitmessage_Method.php
+++ b/src/applications/conduit/method/differential/getcommitmessage/ConduitAPI_differential_getcommitmessage_Method.php
@@ -1,109 +1,139 @@
'required revision_id',
'fields' => 'optional dict',
'edit' => 'optional bool',
);
}
public function defineReturnType() {
return 'nonempty string';
}
public function defineErrorTypes() {
return array(
'ERR_NOT_FOUND' => 'Revision was not found.',
);
}
protected function execute(ConduitAPIRequest $request) {
$id = $request->getValue('revision_id');
$revision = id(new DifferentialRevision())->load($id);
if (!$revision) {
throw new ConduitException('ERR_NOT_FOUND');
}
- $edit = $request->getValue('edit');
- $mode = $edit
- ? DifferentialCommitMessageData::MODE_EDIT
- : DifferentialCommitMessageData::MODE_AMEND;
+ $revision->loadRelationships();
- $message_data = new DifferentialCommitMessageData($revision, $mode);
- $message_data->prepare();
+ $is_edit = $request->getValue('edit');
- if ($mode == DifferentialCommitMessageData::MODE_EDIT) {
+ $aux_fields = DifferentialFieldSelector::newSelector()
+ ->getFieldSpecifications();
+
+ foreach ($aux_fields as $key => $aux_field) {
+ $aux_field->setRevision($revision);
+ if (!$aux_field->shouldAppearOnCommitMessage()) {
+ unset($aux_fields[$key]);
+ }
+ }
+
+ $aux_fields = DifferentialAuxiliaryField::loadFromStorage(
+ $revision,
+ $aux_fields);
+ $aux_fields = mpull($aux_fields, null, 'getCommitMessageKey');
+
+ if ($is_edit) {
$fields = $request->getValue('fields');
- if ($fields) {
-
- static $simple_fields = array(
- 'title' => 'Title',
- 'summary' => 'Summary',
- 'testPlan' => 'Test Plan',
- 'blameRevision' => 'Blame Revision',
- 'revertPlan' => 'Revert Plan',
- 'tasks' => 'Tasks',
- );
-
- foreach ($fields as $field => $value) {
- if (isset($simple_fields[$field])) {
- $message_data->setField($simple_fields[$field], $value);
- } else {
- $overwrite = true;
- static $overwrite_map = array(
- 'reviewerPHIDs' => 'Reviewers',
- 'ccPHIDs' => 'CC',
- 'taskPHIDs' => 'Tasks',
- );
- switch ($field) {
- case 'reviewerPHIDs':
- case 'ccPHIDs':
- $handles = id(new PhabricatorObjectHandleData($value))
- ->loadHandles($handles);
- $value = implode(', ', mpull($handles, 'getName'));
- break;
- default:
- $overwrite = false;
- break;
- }
- if ($overwrite) {
- $message_data->setField($overwrite_map[$field], $value);
- }
+ foreach ($fields as $field => $value) {
+
+ $aux_field = idx($aux_fields, $field);
+ if (!$aux_field) {
+ if ($field == 'tasks') {
+ // TODO: Remove, backcompat for Facebook.
+ continue;
}
+ throw new Exception(
+ "Commit message includes field '{$field}' which does not ".
+ "correspond to any configured field.");
+ }
+
+ if ($aux_field->shouldOverwriteWhenCommitMessageIsEdited()) {
+ $aux_field->setValueFromParsedCommitMessage($value);
}
}
}
- $commit_message = $message_data->getCommitMessage();
+
+ $aux_phids = array();
+ foreach ($aux_fields as $field_key => $field) {
+ $aux_phids[$field_key] = $field->getRequiredHandlePHIDsForCommitMessage();
+ }
+ $phids = array_unique(array_mergev($aux_phids));
+ $handles = id(new PhabricatorObjectHandleData($phids))->loadHandles();
+ foreach ($aux_fields as $field_key => $field) {
+ $field->setHandles(array_select_keys($handles, $aux_phids[$field_key]));
+ }
+
+
+ $commit_message = array();
+ foreach ($aux_fields as $field_key => $field) {
+ $value = $field->renderValueForCommitMessage($is_edit);
+ $label = $field->renderLabelForCommitMessage();
+ if ($value === null || !strlen($value)) {
+ if ($field_key === 'title') {
+ $commit_message[] = '<>';
+ } else {
+ if ($field->shouldAppearOnCommitMessageTemplate() && $is_edit) {
+ $commit_message[] = $label.': ';
+ }
+ }
+ } else {
+ if ($field_key === 'title') {
+ $commit_message[] = $value;
+ } else {
+ $value = str_replace(
+ array("\r\n", "\r"),
+ array("\n", "\n"),
+ $value);
+ if (strpos($value, "\n") !== false) {
+ $commit_message[] = "{$label}:\n{$value}";
+ } else {
+ $commit_message[] = "{$label}: {$value}";
+ }
+ }
+ }
+ }
+ $commit_message = implode("\n\n", $commit_message);
return wordwrap($commit_message, 80);
}
}
diff --git a/src/applications/conduit/method/differential/getcommitmessage/__init__.php b/src/applications/conduit/method/differential/getcommitmessage/__init__.php
index 2de8f9d9d0..85c8391593 100644
--- a/src/applications/conduit/method/differential/getcommitmessage/__init__.php
+++ b/src/applications/conduit/method/differential/getcommitmessage/__init__.php
@@ -1,18 +1,19 @@
revision = $revision;
- $this->mode = $mode;
- $comments = id(new DifferentialComment())->loadAllWhere(
- 'revisionID = %d',
- $revision->getID());
- $this->comments = $comments;
- }
-
- protected function getCommenters() {
- $revision = $this->revision;
-
- $map = array();
- foreach ($this->comments as $comment) {
- $map[$comment->getAuthorPHID()] = true;
- }
-
- unset($map[$revision->getAuthorPHID()]);
- if ($this->getReviewer()) {
- unset($map[$this->getReviewer()]);
- }
-
- return array_keys($map);
- }
-
- private function getReviewer() {
- $reviewer = null;
- foreach ($this->comments as $comment) {
- if ($comment->getAction() == DifferentialAction::ACTION_ACCEPT) {
- $reviewer = $comment->getAuthorPHID();
- } else if ($comment->getAction() == DifferentialAction::ACTION_REJECT) {
- $reviewer = null;
- }
- }
- return $reviewer;
- }
-
- public function prepare() {
- $revision = $this->revision;
-
- if ($revision->getSummary()) {
- $this->setField('Summary', $revision->getSummary());
- }
-
- $this->setField('Test Plan', $revision->getTestPlan());
-
- $reviewer = null;
- $commenters = array();
- $revision->loadRelationships();
-
- if ($this->mode == self::MODE_AMEND) {
- $reviewer = $this->getReviewer();
- $commenters = $this->getCommenters();
- }
-
- $reviewers = $revision->getReviewers();
- $ccphids = $revision->getCCPHIDs();
-
- $phids = array_merge($ccphids, $commenters, $reviewers);
- if ($reviewer) {
- $phids[] = $reviewer;
- }
-
- $handles = id(new PhabricatorObjectHandleData($phids))
- ->loadHandles();
-
- if ($this->mode == self::MODE_AMEND) {
- if ($reviewer) {
- $this->setField('Reviewed By', $handles[$reviewer]->getName());
- }
- }
-
- if ($reviewers) {
- $reviewer_names = array();
- foreach ($reviewers as $uid) {
- $reviewer_names[] = $handles[$uid]->getName();
- }
- $reviewer_names = implode(', ', $reviewer_names);
- $this->setField('Reviewers', $reviewer_names);
- }
-
- $user_handles = array_select_keys($handles, $commenters);
- if ($user_handles) {
- $commenters = implode(', ', mpull($user_handles, 'getName'));
- $this->setField('Commenters', $commenters);
- }
-
- $cc_handles = array_select_keys($handles, $ccphids);
- if ($cc_handles) {
- $cc = implode(', ', mpull($cc_handles, 'getName'));
- $this->setField('CC', $cc);
- }
-
- if ($revision->getRevertPlan()) {
- $this->setField('Revert Plan', $revision->getRevertPlan());
- }
-
- if ($revision->getBlameRevision()) {
- $this->setField('Blame Revision', $revision->getBlameRevision());
- }
-
- if ($this->mode == self::MODE_EDIT) {
- // In edit mode, include blank fields.
- $blank_fields = array('Summary', 'Reviewers', 'CC', 'Revert Plan',
- 'Blame Revision');
- foreach ($blank_fields as $blank_field) {
- if (!$this->getField($blank_field)) {
- $this->setField($blank_field, '');
- }
- }
- }
-
- $this->setField('Title', $revision->getTitle());
- $this->setField('Differential Revision', $revision->getID());
-
- // append custom commit message fields
- $modify_class = PhabricatorEnv::getEnvConfig(
- 'differential.modify-commit-message-class');
-
- if ($modify_class) {
- $modifier = newv($modify_class, array($revision));
- $this->fields = $modifier->modifyFields($this->fields);
- }
- }
-
- public function setField($name, $value) {
- $field = $this->getField($name);
- if ($field) {
- $field->setValue($value);
- } else {
- $this->fields[] = new DifferentialCommitMessageField($name, $value);
- }
- return $this;
- }
-
- private function getField($name) {
- foreach ($this->fields as $field) {
- if ($field->getName() == $name) {
- return $field;
- }
- }
- return null;
- }
-
- public function getCommitMessage() {
- $fields = $this->fields;
-
- $message = array();
-
- $title = $this->getField('Title');
- $message[] = $title->getValue() . "\n";
-
- foreach ($fields as $field) {
- if ($field->getName() != 'Title') {
- $message[] = $field->render();
- }
- }
-
- $message = implode("\n", $message);
- $message = str_replace(
- array("\r\n", "\r"),
- array("\n", "\n"),
- $message);
- $message = $message."\n";
-
- return $message;
- }
-}
diff --git a/src/applications/differential/data/commitmessage/DifferentialCommitMessageField.php b/src/applications/differential/data/commitmessage/DifferentialCommitMessageField.php
deleted file mode 100644
index b70d5ec03a..0000000000
--- a/src/applications/differential/data/commitmessage/DifferentialCommitMessageField.php
+++ /dev/null
@@ -1,49 +0,0 @@
-name = $name;
- $this->value = $value;
- }
-
- public function getName() {
- return $this->name;
- }
-
- public function getValue() {
- return $this->value;
- }
-
- public function setValue($value) {
- $this->value = trim($value);
- }
-
- public function render() {
- $str = "{$this->name}:\n{$this->value}\n";
- if (!strpos($this->value, "\n")) {
- $str = "{$this->name}: {$this->value}";
- }
- return $str;
- }
-}
diff --git a/src/applications/differential/data/commitmessage/DifferentialCommitMessageModifier.php b/src/applications/differential/data/commitmessage/DifferentialCommitMessageModifier.php
deleted file mode 100644
index 58a65cd368..0000000000
--- a/src/applications/differential/data/commitmessage/DifferentialCommitMessageModifier.php
+++ /dev/null
@@ -1,39 +0,0 @@
-revision = $revision;
- }
-
- /**
- * Implementation of this function should remove, modify, or append
- * fields to the $fields representing the fields for the given
- * $revision. It should return the modified dict. These fields are
- * included in the commit message generated by 'arc amend'.
- *
- * @param array The array of fields to modify
- * @return array The updated array of fields
- */
- abstract public function modifyFields(array $fields);
-}
diff --git a/src/applications/differential/data/commitmessage/__init__.php b/src/applications/differential/data/commitmessage/__init__.php
deleted file mode 100644
index c6ce1f81a8..0000000000
--- a/src/applications/differential/data/commitmessage/__init__.php
+++ /dev/null
@@ -1,19 +0,0 @@
-revision = $revision;
$this->actorPHID = $actor_phid;
}
public static function newRevisionFromConduitWithDiff(
array $fields,
DifferentialDiff $diff,
$user_phid) {
$revision = new DifferentialRevision();
$revision->setPHID($revision->generatePHID());
$revision->setAuthorPHID($user_phid);
$revision->setStatus(DifferentialRevisionStatus::NEEDS_REVIEW);
$editor = new DifferentialRevisionEditor($revision, $user_phid);
$editor->copyFieldsFromConduit($fields);
$editor->addDiff($diff, null);
$editor->save();
// Tasks can only be updated after revision has been saved to the
// database. Currently tasks are updated only when a revision is created.
// UI must be used to modify tasks after creating one.
$editor->updateTasks();
return $revision;
}
public function copyFieldsFromConduit(array $fields) {
$revision = $this->revision;
+ $revision->loadRelationships();
$aux_fields = DifferentialFieldSelector::newSelector()
->getFieldSpecifications();
foreach ($aux_fields as $key => $aux_field) {
$aux_field->setRevision($revision);
if (!$aux_field->shouldAppearOnCommitMessage()) {
unset($aux_fields[$key]);
}
}
$aux_fields = mpull($aux_fields, null, 'getCommitMessageKey');
foreach ($fields as $field => $value) {
if (empty($aux_fields[$field])) {
if ($field == 'tasks') {
// TODO: Deprecate once this can be fully supported with custom
// fields. This is just to prevent a backcompat break for Facebook.
$this->setTasks($value);
continue;
}
throw new Exception(
"Parsed commit message contains unrecognized field '{$field}'.");
}
$aux_fields[$field]->setValueFromParsedCommitMessage($value);
}
$aux_fields = array_values($aux_fields);
$this->setAuxiliaryFields($aux_fields);
}
public function setAuxiliaryFields(array $auxiliary_fields) {
$this->auxiliaryFields = $auxiliary_fields;
return $this;
}
public function getRevision() {
return $this->revision;
}
public function setReviewers(array $reviewers) {
$this->reviewers = $reviewers;
return $this;
}
public function setCCPHIDs(array $cc) {
$this->cc = $cc;
return $this;
}
public function setTasks(array $tasks) {
$this->tasks = $tasks;
}
public function addDiff(DifferentialDiff $diff, $comments) {
if ($diff->getRevisionID() &&
$diff->getRevisionID() != $this->getRevision()->getID()) {
$diff_id = (int)$diff->getID();
$targ_id = (int)$this->getRevision()->getID();
$real_id = (int)$diff->getRevisionID();
throw new Exception(
"Can not attach diff #{$diff_id} to Revision D{$targ_id}, it is ".
"already attached to D{$real_id}.");
}
$this->diff = $diff;
$this->comments = $comments;
return $this;
}
protected function getDiff() {
return $this->diff;
}
protected function getComments() {
return $this->comments;
}
protected function getActorPHID() {
return $this->actorPHID;
}
public function isNewRevision() {
return !$this->getRevision()->getID();
}
/**
* A silent update does not trigger Herald rules or send emails. This is used
* for auto-amends at commit time.
*/
public function setSilentUpdate($silent) {
$this->silentUpdate = $silent;
return $this;
}
public function save() {
$revision = $this->getRevision();
// TODO
// $revision->openTransaction();
$is_new = $this->isNewRevision();
if ($is_new) {
// These fields aren't nullable; set them to sensible defaults if they
// haven't been configured. We're just doing this so we can generate an
// ID for the revision if we don't have one already.
$revision->setLineCount(0);
if ($revision->getStatus() === null) {
$revision->setStatus(DifferentialRevisionStatus::NEEDS_REVIEW);
}
if ($revision->getTitle() === null) {
$revision->setTitle('Untitled Revision');
}
if ($revision->getAuthorPHID() === null) {
$revision->setAuthorPHID($this->getActorPHID());
}
if ($revision->getRevertPlan() === null) {
$revision->setRevertPlan('');
}
if ($revision->getBlameRevision() === null) {
$revision->setBlameRevision('');
}
if ($revision->getSummary() === null) {
$revision->setSummary('');
}
if ($revision->getTestPlan() === null) {
$revision->setTestPlan('');
}
$revision->save();
}
$revision->loadRelationships();
$this->willWriteRevision();
if ($this->reviewers === null) {
$this->reviewers = $revision->getReviewers();
}
if ($this->cc === null) {
$this->cc = $revision->getCCPHIDs();
}
// We're going to build up three dictionaries: $add, $rem, and $stable. The
// $add dictionary has added reviewers/CCs. The $rem dictionary has
// reviewers/CCs who have been removed, and the $stable array is
// reviewers/CCs who haven't changed. We're going to send new reviewers/CCs
// a different ("welcome") email than we send stable reviewers/CCs.
$old = array(
'rev' => array_fill_keys($revision->getReviewers(), true),
'ccs' => array_fill_keys($revision->getCCPHIDs(), true),
);
$diff = $this->getDiff();
$xscript_header = null;
$xscript_uri = null;
$new = array(
'rev' => array_fill_keys($this->reviewers, true),
'ccs' => array_fill_keys($this->cc, true),
);
$rem_ccs = array();
if ($diff) {
$diff->setRevisionID($revision->getID());
$revision->setLineCount($diff->getLineCount());
$adapter = new HeraldDifferentialRevisionAdapter(
$revision,
$diff);
$adapter->setExplicitCCs($new['ccs']);
$adapter->setExplicitReviewers($new['rev']);
$adapter->setForbiddenCCs($revision->getUnsubscribedPHIDs());
$xscript = HeraldEngine::loadAndApplyRules($adapter);
$xscript_uri = PhabricatorEnv::getProductionURI(
'/herald/transcript/'.$xscript->getID().'/');
$xscript_phid = $xscript->getPHID();
$xscript_header = $xscript->getXHeraldRulesHeader();
$xscript_header = HeraldTranscript::saveXHeraldRulesHeader(
$revision->getPHID(),
$xscript_header);
$sub = array(
'rev' => array(),
'ccs' => $adapter->getCCsAddedByHerald(),
);
$rem_ccs = $adapter->getCCsRemovedByHerald();
} else {
$sub = array(
'rev' => array(),
'ccs' => array(),
);
}
// Remove any CCs which are prevented by Herald rules.
$sub['ccs'] = array_diff_key($sub['ccs'], $rem_ccs);
$new['ccs'] = array_diff_key($new['ccs'], $rem_ccs);
$add = array();
$rem = array();
$stable = array();
foreach (array('rev', 'ccs') as $key) {
$add[$key] = array();
if ($new[$key] !== null) {
$add[$key] += array_diff_key($new[$key], $old[$key]);
}
$add[$key] += array_diff_key($sub[$key], $old[$key]);
$combined = $sub[$key];
if ($new[$key] !== null) {
$combined += $new[$key];
}
$rem[$key] = array_diff_key($old[$key], $combined);
$stable[$key] = array_diff_key($old[$key], $add[$key] + $rem[$key]);
}
self::alterReviewers(
$revision,
$this->reviewers,
array_keys($rem['rev']),
array_keys($add['rev']),
$this->actorPHID);
/*
// TODO: When Herald is brought over, run through this stuff to figure
// out which adds are Herald's fault.
// TODO: Still need to do this.
if ($add['ccs'] || $rem['ccs']) {
foreach (array_keys($add['ccs']) as $id) {
if (empty($new['ccs'][$id])) {
$reason_phid = 'TODO';//$xscript_phid;
} else {
$reason_phid = $this->getActorPHID();
}
}
foreach (array_keys($rem['ccs']) as $id) {
if (empty($new['ccs'][$id])) {
$reason_phid = $this->getActorPHID();
} else {
$reason_phid = 'TODO';//$xscript_phid;
}
}
}
*/
self::alterCCs(
$revision,
$this->cc,
array_keys($rem['ccs']),
array_keys($add['ccs']),
$this->actorPHID);
$this->updateAuxiliaryFields();
// Add the author and users included from Herald rules to the relevant set
// of users so they get a copy of the email.
if (!$this->silentUpdate) {
if ($is_new) {
$add['rev'][$this->getActorPHID()] = true;
if ($diff) {
$add['rev'] += $adapter->getEmailPHIDsAddedByHerald();
}
} else {
$stable['rev'][$this->getActorPHID()] = true;
if ($diff) {
$stable['rev'] += $adapter->getEmailPHIDsAddedByHerald();
}
}
}
$mail = array();
$phids = array($this->getActorPHID());
$handles = id(new PhabricatorObjectHandleData($phids))
->loadHandles();
$actor_handle = $handles[$this->getActorPHID()];
$changesets = null;
$comment = null;
if ($diff) {
$changesets = $diff->loadChangesets();
// TODO: This should probably be in DifferentialFeedbackEditor?
if (!$is_new) {
$comment = $this->createComment();
}
if ($comment) {
$mail[] = id(new DifferentialNewDiffMail(
$revision,
$actor_handle,
$changesets))
->setIsFirstMailAboutRevision($is_new)
->setIsFirstMailToRecipients($is_new)
->setComments($this->getComments())
->setToPHIDs(array_keys($stable['rev']))
->setCCPHIDs(array_keys($stable['ccs']));
}
// Save the changes we made above.
$diff->setDescription(substr($this->getComments(), 0, 80));
$diff->save();
// An updated diff should require review, as long as it's not committed
// or accepted. The "accepted" status is "sticky" to encourage courtesy
// re-diffs after someone accepts with minor changes/suggestions.
$status = $revision->getStatus();
if ($status != DifferentialRevisionStatus::COMMITTED &&
$status != DifferentialRevisionStatus::ACCEPTED) {
$revision->setStatus(DifferentialRevisionStatus::NEEDS_REVIEW);
}
} else {
$diff = $revision->loadActiveDiff();
if ($diff) {
$changesets = $diff->loadChangesets();
} else {
$changesets = array();
}
}
$revision->save();
$this->didWriteRevision();
$event_data = array(
'revision_id' => $revision->getID(),
'revision_phid' => $revision->getPHID(),
'revision_name' => $revision->getTitle(),
'revision_author_phid' => $revision->getAuthorPHID(),
'action' => $is_new
? DifferentialAction::ACTION_CREATE
: DifferentialAction::ACTION_UPDATE,
'feedback_content' => $is_new
? phutil_utf8_shorten($revision->getSummary(), 140)
: $this->getComments(),
'actor_phid' => $revision->getAuthorPHID(),
);
id(new PhabricatorTimelineEvent('difx', $event_data))
->recordEvent();
id(new PhabricatorFeedStoryPublisher())
->setStoryType(PhabricatorFeedStoryTypeConstants::STORY_DIFFERENTIAL)
->setStoryData($event_data)
->setStoryTime(time())
->setStoryAuthorPHID($revision->getAuthorPHID())
->setRelatedPHIDs(
array(
$revision->getPHID(),
$revision->getAuthorPHID(),
))
->publish();
// TODO
// $revision->saveTransaction();
// TODO: Move this into a worker task thing.
PhabricatorSearchDifferentialIndexer::indexRevision($revision);
if ($this->silentUpdate) {
return;
}
$revision->loadRelationships();
if ($add['rev']) {
$message = id(new DifferentialNewDiffMail(
$revision,
$actor_handle,
$changesets))
->setIsFirstMailAboutRevision($is_new)
->setIsFirstMailToRecipients(true)
->setToPHIDs(array_keys($add['rev']));
if ($is_new) {
// The first time we send an email about a revision, put the CCs in
// the "CC:" field of the same "Review Requested" email that reviewers
// get, so you don't get two initial emails if you're on a list that
// is CC'd.
$message->setCCPHIDs(array_keys($add['ccs']));
}
$mail[] = $message;
}
// If you were added as a reviewer and a CC, just give you the reviewer
// email. We could go to greater lengths to prevent this, but there's
// bunch of stuff with list subscriptions anyway. You can still get two
// emails, but only if a revision is updated and you are added as a reviewer
// at the same time a list you are on is added as a CC, which is rare and
// reasonable.
$add['ccs'] = array_diff_key($add['ccs'], $add['rev']);
if (!$is_new && $add['ccs']) {
$mail[] = id(new DifferentialCCWelcomeMail(
$revision,
$actor_handle,
$changesets))
->setIsFirstMailToRecipients(true)
->setToPHIDs(array_keys($add['ccs']));
}
foreach ($mail as $message) {
$message->setHeraldTranscriptURI($xscript_uri);
$message->setXHeraldRulesHeader($xscript_header);
$message->send();
}
}
public static function addCCAndUpdateRevision(
$revision,
$phid,
$reason) {
self::addCC($revision, $phid, $reason);
$unsubscribed = $revision->getUnsubscribed();
if (isset($unsubscribed[$phid])) {
unset($unsubscribed[$phid]);
$revision->setUnsubscribed($unsubscribed);
$revision->save();
}
}
public static function removeCCAndUpdateRevision(
$revision,
$phid,
$reason) {
self::removeCC($revision, $phid, $reason);
$unsubscribed = $revision->getUnsubscribed();
if (empty($unsubscribed[$phid])) {
$unsubscribed[$phid] = true;
$revision->setUnsubscribed($unsubscribed);
$revision->save();
}
}
public static function addCC(
DifferentialRevision $revision,
$phid,
$reason) {
return self::alterCCs(
$revision,
$revision->getCCPHIDs(),
$rem = array(),
$add = array($phid),
$reason);
}
public static function removeCC(
DifferentialRevision $revision,
$phid,
$reason) {
return self::alterCCs(
$revision,
$revision->getCCPHIDs(),
$rem = array($phid),
$add = array(),
$reason);
}
protected static function alterCCs(
DifferentialRevision $revision,
array $stable_phids,
array $rem_phids,
array $add_phids,
$reason_phid) {
return self::alterRelationships(
$revision,
$stable_phids,
$rem_phids,
$add_phids,
$reason_phid,
DifferentialRevision::RELATION_SUBSCRIBED);
}
public static function alterReviewers(
DifferentialRevision $revision,
array $stable_phids,
array $rem_phids,
array $add_phids,
$reason_phid) {
return self::alterRelationships(
$revision,
$stable_phids,
$rem_phids,
$add_phids,
$reason_phid,
DifferentialRevision::RELATION_REVIEWER);
}
private static function alterRelationships(
DifferentialRevision $revision,
array $stable_phids,
array $rem_phids,
array $add_phids,
$reason_phid,
$relation_type) {
$rem_map = array_fill_keys($rem_phids, true);
$add_map = array_fill_keys($add_phids, true);
$seq_map = array_values($stable_phids);
$seq_map = array_flip($seq_map);
foreach ($rem_map as $phid => $ignored) {
if (!isset($seq_map[$phid])) {
$seq_map[$phid] = count($seq_map);
}
}
foreach ($add_map as $phid => $ignored) {
if (!isset($seq_map[$phid])) {
$seq_map[$phid] = count($seq_map);
}
}
$raw = $revision->getRawRelations($relation_type);
$raw = ipull($raw, null, 'objectPHID');
$sequence = count($seq_map);
foreach ($raw as $phid => $ignored) {
if (isset($seq_map[$phid])) {
$raw[$phid]['sequence'] = $seq_map[$phid];
} else {
$raw[$phid]['sequence'] = $sequence++;
}
}
$raw = isort($raw, 'sequence');
foreach ($raw as $phid => $ignored) {
if (isset($rem_map[$phid])) {
unset($raw[$phid]);
}
}
foreach ($add_phids as $add) {
$raw[$add] = array(
'objectPHID' => $add,
'sequence' => idx($seq_map, $add, $sequence++),
'reasonPHID' => $reason_phid,
);
}
$conn_w = $revision->establishConnection('w');
$sql = array();
foreach ($raw as $relation) {
$sql[] = qsprintf(
$conn_w,
'(%d, %s, %s, %d, %s)',
$revision->getID(),
$relation_type,
$relation['objectPHID'],
$relation['sequence'],
$relation['reasonPHID']);
}
$conn_w->openTransaction();
queryfx(
$conn_w,
'DELETE FROM %T WHERE revisionID = %d AND relation = %s',
DifferentialRevision::RELATIONSHIP_TABLE,
$revision->getID(),
$relation_type);
if ($sql) {
queryfx(
$conn_w,
'INSERT INTO %T
(revisionID, relation, objectPHID, sequence, reasonPHID)
VALUES %Q',
DifferentialRevision::RELATIONSHIP_TABLE,
implode(', ', $sql));
}
$conn_w->saveTransaction();
$revision->loadRelationships();
}
private function createComment() {
$revision_id = $this->revision->getID();
$comment = id(new DifferentialComment())
->setAuthorPHID($this->getActorPHID())
->setRevisionID($revision_id)
->setContent($this->getComments())
->setAction('update');
$comment->save();
return $comment;
}
private function updateTasks() {
if ($this->tasks) {
$task_class = PhabricatorEnv::getEnvConfig(
'differential.attach-task-class');
if ($task_class) {
PhutilSymbolLoader::loadClass($task_class);
$task_attacher = newv($task_class, array());
$ret = $task_attacher->attachTasksToRevision(
$this->actorPHID,
$this->revision,
$this->tasks);
}
}
}
private function updateAuxiliaryFields() {
$aux_map = array();
foreach ($this->auxiliaryFields as $aux_field) {
$key = $aux_field->getStorageKey();
if ($key !== null) {
$val = $aux_field->getValueForStorage();
$aux_map[$key] = $val;
}
}
if (!$aux_map) {
return;
}
$revision = $this->revision;
$fields = id(new DifferentialAuxiliaryField())->loadAllWhere(
'revisionPHID = %s AND name IN (%Ls)',
$revision->getPHID(),
array_keys($aux_map));
$fields = mpull($fields, null, 'getName');
foreach ($aux_map as $key => $val) {
$obj = idx($fields, $key);
if (!$obj) {
$obj = new DifferentialAuxiliaryField();
$obj->setRevisionPHID($revision->getPHID());
$obj->setName($key);
}
if ($obj->getValue() !== $val) {
$obj->setValue($val);
$obj->save();
}
}
}
private function willWriteRevision() {
foreach ($this->auxiliaryFields as $aux_field) {
$aux_field->willWriteRevision($this);
}
}
private function didWriteRevision() {
foreach ($this->auxiliaryFields as $aux_field) {
$aux_field->didWriteRevision($this);
}
}
}
diff --git a/src/applications/differential/field/specification/base/DifferentialFieldSpecification.php b/src/applications/differential/field/specification/base/DifferentialFieldSpecification.php
index 96b5103000..bf2acb8faf 100644
--- a/src/applications/differential/field/specification/base/DifferentialFieldSpecification.php
+++ b/src/applications/differential/field/specification/base/DifferentialFieldSpecification.php
@@ -1,538 +1,627 @@
value = $request->getStr('my-custom-field');
*
* If you have some particularly complicated field, you may need to read
* more data; this is why you have access to the entire request.
*
* You must implement this if you implement @{method:shouldAppearOnEdit}.
*
* You should not perform field validation here; instead, you should implement
* @{method:validateField}.
*
* @param AphrontRequest HTTP request representing a user submitting a form
* with this field in it.
* @return this
* @task edit
*/
public function setValueFromRequest(AphrontRequest $request) {
throw new DifferentialFieldSpecificationIncompleteException($this);
}
/**
* Build a renderable object (generally, some @{class:AphrontFormControl})
* which can be appended to a @{class:AphrontFormView} and represents the
* interface the user sees on the "Edit Revision" screen when interacting
* with this field.
*
* For example:
*
* return id(new AphrontFormTextControl())
* ->setLabel('Custom Field')
* ->setName('my-custom-key')
* ->setValue($this->value);
*
* You must implement this if you implement @{method:shouldAppearOnEdit}.
*
* @return AphrontView|string Something renderable.
* @task edit
*/
public function renderEditControl() {
throw new DifferentialFieldSpecificationIncompleteException($this);
}
/**
* This method will be called after @{method:setValueFromRequest} but before
* the field is saved. It gives you an opportunity to inspect the field value
* and throw a @{class:DifferentialFieldValidationException} if there is a
* problem with the value the user has provided (for example, the value the
* user entered is not correctly formatted).
*
* By default, fields are not validated.
*
* @return void
* @task edit
*/
public function validateField() {
return;
}
/**
* Hook for applying revision changes via the editor. Normally, you should
* not implement this, but a number of builtin fields use the revision object
* itself as storage. If you need to do something similar for whatever reason,
* this method gives you an opportunity to interact with the editor or
* revision before changes are saved (for example, you can write the field's
* value into some property of the revision).
*
* @param DifferentialRevisionEditor Active editor which is applying changes
* to the revision.
* @return void
* @task edit
*/
public function willWriteRevision(DifferentialRevisionEditor $editor) {
return;
}
/**
* Hook after an edit operation has completed. This allows you to update
* link tables or do other write operations which should happen after the
* revision is saved. Normally you don't need to implement this.
*
*
* @param DifferentialRevisionEditor Active editor which has just applied
* changes to the revision.
* @return void
* @task edit
*/
public function didWriteRevision(DifferentialRevisionEditor $editor) {
return;
}
/* -( Extending the Revision View Interface )------------------------------ */
/**
* Determine if this field should appear on the revision detail view
* interface. One use of this interface is to add purely informational
* fields to the revision view, without any sort of backing storage.
*
* If you return true from this method, you must implement the methods
* @{method:renderLabelForRevisionView} and
* @{method:renderValueForRevisionView}.
*
* @return bool True if this field should appear when viewing a revision.
* @task view
*/
public function shouldAppearOnRevisionView() {
return false;
}
/**
* Return a string field label which will appear in the revision detail
* table.
*
* You must implement this method if you return true from
* @{method:shouldAppearOnRevisionView}.
*
* @return string Label for field in revision detail view.
* @task view
*/
public function renderLabelForRevisionView() {
throw new DifferentialFieldSpecificationIncompleteException($this);
}
/**
* Return a markup block representing the field for the revision detail
* view. Note that you can return null to suppress display (for instance,
* if the field shows related objects of some type and the revision doesn't
* have any related objects).
*
* You must implement this method if you return true from
* @{method:shouldAppearOnRevisionView}.
*
* @return string|null Display markup for field value, or null to suppress
* field rendering.
* @task view
*/
public function renderValueForRevisionView() {
throw new DifferentialFieldSpecificationIncompleteException($this);
}
/* -( Extending the Conduit Interface )------------------------------------ */
/**
* @task conduit
*/
public function shouldAppearOnConduitView() {
return false;
}
/**
* @task conduit
*/
public function getValueForConduit() {
throw new DifferentialFieldSpecificationIncompleteException($this);
}
/**
* @task conduit
*/
public function getKeyForConduit() {
$key = $this->getStorageKey();
if ($key === null) {
throw new DifferentialFieldSpecificationIncompleteException($this);
}
return $key;
}
/* -( Extending Commit Messages )------------------------------------------ */
/**
* Determine if this field should appear in commit messages. You should return
* true if this field participates in any part of the commit message workflow,
* even if it is not rendered by default.
*
* If you implement this method, you must implement
* @{method:getCommitMessageKey} and
* @{method:setValueFromParsedCommitMessage}.
*
* @return bool True if this field appears in commit messages in any capacity.
* @task commit
*/
public function shouldAppearOnCommitMessage() {
return false;
}
/**
* Key which identifies this field in parsed commit messages. Commit messages
* exist in two forms: raw textual commit messages and parsed dictionaries of
* fields. This method must return a unique string which identifies this field
* in dictionaries. Principally, this dictionary is shipped to and from arc
* over Conduit. Keys should be appropriate property names, like "testPlan"
* (not "Test Plan") and must be globally unique.
*
* You must implement this method if you return true from
* @{method:shouldAppearOnCommitMessage}.
*
* @return string Key which identifies the field in dictionaries.
* @task commit
*/
public function getCommitMessageKey() {
throw new DifferentialFieldSpecificationIncompleteException($this);
}
/**
* Set this field's value from a value in a parsed commit message dictionary.
* Afterward, this field will go through the normal write workflows and the
* change will be permanently stored via either the storage mechanisms (if
* your field implements them), revision write hooks (if your field implements
* them) or discarded (if your field implements neither, e.g. is just a
* display field).
*
* You must implement this method if you return true from
* @{method:shouldAppearOnCommitMessage}.
*
* @param mixed Field value from a parsed commit message dictionary.
* @return this
* @task commit
*/
public function setValueFromParsedCommitMessage($value) {
throw new DifferentialFieldSpecificationIncompleteException($this);
}
+ /**
+ * In revision control systems which read revision information from the
+ * working copy, the user may edit the commit message outside of invoking
+ * "arc diff --edit". When they do this, only some fields (those fields which
+ * can not be edited by other users) are safe to overwrite. For instance, it
+ * is fine to overwrite "Summary" because no one else can edit it, but not
+ * to overwrite "Reviewers" because reviewers may have been added or removed
+ * via the web interface.
+ *
+ * If a field is safe to overwrite when edited in a working copy commit
+ * message, return true. If the authoritative value should always be used,
+ * return false. By default, fields can not be overwritten.
+ *
+ * @return bool True to indicate the field is save to overwrite.
+ * @task commit
+ */
+ public function shouldOverwriteWhenCommitMessageIsEdited() {
+ return false;
+ }
+
+ /**
+ * Return true if this field should be suggested to the user during
+ * "arc diff --edit". Basicially, return true if the field is something the
+ * user might want to fill out (like "Summary"), and false if it's a
+ * system/display/readonly field (like "Differential Revision"). If this
+ * method returns true, the field will be rendered even if it has no value
+ * during edit and update operations.
+ *
+ * @return bool True to indicate the field should appear in the edit template.
+ * @task commit
+ */
+ public function shouldAppearOnCommitMessageTemplate() {
+ return true;
+ }
+
+ /**
+ * Render a human-readable label for this field, like "Summary" or
+ * "Test Plan". This is distinct from the commit message key, but generally
+ * they should be similar.
+ *
+ * @return string Human-readable field label for commit messages.
+ * @task commit
+ */
+ public function renderLabelForCommitMessage() {
+ throw new DifferentialFieldSpecificationIncompleteException($this);
+ }
+
+ /**
+ * Render a human-readable value for this field when it appears in commit
+ * messages (for instance, lists of users should be rendered as user names).
+ *
+ * The ##$is_edit## parameter allows you to distinguish between commit
+ * messages being rendered for editing and those being rendered for amending
+ * or commit. Some fields may decline to render a value in one mode (for
+ * example, "Reviewed By" appears only when doing commit/amend, not while
+ * editing).
+ *
+ * @param bool True if the message is being edited.
+ * @return string Human-readable field value.
+ * @task commit
+ */
+ public function renderValueForCommitMessage($is_edit) {
+ throw new DifferentialFieldSpecificationIncompleteException($this);
+ }
+
/* -( Loading Additional Data )-------------------------------------------- */
/**
* Specify which @{class:PhabricatorObjectHandles} need to be loaded for your
* field to render correctly.
*
* This is a convenience method which makes the handles available on all
* interfaces where the field appears. If your field needs handles on only
* some interfaces (or needs different handles on different interfaces) you
* can overload the more specific methods to customize which interfaces you
* retrieve handles for. Requesting only the handles you need will improve
* the performance of your field.
*
* You can later retrieve these handles by calling @{method:getHandle}.
*
* @return list List of PHIDs to load handles for.
* @task load
*/
protected function getRequiredHandlePHIDs() {
return array();
}
/**
* Specify which @{class:PhabricatorObjectHandles} need to be loaded for your
* field to render correctly on the view interface.
*
* This is a more specific version of @{method:getRequiredHandlePHIDs} which
* can be overridden to improve field performance by loading only data you
* need.
*
* @return list List of PHIDs to load handles for.
* @task load
*/
public function getRequiredHandlePHIDsForRevisionView() {
return $this->getRequiredHandlePHIDs();
}
/**
* Specify which @{class:PhabricatorObjectHandles} need to be loaded for your
* field to render correctly on the edit interface.
*
* This is a more specific version of @{method:getRequiredHandlePHIDs} which
* can be overridden to improve field performance by loading only data you
* need.
*
* @return list List of PHIDs to load handles for.
* @task load
*/
public function getRequiredHandlePHIDsForRevisionEdit() {
return $this->getRequiredHandlePHIDs();
}
+ /**
+ * Specify which @{class:PhabricatorObjectHandles} need to be loaded for your
+ * field to render correctly on the commit message interface.
+ *
+ * This is a more specific version of @{method:getRequiredHandlePHIDs} which
+ * can be overridden to improve field performance by loading only data you
+ * need.
+ *
+ * @return list List of PHIDs to load handles for.
+ * @task load
+ */
+ public function getRequiredHandlePHIDsForCommitMessage() {
+ return $this->getRequiredHandlePHIDs();
+ }
+
/**
* Specify which diff properties this field needs to load.
*
* @return list List of diff property keys this field requires.
* @task load
*/
public function getRequiredDiffProperties() {
return array();
}
/* -( Contextual Data )---------------------------------------------------- */
/**
* @task context
*/
final public function setRevision(DifferentialRevision $revision) {
$this->revision = $revision;
+ $this->didSetRevision();
return $this;
}
+ /**
+ * @task context
+ */
+ protected function didSetRevision() {
+ return;
+ }
+
+
/**
* @task context
*/
final public function setDiff(DifferentialDiff $diff) {
$this->diff = $diff;
return $this;
}
/**
* @task context
*/
final public function setHandles(array $handles) {
$this->handles = $handles;
return $this;
}
/**
* @task context
*/
final public function setDiffProperties(array $diff_properties) {
$this->diffProperties = $diff_properties;
return $this;
}
/**
* @task context
*/
final public function setUser(PhabricatorUser $user) {
$this->user = $user;
return $this;
}
/**
* @task context
*/
final protected function getRevision() {
if (empty($this->revision)) {
throw new DifferentialFieldDataNotAvailableException($this);
}
return $this->revision;
}
/**
* @task context
*/
final protected function getDiff() {
if (empty($this->diff)) {
throw new DifferentialFieldDataNotAvailableException($this);
}
return $this->diff;
}
/**
* @task context
*/
final protected function getUser() {
if (empty($this->user)) {
throw new DifferentialFieldDataNotAvailableException($this);
}
return $this->user;
}
/**
* Get the handle for an object PHID. You must overload
* @{method:getRequiredHandlePHIDs} (or a more specific version thereof)
* and include the PHID you want in the list for it to be available here.
*
* @return PhabricatorObjectHandle Handle to the object.
* @task context
*/
final protected function getHandle($phid) {
if ($this->handles === null) {
throw new DifferentialFieldDataNotAvailableException($this);
}
if (empty($this->handles[$phid])) {
$class = get_class($this);
throw new Exception(
"A differential field (of class '{$class}') is attempting to retrieve ".
"a handle ('{$phid}') which it did not request. Return all handle ".
"PHIDs you need from getRequiredHandlePHIDs().");
}
return $this->handles[$phid];
}
/**
* Get a diff property which this field previously requested by returning
* the key from @{method:getRequiredDiffProperties}.
*
* @param string Diff property key.
* @return string|null Diff property, or null if the property does not have
* a value.
* @task context
*/
final public function getDiffProperty($key) {
if ($this->diffProperties === null) {
// This will be set to some (possibly empty) array if we've loaded
// properties, so null means diff properties aren't available in this
// context.
throw new DifferentialFieldDataNotAvailableException($this);
}
if (!array_key_exists($key, $this->diffProperties)) {
$class = get_class($this);
throw new Exception(
"A differential field (of class '{$class}') is attempting to retrieve ".
"a diff property ('{$key}') which it did not request. Return all ".
"diff property keys you need from getRequiredDiffProperties().");
}
return $this->diffProperties[$key];
}
}
diff --git a/src/applications/differential/field/specification/blamerev/DifferentialBlameRevisionFieldSpecification.php b/src/applications/differential/field/specification/blamerev/DifferentialBlameRevisionFieldSpecification.php
index c058590cee..5fdcea13be 100644
--- a/src/applications/differential/field/specification/blamerev/DifferentialBlameRevisionFieldSpecification.php
+++ b/src/applications/differential/field/specification/blamerev/DifferentialBlameRevisionFieldSpecification.php
@@ -1,94 +1,106 @@
value;
}
public function setValueFromStorage($value) {
$this->value = $value;
return $this;
}
public function shouldAppearOnEdit() {
return true;
}
public function setValueFromRequest(AphrontRequest $request) {
$this->value = $request->getStr($this->getStorageKey());
return $this;
}
public function renderEditControl() {
return id(new AphrontFormTextControl())
->setLabel('Blame Revision')
->setCaption('Revision which broke the stuff which this change fixes.')
->setName($this->getStorageKey())
->setValue($this->value);
}
public function validateField() {
return;
}
public function shouldAppearOnRevisionView() {
return true;
}
public function renderLabelForRevisionView() {
return 'Blame Revision:';
}
public function renderValueForRevisionView() {
if (!$this->value) {
return null;
}
return phutil_escape_html($this->value);
}
public function shouldAppearOnConduitView() {
return true;
}
public function getValueForConduit() {
return $this->value;
}
public function shouldAppearOnCommitMessage() {
return true;
}
public function getCommitMessageKey() {
return 'blameRevision';
}
public function setValueFromParsedCommitMessage($value) {
$this->value = $value;
return $this;
}
+ public function shouldOverwriteWhenCommitMessageIsEdited() {
+ return true;
+ }
+
+ public function renderLabelForCommitMessage() {
+ return 'Blame Revision';
+ }
+
+ public function renderValueForCommitMessage($is_edit) {
+ return $this->value;
+ }
+
}
diff --git a/src/applications/differential/field/specification/ccs/DifferentialCCsFieldSpecification.php b/src/applications/differential/field/specification/ccs/DifferentialCCsFieldSpecification.php
index 701fb47d12..74107b02a0 100644
--- a/src/applications/differential/field/specification/ccs/DifferentialCCsFieldSpecification.php
+++ b/src/applications/differential/field/specification/ccs/DifferentialCCsFieldSpecification.php
@@ -1,98 +1,121 @@
getCCPHIDs();
}
public function renderLabelForRevisionView() {
return 'CCs:';
}
public function renderValueForRevisionView() {
$cc_phids = $this->getCCPHIDs();
if (!$cc_phids) {
return 'None';
}
$links = array();
foreach ($cc_phids as $cc_phid) {
$links[] = $this->getHandle($cc_phid)->renderLink();
}
return implode(', ', $links);
}
private function getCCPHIDs() {
$revision = $this->getRevision();
return $revision->getCCPHIDs();
}
public function shouldAppearOnEdit() {
- $this->ccs = $this->getCCPHIDs();
return true;
}
+ protected function didSetRevision() {
+ $this->ccs = $this->getCCPHIDs();
+ }
+
public function getRequiredHandlePHIDsForRevisionEdit() {
return $this->ccs;
}
+ public function getRequiredHandlePHIDsForCommitMessage() {
+ return $this->ccs;
+ }
+
public function setValueFromRequest(AphrontRequest $request) {
$this->ccs = $request->getArr('cc');
return $this;
}
public function renderEditControl() {
$cc_map = array();
foreach ($this->ccs as $phid) {
$cc_map[$phid] = $this->getHandle($phid)->getFullName();
}
return id(new AphrontFormTokenizerControl())
->setLabel('CC')
->setName('cc')
->setDatasource('/typeahead/common/mailable/')
->setValue($cc_map);
}
public function willWriteRevision(DifferentialRevisionEditor $editor) {
$editor->setCCPHIDs($this->ccs);
}
public function shouldAppearOnCommitMessage() {
return true;
}
public function getCommitMessageKey() {
return 'ccPHIDs';
}
public function setValueFromParsedCommitMessage($value) {
$this->value = nonempty($value, array());
return $this;
}
+ public function renderLabelForCommitMessage() {
+ return 'CC';
+ }
+
+ public function renderValueForCommitMessage($is_edit) {
+ if (!$this->ccs) {
+ return null;
+ }
+
+ $names = array();
+ foreach ($this->ccs as $phid) {
+ $names[] = $this->getHandle($phid)->getName();
+ }
+ return implode(', ', $names);
+ }
+
}
diff --git a/src/applications/differential/field/specification/gitsvnid/DifferentialGitSVNIDFieldSpecification.php b/src/applications/differential/field/specification/gitsvnid/DifferentialGitSVNIDFieldSpecification.php
index c908946303..1fcff06fbf 100644
--- a/src/applications/differential/field/specification/gitsvnid/DifferentialGitSVNIDFieldSpecification.php
+++ b/src/applications/differential/field/specification/gitsvnid/DifferentialGitSVNIDFieldSpecification.php
@@ -1,37 +1,49 @@
gitSVNID = $value;
return $this;
}
+ public function renderLabelForCommitMessage() {
+ return 'git-svn-id';
+ }
+
+ public function renderValueForCommitMessage($is_edit) {
+ return null;
+ }
+
}
diff --git a/src/applications/differential/field/specification/revertplan/DifferentialRevertPlanFieldSpecification.php b/src/applications/differential/field/specification/revertplan/DifferentialRevertPlanFieldSpecification.php
index e84950363f..790758e4a0 100644
--- a/src/applications/differential/field/specification/revertplan/DifferentialRevertPlanFieldSpecification.php
+++ b/src/applications/differential/field/specification/revertplan/DifferentialRevertPlanFieldSpecification.php
@@ -1,94 +1,106 @@
value;
}
public function setValueFromStorage($value) {
$this->value = $value;
return $this;
}
public function shouldAppearOnEdit() {
return true;
}
public function setValueFromRequest(AphrontRequest $request) {
$this->value = $request->getStr($this->getStorageKey());
return $this;
}
public function renderEditControl() {
return id(new AphrontFormTextAreaControl())
->setLabel('Revert Plan')
->setName($this->getStorageKey())
->setCaption('Special steps required to safely revert this change.')
->setValue($this->value);
}
public function validateField() {
return;
}
public function shouldAppearOnRevisionView() {
return true;
}
public function renderLabelForRevisionView() {
return 'Revert Plan:';
}
public function renderValueForRevisionView() {
if (!$this->value) {
return null;
}
return phutil_escape_html($this->value);
}
public function shouldAppearOnConduitView() {
return true;
}
public function getValueForConduit() {
return $this->value;
}
public function shouldAppearOnCommitMessage() {
return true;
}
public function getCommitMessageKey() {
return 'revertPlan';
}
public function setValueFromParsedCommitMessage($value) {
$this->value = $value;
return $this;
}
+ public function shouldOverwriteWhenCommitMessageIsEdited() {
+ return true;
+ }
+
+ public function renderLabelForCommitMessage() {
+ return 'Revert Plan';
+ }
+
+ public function renderValueForCommitMessage($is_edit) {
+ return $this->value;
+ }
+
}
diff --git a/src/applications/differential/field/specification/reviewedby/DifferentialReviewedByFieldSpecification.php b/src/applications/differential/field/specification/reviewedby/DifferentialReviewedByFieldSpecification.php
index f5904e2ee2..78158e4d57 100644
--- a/src/applications/differential/field/specification/reviewedby/DifferentialReviewedByFieldSpecification.php
+++ b/src/applications/differential/field/specification/reviewedby/DifferentialReviewedByFieldSpecification.php
@@ -1,38 +1,92 @@
reviewedBy = array();
+ $revision = $this->getRevision();
+
+ $status = $revision->getStatus();
+ if ($status == DifferentialRevisionStatus::ACCEPTED ||
+ $status == DifferentialRevisionStatus::COMMITTED) {
+ $reviewer = null;
+ $comments = $revision->loadComments();
+ foreach ($comments as $comment) {
+ $action = $comment->getAction();
+ if ($action == DifferentialAction::ACTION_ACCEPT) {
+ $reviewer = $comment->getAuthorPHID();
+ } else if ($action == DifferentialAction::ACTION_REJECT ||
+ $action == DifferentialAction::ACTION_ABANDON ||
+ $action == DifferentialAction::ACTION_RETHINK) {
+ $reviewer = null;
+ }
+ }
+
+ if ($reviewer) {
+ $this->reviewedBy = array($reviewer);
+ }
+ }
+ }
+
public function shouldAppearOnCommitMessage() {
return true;
}
public function getCommitMessageKey() {
return 'reviewedByPHIDs';
}
public function setValueFromParsedCommitMessage($value) {
$this->reviewedBy = $value;
return $this;
}
+ public function shouldAppearOnCommitMessageTemplate() {
+ return false;
+ }
+
+ public function renderLabelForCommitMessage() {
+ return 'Reviewed By';
+ }
+
+ public function getRequiredHandlePHIDsForCommitMessage() {
+ return $this->reviewedBy;
+ }
+
+ public function renderValueForCommitMessage($is_edit) {
+ if ($is_edit) {
+ return null;
+ }
+
+ if (!$this->reviewedBy) {
+ return null;
+ }
+
+ $names = array();
+ foreach ($this->reviewedBy as $phid) {
+ $names[] = $this->getHandle($phid)->getName();
+ }
+
+ return implode(', ', $names);
+ }
}
diff --git a/src/applications/differential/field/specification/reviewedby/__init__.php b/src/applications/differential/field/specification/reviewedby/__init__.php
index a87a459dbd..5240ff8da0 100644
--- a/src/applications/differential/field/specification/reviewedby/__init__.php
+++ b/src/applications/differential/field/specification/reviewedby/__init__.php
@@ -1,12 +1,14 @@
getReviewerPHIDs();
}
public function renderLabelForRevisionView() {
return 'Reviewers:';
}
public function renderValueForRevisionView() {
$reviewer_phids = $this->getReviewerPHIDs();
if (!$reviewer_phids) {
return 'None';
}
$links = array();
foreach ($reviewer_phids as $reviewer_phid) {
$links[] = $this->getHandle($reviewer_phid)->renderLink();
}
return implode(', ', $links);
}
private function getReviewerPHIDs() {
$revision = $this->getRevision();
return $revision->getReviewers();
}
public function shouldAppearOnEdit() {
- $this->reviewers = $this->getReviewerPHIDs();
return true;
}
+ protected function didSetRevision() {
+ $this->reviewers = $this->getReviewerPHIDs();
+ }
+
public function getRequiredHandlePHIDsForRevisionEdit() {
return $this->reviewers;
}
public function setValueFromRequest(AphrontRequest $request) {
$this->reviewers = $request->getArr('reviewers');
return $this;
}
public function validateField() {
if (in_array($this->getUser()->getPHID(), $this->reviewers)) {
$this->error = 'Invalid';
throw new DifferentialFieldValidationException(
"You may not review your own revision!");
}
}
public function renderEditControl() {
$reviewer_map = array();
foreach ($this->reviewers as $phid) {
$reviewer_map[$phid] = $this->getHandle($phid)->getFullName();
}
return id(new AphrontFormTokenizerControl())
->setLabel('Reviewers')
->setName('reviewers')
->setDatasource('/typeahead/common/users/')
->setValue($reviewer_map)
->setError($this->error);
}
public function willWriteRevision(DifferentialRevisionEditor $editor) {
$editor->setReviewers($this->reviewers);
}
public function shouldAppearOnCommitMessage() {
return true;
}
public function getCommitMessageKey() {
return 'reviewerPHIDs';
}
public function setValueFromParsedCommitMessage($value) {
$this->reviewers = nonempty($value, array());
return $this;
}
+ public function renderLabelForCommitMessage() {
+ return 'Reviewers';
+ }
+
+ public function getRequiredHandlePHIDsForCommitMessage() {
+ return $this->reviewers;
+ }
+
+ public function renderValueForCommitMessage($is_edit) {
+ if (!$this->reviewers) {
+ return null;
+ }
+
+ $names = array();
+ foreach ($this->reviewers as $phid) {
+ $names[] = $this->getHandle($phid)->getName();
+ }
+
+ return implode(', ', $names);
+ }
+
}
diff --git a/src/applications/differential/field/specification/revisionid/DifferentialRevisionIDFieldSpecification.php b/src/applications/differential/field/specification/revisionid/DifferentialRevisionIDFieldSpecification.php
index e1f1cf30b3..02eade8f06 100644
--- a/src/applications/differential/field/specification/revisionid/DifferentialRevisionIDFieldSpecification.php
+++ b/src/applications/differential/field/specification/revisionid/DifferentialRevisionIDFieldSpecification.php
@@ -1,38 +1,50 @@
id = $this->getRevision()->getID();
+ }
+
public function shouldAppearOnCommitMessage() {
return true;
}
public function getCommitMessageKey() {
return 'revisionID';
}
public function setValueFromParsedCommitMessage($value) {
$this->id = $value;
return $this;
}
+ public function renderLabelForCommitMessage() {
+ return 'Differential Revision';
+ }
+
+ public function renderValueForCommitMessage($is_edit) {
+ return $this->id;
+ }
+
}
diff --git a/src/applications/differential/field/specification/summary/DifferentialSummaryFieldSpecification.php b/src/applications/differential/field/specification/summary/DifferentialSummaryFieldSpecification.php
index 46209c907f..a7e5ad50ed 100644
--- a/src/applications/differential/field/specification/summary/DifferentialSummaryFieldSpecification.php
+++ b/src/applications/differential/field/specification/summary/DifferentialSummaryFieldSpecification.php
@@ -1,58 +1,73 @@
summary = $this->getRevision()->getSummary();
return true;
}
+ protected function didSetRevision() {
+ $this->summary = $this->getRevision()->getSummary();
+ }
+
public function setValueFromRequest(AphrontRequest $request) {
$this->summary = $request->getStr('summary');
return $this;
}
public function renderEditControl() {
return id(new AphrontFormTextAreaControl())
->setLabel('Summary')
->setName('summary')
->setValue($this->summary);
}
public function willWriteRevision(DifferentialRevisionEditor $editor) {
$this->getRevision()->setSummary($this->summary);
}
public function shouldAppearOnCommitMessage() {
return true;
}
public function getCommitMessageKey() {
return 'summary';
}
public function setValueFromParsedCommitMessage($value) {
$this->summary = (string)$value;
return $this;
}
+ public function shouldOverwriteWhenCommitMessageIsEdited() {
+ return true;
+ }
+
+ public function renderLabelForCommitMessage() {
+ return 'Summary';
+ }
+
+ public function renderValueForCommitMessage($is_edit) {
+ return $this->summary;
+ }
+
}
diff --git a/src/applications/differential/field/specification/testplan/DifferentialTestPlanFieldSpecification.php b/src/applications/differential/field/specification/testplan/DifferentialTestPlanFieldSpecification.php
index 8eed5dc248..14b46a7a9c 100644
--- a/src/applications/differential/field/specification/testplan/DifferentialTestPlanFieldSpecification.php
+++ b/src/applications/differential/field/specification/testplan/DifferentialTestPlanFieldSpecification.php
@@ -1,70 +1,85 @@
plan = $this->getRevision()->getTestPlan();
return true;
}
+ protected function didSetRevision() {
+ $this->plan = $this->getRevision()->getTestPlan();
+ }
+
public function setValueFromRequest(AphrontRequest $request) {
$this->plan = $request->getStr('testplan');
$this->error = null;
return $this;
}
public function renderEditControl() {
return id(new AphrontFormTextAreaControl())
->setLabel('Test Plan')
->setName('testplan')
->setValue($this->plan)
->setError($this->error);
}
public function willWriteRevision(DifferentialRevisionEditor $editor) {
$this->getRevision()->setTestPlan($this->plan);
}
public function validateField() {
if (!strlen($this->plan)) {
$this->error = 'Required';
throw new DifferentialFieldValidationException(
"You must provide a test plan.");
}
}
public function shouldAppearOnCommitMessage() {
return true;
}
public function getCommitMessageKey() {
return 'testPlan';
}
public function setValueFromParsedCommitMessage($value) {
$this->plan = $value;
return $this;
}
+ public function shouldOverwriteWhenCommitMessageIsEdited() {
+ return true;
+ }
+
+ public function renderLabelForCommitMessage() {
+ return 'Test Plan';
+ }
+
+ public function renderValueForCommitMessage($is_edit) {
+ return $this->plan;
+ }
+
}
diff --git a/src/applications/differential/field/specification/title/DifferentialTitleFieldSpecification.php b/src/applications/differential/field/specification/title/DifferentialTitleFieldSpecification.php
index 7b6bb94dc2..b4ba293935 100644
--- a/src/applications/differential/field/specification/title/DifferentialTitleFieldSpecification.php
+++ b/src/applications/differential/field/specification/title/DifferentialTitleFieldSpecification.php
@@ -1,70 +1,85 @@
title = $this->getRevision()->getTitle();
return true;
}
+ protected function didSetRevision() {
+ $this->title = $this->getRevision()->getTitle();
+ }
+
public function setValueFromRequest(AphrontRequest $request) {
$this->title = $request->getStr('title');
$this->error = null;
return $this;
}
public function renderEditControl() {
return id(new AphrontFormTextAreaControl())
->setLabel('Title')
->setName('title')
->setHeight(AphrontFormTextAreaControl::HEIGHT_VERY_SHORT)
->setError($this->error)
->setValue($this->title);
}
public function willWriteRevision(DifferentialRevisionEditor $editor) {
$this->getRevision()->setTitle($this->title);
}
public function validateField() {
if (!strlen($this->title)) {
$this->error = 'Required';
throw new DifferentialFieldValidationException(
"You must provide a title.");
}
}
public function shouldAppearOnCommitMessage() {
return true;
}
public function getCommitMessageKey() {
return 'title';
}
public function setValueFromParsedCommitMessage($value) {
$this->title = $value;
return $this;
}
+ public function shouldOverwriteWhenCommitMessageIsEdited() {
+ return true;
+ }
+
+ public function renderLabelForCommitMessage() {
+ return 'Title';
+ }
+
+ public function renderValueForCommitMessage($is_edit) {
+ return $this->title;
+ }
+
}