Merge branch 'master' into redesign-2015
This commit is contained in:
14
resources/sql/autopatches/20150617.harbor.1.lint.sql
Normal file
14
resources/sql/autopatches/20150617.harbor.1.lint.sql
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
CREATE TABLE {$NAMESPACE}_harbormaster.harbormaster_buildlintmessage (
|
||||||
|
id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
|
||||||
|
buildTargetPHID VARBINARY(64) NOT NULL,
|
||||||
|
path LONGTEXT NOT NULL,
|
||||||
|
line INT UNSIGNED,
|
||||||
|
characterOffset INT UNSIGNED,
|
||||||
|
code VARCHAR(32) COLLATE {$COLLATE_TEXT} NOT NULL,
|
||||||
|
severity VARCHAR(32) COLLATE {$COLLATE_TEXT} NOT NULL,
|
||||||
|
name VARCHAR(255) COLLATE {$COLLATE_TEXT} NOT NULL,
|
||||||
|
properties LONGTEXT COLLATE {$COLLATE_TEXT} NOT NULL,
|
||||||
|
dateCreated INT UNSIGNED NOT NULL,
|
||||||
|
dateModified INT UNSIGNED NOT NULL,
|
||||||
|
KEY `key_target` (buildTargetPHID)
|
||||||
|
) ENGINE=INNODB, COLLATE {$COLLATE_TEXT};
|
||||||
13
resources/sql/autopatches/20150617.harbor.2.unit.sql
Normal file
13
resources/sql/autopatches/20150617.harbor.2.unit.sql
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
CREATE TABLE {$NAMESPACE}_harbormaster.harbormaster_buildunitmessage (
|
||||||
|
id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
|
||||||
|
buildTargetPHID VARBINARY(64) NOT NULL,
|
||||||
|
engine VARCHAR(255) COLLATE {$COLLATE_TEXT} NOT NULL,
|
||||||
|
namespace VARCHAR(255) COLLATE {$COLLATE_TEXT} NOT NULL,
|
||||||
|
name VARCHAR(255) COLLATE {$COLLATE_TEXT} NOT NULL,
|
||||||
|
result VARCHAR(32) COLLATE {$COLLATE_TEXT} NOT NULL,
|
||||||
|
duration DOUBLE,
|
||||||
|
properties LONGTEXT COLLATE {$COLLATE_TEXT} NOT NULL,
|
||||||
|
dateCreated INT UNSIGNED NOT NULL,
|
||||||
|
dateModified INT UNSIGNED NOT NULL,
|
||||||
|
KEY `key_target` (buildTargetPHID)
|
||||||
|
) ENGINE=INNODB, COLLATE {$COLLATE_TEXT};
|
||||||
2
resources/sql/autopatches/20150618.harbor.1.planauto.sql
Normal file
2
resources/sql/autopatches/20150618.harbor.1.planauto.sql
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
ALTER TABLE {$NAMESPACE}_harbormaster.harbormaster_buildplan
|
||||||
|
ADD planAutoKey VARCHAR(32) COLLATE {$COLLATE_TEXT};
|
||||||
2
resources/sql/autopatches/20150618.harbor.2.stepauto.sql
Normal file
2
resources/sql/autopatches/20150618.harbor.2.stepauto.sql
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
ALTER TABLE {$NAMESPACE}_harbormaster.harbormaster_buildstep
|
||||||
|
ADD stepAutoKey VARCHAR(32) COLLATE {$COLLATE_TEXT};
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
ALTER TABLE {$NAMESPACE}_harbormaster.harbormaster_build
|
||||||
|
ADD planAutoKey VARCHAR(32) COLLATE {$COLLATE_TEXT};
|
||||||
2
resources/sql/autopatches/20150621.phrase.1.sql
Normal file
2
resources/sql/autopatches/20150621.phrase.1.sql
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
ALTER TABLE {$NAMESPACE}_passphrase.passphrase_credential
|
||||||
|
ADD authorPHID VARBINARY(64) NOT NULL;
|
||||||
2
resources/sql/autopatches/20150621.phrase.2.sql
Normal file
2
resources/sql/autopatches/20150621.phrase.2.sql
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
ALTER TABLE {$NAMESPACE}_passphrase.passphrase_credential
|
||||||
|
ADD spacePHID VARBINARY(64);
|
||||||
@@ -360,6 +360,7 @@ phutil_register_library_map(array(
|
|||||||
'DifferentialDiffTableOfContentsView' => 'applications/differential/view/DifferentialDiffTableOfContentsView.php',
|
'DifferentialDiffTableOfContentsView' => 'applications/differential/view/DifferentialDiffTableOfContentsView.php',
|
||||||
'DifferentialDiffTestCase' => 'applications/differential/storage/__tests__/DifferentialDiffTestCase.php',
|
'DifferentialDiffTestCase' => 'applications/differential/storage/__tests__/DifferentialDiffTestCase.php',
|
||||||
'DifferentialDiffTransaction' => 'applications/differential/storage/DifferentialDiffTransaction.php',
|
'DifferentialDiffTransaction' => 'applications/differential/storage/DifferentialDiffTransaction.php',
|
||||||
|
'DifferentialDiffTransactionQuery' => 'applications/differential/query/DifferentialDiffTransactionQuery.php',
|
||||||
'DifferentialDiffViewController' => 'applications/differential/controller/DifferentialDiffViewController.php',
|
'DifferentialDiffViewController' => 'applications/differential/controller/DifferentialDiffViewController.php',
|
||||||
'DifferentialDoorkeeperRevisionFeedStoryPublisher' => 'applications/differential/doorkeeper/DifferentialDoorkeeperRevisionFeedStoryPublisher.php',
|
'DifferentialDoorkeeperRevisionFeedStoryPublisher' => 'applications/differential/doorkeeper/DifferentialDoorkeeperRevisionFeedStoryPublisher.php',
|
||||||
'DifferentialDraft' => 'applications/differential/storage/DifferentialDraft.php',
|
'DifferentialDraft' => 'applications/differential/storage/DifferentialDraft.php',
|
||||||
@@ -826,19 +827,22 @@ phutil_register_library_map(array(
|
|||||||
'FundInitiativeTransactionQuery' => 'applications/fund/query/FundInitiativeTransactionQuery.php',
|
'FundInitiativeTransactionQuery' => 'applications/fund/query/FundInitiativeTransactionQuery.php',
|
||||||
'FundInitiativeViewController' => 'applications/fund/controller/FundInitiativeViewController.php',
|
'FundInitiativeViewController' => 'applications/fund/controller/FundInitiativeViewController.php',
|
||||||
'FundSchemaSpec' => 'applications/fund/storage/FundSchemaSpec.php',
|
'FundSchemaSpec' => 'applications/fund/storage/FundSchemaSpec.php',
|
||||||
|
'HarbormasterArcLintBuildStepImplementation' => 'applications/harbormaster/step/HarbormasterArcLintBuildStepImplementation.php',
|
||||||
|
'HarbormasterArcUnitBuildStepImplementation' => 'applications/harbormaster/step/HarbormasterArcUnitBuildStepImplementation.php',
|
||||||
|
'HarbormasterAutotargetsTestCase' => 'applications/harbormaster/__tests__/HarbormasterAutotargetsTestCase.php',
|
||||||
'HarbormasterBuild' => 'applications/harbormaster/storage/build/HarbormasterBuild.php',
|
'HarbormasterBuild' => 'applications/harbormaster/storage/build/HarbormasterBuild.php',
|
||||||
'HarbormasterBuildAbortedException' => 'applications/harbormaster/exception/HarbormasterBuildAbortedException.php',
|
'HarbormasterBuildAbortedException' => 'applications/harbormaster/exception/HarbormasterBuildAbortedException.php',
|
||||||
'HarbormasterBuildActionController' => 'applications/harbormaster/controller/HarbormasterBuildActionController.php',
|
'HarbormasterBuildActionController' => 'applications/harbormaster/controller/HarbormasterBuildActionController.php',
|
||||||
|
'HarbormasterBuildArcanistAutoplan' => 'applications/harbormaster/autoplan/HarbormasterBuildArcanistAutoplan.php',
|
||||||
'HarbormasterBuildArtifact' => 'applications/harbormaster/storage/build/HarbormasterBuildArtifact.php',
|
'HarbormasterBuildArtifact' => 'applications/harbormaster/storage/build/HarbormasterBuildArtifact.php',
|
||||||
'HarbormasterBuildArtifactQuery' => 'applications/harbormaster/query/HarbormasterBuildArtifactQuery.php',
|
'HarbormasterBuildArtifactQuery' => 'applications/harbormaster/query/HarbormasterBuildArtifactQuery.php',
|
||||||
|
'HarbormasterBuildAutoplan' => 'applications/harbormaster/autoplan/HarbormasterBuildAutoplan.php',
|
||||||
'HarbormasterBuildCommand' => 'applications/harbormaster/storage/HarbormasterBuildCommand.php',
|
'HarbormasterBuildCommand' => 'applications/harbormaster/storage/HarbormasterBuildCommand.php',
|
||||||
'HarbormasterBuildDependencyDatasource' => 'applications/harbormaster/typeahead/HarbormasterBuildDependencyDatasource.php',
|
'HarbormasterBuildDependencyDatasource' => 'applications/harbormaster/typeahead/HarbormasterBuildDependencyDatasource.php',
|
||||||
'HarbormasterBuildEngine' => 'applications/harbormaster/engine/HarbormasterBuildEngine.php',
|
'HarbormasterBuildEngine' => 'applications/harbormaster/engine/HarbormasterBuildEngine.php',
|
||||||
'HarbormasterBuildFailureException' => 'applications/harbormaster/exception/HarbormasterBuildFailureException.php',
|
'HarbormasterBuildFailureException' => 'applications/harbormaster/exception/HarbormasterBuildFailureException.php',
|
||||||
'HarbormasterBuildGraph' => 'applications/harbormaster/engine/HarbormasterBuildGraph.php',
|
'HarbormasterBuildGraph' => 'applications/harbormaster/engine/HarbormasterBuildGraph.php',
|
||||||
'HarbormasterBuildItem' => 'applications/harbormaster/storage/build/HarbormasterBuildItem.php',
|
'HarbormasterBuildLintMessage' => 'applications/harbormaster/storage/build/HarbormasterBuildLintMessage.php',
|
||||||
'HarbormasterBuildItemPHIDType' => 'applications/harbormaster/phid/HarbormasterBuildItemPHIDType.php',
|
|
||||||
'HarbormasterBuildItemQuery' => 'applications/harbormaster/query/HarbormasterBuildItemQuery.php',
|
|
||||||
'HarbormasterBuildLog' => 'applications/harbormaster/storage/build/HarbormasterBuildLog.php',
|
'HarbormasterBuildLog' => 'applications/harbormaster/storage/build/HarbormasterBuildLog.php',
|
||||||
'HarbormasterBuildLogPHIDType' => 'applications/harbormaster/phid/HarbormasterBuildLogPHIDType.php',
|
'HarbormasterBuildLogPHIDType' => 'applications/harbormaster/phid/HarbormasterBuildLogPHIDType.php',
|
||||||
'HarbormasterBuildLogQuery' => 'applications/harbormaster/query/HarbormasterBuildLogQuery.php',
|
'HarbormasterBuildLogQuery' => 'applications/harbormaster/query/HarbormasterBuildLogQuery.php',
|
||||||
@@ -870,6 +874,7 @@ phutil_register_library_map(array(
|
|||||||
'HarbormasterBuildTransaction' => 'applications/harbormaster/storage/HarbormasterBuildTransaction.php',
|
'HarbormasterBuildTransaction' => 'applications/harbormaster/storage/HarbormasterBuildTransaction.php',
|
||||||
'HarbormasterBuildTransactionEditor' => 'applications/harbormaster/editor/HarbormasterBuildTransactionEditor.php',
|
'HarbormasterBuildTransactionEditor' => 'applications/harbormaster/editor/HarbormasterBuildTransactionEditor.php',
|
||||||
'HarbormasterBuildTransactionQuery' => 'applications/harbormaster/query/HarbormasterBuildTransactionQuery.php',
|
'HarbormasterBuildTransactionQuery' => 'applications/harbormaster/query/HarbormasterBuildTransactionQuery.php',
|
||||||
|
'HarbormasterBuildUnitMessage' => 'applications/harbormaster/storage/build/HarbormasterBuildUnitMessage.php',
|
||||||
'HarbormasterBuildViewController' => 'applications/harbormaster/controller/HarbormasterBuildViewController.php',
|
'HarbormasterBuildViewController' => 'applications/harbormaster/controller/HarbormasterBuildViewController.php',
|
||||||
'HarbormasterBuildWorker' => 'applications/harbormaster/worker/HarbormasterBuildWorker.php',
|
'HarbormasterBuildWorker' => 'applications/harbormaster/worker/HarbormasterBuildWorker.php',
|
||||||
'HarbormasterBuildable' => 'applications/harbormaster/storage/HarbormasterBuildable.php',
|
'HarbormasterBuildable' => 'applications/harbormaster/storage/HarbormasterBuildable.php',
|
||||||
@@ -901,6 +906,7 @@ phutil_register_library_map(array(
|
|||||||
'HarbormasterPlanRunController' => 'applications/harbormaster/controller/HarbormasterPlanRunController.php',
|
'HarbormasterPlanRunController' => 'applications/harbormaster/controller/HarbormasterPlanRunController.php',
|
||||||
'HarbormasterPlanViewController' => 'applications/harbormaster/controller/HarbormasterPlanViewController.php',
|
'HarbormasterPlanViewController' => 'applications/harbormaster/controller/HarbormasterPlanViewController.php',
|
||||||
'HarbormasterPublishFragmentBuildStepImplementation' => 'applications/harbormaster/step/HarbormasterPublishFragmentBuildStepImplementation.php',
|
'HarbormasterPublishFragmentBuildStepImplementation' => 'applications/harbormaster/step/HarbormasterPublishFragmentBuildStepImplementation.php',
|
||||||
|
'HarbormasterQueryAutotargetsConduitAPIMethod' => 'applications/harbormaster/conduit/HarbormasterQueryAutotargetsConduitAPIMethod.php',
|
||||||
'HarbormasterQueryBuildablesConduitAPIMethod' => 'applications/harbormaster/conduit/HarbormasterQueryBuildablesConduitAPIMethod.php',
|
'HarbormasterQueryBuildablesConduitAPIMethod' => 'applications/harbormaster/conduit/HarbormasterQueryBuildablesConduitAPIMethod.php',
|
||||||
'HarbormasterQueryBuildsConduitAPIMethod' => 'applications/harbormaster/conduit/HarbormasterQueryBuildsConduitAPIMethod.php',
|
'HarbormasterQueryBuildsConduitAPIMethod' => 'applications/harbormaster/conduit/HarbormasterQueryBuildsConduitAPIMethod.php',
|
||||||
'HarbormasterRemarkupRule' => 'applications/harbormaster/remarkup/HarbormasterRemarkupRule.php',
|
'HarbormasterRemarkupRule' => 'applications/harbormaster/remarkup/HarbormasterRemarkupRule.php',
|
||||||
@@ -911,6 +917,7 @@ phutil_register_library_map(array(
|
|||||||
'HarbormasterStepAddController' => 'applications/harbormaster/controller/HarbormasterStepAddController.php',
|
'HarbormasterStepAddController' => 'applications/harbormaster/controller/HarbormasterStepAddController.php',
|
||||||
'HarbormasterStepDeleteController' => 'applications/harbormaster/controller/HarbormasterStepDeleteController.php',
|
'HarbormasterStepDeleteController' => 'applications/harbormaster/controller/HarbormasterStepDeleteController.php',
|
||||||
'HarbormasterStepEditController' => 'applications/harbormaster/controller/HarbormasterStepEditController.php',
|
'HarbormasterStepEditController' => 'applications/harbormaster/controller/HarbormasterStepEditController.php',
|
||||||
|
'HarbormasterTargetEngine' => 'applications/harbormaster/engine/HarbormasterTargetEngine.php',
|
||||||
'HarbormasterTargetWorker' => 'applications/harbormaster/worker/HarbormasterTargetWorker.php',
|
'HarbormasterTargetWorker' => 'applications/harbormaster/worker/HarbormasterTargetWorker.php',
|
||||||
'HarbormasterThrowExceptionBuildStep' => 'applications/harbormaster/step/HarbormasterThrowExceptionBuildStep.php',
|
'HarbormasterThrowExceptionBuildStep' => 'applications/harbormaster/step/HarbormasterThrowExceptionBuildStep.php',
|
||||||
'HarbormasterUIEventListener' => 'applications/harbormaster/event/HarbormasterUIEventListener.php',
|
'HarbormasterUIEventListener' => 'applications/harbormaster/event/HarbormasterUIEventListener.php',
|
||||||
@@ -1262,6 +1269,7 @@ phutil_register_library_map(array(
|
|||||||
'PassphraseConduitAPIMethod' => 'applications/passphrase/conduit/PassphraseConduitAPIMethod.php',
|
'PassphraseConduitAPIMethod' => 'applications/passphrase/conduit/PassphraseConduitAPIMethod.php',
|
||||||
'PassphraseController' => 'applications/passphrase/controller/PassphraseController.php',
|
'PassphraseController' => 'applications/passphrase/controller/PassphraseController.php',
|
||||||
'PassphraseCredential' => 'applications/passphrase/storage/PassphraseCredential.php',
|
'PassphraseCredential' => 'applications/passphrase/storage/PassphraseCredential.php',
|
||||||
|
'PassphraseCredentialAuthorPolicyRule' => 'applications/passphrase/policyrule/PassphraseCredentialAuthorPolicyRule.php',
|
||||||
'PassphraseCredentialConduitController' => 'applications/passphrase/controller/PassphraseCredentialConduitController.php',
|
'PassphraseCredentialConduitController' => 'applications/passphrase/controller/PassphraseCredentialConduitController.php',
|
||||||
'PassphraseCredentialControl' => 'applications/passphrase/view/PassphraseCredentialControl.php',
|
'PassphraseCredentialControl' => 'applications/passphrase/view/PassphraseCredentialControl.php',
|
||||||
'PassphraseCredentialCreateController' => 'applications/passphrase/controller/PassphraseCredentialCreateController.php',
|
'PassphraseCredentialCreateController' => 'applications/passphrase/controller/PassphraseCredentialCreateController.php',
|
||||||
@@ -1281,6 +1289,8 @@ phutil_register_library_map(array(
|
|||||||
'PassphraseCredentialTypeTestCase' => 'applications/passphrase/credentialtype/__tests__/PassphraseCredentialTypeTestCase.php',
|
'PassphraseCredentialTypeTestCase' => 'applications/passphrase/credentialtype/__tests__/PassphraseCredentialTypeTestCase.php',
|
||||||
'PassphraseCredentialViewController' => 'applications/passphrase/controller/PassphraseCredentialViewController.php',
|
'PassphraseCredentialViewController' => 'applications/passphrase/controller/PassphraseCredentialViewController.php',
|
||||||
'PassphraseDAO' => 'applications/passphrase/storage/PassphraseDAO.php',
|
'PassphraseDAO' => 'applications/passphrase/storage/PassphraseDAO.php',
|
||||||
|
'PassphraseDefaultEditCapability' => 'applications/passphrase/capability/PassphraseDefaultEditCapability.php',
|
||||||
|
'PassphraseDefaultViewCapability' => 'applications/passphrase/capability/PassphraseDefaultViewCapability.php',
|
||||||
'PassphraseNoteCredentialType' => 'applications/passphrase/credentialtype/PassphraseNoteCredentialType.php',
|
'PassphraseNoteCredentialType' => 'applications/passphrase/credentialtype/PassphraseNoteCredentialType.php',
|
||||||
'PassphrasePasswordCredentialType' => 'applications/passphrase/credentialtype/PassphrasePasswordCredentialType.php',
|
'PassphrasePasswordCredentialType' => 'applications/passphrase/credentialtype/PassphrasePasswordCredentialType.php',
|
||||||
'PassphrasePasswordKey' => 'applications/passphrase/keys/PassphrasePasswordKey.php',
|
'PassphrasePasswordKey' => 'applications/passphrase/keys/PassphrasePasswordKey.php',
|
||||||
@@ -3710,6 +3720,7 @@ phutil_register_library_map(array(
|
|||||||
'DifferentialDiffTableOfContentsView' => 'AphrontView',
|
'DifferentialDiffTableOfContentsView' => 'AphrontView',
|
||||||
'DifferentialDiffTestCase' => 'PhutilTestCase',
|
'DifferentialDiffTestCase' => 'PhutilTestCase',
|
||||||
'DifferentialDiffTransaction' => 'PhabricatorApplicationTransaction',
|
'DifferentialDiffTransaction' => 'PhabricatorApplicationTransaction',
|
||||||
|
'DifferentialDiffTransactionQuery' => 'PhabricatorApplicationTransactionQuery',
|
||||||
'DifferentialDiffViewController' => 'DifferentialController',
|
'DifferentialDiffViewController' => 'DifferentialController',
|
||||||
'DifferentialDoorkeeperRevisionFeedStoryPublisher' => 'DoorkeeperFeedStoryPublisher',
|
'DifferentialDoorkeeperRevisionFeedStoryPublisher' => 'DoorkeeperFeedStoryPublisher',
|
||||||
'DifferentialDraft' => 'DifferentialDAO',
|
'DifferentialDraft' => 'DifferentialDAO',
|
||||||
@@ -4241,6 +4252,9 @@ phutil_register_library_map(array(
|
|||||||
'FundInitiativeTransactionQuery' => 'PhabricatorApplicationTransactionQuery',
|
'FundInitiativeTransactionQuery' => 'PhabricatorApplicationTransactionQuery',
|
||||||
'FundInitiativeViewController' => 'FundController',
|
'FundInitiativeViewController' => 'FundController',
|
||||||
'FundSchemaSpec' => 'PhabricatorConfigSchemaSpec',
|
'FundSchemaSpec' => 'PhabricatorConfigSchemaSpec',
|
||||||
|
'HarbormasterArcLintBuildStepImplementation' => 'HarbormasterBuildStepImplementation',
|
||||||
|
'HarbormasterArcUnitBuildStepImplementation' => 'HarbormasterBuildStepImplementation',
|
||||||
|
'HarbormasterAutotargetsTestCase' => 'PhabricatorTestCase',
|
||||||
'HarbormasterBuild' => array(
|
'HarbormasterBuild' => array(
|
||||||
'HarbormasterDAO',
|
'HarbormasterDAO',
|
||||||
'PhabricatorApplicationTransactionInterface',
|
'PhabricatorApplicationTransactionInterface',
|
||||||
@@ -4248,19 +4262,19 @@ phutil_register_library_map(array(
|
|||||||
),
|
),
|
||||||
'HarbormasterBuildAbortedException' => 'Exception',
|
'HarbormasterBuildAbortedException' => 'Exception',
|
||||||
'HarbormasterBuildActionController' => 'HarbormasterController',
|
'HarbormasterBuildActionController' => 'HarbormasterController',
|
||||||
|
'HarbormasterBuildArcanistAutoplan' => 'HarbormasterBuildAutoplan',
|
||||||
'HarbormasterBuildArtifact' => array(
|
'HarbormasterBuildArtifact' => array(
|
||||||
'HarbormasterDAO',
|
'HarbormasterDAO',
|
||||||
'PhabricatorPolicyInterface',
|
'PhabricatorPolicyInterface',
|
||||||
),
|
),
|
||||||
'HarbormasterBuildArtifactQuery' => 'PhabricatorCursorPagedPolicyAwareQuery',
|
'HarbormasterBuildArtifactQuery' => 'PhabricatorCursorPagedPolicyAwareQuery',
|
||||||
|
'HarbormasterBuildAutoplan' => 'Phobject',
|
||||||
'HarbormasterBuildCommand' => 'HarbormasterDAO',
|
'HarbormasterBuildCommand' => 'HarbormasterDAO',
|
||||||
'HarbormasterBuildDependencyDatasource' => 'PhabricatorTypeaheadDatasource',
|
'HarbormasterBuildDependencyDatasource' => 'PhabricatorTypeaheadDatasource',
|
||||||
'HarbormasterBuildEngine' => 'Phobject',
|
'HarbormasterBuildEngine' => 'Phobject',
|
||||||
'HarbormasterBuildFailureException' => 'Exception',
|
'HarbormasterBuildFailureException' => 'Exception',
|
||||||
'HarbormasterBuildGraph' => 'AbstractDirectedGraph',
|
'HarbormasterBuildGraph' => 'AbstractDirectedGraph',
|
||||||
'HarbormasterBuildItem' => 'HarbormasterDAO',
|
'HarbormasterBuildLintMessage' => 'HarbormasterDAO',
|
||||||
'HarbormasterBuildItemPHIDType' => 'PhabricatorPHIDType',
|
|
||||||
'HarbormasterBuildItemQuery' => 'PhabricatorCursorPagedPolicyAwareQuery',
|
|
||||||
'HarbormasterBuildLog' => array(
|
'HarbormasterBuildLog' => array(
|
||||||
'HarbormasterDAO',
|
'HarbormasterDAO',
|
||||||
'PhabricatorPolicyInterface',
|
'PhabricatorPolicyInterface',
|
||||||
@@ -4314,6 +4328,7 @@ phutil_register_library_map(array(
|
|||||||
'HarbormasterBuildTransaction' => 'PhabricatorApplicationTransaction',
|
'HarbormasterBuildTransaction' => 'PhabricatorApplicationTransaction',
|
||||||
'HarbormasterBuildTransactionEditor' => 'PhabricatorApplicationTransactionEditor',
|
'HarbormasterBuildTransactionEditor' => 'PhabricatorApplicationTransactionEditor',
|
||||||
'HarbormasterBuildTransactionQuery' => 'PhabricatorApplicationTransactionQuery',
|
'HarbormasterBuildTransactionQuery' => 'PhabricatorApplicationTransactionQuery',
|
||||||
|
'HarbormasterBuildUnitMessage' => 'HarbormasterDAO',
|
||||||
'HarbormasterBuildViewController' => 'HarbormasterController',
|
'HarbormasterBuildViewController' => 'HarbormasterController',
|
||||||
'HarbormasterBuildWorker' => 'HarbormasterWorker',
|
'HarbormasterBuildWorker' => 'HarbormasterWorker',
|
||||||
'HarbormasterBuildable' => array(
|
'HarbormasterBuildable' => array(
|
||||||
@@ -4349,6 +4364,7 @@ phutil_register_library_map(array(
|
|||||||
'HarbormasterPlanRunController' => 'HarbormasterController',
|
'HarbormasterPlanRunController' => 'HarbormasterController',
|
||||||
'HarbormasterPlanViewController' => 'HarbormasterPlanController',
|
'HarbormasterPlanViewController' => 'HarbormasterPlanController',
|
||||||
'HarbormasterPublishFragmentBuildStepImplementation' => 'HarbormasterBuildStepImplementation',
|
'HarbormasterPublishFragmentBuildStepImplementation' => 'HarbormasterBuildStepImplementation',
|
||||||
|
'HarbormasterQueryAutotargetsConduitAPIMethod' => 'HarbormasterConduitAPIMethod',
|
||||||
'HarbormasterQueryBuildablesConduitAPIMethod' => 'HarbormasterConduitAPIMethod',
|
'HarbormasterQueryBuildablesConduitAPIMethod' => 'HarbormasterConduitAPIMethod',
|
||||||
'HarbormasterQueryBuildsConduitAPIMethod' => 'HarbormasterConduitAPIMethod',
|
'HarbormasterQueryBuildsConduitAPIMethod' => 'HarbormasterConduitAPIMethod',
|
||||||
'HarbormasterRemarkupRule' => 'PhabricatorObjectRemarkupRule',
|
'HarbormasterRemarkupRule' => 'PhabricatorObjectRemarkupRule',
|
||||||
@@ -4359,6 +4375,7 @@ phutil_register_library_map(array(
|
|||||||
'HarbormasterStepAddController' => 'HarbormasterController',
|
'HarbormasterStepAddController' => 'HarbormasterController',
|
||||||
'HarbormasterStepDeleteController' => 'HarbormasterController',
|
'HarbormasterStepDeleteController' => 'HarbormasterController',
|
||||||
'HarbormasterStepEditController' => 'HarbormasterController',
|
'HarbormasterStepEditController' => 'HarbormasterController',
|
||||||
|
'HarbormasterTargetEngine' => 'Phobject',
|
||||||
'HarbormasterTargetWorker' => 'HarbormasterWorker',
|
'HarbormasterTargetWorker' => 'HarbormasterWorker',
|
||||||
'HarbormasterThrowExceptionBuildStep' => 'HarbormasterBuildStepImplementation',
|
'HarbormasterThrowExceptionBuildStep' => 'HarbormasterBuildStepImplementation',
|
||||||
'HarbormasterUIEventListener' => 'PhabricatorEventListener',
|
'HarbormasterUIEventListener' => 'PhabricatorEventListener',
|
||||||
@@ -4768,7 +4785,9 @@ phutil_register_library_map(array(
|
|||||||
'PhabricatorApplicationTransactionInterface',
|
'PhabricatorApplicationTransactionInterface',
|
||||||
'PhabricatorPolicyInterface',
|
'PhabricatorPolicyInterface',
|
||||||
'PhabricatorDestructibleInterface',
|
'PhabricatorDestructibleInterface',
|
||||||
|
'PhabricatorSpacesInterface',
|
||||||
),
|
),
|
||||||
|
'PassphraseCredentialAuthorPolicyRule' => 'PhabricatorPolicyRule',
|
||||||
'PassphraseCredentialConduitController' => 'PassphraseController',
|
'PassphraseCredentialConduitController' => 'PassphraseController',
|
||||||
'PassphraseCredentialControl' => 'AphrontFormControl',
|
'PassphraseCredentialControl' => 'AphrontFormControl',
|
||||||
'PassphraseCredentialCreateController' => 'PassphraseController',
|
'PassphraseCredentialCreateController' => 'PassphraseController',
|
||||||
@@ -4788,6 +4807,8 @@ phutil_register_library_map(array(
|
|||||||
'PassphraseCredentialTypeTestCase' => 'PhabricatorTestCase',
|
'PassphraseCredentialTypeTestCase' => 'PhabricatorTestCase',
|
||||||
'PassphraseCredentialViewController' => 'PassphraseController',
|
'PassphraseCredentialViewController' => 'PassphraseController',
|
||||||
'PassphraseDAO' => 'PhabricatorLiskDAO',
|
'PassphraseDAO' => 'PhabricatorLiskDAO',
|
||||||
|
'PassphraseDefaultEditCapability' => 'PhabricatorPolicyCapability',
|
||||||
|
'PassphraseDefaultViewCapability' => 'PhabricatorPolicyCapability',
|
||||||
'PassphraseNoteCredentialType' => 'PassphraseCredentialType',
|
'PassphraseNoteCredentialType' => 'PassphraseCredentialType',
|
||||||
'PassphrasePasswordCredentialType' => 'PassphraseCredentialType',
|
'PassphrasePasswordCredentialType' => 'PassphraseCredentialType',
|
||||||
'PassphrasePasswordKey' => 'PassphraseAbstractKey',
|
'PassphrasePasswordKey' => 'PassphraseAbstractKey',
|
||||||
|
|||||||
@@ -606,6 +606,23 @@ abstract class PhabricatorApplication
|
|||||||
return idx($spec, 'template');
|
return idx($spec, 'template');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
final public function getDefaultObjectTypePolicyMap() {
|
||||||
|
$map = array();
|
||||||
|
|
||||||
|
foreach ($this->getCustomCapabilities() as $capability => $spec) {
|
||||||
|
if (empty($spec['template'])) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (empty($spec['capability'])) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
$default = $this->getPolicy($capability);
|
||||||
|
$map[$spec['template']][$spec['capability']] = $default;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $map;
|
||||||
|
}
|
||||||
|
|
||||||
public function getApplicationSearchDocumentTypes() {
|
public function getApplicationSearchDocumentTypes() {
|
||||||
return array();
|
return array();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -53,6 +53,7 @@ final class PhabricatorCountdownApplication extends PhabricatorApplication {
|
|||||||
PhabricatorCountdownDefaultViewCapability::CAPABILITY => array(
|
PhabricatorCountdownDefaultViewCapability::CAPABILITY => array(
|
||||||
'caption' => pht('Default view policy for new countdowns.'),
|
'caption' => pht('Default view policy for new countdowns.'),
|
||||||
'template' => PhabricatorCountdownCountdownPHIDType::TYPECONST,
|
'template' => PhabricatorCountdownCountdownPHIDType::TYPECONST,
|
||||||
|
'capability' => PhabricatorPolicyCapability::CAN_VIEW,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -187,6 +187,7 @@ final class PhabricatorDifferentialApplication extends PhabricatorApplication {
|
|||||||
DifferentialDefaultViewCapability::CAPABILITY => array(
|
DifferentialDefaultViewCapability::CAPABILITY => array(
|
||||||
'caption' => pht('Default view policy for newly created revisions.'),
|
'caption' => pht('Default view policy for newly created revisions.'),
|
||||||
'template' => DifferentialRevisionPHIDType::TYPECONST,
|
'template' => DifferentialRevisionPHIDType::TYPECONST,
|
||||||
|
'capability' => PhabricatorPolicyCapability::CAN_VIEW,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,10 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
final class DifferentialDiffTransactionQuery
|
||||||
|
extends PhabricatorApplicationTransactionQuery {
|
||||||
|
|
||||||
|
public function getTemplateApplicationTransaction() {
|
||||||
|
return new DifferentialDiffTransaction();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -381,14 +381,16 @@ final class DifferentialDiff
|
|||||||
$results = array();
|
$results = array();
|
||||||
|
|
||||||
$results['buildable.diff'] = $this->getID();
|
$results['buildable.diff'] = $this->getID();
|
||||||
$revision = $this->getRevision();
|
if ($this->revisionID) {
|
||||||
$results['buildable.revision'] = $revision->getID();
|
$revision = $this->getRevision();
|
||||||
$repo = $revision->getRepository();
|
$results['buildable.revision'] = $revision->getID();
|
||||||
|
$repo = $revision->getRepository();
|
||||||
|
|
||||||
if ($repo) {
|
if ($repo) {
|
||||||
$results['repository.callsign'] = $repo->getCallsign();
|
$results['repository.callsign'] = $repo->getCallsign();
|
||||||
$results['repository.vcs'] = $repo->getVersionControlSystem();
|
$results['repository.vcs'] = $repo->getVersionControlSystem();
|
||||||
$results['repository.uri'] = $repo->getPublicCloneURI();
|
$results['repository.uri'] = $repo->getPublicCloneURI();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return $results;
|
return $results;
|
||||||
|
|||||||
@@ -142,10 +142,12 @@ final class PhabricatorDiffusionApplication extends PhabricatorApplication {
|
|||||||
return array(
|
return array(
|
||||||
DiffusionDefaultViewCapability::CAPABILITY => array(
|
DiffusionDefaultViewCapability::CAPABILITY => array(
|
||||||
'template' => PhabricatorRepositoryRepositoryPHIDType::TYPECONST,
|
'template' => PhabricatorRepositoryRepositoryPHIDType::TYPECONST,
|
||||||
|
'capability' => PhabricatorPolicyCapability::CAN_VIEW,
|
||||||
),
|
),
|
||||||
DiffusionDefaultEditCapability::CAPABILITY => array(
|
DiffusionDefaultEditCapability::CAPABILITY => array(
|
||||||
'default' => PhabricatorPolicies::POLICY_ADMIN,
|
'default' => PhabricatorPolicies::POLICY_ADMIN,
|
||||||
'template' => PhabricatorRepositoryRepositoryPHIDType::TYPECONST,
|
'template' => PhabricatorRepositoryRepositoryPHIDType::TYPECONST,
|
||||||
|
'capability' => PhabricatorPolicyCapability::CAN_EDIT,
|
||||||
),
|
),
|
||||||
DiffusionDefaultPushCapability::CAPABILITY => array(
|
DiffusionDefaultPushCapability::CAPABILITY => array(
|
||||||
'template' => PhabricatorRepositoryRepositoryPHIDType::TYPECONST,
|
'template' => PhabricatorRepositoryRepositoryPHIDType::TYPECONST,
|
||||||
|
|||||||
@@ -57,10 +57,12 @@ final class PhabricatorDivinerApplication extends PhabricatorApplication {
|
|||||||
return array(
|
return array(
|
||||||
DivinerDefaultViewCapability::CAPABILITY => array(
|
DivinerDefaultViewCapability::CAPABILITY => array(
|
||||||
'template' => DivinerBookPHIDType::TYPECONST,
|
'template' => DivinerBookPHIDType::TYPECONST,
|
||||||
|
'capability' => PhabricatorPolicyCapability::CAN_VIEW,
|
||||||
),
|
),
|
||||||
DivinerDefaultEditCapability::CAPABILITY => array(
|
DivinerDefaultEditCapability::CAPABILITY => array(
|
||||||
'default' => PhabricatorPolicies::POLICY_ADMIN,
|
'default' => PhabricatorPolicies::POLICY_ADMIN,
|
||||||
'template' => DivinerBookPHIDType::TYPECONST,
|
'template' => DivinerBookPHIDType::TYPECONST,
|
||||||
|
'capability' => PhabricatorPolicyCapability::CAN_EDIT,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -74,10 +74,12 @@ final class PhabricatorDrydockApplication extends PhabricatorApplication {
|
|||||||
return array(
|
return array(
|
||||||
DrydockDefaultViewCapability::CAPABILITY => array(
|
DrydockDefaultViewCapability::CAPABILITY => array(
|
||||||
'template' => DrydockBlueprintPHIDType::TYPECONST,
|
'template' => DrydockBlueprintPHIDType::TYPECONST,
|
||||||
|
'capability' => PhabricatorPolicyCapability::CAN_VIEW,
|
||||||
),
|
),
|
||||||
DrydockDefaultEditCapability::CAPABILITY => array(
|
DrydockDefaultEditCapability::CAPABILITY => array(
|
||||||
'default' => PhabricatorPolicies::POLICY_ADMIN,
|
'default' => PhabricatorPolicies::POLICY_ADMIN,
|
||||||
'template' => DrydockBlueprintPHIDType::TYPECONST,
|
'template' => DrydockBlueprintPHIDType::TYPECONST,
|
||||||
|
'capability' => PhabricatorPolicyCapability::CAN_EDIT,
|
||||||
),
|
),
|
||||||
DrydockCreateBlueprintsCapability::CAPABILITY => array(
|
DrydockCreateBlueprintsCapability::CAPABILITY => array(
|
||||||
'default' => PhabricatorPolicies::POLICY_ADMIN,
|
'default' => PhabricatorPolicies::POLICY_ADMIN,
|
||||||
|
|||||||
@@ -61,6 +61,7 @@ final class PhabricatorFilesApplication extends PhabricatorApplication {
|
|||||||
FilesDefaultViewCapability::CAPABILITY => array(
|
FilesDefaultViewCapability::CAPABILITY => array(
|
||||||
'caption' => pht('Default view policy for newly created files.'),
|
'caption' => pht('Default view policy for newly created files.'),
|
||||||
'template' => PhabricatorFileFilePHIDType::TYPECONST,
|
'template' => PhabricatorFileFilePHIDType::TYPECONST,
|
||||||
|
'capability' => PhabricatorPolicyCapability::CAN_VIEW,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,61 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
final class HarbormasterAutotargetsTestCase extends PhabricatorTestCase {
|
||||||
|
|
||||||
|
protected function getPhabricatorTestCaseConfiguration() {
|
||||||
|
return array(
|
||||||
|
self::PHABRICATOR_TESTCONFIG_BUILD_STORAGE_FIXTURES => true,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testGenerateHarbormasterAutotargets() {
|
||||||
|
$viewer = $this->generateNewTestUser();
|
||||||
|
|
||||||
|
$raw_diff = <<<EODIFF
|
||||||
|
diff --git a/fruit b/fruit
|
||||||
|
new file mode 100644
|
||||||
|
index 0000000..1c0f49d
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/fruit
|
||||||
|
@@ -0,0 +1,2 @@
|
||||||
|
+apal
|
||||||
|
+banan
|
||||||
|
EODIFF;
|
||||||
|
|
||||||
|
$parser = new ArcanistDiffParser();
|
||||||
|
$changes = $parser->parseDiff($raw_diff);
|
||||||
|
|
||||||
|
$diff = DifferentialDiff::newFromRawChanges($viewer, $changes)
|
||||||
|
->setLintStatus(DifferentialLintStatus::LINT_AUTO_SKIP)
|
||||||
|
->setUnitStatus(DifferentialUnitStatus::UNIT_AUTO_SKIP)
|
||||||
|
->attachRevision(null)
|
||||||
|
->save();
|
||||||
|
|
||||||
|
$params = array(
|
||||||
|
'objectPHID' => $diff->getPHID(),
|
||||||
|
'targetKeys' => array(
|
||||||
|
HarbormasterArcLintBuildStepImplementation::STEPKEY,
|
||||||
|
HarbormasterArcUnitBuildStepImplementation::STEPKEY,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
// Creation of autotargets should work from an empty state.
|
||||||
|
$result = id(new ConduitCall('harbormaster.queryautotargets', $params))
|
||||||
|
->setUser($viewer)
|
||||||
|
->execute();
|
||||||
|
|
||||||
|
$targets = idx($result, 'targetMap');
|
||||||
|
foreach ($params['targetKeys'] as $target_key) {
|
||||||
|
$this->assertTrue((bool)$result['targetMap'][$target_key]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Querying the same autotargets again should produce the same results,
|
||||||
|
// not make new ones.
|
||||||
|
$retry = id(new ConduitCall('harbormaster.queryautotargets', $params))
|
||||||
|
->setUser($viewer)
|
||||||
|
->execute();
|
||||||
|
|
||||||
|
$this->assertEqual($result, $retry);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
final class HarbormasterBuildArcanistAutoplan
|
||||||
|
extends HarbormasterBuildAutoplan {
|
||||||
|
|
||||||
|
const PLANKEY = 'arcanist';
|
||||||
|
|
||||||
|
public function getAutoplanPlanKey() {
|
||||||
|
return self::PLANKEY;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getAutoplanName() {
|
||||||
|
return pht('Arcanist Client Results');
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,44 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
abstract class HarbormasterBuildAutoplan extends Phobject {
|
||||||
|
|
||||||
|
abstract public function getAutoplanPlanKey();
|
||||||
|
abstract public function getAutoplanName();
|
||||||
|
|
||||||
|
public static function getAutoplan($key) {
|
||||||
|
return idx(self::getAllAutoplans(), $key);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function getAllAutoplans() {
|
||||||
|
static $plans;
|
||||||
|
|
||||||
|
if ($plans === null) {
|
||||||
|
$objects = id(new PhutilSymbolLoader())
|
||||||
|
->setAncestorClass(__CLASS__)
|
||||||
|
->loadObjects();
|
||||||
|
|
||||||
|
$map = array();
|
||||||
|
foreach ($objects as $object) {
|
||||||
|
$key = $object->getAutoplanPlanKey();
|
||||||
|
if (!empty($map[$key])) {
|
||||||
|
$other = $map[$key];
|
||||||
|
throw new Exception(
|
||||||
|
pht(
|
||||||
|
'Two build autoplans (of classes "%s" and "%s") define the same '.
|
||||||
|
'key ("%s"). Each autoplan must have a unique key.',
|
||||||
|
get_class($other),
|
||||||
|
get_class($object),
|
||||||
|
$key));
|
||||||
|
}
|
||||||
|
$map[$key] = $object;
|
||||||
|
}
|
||||||
|
|
||||||
|
ksort($map);
|
||||||
|
|
||||||
|
$plans = $map;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $plans;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,76 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
final class HarbormasterQueryAutotargetsConduitAPIMethod
|
||||||
|
extends HarbormasterConduitAPIMethod {
|
||||||
|
|
||||||
|
public function getAPIMethodName() {
|
||||||
|
return 'harbormaster.queryautotargets';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getMethodDescription() {
|
||||||
|
return pht('Load or create build autotargets.');
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function defineParamTypes() {
|
||||||
|
return array(
|
||||||
|
'objectPHID' => 'phid',
|
||||||
|
'targetKeys' => 'list<string>',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function defineReturnType() {
|
||||||
|
return 'map<string, phid>';
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function execute(ConduitAPIRequest $request) {
|
||||||
|
$viewer = $request->getUser();
|
||||||
|
|
||||||
|
$phid = $request->getValue('objectPHID');
|
||||||
|
|
||||||
|
// NOTE: We use withNames() to let monograms like "D123" work, which makes
|
||||||
|
// this a little easier to test. Real PHIDs will still work as expected.
|
||||||
|
|
||||||
|
$object = id(new PhabricatorObjectQuery())
|
||||||
|
->setViewer($viewer)
|
||||||
|
->withNames(array($phid))
|
||||||
|
->executeOne();
|
||||||
|
if (!$object) {
|
||||||
|
throw new Exception(
|
||||||
|
pht(
|
||||||
|
'No such object "%s" exists.',
|
||||||
|
$phid));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!($object instanceof HarbormasterBuildableInterface)) {
|
||||||
|
throw new Exception(
|
||||||
|
pht(
|
||||||
|
'Object "%s" does not implement interface "%s". Autotargets may '.
|
||||||
|
'only be queried for buildable objects.',
|
||||||
|
$phid,
|
||||||
|
'HarbormasterBuildableInterface'));
|
||||||
|
}
|
||||||
|
|
||||||
|
$autotargets = $request->getValue('targetKeys', array());
|
||||||
|
|
||||||
|
if ($autotargets) {
|
||||||
|
$targets = id(new HarbormasterTargetEngine())
|
||||||
|
->setViewer($viewer)
|
||||||
|
->setObject($object)
|
||||||
|
->setAutoTargetKeys($autotargets)
|
||||||
|
->buildTargets();
|
||||||
|
} else {
|
||||||
|
$targets = array();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reorder the results according to the request order so we can make test
|
||||||
|
// assertions that subsequent calls return the same results.
|
||||||
|
|
||||||
|
$map = mpull($targets, 'getPHID');
|
||||||
|
$map = array_select_keys($map, $autotargets);
|
||||||
|
|
||||||
|
return array(
|
||||||
|
'targetMap' => $map,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -2,21 +2,4 @@
|
|||||||
|
|
||||||
abstract class HarbormasterController extends PhabricatorController {
|
abstract class HarbormasterController extends PhabricatorController {
|
||||||
|
|
||||||
protected function buildApplicationCrumbs() {
|
|
||||||
$crumbs = parent::buildApplicationCrumbs();
|
|
||||||
|
|
||||||
$can_create = $this->hasApplicationCapability(
|
|
||||||
HarbormasterManagePlansCapability::CAPABILITY);
|
|
||||||
|
|
||||||
$crumbs->addAction(
|
|
||||||
id(new PHUIListItemView())
|
|
||||||
->setName(pht('New Build Plan'))
|
|
||||||
->setHref($this->getApplicationURI('plan/edit/'))
|
|
||||||
->setDisabled(!$can_create)
|
|
||||||
->setWorkflow(!$can_create)
|
|
||||||
->setIcon('fa-plus-square'));
|
|
||||||
|
|
||||||
return $crumbs;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,22 +3,20 @@
|
|||||||
final class HarbormasterPlanDisableController
|
final class HarbormasterPlanDisableController
|
||||||
extends HarbormasterPlanController {
|
extends HarbormasterPlanController {
|
||||||
|
|
||||||
private $id;
|
public function handleRequest(AphrontRequest $request) {
|
||||||
|
$viewer = $this->getViewer();
|
||||||
public function willProcessRequest(array $data) {
|
|
||||||
$this->id = $data['id'];
|
|
||||||
}
|
|
||||||
|
|
||||||
public function processRequest() {
|
|
||||||
$request = $this->getRequest();
|
|
||||||
$viewer = $request->getUser();
|
|
||||||
|
|
||||||
$this->requireApplicationCapability(
|
$this->requireApplicationCapability(
|
||||||
HarbormasterManagePlansCapability::CAPABILITY);
|
HarbormasterManagePlansCapability::CAPABILITY);
|
||||||
|
|
||||||
$plan = id(new HarbormasterBuildPlanQuery())
|
$plan = id(new HarbormasterBuildPlanQuery())
|
||||||
->setViewer($viewer)
|
->setViewer($viewer)
|
||||||
->withIDs(array($this->id))
|
->withIDs(array($request->getURIData('id')))
|
||||||
|
->requireCapabilities(
|
||||||
|
array(
|
||||||
|
PhabricatorPolicyCapability::CAN_VIEW,
|
||||||
|
PhabricatorPolicyCapability::CAN_EDIT,
|
||||||
|
))
|
||||||
->executeOne();
|
->executeOne();
|
||||||
if (!$plan) {
|
if (!$plan) {
|
||||||
return new Aphront404Response();
|
return new Aphront404Response();
|
||||||
@@ -63,14 +61,11 @@ final class HarbormasterPlanDisableController
|
|||||||
$button = pht('Disable Plan');
|
$button = pht('Disable Plan');
|
||||||
}
|
}
|
||||||
|
|
||||||
$dialog = id(new AphrontDialogView())
|
return $this->newDialog()
|
||||||
->setUser($viewer)
|
|
||||||
->setTitle($title)
|
->setTitle($title)
|
||||||
->appendChild($body)
|
->appendChild($body)
|
||||||
->addSubmitButton($button)
|
->addSubmitButton($button)
|
||||||
->addCancelButton($plan_uri);
|
->addCancelButton($plan_uri);
|
||||||
|
|
||||||
return id(new AphrontDialogResponse())->setDialog($dialog);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,23 +2,22 @@
|
|||||||
|
|
||||||
final class HarbormasterPlanEditController extends HarbormasterPlanController {
|
final class HarbormasterPlanEditController extends HarbormasterPlanController {
|
||||||
|
|
||||||
private $id;
|
public function handleRequest(AphrontRequest $request) {
|
||||||
|
$viewer = $this->getViewer();
|
||||||
public function willProcessRequest(array $data) {
|
|
||||||
$this->id = idx($data, 'id');
|
|
||||||
}
|
|
||||||
|
|
||||||
public function processRequest() {
|
|
||||||
$request = $this->getRequest();
|
|
||||||
$viewer = $request->getUser();
|
|
||||||
|
|
||||||
$this->requireApplicationCapability(
|
$this->requireApplicationCapability(
|
||||||
HarbormasterManagePlansCapability::CAPABILITY);
|
HarbormasterManagePlansCapability::CAPABILITY);
|
||||||
|
|
||||||
if ($this->id) {
|
$id = $request->getURIData('id');
|
||||||
|
if ($id) {
|
||||||
$plan = id(new HarbormasterBuildPlanQuery())
|
$plan = id(new HarbormasterBuildPlanQuery())
|
||||||
->setViewer($viewer)
|
->setViewer($viewer)
|
||||||
->withIDs(array($this->id))
|
->withIDs(array($id))
|
||||||
|
->requireCapabilities(
|
||||||
|
array(
|
||||||
|
PhabricatorPolicyCapability::CAN_VIEW,
|
||||||
|
PhabricatorPolicyCapability::CAN_EDIT,
|
||||||
|
))
|
||||||
->executeOne();
|
->executeOne();
|
||||||
if (!$plan) {
|
if (!$plan) {
|
||||||
return new Aphront404Response();
|
return new Aphront404Response();
|
||||||
@@ -43,6 +42,7 @@ final class HarbormasterPlanEditController extends HarbormasterPlanController {
|
|||||||
|
|
||||||
$editor = id(new HarbormasterBuildPlanEditor())
|
$editor = id(new HarbormasterBuildPlanEditor())
|
||||||
->setActor($viewer)
|
->setActor($viewer)
|
||||||
|
->setContinueOnNoEffect(true)
|
||||||
->setContentSourceFromRequest($request);
|
->setContentSourceFromRequest($request);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -2,19 +2,13 @@
|
|||||||
|
|
||||||
final class HarbormasterPlanListController extends HarbormasterPlanController {
|
final class HarbormasterPlanListController extends HarbormasterPlanController {
|
||||||
|
|
||||||
private $queryKey;
|
|
||||||
|
|
||||||
public function shouldAllowPublic() {
|
public function shouldAllowPublic() {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function willProcessRequest(array $data) {
|
public function handleRequest(AphrontRequest $request) {
|
||||||
$this->queryKey = idx($data, 'queryKey');
|
|
||||||
}
|
|
||||||
|
|
||||||
public function processRequest() {
|
|
||||||
$controller = id(new PhabricatorApplicationSearchController())
|
$controller = id(new PhabricatorApplicationSearchController())
|
||||||
->setQueryKey($this->queryKey)
|
->setQueryKey($request->getURIData('queryKey'))
|
||||||
->setSearchEngine(new HarbormasterBuildPlanSearchEngine())
|
->setSearchEngine(new HarbormasterBuildPlanSearchEngine())
|
||||||
->setNavigation($this->buildSideNavView());
|
->setNavigation($this->buildSideNavView());
|
||||||
|
|
||||||
@@ -44,4 +38,22 @@ final class HarbormasterPlanListController extends HarbormasterPlanController {
|
|||||||
return $this->buildSideNavView(true)->getMenu();
|
return $this->buildSideNavView(true)->getMenu();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected function buildApplicationCrumbs() {
|
||||||
|
$crumbs = parent::buildApplicationCrumbs();
|
||||||
|
|
||||||
|
$can_create = $this->hasApplicationCapability(
|
||||||
|
HarbormasterManagePlansCapability::CAPABILITY);
|
||||||
|
|
||||||
|
$crumbs->addAction(
|
||||||
|
id(new PHUIListItemView())
|
||||||
|
->setName(pht('New Build Plan'))
|
||||||
|
->setHref($this->getApplicationURI('plan/edit/'))
|
||||||
|
->setDisabled(!$can_create)
|
||||||
|
->setWorkflow(!$can_create)
|
||||||
|
->setIcon('fa-plus-square'));
|
||||||
|
|
||||||
|
return $crumbs;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,20 +2,18 @@
|
|||||||
|
|
||||||
final class HarbormasterPlanRunController extends HarbormasterController {
|
final class HarbormasterPlanRunController extends HarbormasterController {
|
||||||
|
|
||||||
private $id;
|
public function handleRequest(AphrontRequest $request) {
|
||||||
|
$viewer = $this->getViewer();
|
||||||
public function willProcessRequest(array $data) {
|
|
||||||
$this->id = $data['id'];
|
|
||||||
}
|
|
||||||
|
|
||||||
public function processRequest() {
|
|
||||||
$request = $this->getRequest();
|
|
||||||
$viewer = $request->getUser();
|
|
||||||
|
|
||||||
$this->requireApplicationCapability(
|
$this->requireApplicationCapability(
|
||||||
HarbormasterManagePlansCapability::CAPABILITY);
|
HarbormasterManagePlansCapability::CAPABILITY);
|
||||||
|
|
||||||
$plan_id = $this->id;
|
$plan_id = $request->getURIData('id');
|
||||||
|
|
||||||
|
// NOTE: At least for now, this only requires the "Can Manage Plans"
|
||||||
|
// capability, not the "Can Edit" capability. Possibly it should have
|
||||||
|
// a more stringent requirement, though.
|
||||||
|
|
||||||
$plan = id(new HarbormasterBuildPlanQuery())
|
$plan = id(new HarbormasterBuildPlanQuery())
|
||||||
->setViewer($viewer)
|
->setViewer($viewer)
|
||||||
->withIDs(array($plan_id))
|
->withIDs(array($plan_id))
|
||||||
@@ -87,15 +85,12 @@ final class HarbormasterPlanRunController extends HarbormasterController {
|
|||||||
->setError($e_name)
|
->setError($e_name)
|
||||||
->setValue($v_name));
|
->setValue($v_name));
|
||||||
|
|
||||||
$dialog = id(new AphrontDialogView())
|
return $this->newDialog()
|
||||||
->setWidth(AphrontDialogView::WIDTH_FULL)
|
->setWidth(AphrontDialogView::WIDTH_FULL)
|
||||||
->setUser($viewer)
|
|
||||||
->setTitle($title)
|
->setTitle($title)
|
||||||
->appendChild($form)
|
->appendChild($form)
|
||||||
->addCancelButton($cancel_uri)
|
->addCancelButton($cancel_uri)
|
||||||
->addSubmitButton($save_button);
|
->addSubmitButton($save_button);
|
||||||
|
|
||||||
return id(new AphrontDialogResponse())->setDialog($dialog);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,17 +2,10 @@
|
|||||||
|
|
||||||
final class HarbormasterPlanViewController extends HarbormasterPlanController {
|
final class HarbormasterPlanViewController extends HarbormasterPlanController {
|
||||||
|
|
||||||
private $id;
|
public function handleRequest(AphrontRequest $request) {
|
||||||
|
$viewer = $this->getviewer();
|
||||||
|
|
||||||
public function willProcessRequest(array $data) {
|
$id = $request->getURIData('id');
|
||||||
$this->id = $data['id'];
|
|
||||||
}
|
|
||||||
|
|
||||||
public function processRequest() {
|
|
||||||
$request = $this->getRequest();
|
|
||||||
$viewer = $request->getUser();
|
|
||||||
|
|
||||||
$id = $this->id;
|
|
||||||
|
|
||||||
$plan = id(new HarbormasterBuildPlanQuery())
|
$plan = id(new HarbormasterBuildPlanQuery())
|
||||||
->setViewer($viewer)
|
->setViewer($viewer)
|
||||||
@@ -79,11 +72,9 @@ final class HarbormasterPlanViewController extends HarbormasterPlanController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private function buildStepList(HarbormasterBuildPlan $plan) {
|
private function buildStepList(HarbormasterBuildPlan $plan) {
|
||||||
$request = $this->getRequest();
|
$viewer = $this->getViewer();
|
||||||
$viewer = $request->getUser();
|
|
||||||
|
|
||||||
$run_order =
|
$run_order = HarbormasterBuildGraph::determineDependencyExecution($plan);
|
||||||
HarbormasterBuildGraph::determineDependencyExecution($plan);
|
|
||||||
|
|
||||||
$steps = id(new HarbormasterBuildStepQuery())
|
$steps = id(new HarbormasterBuildStepQuery())
|
||||||
->setViewer($viewer)
|
->setViewer($viewer)
|
||||||
@@ -91,9 +82,16 @@ final class HarbormasterPlanViewController extends HarbormasterPlanController {
|
|||||||
->execute();
|
->execute();
|
||||||
$steps = mpull($steps, null, 'getPHID');
|
$steps = mpull($steps, null, 'getPHID');
|
||||||
|
|
||||||
$can_edit = $this->hasApplicationCapability(
|
$has_manage = $this->hasApplicationCapability(
|
||||||
HarbormasterManagePlansCapability::CAPABILITY);
|
HarbormasterManagePlansCapability::CAPABILITY);
|
||||||
|
|
||||||
|
$has_edit = PhabricatorPolicyFilter::hasCapability(
|
||||||
|
$viewer,
|
||||||
|
$plan,
|
||||||
|
PhabricatorPolicyCapability::CAN_EDIT);
|
||||||
|
|
||||||
|
$can_edit = ($has_manage && $has_edit);
|
||||||
|
|
||||||
$step_list = id(new PHUIObjectItemListView())
|
$step_list = id(new PHUIObjectItemListView())
|
||||||
->setUser($viewer)
|
->setUser($viewer)
|
||||||
->setNoDataString(
|
->setNoDataString(
|
||||||
@@ -222,12 +220,32 @@ final class HarbormasterPlanViewController extends HarbormasterPlanController {
|
|||||||
$step_list->addItem($item);
|
$step_list->addItem($item);
|
||||||
}
|
}
|
||||||
|
|
||||||
return array($step_list, $has_any_conflicts, $is_deadlocking);
|
$step_list->setFlush(true);
|
||||||
|
|
||||||
|
$plan_id = $plan->getID();
|
||||||
|
|
||||||
|
$header = id(new PHUIHeaderView())
|
||||||
|
->setHeader(pht('Build Steps'))
|
||||||
|
->addActionLink(
|
||||||
|
id(new PHUIButtonView())
|
||||||
|
->setText(pht('Add Build Step'))
|
||||||
|
->setHref($this->getApplicationURI("step/add/{$plan_id}/"))
|
||||||
|
->setTag('a')
|
||||||
|
->setIcon(
|
||||||
|
id(new PHUIIconView())
|
||||||
|
->setIconFont('fa-plus'))
|
||||||
|
->setDisabled(!$can_edit)
|
||||||
|
->setWorkflow(true));
|
||||||
|
|
||||||
|
$step_box = id(new PHUIObjectBoxView())
|
||||||
|
->setHeader($header)
|
||||||
|
->appendChild($step_list);
|
||||||
|
|
||||||
|
return array($step_box, $has_any_conflicts, $is_deadlocking);
|
||||||
}
|
}
|
||||||
|
|
||||||
private function buildActionList(HarbormasterBuildPlan $plan) {
|
private function buildActionList(HarbormasterBuildPlan $plan) {
|
||||||
$request = $this->getRequest();
|
$viewer = $this->getViewer();
|
||||||
$viewer = $request->getUser();
|
|
||||||
$id = $plan->getID();
|
$id = $plan->getID();
|
||||||
|
|
||||||
$list = id(new PhabricatorActionListView())
|
$list = id(new PhabricatorActionListView())
|
||||||
@@ -235,9 +253,16 @@ final class HarbormasterPlanViewController extends HarbormasterPlanController {
|
|||||||
->setObject($plan)
|
->setObject($plan)
|
||||||
->setObjectURI($this->getApplicationURI("plan/{$id}/"));
|
->setObjectURI($this->getApplicationURI("plan/{$id}/"));
|
||||||
|
|
||||||
$can_edit = $this->hasApplicationCapability(
|
$has_manage = $this->hasApplicationCapability(
|
||||||
HarbormasterManagePlansCapability::CAPABILITY);
|
HarbormasterManagePlansCapability::CAPABILITY);
|
||||||
|
|
||||||
|
$has_edit = PhabricatorPolicyFilter::hasCapability(
|
||||||
|
$viewer,
|
||||||
|
$plan,
|
||||||
|
PhabricatorPolicyCapability::CAN_EDIT);
|
||||||
|
|
||||||
|
$can_edit = ($has_manage && $has_edit);
|
||||||
|
|
||||||
$list->addAction(
|
$list->addAction(
|
||||||
id(new PhabricatorActionView())
|
id(new PhabricatorActionView())
|
||||||
->setName(pht('Edit Plan'))
|
->setName(pht('Edit Plan'))
|
||||||
@@ -264,20 +289,12 @@ final class HarbormasterPlanViewController extends HarbormasterPlanController {
|
|||||||
->setIcon('fa-ban'));
|
->setIcon('fa-ban'));
|
||||||
}
|
}
|
||||||
|
|
||||||
$list->addAction(
|
|
||||||
id(new PhabricatorActionView())
|
|
||||||
->setName(pht('Add Build Step'))
|
|
||||||
->setHref($this->getApplicationURI("step/add/{$id}/"))
|
|
||||||
->setWorkflow(true)
|
|
||||||
->setDisabled(!$can_edit)
|
|
||||||
->setIcon('fa-plus'));
|
|
||||||
|
|
||||||
$list->addAction(
|
$list->addAction(
|
||||||
id(new PhabricatorActionView())
|
id(new PhabricatorActionView())
|
||||||
->setName(pht('Run Plan Manually'))
|
->setName(pht('Run Plan Manually'))
|
||||||
->setHref($this->getApplicationURI("plan/run/{$id}/"))
|
->setHref($this->getApplicationURI("plan/run/{$id}/"))
|
||||||
->setWorkflow(true)
|
->setWorkflow(true)
|
||||||
->setDisabled(!$can_edit)
|
->setDisabled(!$has_manage)
|
||||||
->setIcon('fa-play-circle'));
|
->setIcon('fa-play-circle'));
|
||||||
|
|
||||||
return $list;
|
return $list;
|
||||||
|
|||||||
@@ -2,22 +2,20 @@
|
|||||||
|
|
||||||
final class HarbormasterStepAddController extends HarbormasterController {
|
final class HarbormasterStepAddController extends HarbormasterController {
|
||||||
|
|
||||||
private $id;
|
public function handleRequest(AphrontRequest $request) {
|
||||||
|
$viewer = $this->getViewer();
|
||||||
public function willProcessRequest(array $data) {
|
|
||||||
$this->id = $data['id'];
|
|
||||||
}
|
|
||||||
|
|
||||||
public function processRequest() {
|
|
||||||
$request = $this->getRequest();
|
|
||||||
$viewer = $request->getUser();
|
|
||||||
|
|
||||||
$this->requireApplicationCapability(
|
$this->requireApplicationCapability(
|
||||||
HarbormasterManagePlansCapability::CAPABILITY);
|
HarbormasterManagePlansCapability::CAPABILITY);
|
||||||
|
|
||||||
$plan = id(new HarbormasterBuildPlanQuery())
|
$plan = id(new HarbormasterBuildPlanQuery())
|
||||||
->setViewer($viewer)
|
->setViewer($viewer)
|
||||||
->withIDs(array($this->id))
|
->withIDs(array($request->getURIData('id')))
|
||||||
|
->requireCapabilities(
|
||||||
|
array(
|
||||||
|
PhabricatorPolicyCapability::CAN_VIEW,
|
||||||
|
PhabricatorPolicyCapability::CAN_EDIT,
|
||||||
|
))
|
||||||
->executeOne();
|
->executeOne();
|
||||||
if (!$plan) {
|
if (!$plan) {
|
||||||
return new Aphront404Response();
|
return new Aphront404Response();
|
||||||
@@ -26,10 +24,17 @@ final class HarbormasterStepAddController extends HarbormasterController {
|
|||||||
$plan_id = $plan->getID();
|
$plan_id = $plan->getID();
|
||||||
$cancel_uri = $this->getApplicationURI("plan/{$plan_id}/");
|
$cancel_uri = $this->getApplicationURI("plan/{$plan_id}/");
|
||||||
|
|
||||||
|
$all = HarbormasterBuildStepImplementation::getImplementations();
|
||||||
|
foreach ($all as $key => $impl) {
|
||||||
|
if ($impl->shouldRequireAutotargeting()) {
|
||||||
|
unset($all[$key]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
$errors = array();
|
$errors = array();
|
||||||
if ($request->isFormPost()) {
|
if ($request->isFormPost()) {
|
||||||
$class = $request->getStr('class');
|
$class = $request->getStr('class');
|
||||||
if (!HarbormasterBuildStepImplementation::getImplementation($class)) {
|
if (empty($all[$class])) {
|
||||||
$errors[] = pht('Choose the type of build step you want to add.');
|
$errors[] = pht('Choose the type of build step you want to add.');
|
||||||
}
|
}
|
||||||
if (!$errors) {
|
if (!$errors) {
|
||||||
@@ -41,7 +46,6 @@ final class HarbormasterStepAddController extends HarbormasterController {
|
|||||||
$control = id(new AphrontFormRadioButtonControl())
|
$control = id(new AphrontFormRadioButtonControl())
|
||||||
->setName('class');
|
->setName('class');
|
||||||
|
|
||||||
$all = HarbormasterBuildStepImplementation::getImplementations();
|
|
||||||
foreach ($all as $class => $implementation) {
|
foreach ($all as $class => $implementation) {
|
||||||
$control->addButton(
|
$control->addButton(
|
||||||
$class,
|
$class,
|
||||||
|
|||||||
@@ -2,27 +2,25 @@
|
|||||||
|
|
||||||
final class HarbormasterStepDeleteController extends HarbormasterController {
|
final class HarbormasterStepDeleteController extends HarbormasterController {
|
||||||
|
|
||||||
private $id;
|
public function handleRequest(AphrontRequest $request) {
|
||||||
|
$viewer = $this->getViewer();
|
||||||
public function willProcessRequest(array $data) {
|
|
||||||
$this->id = $data['id'];
|
|
||||||
}
|
|
||||||
|
|
||||||
public function processRequest() {
|
|
||||||
$request = $this->getRequest();
|
|
||||||
$viewer = $request->getUser();
|
|
||||||
|
|
||||||
$this->requireApplicationCapability(
|
$this->requireApplicationCapability(
|
||||||
HarbormasterManagePlansCapability::CAPABILITY);
|
HarbormasterManagePlansCapability::CAPABILITY);
|
||||||
|
|
||||||
$id = $this->id;
|
$id = $request->getURIData('id');
|
||||||
|
|
||||||
$step = id(new HarbormasterBuildStepQuery())
|
$step = id(new HarbormasterBuildStepQuery())
|
||||||
->setViewer($viewer)
|
->setViewer($viewer)
|
||||||
->withIDs(array($id))
|
->withIDs(array($id))
|
||||||
|
->requireCapabilities(
|
||||||
|
array(
|
||||||
|
PhabricatorPolicyCapability::CAN_VIEW,
|
||||||
|
PhabricatorPolicyCapability::CAN_EDIT,
|
||||||
|
))
|
||||||
->executeOne();
|
->executeOne();
|
||||||
if ($step === null) {
|
if (!$step) {
|
||||||
throw new Exception(pht('Build step not found!'));
|
return new Aphront404Response();
|
||||||
}
|
}
|
||||||
|
|
||||||
$plan_id = $step->getBuildPlan()->getID();
|
$plan_id = $step->getBuildPlan()->getID();
|
||||||
@@ -33,19 +31,14 @@ final class HarbormasterStepDeleteController extends HarbormasterController {
|
|||||||
return id(new AphrontRedirectResponse())->setURI($done_uri);
|
return id(new AphrontRedirectResponse())->setURI($done_uri);
|
||||||
}
|
}
|
||||||
|
|
||||||
$dialog = new AphrontDialogView();
|
return $this->newDialog()
|
||||||
$dialog->setTitle(pht('Really Delete Step?'))
|
->setTitle(pht('Really Delete Step?'))
|
||||||
->setUser($viewer)
|
->appendParagraph(
|
||||||
->addSubmitButton(pht('Delete Build Step'))
|
|
||||||
->addCancelButton($done_uri);
|
|
||||||
$dialog->appendChild(
|
|
||||||
phutil_tag(
|
|
||||||
'p',
|
|
||||||
array(),
|
|
||||||
pht(
|
pht(
|
||||||
"Are you sure you want to delete this step? ".
|
"Are you sure you want to delete this step? ".
|
||||||
"This can't be undone!")));
|
"This can't be undone!"))
|
||||||
return id(new AphrontDialogResponse())->setDialog($dialog);
|
->addCancelButton($done_uri)
|
||||||
|
->addSubmitButton(pht('Delete Build Step'));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,27 +2,22 @@
|
|||||||
|
|
||||||
final class HarbormasterStepEditController extends HarbormasterController {
|
final class HarbormasterStepEditController extends HarbormasterController {
|
||||||
|
|
||||||
private $id;
|
public function handleRequest(AphrontRequest $request) {
|
||||||
private $planID;
|
$viewer = $this->getViewer();
|
||||||
private $className;
|
|
||||||
|
|
||||||
public function willProcessRequest(array $data) {
|
|
||||||
$this->id = idx($data, 'id');
|
|
||||||
$this->planID = idx($data, 'plan');
|
|
||||||
$this->className = idx($data, 'class');
|
|
||||||
}
|
|
||||||
|
|
||||||
public function processRequest() {
|
|
||||||
$request = $this->getRequest();
|
|
||||||
$viewer = $request->getUser();
|
|
||||||
|
|
||||||
$this->requireApplicationCapability(
|
$this->requireApplicationCapability(
|
||||||
HarbormasterManagePlansCapability::CAPABILITY);
|
HarbormasterManagePlansCapability::CAPABILITY);
|
||||||
|
|
||||||
if ($this->id) {
|
$id = $request->getURIData('id');
|
||||||
|
if ($id) {
|
||||||
$step = id(new HarbormasterBuildStepQuery())
|
$step = id(new HarbormasterBuildStepQuery())
|
||||||
->setViewer($viewer)
|
->setViewer($viewer)
|
||||||
->withIDs(array($this->id))
|
->withIDs(array($id))
|
||||||
|
->requireCapabilities(
|
||||||
|
array(
|
||||||
|
PhabricatorPolicyCapability::CAN_VIEW,
|
||||||
|
PhabricatorPolicyCapability::CAN_EDIT,
|
||||||
|
))
|
||||||
->executeOne();
|
->executeOne();
|
||||||
if (!$step) {
|
if (!$step) {
|
||||||
return new Aphront404Response();
|
return new Aphront404Response();
|
||||||
@@ -31,23 +26,35 @@ final class HarbormasterStepEditController extends HarbormasterController {
|
|||||||
|
|
||||||
$is_new = false;
|
$is_new = false;
|
||||||
} else {
|
} else {
|
||||||
|
$plan_id = $request->getURIData('plan');
|
||||||
|
$class = $request->getURIData('class');
|
||||||
|
|
||||||
$plan = id(new HarbormasterBuildPlanQuery())
|
$plan = id(new HarbormasterBuildPlanQuery())
|
||||||
->setViewer($viewer)
|
->setViewer($viewer)
|
||||||
->withIDs(array($this->planID))
|
->withIDs(array($plan_id))
|
||||||
->executeOne();
|
->requireCapabilities(
|
||||||
|
array(
|
||||||
|
PhabricatorPolicyCapability::CAN_VIEW,
|
||||||
|
PhabricatorPolicyCapability::CAN_EDIT,
|
||||||
|
))
|
||||||
|
->executeOne();
|
||||||
if (!$plan) {
|
if (!$plan) {
|
||||||
return new Aphront404Response();
|
return new Aphront404Response();
|
||||||
}
|
}
|
||||||
|
|
||||||
$impl = HarbormasterBuildStepImplementation::getImplementation(
|
$impl = HarbormasterBuildStepImplementation::getImplementation($class);
|
||||||
$this->className);
|
|
||||||
if (!$impl) {
|
if (!$impl) {
|
||||||
return new Aphront404Response();
|
return new Aphront404Response();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ($impl->shouldRequireAutotargeting()) {
|
||||||
|
// No manual creation of autotarget steps.
|
||||||
|
return new Aphront404Response();
|
||||||
|
}
|
||||||
|
|
||||||
$step = HarbormasterBuildStep::initializeNewStep($viewer)
|
$step = HarbormasterBuildStep::initializeNewStep($viewer)
|
||||||
->setBuildPlanPHID($plan->getPHID())
|
->setBuildPlanPHID($plan->getPHID())
|
||||||
->setClassName($this->className);
|
->setClassName($class);
|
||||||
|
|
||||||
$is_new = true;
|
$is_new = true;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,251 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
final class HarbormasterTargetEngine extends Phobject {
|
||||||
|
|
||||||
|
private $viewer;
|
||||||
|
private $object;
|
||||||
|
private $autoTargetKeys;
|
||||||
|
|
||||||
|
public function setViewer($viewer) {
|
||||||
|
$this->viewer = $viewer;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getViewer() {
|
||||||
|
return $this->viewer;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setObject(HarbormasterBuildableInterface $object) {
|
||||||
|
$this->object = $object;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getObject() {
|
||||||
|
return $this->object;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setAutoTargetKeys(array $auto_keys) {
|
||||||
|
$this->autoTargetKeys = $auto_keys;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getAutoTargetKeys() {
|
||||||
|
return $this->autoTargetKeys;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function buildTargets() {
|
||||||
|
$object = $this->getObject();
|
||||||
|
$viewer = $this->getViewer();
|
||||||
|
|
||||||
|
$step_map = $this->generateBuildStepMap($this->getAutoTargetKeys());
|
||||||
|
|
||||||
|
$buildable = HarbormasterBuildable::createOrLoadExisting(
|
||||||
|
$viewer,
|
||||||
|
$object->getHarbormasterBuildablePHID(),
|
||||||
|
$object->getHarbormasterContainerPHID());
|
||||||
|
|
||||||
|
$target_map = $this->generateBuildTargetMap($buildable, $step_map);
|
||||||
|
|
||||||
|
return $target_map;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a map of the @{class:HarbormasterBuildStep} objects for a list of
|
||||||
|
* autotarget keys.
|
||||||
|
*
|
||||||
|
* This method creates the steps if they do not yet exist.
|
||||||
|
*
|
||||||
|
* @param list<string> Autotarget keys, like `"core.arc.lint"`.
|
||||||
|
* @return map<string, object> Map of keys to step objects.
|
||||||
|
*/
|
||||||
|
private function generateBuildStepMap(array $autotargets) {
|
||||||
|
$viewer = $this->getViewer();
|
||||||
|
|
||||||
|
$autosteps = $this->getAutosteps($autotargets);
|
||||||
|
$autosteps = mgroup($autosteps, 'getBuildStepAutotargetPlanKey');
|
||||||
|
|
||||||
|
$plans = id(new HarbormasterBuildPlanQuery())
|
||||||
|
->setViewer($viewer)
|
||||||
|
->withPlanAutoKeys(array_keys($autosteps))
|
||||||
|
->needBuildSteps(true)
|
||||||
|
->execute();
|
||||||
|
$plans = mpull($plans, null, 'getPlanAutoKey');
|
||||||
|
|
||||||
|
// NOTE: When creating the plan and steps, we save the autokeys as the
|
||||||
|
// names. These won't actually be shown in the UI, but make the data more
|
||||||
|
// consistent for secondary consumers like typeaheads.
|
||||||
|
|
||||||
|
$step_map = array();
|
||||||
|
foreach ($autosteps as $plan_key => $steps) {
|
||||||
|
$plan = idx($plans, $plan_key);
|
||||||
|
if (!$plan) {
|
||||||
|
$plan = HarbormasterBuildPlan::initializeNewBuildPlan($viewer)
|
||||||
|
->setName($plan_key)
|
||||||
|
->setPlanAutoKey($plan_key);
|
||||||
|
}
|
||||||
|
|
||||||
|
$current = $plan->getBuildSteps();
|
||||||
|
$current = mpull($current, null, 'getStepAutoKey');
|
||||||
|
$new_steps = array();
|
||||||
|
|
||||||
|
foreach ($steps as $step_key => $step) {
|
||||||
|
if (isset($current[$step_key])) {
|
||||||
|
$step_map[$step_key] = $current[$step_key];
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$new_step = HarbormasterBuildStep::initializeNewStep($viewer)
|
||||||
|
->setName($step_key)
|
||||||
|
->setClassName(get_class($step))
|
||||||
|
->setStepAutoKey($step_key);
|
||||||
|
|
||||||
|
$new_steps[$step_key] = $new_step;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($new_steps) {
|
||||||
|
$plan->openTransaction();
|
||||||
|
if (!$plan->getPHID()) {
|
||||||
|
$plan->save();
|
||||||
|
}
|
||||||
|
foreach ($new_steps as $step_key => $step) {
|
||||||
|
$step->setBuildPlanPHID($plan->getPHID());
|
||||||
|
$step->save();
|
||||||
|
|
||||||
|
$step->attachBuildPlan($plan);
|
||||||
|
$step_map[$step_key] = $step;
|
||||||
|
}
|
||||||
|
$plan->saveTransaction();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $step_map;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get all of the @{class:HarbormasterBuildStepImplementation} objects for
|
||||||
|
* a list of autotarget keys.
|
||||||
|
*
|
||||||
|
* @param list<string> Autotarget keys, like `"core.arc.lint"`.
|
||||||
|
* @return map<string, object> Map of keys to implementations.
|
||||||
|
*/
|
||||||
|
private function getAutosteps(array $autotargets) {
|
||||||
|
$all_steps = HarbormasterBuildStepImplementation::getImplementations();
|
||||||
|
$all_steps = mpull($all_steps, null, 'getBuildStepAutotargetStepKey');
|
||||||
|
|
||||||
|
// Make sure all the targets really exist.
|
||||||
|
foreach ($autotargets as $autotarget) {
|
||||||
|
if (empty($all_steps[$autotarget])) {
|
||||||
|
throw new Exception(
|
||||||
|
pht(
|
||||||
|
'No build step provides autotarget "%s"!',
|
||||||
|
$autotarget));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return array_select_keys($all_steps, $autotargets);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a list of @{class:HarbormasterBuildTarget} objects for a list of
|
||||||
|
* autotarget keys.
|
||||||
|
*
|
||||||
|
* If some targets or builds do not exist, they are created.
|
||||||
|
*
|
||||||
|
* @param HarbormasterBuildable A buildable.
|
||||||
|
* @param map<string, object> Map of keys to steps.
|
||||||
|
* @return map<string, object> Map of keys to targets.
|
||||||
|
*/
|
||||||
|
private function generateBuildTargetMap(
|
||||||
|
HarbormasterBuildable $buildable,
|
||||||
|
array $step_map) {
|
||||||
|
|
||||||
|
$viewer = $this->getViewer();
|
||||||
|
$plan_map = mgroup($step_map, 'getBuildPlanPHID');
|
||||||
|
|
||||||
|
$builds = id(new HarbormasterBuildQuery())
|
||||||
|
->setViewer($viewer)
|
||||||
|
->withBuildablePHIDs(array($buildable->getPHID()))
|
||||||
|
->withBuildPlanPHIDs(array_keys($plan_map))
|
||||||
|
->needBuildTargets(true)
|
||||||
|
->execute();
|
||||||
|
|
||||||
|
$autobuilds = array();
|
||||||
|
foreach ($builds as $build) {
|
||||||
|
$plan_key = $build->getBuildPlan()->getPlanAutoKey();
|
||||||
|
$autobuilds[$plan_key] = $build;
|
||||||
|
}
|
||||||
|
|
||||||
|
$new_builds = array();
|
||||||
|
foreach ($plan_map as $plan_phid => $steps) {
|
||||||
|
$plan = head($steps)->getBuildPlan();
|
||||||
|
$plan_key = $plan->getPlanAutoKey();
|
||||||
|
|
||||||
|
$build = idx($autobuilds, $plan_key);
|
||||||
|
if ($build) {
|
||||||
|
// We already have a build for this set of targets, so we don't need
|
||||||
|
// to do any work. (It's possible the build is an older build that
|
||||||
|
// doesn't have all of the right targets if new autotargets were
|
||||||
|
// recently introduced, but we don't currently try to construct them.)
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// NOTE: Normally, `applyPlan()` does not actually generate targets.
|
||||||
|
// We need to apply the plan in-process to perform target generation.
|
||||||
|
// This is fine as long as autotargets are empty containers that don't
|
||||||
|
// do any work, which they always should be.
|
||||||
|
|
||||||
|
PhabricatorWorker::setRunAllTasksInProcess(true);
|
||||||
|
try {
|
||||||
|
|
||||||
|
// NOTE: We might race another process here to create the same build
|
||||||
|
// with the same `planAutoKey`. The database will prevent this and
|
||||||
|
// using autotargets only currently makes sense if you just created the
|
||||||
|
// resource and "own" it, so we don't try to handle this, but may need
|
||||||
|
// to be more careful here if use of autotargets expands.
|
||||||
|
|
||||||
|
$build = $buildable->applyPlan($plan);
|
||||||
|
PhabricatorWorker::setRunAllTasksInProcess(false);
|
||||||
|
} catch (Exception $ex) {
|
||||||
|
PhabricatorWorker::setRunAllTasksInProcess(false);
|
||||||
|
throw $ex;
|
||||||
|
}
|
||||||
|
|
||||||
|
$new_builds[] = $build;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($new_builds) {
|
||||||
|
$all_targets = id(new HarbormasterBuildTargetQuery())
|
||||||
|
->setViewer($viewer)
|
||||||
|
->withBuildPHIDs(mpull($new_builds, 'getPHID'))
|
||||||
|
->execute();
|
||||||
|
} else {
|
||||||
|
$all_targets = array();
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($builds as $build) {
|
||||||
|
foreach ($build->getBuildTargets() as $target) {
|
||||||
|
$all_targets[] = $target;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$target_map = array();
|
||||||
|
foreach ($all_targets as $target) {
|
||||||
|
$target_key = $target
|
||||||
|
->getImplementation()
|
||||||
|
->getBuildStepAutotargetStepKey();
|
||||||
|
if (!$target_key) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
$target_map[$target_key] = $target;
|
||||||
|
}
|
||||||
|
|
||||||
|
$target_map = array_select_keys($target_map, array_keys($step_map));
|
||||||
|
|
||||||
|
return $target_map;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@@ -1,33 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
final class HarbormasterBuildItemPHIDType extends PhabricatorPHIDType {
|
|
||||||
|
|
||||||
const TYPECONST = 'HMBI';
|
|
||||||
|
|
||||||
public function getTypeName() {
|
|
||||||
return pht('Build Item');
|
|
||||||
}
|
|
||||||
|
|
||||||
public function newObject() {
|
|
||||||
return new HarbormasterBuildItem();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected function buildQueryForObjects(
|
|
||||||
PhabricatorObjectQuery $query,
|
|
||||||
array $phids) {
|
|
||||||
|
|
||||||
return id(new HarbormasterBuildItemQuery())
|
|
||||||
->withPHIDs($phids);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function loadHandles(
|
|
||||||
PhabricatorHandleQuery $query,
|
|
||||||
array $handles,
|
|
||||||
array $objects) {
|
|
||||||
|
|
||||||
foreach ($handles as $phid => $handle) {
|
|
||||||
$build_item = $objects[$phid];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,60 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
final class HarbormasterBuildItemQuery
|
|
||||||
extends PhabricatorCursorPagedPolicyAwareQuery {
|
|
||||||
|
|
||||||
private $ids;
|
|
||||||
private $phids;
|
|
||||||
|
|
||||||
public function withIDs(array $ids) {
|
|
||||||
$this->ids = $ids;
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function withPHIDs(array $phids) {
|
|
||||||
$this->phids = $phids;
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected function loadPage() {
|
|
||||||
$table = new HarbormasterBuildItem();
|
|
||||||
$conn_r = $table->establishConnection('r');
|
|
||||||
|
|
||||||
$data = queryfx_all(
|
|
||||||
$conn_r,
|
|
||||||
'SELECT * FROM %T %Q %Q %Q',
|
|
||||||
$table->getTableName(),
|
|
||||||
$this->buildWhereClause($conn_r),
|
|
||||||
$this->buildOrderClause($conn_r),
|
|
||||||
$this->buildLimitClause($conn_r));
|
|
||||||
|
|
||||||
return $table->loadAllFromArray($data);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected function buildWhereClause(AphrontDatabaseConnection $conn_r) {
|
|
||||||
$where = array();
|
|
||||||
|
|
||||||
if ($this->ids) {
|
|
||||||
$where[] = qsprintf(
|
|
||||||
$conn_r,
|
|
||||||
'id IN (%Ld)',
|
|
||||||
$this->ids);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($this->phids) {
|
|
||||||
$where[] = qsprintf(
|
|
||||||
$conn_r,
|
|
||||||
'phid in (%Ls)',
|
|
||||||
$this->phids);
|
|
||||||
}
|
|
||||||
|
|
||||||
$where[] = $this->buildPagingClause($conn_r);
|
|
||||||
|
|
||||||
return $this->formatWhereClause($where);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getQueryApplicationClass() {
|
|
||||||
return 'PhabricatorHarbormasterApplication';
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -7,6 +7,8 @@ final class HarbormasterBuildPlanQuery
|
|||||||
private $phids;
|
private $phids;
|
||||||
private $statuses;
|
private $statuses;
|
||||||
private $datasourceQuery;
|
private $datasourceQuery;
|
||||||
|
private $planAutoKeys;
|
||||||
|
private $needBuildSteps;
|
||||||
|
|
||||||
public function withIDs(array $ids) {
|
public function withIDs(array $ids) {
|
||||||
$this->ids = $ids;
|
$this->ids = $ids;
|
||||||
@@ -28,6 +30,16 @@ final class HarbormasterBuildPlanQuery
|
|||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function withPlanAutoKeys(array $keys) {
|
||||||
|
$this->planAutoKeys = $keys;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function needBuildSteps($need) {
|
||||||
|
$this->needBuildSteps = $need;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
public function newResultObject() {
|
public function newResultObject() {
|
||||||
return new HarbormasterBuildPlan();
|
return new HarbormasterBuildPlan();
|
||||||
}
|
}
|
||||||
@@ -36,6 +48,26 @@ final class HarbormasterBuildPlanQuery
|
|||||||
return $this->loadStandardPage($this->newResultObject());
|
return $this->loadStandardPage($this->newResultObject());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected function didFilterPage(array $page) {
|
||||||
|
if ($this->needBuildSteps) {
|
||||||
|
$plan_phids = mpull($page, 'getPHID');
|
||||||
|
|
||||||
|
$steps = id(new HarbormasterBuildStepQuery())
|
||||||
|
->setParentQuery($this)
|
||||||
|
->setViewer($this->getViewer())
|
||||||
|
->withBuildPlanPHIDs($plan_phids)
|
||||||
|
->execute();
|
||||||
|
$steps = mgroup($steps, 'getBuildPlanPHID');
|
||||||
|
|
||||||
|
foreach ($page as $plan) {
|
||||||
|
$plan_steps = idx($steps, $plan->getPHID(), array());
|
||||||
|
$plan->attachBuildSteps($plan_steps);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $page;
|
||||||
|
}
|
||||||
|
|
||||||
protected function buildWhereClauseParts(AphrontDatabaseConnection $conn) {
|
protected function buildWhereClauseParts(AphrontDatabaseConnection $conn) {
|
||||||
$where = parent::buildWhereClauseParts($conn);
|
$where = parent::buildWhereClauseParts($conn);
|
||||||
|
|
||||||
@@ -67,6 +99,13 @@ final class HarbormasterBuildPlanQuery
|
|||||||
$this->datasourceQuery);
|
$this->datasourceQuery);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ($this->planAutoKeys !== null) {
|
||||||
|
$where[] = qsprintf(
|
||||||
|
$conn,
|
||||||
|
'planAutoKey IN (%Ls)',
|
||||||
|
$this->planAutoKeys);
|
||||||
|
}
|
||||||
|
|
||||||
return $where;
|
return $where;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -88,6 +88,10 @@ final class HarbormasterBuildPlanSearchEngine
|
|||||||
$item->setDisabled(true);
|
$item->setDisabled(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ($plan->isAutoplan()) {
|
||||||
|
$item->addIcon('fa-lock grey', pht('Autoplan'));
|
||||||
|
}
|
||||||
|
|
||||||
$item->setHref($this->getApplicationURI("plan/{$id}/"));
|
$item->setHref($this->getApplicationURI("plan/{$id}/"));
|
||||||
|
|
||||||
$list->addItem($item);
|
$list->addItem($item);
|
||||||
|
|||||||
@@ -0,0 +1,38 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
final class HarbormasterArcLintBuildStepImplementation
|
||||||
|
extends HarbormasterBuildStepImplementation {
|
||||||
|
|
||||||
|
const STEPKEY = 'arcanist.lint';
|
||||||
|
|
||||||
|
public function getBuildStepAutotargetPlanKey() {
|
||||||
|
return HarbormasterBuildArcanistAutoplan::PLANKEY;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getBuildStepAutotargetStepKey() {
|
||||||
|
return self::STEPKEY;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function shouldRequireAutotargeting() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getName() {
|
||||||
|
return pht('Arcanist Lint Results');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getGenericDescription() {
|
||||||
|
return pht('Automatic `arc lint` step.');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function execute(
|
||||||
|
HarbormasterBuild $build,
|
||||||
|
HarbormasterBuildTarget $build_target) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function shouldWaitForMessage(HarbormasterBuildTarget $target) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
final class HarbormasterArcUnitBuildStepImplementation
|
||||||
|
extends HarbormasterBuildStepImplementation {
|
||||||
|
|
||||||
|
const STEPKEY = 'arcanist.unit';
|
||||||
|
|
||||||
|
public function getBuildStepAutotargetPlanKey() {
|
||||||
|
return HarbormasterBuildArcanistAutoplan::PLANKEY;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getBuildStepAutotargetStepKey() {
|
||||||
|
return self::STEPKEY;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function shouldRequireAutotargeting() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getName() {
|
||||||
|
return pht('Arcanist Unit Results');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getGenericDescription() {
|
||||||
|
return pht('Automatic `arc unit` step.');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function execute(
|
||||||
|
HarbormasterBuild $build,
|
||||||
|
HarbormasterBuildTarget $build_target) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function shouldWaitForMessage(HarbormasterBuildTarget $target) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -1,5 +1,8 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @task autotarget Automatic Targets
|
||||||
|
*/
|
||||||
abstract class HarbormasterBuildStepImplementation extends Phobject {
|
abstract class HarbormasterBuildStepImplementation extends Phobject {
|
||||||
|
|
||||||
private $settings;
|
private $settings;
|
||||||
@@ -249,4 +252,20 @@ abstract class HarbormasterBuildStepImplementation extends Phobject {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* -( Automatic Targets )-------------------------------------------------- */
|
||||||
|
|
||||||
|
|
||||||
|
public function getBuildStepAutotargetStepKey() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getBuildStepAutotargetPlanKey() {
|
||||||
|
throw new PhutilMethodNotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function shouldRequireAutotargeting() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -141,8 +141,14 @@ final class HarbormasterBuildable extends HarbormasterDAO
|
|||||||
$build = HarbormasterBuild::initializeNewBuild($viewer)
|
$build = HarbormasterBuild::initializeNewBuild($viewer)
|
||||||
->setBuildablePHID($this->getPHID())
|
->setBuildablePHID($this->getPHID())
|
||||||
->setBuildPlanPHID($plan->getPHID())
|
->setBuildPlanPHID($plan->getPHID())
|
||||||
->setBuildStatus(HarbormasterBuild::STATUS_PENDING)
|
->setBuildStatus(HarbormasterBuild::STATUS_PENDING);
|
||||||
->save();
|
|
||||||
|
$auto_key = $plan->getPlanAutoKey();
|
||||||
|
if ($auto_key) {
|
||||||
|
$build->setPlanAutoKey($auto_key);
|
||||||
|
}
|
||||||
|
|
||||||
|
$build->save();
|
||||||
|
|
||||||
PhabricatorWorker::scheduleTask(
|
PhabricatorWorker::scheduleTask(
|
||||||
'HarbormasterBuildWorker',
|
'HarbormasterBuildWorker',
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ final class HarbormasterBuild extends HarbormasterDAO
|
|||||||
protected $buildPlanPHID;
|
protected $buildPlanPHID;
|
||||||
protected $buildStatus;
|
protected $buildStatus;
|
||||||
protected $buildGeneration;
|
protected $buildGeneration;
|
||||||
|
protected $planAutoKey;
|
||||||
|
|
||||||
private $buildable = self::ATTACHABLE;
|
private $buildable = self::ATTACHABLE;
|
||||||
private $buildPlan = self::ATTACHABLE;
|
private $buildPlan = self::ATTACHABLE;
|
||||||
@@ -148,6 +149,7 @@ final class HarbormasterBuild extends HarbormasterDAO
|
|||||||
self::CONFIG_COLUMN_SCHEMA => array(
|
self::CONFIG_COLUMN_SCHEMA => array(
|
||||||
'buildStatus' => 'text32',
|
'buildStatus' => 'text32',
|
||||||
'buildGeneration' => 'uint32',
|
'buildGeneration' => 'uint32',
|
||||||
|
'planAutoKey' => 'text32?',
|
||||||
),
|
),
|
||||||
self::CONFIG_KEY_SCHEMA => array(
|
self::CONFIG_KEY_SCHEMA => array(
|
||||||
'key_buildable' => array(
|
'key_buildable' => array(
|
||||||
@@ -159,6 +161,10 @@ final class HarbormasterBuild extends HarbormasterDAO
|
|||||||
'key_status' => array(
|
'key_status' => array(
|
||||||
'columns' => array('buildStatus'),
|
'columns' => array('buildStatus'),
|
||||||
),
|
),
|
||||||
|
'key_planautokey' => array(
|
||||||
|
'columns' => array('buildablePHID', 'planAutoKey'),
|
||||||
|
'unique' => true,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
) + parent::getConfiguration();
|
) + parent::getConfiguration();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,19 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
final class HarbormasterBuildItem extends HarbormasterDAO {
|
|
||||||
|
|
||||||
protected $name;
|
|
||||||
|
|
||||||
protected function getConfiguration() {
|
|
||||||
return array(
|
|
||||||
self::CONFIG_AUX_PHID => true,
|
|
||||||
self::CONFIG_NO_TABLE => true,
|
|
||||||
) + parent::getConfiguration();
|
|
||||||
}
|
|
||||||
|
|
||||||
public function generatePHID() {
|
|
||||||
return PhabricatorPHID::generateNewPHID(
|
|
||||||
HarbormasterBuildItemPHIDType::TYPECONST);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,98 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
final class HarbormasterBuildLintMessage
|
||||||
|
extends HarbormasterDAO {
|
||||||
|
|
||||||
|
protected $buildTargetPHID;
|
||||||
|
protected $path;
|
||||||
|
protected $line;
|
||||||
|
protected $characterOffset;
|
||||||
|
protected $code;
|
||||||
|
protected $severity;
|
||||||
|
protected $name;
|
||||||
|
protected $properties = array();
|
||||||
|
|
||||||
|
private $buildTarget = self::ATTACHABLE;
|
||||||
|
|
||||||
|
public static function initializeNewLintMessage(
|
||||||
|
HarbormasterBuildTarget $build_target) {
|
||||||
|
return id(new HarbormasterBuildLintMessage())
|
||||||
|
->setBuildTargetPHID($build_target->getPHID());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function newFromDictionary(
|
||||||
|
HarbormasterBuildTarget $build_target,
|
||||||
|
array $dict) {
|
||||||
|
|
||||||
|
$obj = self::initializeNewLintMessage($build_target);
|
||||||
|
|
||||||
|
$spec = array(
|
||||||
|
'path' => 'string',
|
||||||
|
'line' => 'optional int',
|
||||||
|
'char' => 'optional int',
|
||||||
|
'code' => 'string',
|
||||||
|
'severity' => 'string',
|
||||||
|
'name' => 'string',
|
||||||
|
'description' => 'optional string',
|
||||||
|
);
|
||||||
|
|
||||||
|
// We're just going to ignore extra keys for now, to make it easier to
|
||||||
|
// add stuff here later on.
|
||||||
|
$dict = array_select_keys($dict, array_keys($spec));
|
||||||
|
PhutilTypeSpec::checkMap($dict, $spec);
|
||||||
|
|
||||||
|
$obj->setPath($dict['path']);
|
||||||
|
$obj->setLine(idx($dict, 'line'));
|
||||||
|
$obj->setCharacterOffset(idx($dict, 'char'));
|
||||||
|
$obj->setCode($dict['code']);
|
||||||
|
$obj->setSeverity($dict['severity']);
|
||||||
|
$obj->setName($dict['name']);
|
||||||
|
|
||||||
|
$description = idx($dict, 'description');
|
||||||
|
if (strlen($description)) {
|
||||||
|
$obj->setProperty('description', $description);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $obj;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getConfiguration() {
|
||||||
|
return array(
|
||||||
|
self::CONFIG_SERIALIZATION => array(
|
||||||
|
'properties' => self::SERIALIZATION_JSON,
|
||||||
|
),
|
||||||
|
self::CONFIG_COLUMN_SCHEMA => array(
|
||||||
|
'path' => 'text',
|
||||||
|
'line' => 'uint32?',
|
||||||
|
'characterOffset' => 'uint32?',
|
||||||
|
'code' => 'text32',
|
||||||
|
'severity' => 'text32',
|
||||||
|
'name' => 'text255',
|
||||||
|
),
|
||||||
|
self::CONFIG_KEY_SCHEMA => array(
|
||||||
|
'key_target' => array(
|
||||||
|
'columns' => array('buildTargetPHID'),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
) + parent::getConfiguration();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function attachBuildTarget(HarbormasterBuildTarget $build_target) {
|
||||||
|
$this->buildTarget = $build_target;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getBuildTarget() {
|
||||||
|
return $this->assertAttached($this->buildTarget);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getProperty($key, $default = null) {
|
||||||
|
return idx($this->properties, $key, $default);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setProperty($key, $value) {
|
||||||
|
$this->properties[$key] = $value;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -175,8 +175,16 @@ final class HarbormasterBuildTarget extends HarbormasterDAO
|
|||||||
return $this->implementation;
|
return $this->implementation;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function isAutotarget() {
|
||||||
|
try {
|
||||||
|
return (bool)$this->getImplementation()->getBuildStepAutotargetPlanKey();
|
||||||
|
} catch (Exception $e) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public function getName() {
|
public function getName() {
|
||||||
if (strlen($this->name)) {
|
if (strlen($this->name) && !$this->isAutotarget()) {
|
||||||
return $this->name;
|
return $this->name;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,100 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
final class HarbormasterBuildUnitMessage
|
||||||
|
extends HarbormasterDAO {
|
||||||
|
|
||||||
|
protected $buildTargetPHID;
|
||||||
|
protected $engine;
|
||||||
|
protected $namespace;
|
||||||
|
protected $name;
|
||||||
|
protected $result;
|
||||||
|
protected $duration;
|
||||||
|
protected $properties = array();
|
||||||
|
|
||||||
|
private $buildTarget = self::ATTACHABLE;
|
||||||
|
|
||||||
|
public static function initializeNewUnitMessage(
|
||||||
|
HarbormasterBuildTarget $build_target) {
|
||||||
|
return id(new HarbormasterBuildLintMessage())
|
||||||
|
->setBuildTargetPHID($build_target->getPHID());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function newFromDictionary(
|
||||||
|
HarbormasterBuildTarget $build_target,
|
||||||
|
array $dict) {
|
||||||
|
|
||||||
|
$obj = self::initializeNewUnitMessage($build_target);
|
||||||
|
|
||||||
|
$spec = array(
|
||||||
|
'engine' => 'optional string',
|
||||||
|
'namespace' => 'optional string',
|
||||||
|
'name' => 'string',
|
||||||
|
'result' => 'string',
|
||||||
|
'duration' => 'optional float',
|
||||||
|
'path' => 'optional string',
|
||||||
|
'coverage' => 'optional string',
|
||||||
|
);
|
||||||
|
|
||||||
|
// We're just going to ignore extra keys for now, to make it easier to
|
||||||
|
// add stuff here later on.
|
||||||
|
$dict = array_select_keys($dict, array_keys($spec));
|
||||||
|
PhutilTypeSpec::checkMap($dict, $spec);
|
||||||
|
|
||||||
|
$obj->setEngine(idx($dict, 'engine', ''));
|
||||||
|
$obj->setNamespace(idx($dict, 'namespace', ''));
|
||||||
|
$obj->setName($dict['name']);
|
||||||
|
$obj->setResult($dict['result']);
|
||||||
|
$obj->setDuration(idx($dict, 'duration'));
|
||||||
|
|
||||||
|
$path = idx($dict, 'path');
|
||||||
|
if (strlen($path)) {
|
||||||
|
$obj->setProperty('path', $path);
|
||||||
|
}
|
||||||
|
|
||||||
|
$coverage = idx($dict, 'coverage');
|
||||||
|
if (strlen($coverage)) {
|
||||||
|
$obj->setProperty('coverage', $coverage);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $obj;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getConfiguration() {
|
||||||
|
return array(
|
||||||
|
self::CONFIG_SERIALIZATION => array(
|
||||||
|
'properties' => self::SERIALIZATION_JSON,
|
||||||
|
),
|
||||||
|
self::CONFIG_COLUMN_SCHEMA => array(
|
||||||
|
'engine' => 'text255',
|
||||||
|
'namespace' => 'text255',
|
||||||
|
'name' => 'text255',
|
||||||
|
'result' => 'text32',
|
||||||
|
'duration' => 'double?',
|
||||||
|
),
|
||||||
|
self::CONFIG_KEY_SCHEMA => array(
|
||||||
|
'key_target' => array(
|
||||||
|
'columns' => array('buildTargetPHID'),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
) + parent::getConfiguration();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function attachBuildTarget(HarbormasterBuildTarget $build_target) {
|
||||||
|
$this->buildTarget = $build_target;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getBuildTarget() {
|
||||||
|
return $this->assertAttached($this->buildTarget);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getProperty($key, $default = null) {
|
||||||
|
return idx($this->properties, $key, $default);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setProperty($key, $value) {
|
||||||
|
$this->properties[$key] = $value;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -1,5 +1,8 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @task autoplan Autoplans
|
||||||
|
*/
|
||||||
final class HarbormasterBuildPlan extends HarbormasterDAO
|
final class HarbormasterBuildPlan extends HarbormasterDAO
|
||||||
implements
|
implements
|
||||||
PhabricatorApplicationTransactionInterface,
|
PhabricatorApplicationTransactionInterface,
|
||||||
@@ -8,6 +11,7 @@ final class HarbormasterBuildPlan extends HarbormasterDAO
|
|||||||
|
|
||||||
protected $name;
|
protected $name;
|
||||||
protected $planStatus;
|
protected $planStatus;
|
||||||
|
protected $planAutoKey;
|
||||||
|
|
||||||
const STATUS_ACTIVE = 'active';
|
const STATUS_ACTIVE = 'active';
|
||||||
const STATUS_DISABLED = 'disabled';
|
const STATUS_DISABLED = 'disabled';
|
||||||
@@ -16,7 +20,9 @@ final class HarbormasterBuildPlan extends HarbormasterDAO
|
|||||||
|
|
||||||
public static function initializeNewBuildPlan(PhabricatorUser $actor) {
|
public static function initializeNewBuildPlan(PhabricatorUser $actor) {
|
||||||
return id(new HarbormasterBuildPlan())
|
return id(new HarbormasterBuildPlan())
|
||||||
->setPlanStatus(self::STATUS_ACTIVE);
|
->setName('')
|
||||||
|
->setPlanStatus(self::STATUS_ACTIVE)
|
||||||
|
->attachBuildSteps(array());
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function getConfiguration() {
|
protected function getConfiguration() {
|
||||||
@@ -25,6 +31,7 @@ final class HarbormasterBuildPlan extends HarbormasterDAO
|
|||||||
self::CONFIG_COLUMN_SCHEMA => array(
|
self::CONFIG_COLUMN_SCHEMA => array(
|
||||||
'name' => 'sort128',
|
'name' => 'sort128',
|
||||||
'planStatus' => 'text32',
|
'planStatus' => 'text32',
|
||||||
|
'planAutoKey' => 'text32?',
|
||||||
),
|
),
|
||||||
self::CONFIG_KEY_SCHEMA => array(
|
self::CONFIG_KEY_SCHEMA => array(
|
||||||
'key_status' => array(
|
'key_status' => array(
|
||||||
@@ -33,6 +40,10 @@ final class HarbormasterBuildPlan extends HarbormasterDAO
|
|||||||
'key_name' => array(
|
'key_name' => array(
|
||||||
'columns' => array('name'),
|
'columns' => array('name'),
|
||||||
),
|
),
|
||||||
|
'key_planautokey' => array(
|
||||||
|
'columns' => array('planAutoKey'),
|
||||||
|
'unique' => true,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
) + parent::getConfiguration();
|
) + parent::getConfiguration();
|
||||||
}
|
}
|
||||||
@@ -57,6 +68,33 @@ final class HarbormasterBuildPlan extends HarbormasterDAO
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* -( Autoplans )---------------------------------------------------------- */
|
||||||
|
|
||||||
|
|
||||||
|
public function isAutoplan() {
|
||||||
|
return ($this->getPlanAutoKey() !== null);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public function getAutoplan() {
|
||||||
|
if (!$this->isAutoplan()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return HarbormasterBuildAutoplan::getAutoplan($this->getPlanAutoKey());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public function getName() {
|
||||||
|
$autoplan = $this->getAutoplan();
|
||||||
|
if ($autoplan) {
|
||||||
|
return $autoplan->getAutoplanName();
|
||||||
|
}
|
||||||
|
|
||||||
|
return parent::getName();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* -( PhabricatorSubscribableInterface )----------------------------------- */
|
/* -( PhabricatorSubscribableInterface )----------------------------------- */
|
||||||
|
|
||||||
|
|
||||||
@@ -102,12 +140,22 @@ final class HarbormasterBuildPlan extends HarbormasterDAO
|
|||||||
public function getCapabilities() {
|
public function getCapabilities() {
|
||||||
return array(
|
return array(
|
||||||
PhabricatorPolicyCapability::CAN_VIEW,
|
PhabricatorPolicyCapability::CAN_VIEW,
|
||||||
|
PhabricatorPolicyCapability::CAN_EDIT,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getPolicy($capability) {
|
public function getPolicy($capability) {
|
||||||
switch ($capability) {
|
switch ($capability) {
|
||||||
case PhabricatorPolicyCapability::CAN_VIEW:
|
case PhabricatorPolicyCapability::CAN_VIEW:
|
||||||
|
return PhabricatorPolicies::getMostOpenPolicy();
|
||||||
|
case PhabricatorPolicyCapability::CAN_EDIT:
|
||||||
|
// NOTE: In practice, this policy is always limited by the "Mangage
|
||||||
|
// Build Plans" policy.
|
||||||
|
|
||||||
|
if ($this->isAutoplan()) {
|
||||||
|
return PhabricatorPolicies::POLICY_NOONE;
|
||||||
|
}
|
||||||
|
|
||||||
return PhabricatorPolicies::getMostOpenPolicy();
|
return PhabricatorPolicies::getMostOpenPolicy();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -117,6 +165,19 @@ final class HarbormasterBuildPlan extends HarbormasterDAO
|
|||||||
}
|
}
|
||||||
|
|
||||||
public function describeAutomaticCapability($capability) {
|
public function describeAutomaticCapability($capability) {
|
||||||
return null;
|
$messages = array();
|
||||||
|
|
||||||
|
switch ($capability) {
|
||||||
|
case PhabricatorPolicyCapability::CAN_EDIT:
|
||||||
|
if ($this->isAutoplan()) {
|
||||||
|
$messages[] = pht(
|
||||||
|
'This is an autoplan (a builtin plan provided by an application) '.
|
||||||
|
'so it can not be edited.');
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $messages;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,13 +12,16 @@ final class HarbormasterBuildStep extends HarbormasterDAO
|
|||||||
protected $className;
|
protected $className;
|
||||||
protected $details = array();
|
protected $details = array();
|
||||||
protected $sequence = 0;
|
protected $sequence = 0;
|
||||||
|
protected $stepAutoKey;
|
||||||
|
|
||||||
private $buildPlan = self::ATTACHABLE;
|
private $buildPlan = self::ATTACHABLE;
|
||||||
private $customFields = self::ATTACHABLE;
|
private $customFields = self::ATTACHABLE;
|
||||||
private $implementation;
|
private $implementation;
|
||||||
|
|
||||||
public static function initializeNewStep(PhabricatorUser $actor) {
|
public static function initializeNewStep(PhabricatorUser $actor) {
|
||||||
return id(new HarbormasterBuildStep());
|
return id(new HarbormasterBuildStep())
|
||||||
|
->setName('')
|
||||||
|
->setDescription('');
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function getConfiguration() {
|
protected function getConfiguration() {
|
||||||
@@ -37,11 +40,16 @@ final class HarbormasterBuildStep extends HarbormasterDAO
|
|||||||
// which predated editable names. These should be backfilled with
|
// which predated editable names. These should be backfilled with
|
||||||
// default names, then the code for handling `null` shoudl be removed.
|
// default names, then the code for handling `null` shoudl be removed.
|
||||||
'name' => 'text255?',
|
'name' => 'text255?',
|
||||||
|
'stepAutoKey' => 'text32?',
|
||||||
),
|
),
|
||||||
self::CONFIG_KEY_SCHEMA => array(
|
self::CONFIG_KEY_SCHEMA => array(
|
||||||
'key_plan' => array(
|
'key_plan' => array(
|
||||||
'columns' => array('buildPlanPHID'),
|
'columns' => array('buildPlanPHID'),
|
||||||
),
|
),
|
||||||
|
'key_stepautokey' => array(
|
||||||
|
'columns' => array('buildPlanPHID', 'stepAutoKey'),
|
||||||
|
'unique' => true,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
) + parent::getConfiguration();
|
) + parent::getConfiguration();
|
||||||
}
|
}
|
||||||
@@ -88,6 +96,10 @@ final class HarbormasterBuildStep extends HarbormasterDAO
|
|||||||
return $this->implementation;
|
return $this->implementation;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function isAutostep() {
|
||||||
|
return ($this->getStepAutoKey() !== null);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* -( PhabricatorApplicationTransactionInterface )------------------------- */
|
/* -( PhabricatorApplicationTransactionInterface )------------------------- */
|
||||||
|
|
||||||
@@ -118,6 +130,7 @@ final class HarbormasterBuildStep extends HarbormasterDAO
|
|||||||
public function getCapabilities() {
|
public function getCapabilities() {
|
||||||
return array(
|
return array(
|
||||||
PhabricatorPolicyCapability::CAN_VIEW,
|
PhabricatorPolicyCapability::CAN_VIEW,
|
||||||
|
PhabricatorPolicyCapability::CAN_EDIT,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -77,9 +77,11 @@ final class PhabricatorLegalpadApplication extends PhabricatorApplication {
|
|||||||
LegalpadCreateDocumentsCapability::CAPABILITY => array(),
|
LegalpadCreateDocumentsCapability::CAPABILITY => array(),
|
||||||
LegalpadDefaultViewCapability::CAPABILITY => array(
|
LegalpadDefaultViewCapability::CAPABILITY => array(
|
||||||
'template' => PhabricatorLegalpadDocumentPHIDType::TYPECONST,
|
'template' => PhabricatorLegalpadDocumentPHIDType::TYPECONST,
|
||||||
|
'capability' => PhabricatorPolicyCapability::CAN_VIEW,
|
||||||
),
|
),
|
||||||
LegalpadDefaultEditCapability::CAPABILITY => array(
|
LegalpadDefaultEditCapability::CAPABILITY => array(
|
||||||
'template' => PhabricatorLegalpadDocumentPHIDType::TYPECONST,
|
'template' => PhabricatorLegalpadDocumentPHIDType::TYPECONST,
|
||||||
|
'capability' => PhabricatorPolicyCapability::CAN_EDIT,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -132,10 +132,12 @@ final class PhabricatorManiphestApplication extends PhabricatorApplication {
|
|||||||
ManiphestDefaultViewCapability::CAPABILITY => array(
|
ManiphestDefaultViewCapability::CAPABILITY => array(
|
||||||
'caption' => pht('Default view policy for newly created tasks.'),
|
'caption' => pht('Default view policy for newly created tasks.'),
|
||||||
'template' => ManiphestTaskPHIDType::TYPECONST,
|
'template' => ManiphestTaskPHIDType::TYPECONST,
|
||||||
|
'capability' => PhabricatorPolicyCapability::CAN_VIEW,
|
||||||
),
|
),
|
||||||
ManiphestDefaultEditCapability::CAPABILITY => array(
|
ManiphestDefaultEditCapability::CAPABILITY => array(
|
||||||
'caption' => pht('Default edit policy for newly created tasks.'),
|
'caption' => pht('Default edit policy for newly created tasks.'),
|
||||||
'template' => ManiphestTaskPHIDType::TYPECONST,
|
'template' => ManiphestTaskPHIDType::TYPECONST,
|
||||||
|
'capability' => PhabricatorPolicyCapability::CAN_EDIT,
|
||||||
),
|
),
|
||||||
ManiphestEditStatusCapability::CAPABILITY => array(),
|
ManiphestEditStatusCapability::CAPABILITY => array(),
|
||||||
ManiphestEditAssignCapability::CAPABILITY => array(),
|
ManiphestEditAssignCapability::CAPABILITY => array(),
|
||||||
|
|||||||
@@ -25,6 +25,12 @@ final class ManiphestBatchEditController extends ManiphestController {
|
|||||||
$task_ids = $request->getStrList('batch');
|
$task_ids = $request->getStrList('batch');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!$task_ids) {
|
||||||
|
throw new Exception(
|
||||||
|
pht(
|
||||||
|
'No tasks are selected.'));
|
||||||
|
}
|
||||||
|
|
||||||
$tasks = id(new ManiphestTaskQuery())
|
$tasks = id(new ManiphestTaskQuery())
|
||||||
->setViewer($viewer)
|
->setViewer($viewer)
|
||||||
->withIDs($task_ids)
|
->withIDs($task_ids)
|
||||||
@@ -37,6 +43,12 @@ final class ManiphestBatchEditController extends ManiphestController {
|
|||||||
->needProjectPHIDs(true)
|
->needProjectPHIDs(true)
|
||||||
->execute();
|
->execute();
|
||||||
|
|
||||||
|
if (!$tasks) {
|
||||||
|
throw new Exception(
|
||||||
|
pht(
|
||||||
|
"You don't have permission to edit any of the selected tasks."));
|
||||||
|
}
|
||||||
|
|
||||||
if ($project) {
|
if ($project) {
|
||||||
$cancel_uri = '/project/board/'.$project->getID().'/';
|
$cancel_uri = '/project/board/'.$project->getID().'/';
|
||||||
$redirect_uri = $cancel_uri;
|
$redirect_uri = $cancel_uri;
|
||||||
|
|||||||
@@ -6,13 +6,13 @@
|
|||||||
*/
|
*/
|
||||||
final class ManiphestTaskQuery extends PhabricatorCursorPagedPolicyAwareQuery {
|
final class ManiphestTaskQuery extends PhabricatorCursorPagedPolicyAwareQuery {
|
||||||
|
|
||||||
private $taskIDs = array();
|
private $taskIDs;
|
||||||
private $taskPHIDs = array();
|
private $taskPHIDs;
|
||||||
private $authorPHIDs = array();
|
private $authorPHIDs;
|
||||||
private $ownerPHIDs = array();
|
private $ownerPHIDs;
|
||||||
private $noOwner;
|
private $noOwner;
|
||||||
private $anyOwner;
|
private $anyOwner;
|
||||||
private $subscriberPHIDs = array();
|
private $subscriberPHIDs;
|
||||||
private $dateCreatedAfter;
|
private $dateCreatedAfter;
|
||||||
private $dateCreatedBefore;
|
private $dateCreatedBefore;
|
||||||
private $dateModifiedAfter;
|
private $dateModifiedAfter;
|
||||||
@@ -216,75 +216,7 @@ final class ManiphestTaskQuery extends PhabricatorCursorPagedPolicyAwareQuery {
|
|||||||
$task_dao = new ManiphestTask();
|
$task_dao = new ManiphestTask();
|
||||||
$conn = $task_dao->establishConnection('r');
|
$conn = $task_dao->establishConnection('r');
|
||||||
|
|
||||||
$where = array();
|
$where = $this->buildWhereClause($conn);
|
||||||
$where[] = $this->buildTaskIDsWhereClause($conn);
|
|
||||||
$where[] = $this->buildTaskPHIDsWhereClause($conn);
|
|
||||||
$where[] = $this->buildStatusWhereClause($conn);
|
|
||||||
$where[] = $this->buildStatusesWhereClause($conn);
|
|
||||||
$where[] = $this->buildDependenciesWhereClause($conn);
|
|
||||||
$where[] = $this->buildAuthorWhereClause($conn);
|
|
||||||
$where[] = $this->buildOwnerWhereClause($conn);
|
|
||||||
$where[] = $this->buildFullTextWhereClause($conn);
|
|
||||||
|
|
||||||
if ($this->dateCreatedAfter) {
|
|
||||||
$where[] = qsprintf(
|
|
||||||
$conn,
|
|
||||||
'task.dateCreated >= %d',
|
|
||||||
$this->dateCreatedAfter);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($this->dateCreatedBefore) {
|
|
||||||
$where[] = qsprintf(
|
|
||||||
$conn,
|
|
||||||
'task.dateCreated <= %d',
|
|
||||||
$this->dateCreatedBefore);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($this->dateModifiedAfter) {
|
|
||||||
$where[] = qsprintf(
|
|
||||||
$conn,
|
|
||||||
'task.dateModified >= %d',
|
|
||||||
$this->dateModifiedAfter);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($this->dateModifiedBefore) {
|
|
||||||
$where[] = qsprintf(
|
|
||||||
$conn,
|
|
||||||
'task.dateModified <= %d',
|
|
||||||
$this->dateModifiedBefore);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($this->priorities) {
|
|
||||||
$where[] = qsprintf(
|
|
||||||
$conn,
|
|
||||||
'task.priority IN (%Ld)',
|
|
||||||
$this->priorities);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($this->subpriorities) {
|
|
||||||
$where[] = qsprintf(
|
|
||||||
$conn,
|
|
||||||
'task.subpriority IN (%Lf)',
|
|
||||||
$this->subpriorities);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($this->subpriorityMin) {
|
|
||||||
$where[] = qsprintf(
|
|
||||||
$conn,
|
|
||||||
'task.subpriority >= %f',
|
|
||||||
$this->subpriorityMin);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($this->subpriorityMax) {
|
|
||||||
$where[] = qsprintf(
|
|
||||||
$conn,
|
|
||||||
'task.subpriority <= %f',
|
|
||||||
$this->subpriorityMax);
|
|
||||||
}
|
|
||||||
|
|
||||||
$where[] = $this->buildWhereClauseParts($conn);
|
|
||||||
|
|
||||||
$where = $this->formatWhereClause($where);
|
|
||||||
|
|
||||||
$group_column = '';
|
$group_column = '';
|
||||||
switch ($this->groupBy) {
|
switch ($this->groupBy) {
|
||||||
@@ -392,26 +324,99 @@ final class ManiphestTaskQuery extends PhabricatorCursorPagedPolicyAwareQuery {
|
|||||||
return $tasks;
|
return $tasks;
|
||||||
}
|
}
|
||||||
|
|
||||||
private function buildTaskIDsWhereClause(AphrontDatabaseConnection $conn) {
|
protected function buildWhereClauseParts(AphrontDatabaseConnection $conn) {
|
||||||
if (!$this->taskIDs) {
|
$where = parent::buildWhereClauseParts($conn);
|
||||||
return null;
|
|
||||||
|
$where[] = $this->buildStatusWhereClause($conn);
|
||||||
|
$where[] = $this->buildDependenciesWhereClause($conn);
|
||||||
|
$where[] = $this->buildOwnerWhereClause($conn);
|
||||||
|
$where[] = $this->buildFullTextWhereClause($conn);
|
||||||
|
|
||||||
|
if ($this->taskIDs !== null) {
|
||||||
|
$where[] = qsprintf(
|
||||||
|
$conn,
|
||||||
|
'task.id in (%Ld)',
|
||||||
|
$this->taskIDs);
|
||||||
}
|
}
|
||||||
|
|
||||||
return qsprintf(
|
if ($this->taskPHIDs !== null) {
|
||||||
$conn,
|
$where[] = qsprintf(
|
||||||
'task.id in (%Ld)',
|
$conn,
|
||||||
$this->taskIDs);
|
'task.phid in (%Ls)',
|
||||||
}
|
$this->taskPHIDs);
|
||||||
|
|
||||||
private function buildTaskPHIDsWhereClause(AphrontDatabaseConnection $conn) {
|
|
||||||
if (!$this->taskPHIDs) {
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return qsprintf(
|
if ($this->statuses !== null) {
|
||||||
$conn,
|
$where[] = qsprintf(
|
||||||
'task.phid in (%Ls)',
|
$conn,
|
||||||
$this->taskPHIDs);
|
'task.status IN (%Ls)',
|
||||||
|
$this->statuses);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($this->authorPHIDs !== null) {
|
||||||
|
$where[] = qsprintf(
|
||||||
|
$conn,
|
||||||
|
'task.authorPHID in (%Ls)',
|
||||||
|
$this->authorPHIDs);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($this->dateCreatedAfter) {
|
||||||
|
$where[] = qsprintf(
|
||||||
|
$conn,
|
||||||
|
'task.dateCreated >= %d',
|
||||||
|
$this->dateCreatedAfter);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($this->dateCreatedBefore) {
|
||||||
|
$where[] = qsprintf(
|
||||||
|
$conn,
|
||||||
|
'task.dateCreated <= %d',
|
||||||
|
$this->dateCreatedBefore);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($this->dateModifiedAfter) {
|
||||||
|
$where[] = qsprintf(
|
||||||
|
$conn,
|
||||||
|
'task.dateModified >= %d',
|
||||||
|
$this->dateModifiedAfter);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($this->dateModifiedBefore) {
|
||||||
|
$where[] = qsprintf(
|
||||||
|
$conn,
|
||||||
|
'task.dateModified <= %d',
|
||||||
|
$this->dateModifiedBefore);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($this->priorities !== null) {
|
||||||
|
$where[] = qsprintf(
|
||||||
|
$conn,
|
||||||
|
'task.priority IN (%Ld)',
|
||||||
|
$this->priorities);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($this->subpriorities !== null) {
|
||||||
|
$where[] = qsprintf(
|
||||||
|
$conn,
|
||||||
|
'task.subpriority IN (%Lf)',
|
||||||
|
$this->subpriorities);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($this->subpriorityMin !== null) {
|
||||||
|
$where[] = qsprintf(
|
||||||
|
$conn,
|
||||||
|
'task.subpriority >= %f',
|
||||||
|
$this->subpriorityMin);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($this->subpriorityMax !== null) {
|
||||||
|
$where[] = qsprintf(
|
||||||
|
$conn,
|
||||||
|
'task.subpriority <= %f',
|
||||||
|
$this->subpriorityMax);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $where;
|
||||||
}
|
}
|
||||||
|
|
||||||
private function buildStatusWhereClause(AphrontDatabaseConnection $conn) {
|
private function buildStatusWhereClause(AphrontDatabaseConnection $conn) {
|
||||||
@@ -448,27 +453,6 @@ final class ManiphestTaskQuery extends PhabricatorCursorPagedPolicyAwareQuery {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private function buildStatusesWhereClause(AphrontDatabaseConnection $conn) {
|
|
||||||
if ($this->statuses) {
|
|
||||||
return qsprintf(
|
|
||||||
$conn,
|
|
||||||
'task.status IN (%Ls)',
|
|
||||||
$this->statuses);
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
private function buildAuthorWhereClause(AphrontDatabaseConnection $conn) {
|
|
||||||
if (!$this->authorPHIDs) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return qsprintf(
|
|
||||||
$conn,
|
|
||||||
'task.authorPHID in (%Ls)',
|
|
||||||
$this->authorPHIDs);
|
|
||||||
}
|
|
||||||
|
|
||||||
private function buildOwnerWhereClause(AphrontDatabaseConnection $conn) {
|
private function buildOwnerWhereClause(AphrontDatabaseConnection $conn) {
|
||||||
$subclause = array();
|
$subclause = array();
|
||||||
|
|
||||||
@@ -590,7 +574,7 @@ final class ManiphestTaskQuery extends PhabricatorCursorPagedPolicyAwareQuery {
|
|||||||
id(new ManiphestTask())->getTableName());
|
id(new ManiphestTask())->getTableName());
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($this->subscriberPHIDs) {
|
if ($this->subscriberPHIDs !== null) {
|
||||||
$joins[] = qsprintf(
|
$joins[] = qsprintf(
|
||||||
$conn_r,
|
$conn_r,
|
||||||
'JOIN %T e_ccs ON e_ccs.src = task.phid '.
|
'JOIN %T e_ccs ON e_ccs.src = task.phid '.
|
||||||
|
|||||||
@@ -73,10 +73,12 @@ final class PhabricatorNuanceApplication extends PhabricatorApplication {
|
|||||||
NuanceSourceDefaultViewCapability::CAPABILITY => array(
|
NuanceSourceDefaultViewCapability::CAPABILITY => array(
|
||||||
'caption' => pht('Default view policy for newly created sources.'),
|
'caption' => pht('Default view policy for newly created sources.'),
|
||||||
'template' => NuanceSourcePHIDType::TYPECONST,
|
'template' => NuanceSourcePHIDType::TYPECONST,
|
||||||
|
'capability' => PhabricatorPolicyCapability::CAN_VIEW,
|
||||||
),
|
),
|
||||||
NuanceSourceDefaultEditCapability::CAPABILITY => array(
|
NuanceSourceDefaultEditCapability::CAPABILITY => array(
|
||||||
'caption' => pht('Default edit policy for newly created sources.'),
|
'caption' => pht('Default edit policy for newly created sources.'),
|
||||||
'template' => NuanceSourcePHIDType::TYPECONST,
|
'template' => NuanceSourcePHIDType::TYPECONST,
|
||||||
|
'capability' => PhabricatorPolicyCapability::CAN_EDIT,
|
||||||
),
|
),
|
||||||
NuanceSourceManageCapability::CAPABILITY => array(),
|
NuanceSourceManageCapability::CAPABILITY => array(),
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -63,4 +63,24 @@ final class PhabricatorPassphraseApplication extends PhabricatorApplication {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected function getCustomCapabilities() {
|
||||||
|
$policy_key = id(new PassphraseCredentialAuthorPolicyRule())
|
||||||
|
->getObjectPolicyFullKey();
|
||||||
|
|
||||||
|
return array(
|
||||||
|
PassphraseDefaultViewCapability::CAPABILITY => array(
|
||||||
|
'caption' => pht('Default view policy for newly created credentials.'),
|
||||||
|
'template' => PassphraseCredentialPHIDType::TYPECONST,
|
||||||
|
'capability' => PhabricatorPolicyCapability::CAN_VIEW,
|
||||||
|
'default' => $policy_key,
|
||||||
|
),
|
||||||
|
PassphraseDefaultEditCapability::CAPABILITY => array(
|
||||||
|
'caption' => pht('Default edit policy for newly created credentials.'),
|
||||||
|
'template' => PassphraseCredentialPHIDType::TYPECONST,
|
||||||
|
'capability' => PhabricatorPolicyCapability::CAN_EDIT,
|
||||||
|
'default' => $policy_key,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,12 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
final class PassphraseDefaultEditCapability
|
||||||
|
extends PhabricatorPolicyCapability {
|
||||||
|
|
||||||
|
const CAPABILITY = 'passphrase.default.edit';
|
||||||
|
|
||||||
|
public function getCapabilityName() {
|
||||||
|
return pht('Default Edit Policy');
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
final class PassphraseDefaultViewCapability
|
||||||
|
extends PhabricatorPolicyCapability {
|
||||||
|
|
||||||
|
const CAPABILITY = 'passphrase.default.view';
|
||||||
|
|
||||||
|
public function getCapabilityName() {
|
||||||
|
return pht('Default View Policy');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function shouldAllowPublicPolicySetting() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -60,6 +60,7 @@ final class PassphraseCredentialEditController extends PassphraseController {
|
|||||||
$e_name = true;
|
$e_name = true;
|
||||||
|
|
||||||
$v_desc = $credential->getDescription();
|
$v_desc = $credential->getDescription();
|
||||||
|
$v_space = $credential->getSpacePHID();
|
||||||
|
|
||||||
$v_username = $credential->getUsername();
|
$v_username = $credential->getUsername();
|
||||||
$e_username = true;
|
$e_username = true;
|
||||||
@@ -93,6 +94,7 @@ final class PassphraseCredentialEditController extends PassphraseController {
|
|||||||
$v_is_locked = $request->getStr('lock');
|
$v_is_locked = $request->getStr('lock');
|
||||||
|
|
||||||
$v_secret = $request->getStr('secret');
|
$v_secret = $request->getStr('secret');
|
||||||
|
$v_space = $request->getStr('spacePHID');
|
||||||
$v_password = $request->getStr('password');
|
$v_password = $request->getStr('password');
|
||||||
$v_decrypt = $v_secret;
|
$v_decrypt = $v_secret;
|
||||||
|
|
||||||
@@ -127,6 +129,7 @@ final class PassphraseCredentialEditController extends PassphraseController {
|
|||||||
$type_is_locked = PassphraseCredentialTransaction::TYPE_LOCK;
|
$type_is_locked = PassphraseCredentialTransaction::TYPE_LOCK;
|
||||||
$type_view_policy = PhabricatorTransactions::TYPE_VIEW_POLICY;
|
$type_view_policy = PhabricatorTransactions::TYPE_VIEW_POLICY;
|
||||||
$type_edit_policy = PhabricatorTransactions::TYPE_EDIT_POLICY;
|
$type_edit_policy = PhabricatorTransactions::TYPE_EDIT_POLICY;
|
||||||
|
$type_space = PhabricatorTransactions::TYPE_SPACE;
|
||||||
|
|
||||||
$xactions = array();
|
$xactions = array();
|
||||||
|
|
||||||
@@ -146,6 +149,10 @@ final class PassphraseCredentialEditController extends PassphraseController {
|
|||||||
->setTransactionType($type_edit_policy)
|
->setTransactionType($type_edit_policy)
|
||||||
->setNewValue($v_edit_policy);
|
->setNewValue($v_edit_policy);
|
||||||
|
|
||||||
|
$xactions[] = id(new PassphraseCredentialTransaction())
|
||||||
|
->setTransactionType($type_space)
|
||||||
|
->setNewValue($v_space);
|
||||||
|
|
||||||
// Open a transaction in case we're writing a new secret; this limits
|
// Open a transaction in case we're writing a new secret; this limits
|
||||||
// the amount of code which handles secret plaintexts.
|
// the amount of code which handles secret plaintexts.
|
||||||
$credential->openTransaction();
|
$credential->openTransaction();
|
||||||
@@ -244,13 +251,13 @@ final class PassphraseCredentialEditController extends PassphraseController {
|
|||||||
->setValue($type->getCredentialTypeName()))
|
->setValue($type->getCredentialTypeName()))
|
||||||
->appendChild(
|
->appendChild(
|
||||||
id(new AphrontFormDividerControl()))
|
id(new AphrontFormDividerControl()))
|
||||||
->appendChild(
|
->appendControl(
|
||||||
id(new AphrontFormPolicyControl())
|
id(new AphrontFormPolicyControl())
|
||||||
->setName('viewPolicy')
|
->setName('viewPolicy')
|
||||||
->setPolicyObject($credential)
|
->setPolicyObject($credential)
|
||||||
->setCapability(PhabricatorPolicyCapability::CAN_VIEW)
|
->setCapability(PhabricatorPolicyCapability::CAN_VIEW)
|
||||||
->setPolicies($policies))
|
->setPolicies($policies))
|
||||||
->appendChild(
|
->appendControl(
|
||||||
id(new AphrontFormPolicyControl())
|
id(new AphrontFormPolicyControl())
|
||||||
->setName('editPolicy')
|
->setName('editPolicy')
|
||||||
->setPolicyObject($credential)
|
->setPolicyObject($credential)
|
||||||
|
|||||||
@@ -0,0 +1,48 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
final class PassphraseCredentialAuthorPolicyRule
|
||||||
|
extends PhabricatorPolicyRule {
|
||||||
|
|
||||||
|
public function getObjectPolicyKey() {
|
||||||
|
return 'passphrase.author';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getObjectPolicyName() {
|
||||||
|
return pht('Credential Author');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getPolicyExplanation() {
|
||||||
|
return pht('The author of this credential can take this action.');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getRuleDescription() {
|
||||||
|
return pht('credential author');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function canApplyToObject(PhabricatorPolicyInterface $object) {
|
||||||
|
return ($object instanceof PassphraseCredential);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function applyRule(
|
||||||
|
PhabricatorUser $viewer,
|
||||||
|
$value,
|
||||||
|
PhabricatorPolicyInterface $object) {
|
||||||
|
|
||||||
|
$author_phid = $object->getAuthorPHID();
|
||||||
|
if (!$author_phid) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$viewer_phid = $viewer->getPHID();
|
||||||
|
if (!$viewer_phid) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ($viewer_phid == $author_phid);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getValueControlType() {
|
||||||
|
return self::CONTROL_TYPE_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -53,19 +53,12 @@ final class PassphraseCredentialQuery
|
|||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function newResultObject() {
|
||||||
|
return new PassphraseCredential();
|
||||||
|
}
|
||||||
|
|
||||||
protected function loadPage() {
|
protected function loadPage() {
|
||||||
$table = new PassphraseCredential();
|
return $this->loadStandardPage($this->newResultObject());
|
||||||
$conn_r = $table->establishConnection('r');
|
|
||||||
|
|
||||||
$rows = queryfx_all(
|
|
||||||
$conn_r,
|
|
||||||
'SELECT * FROM %T %Q %Q %Q',
|
|
||||||
$table->getTableName(),
|
|
||||||
$this->buildWhereClause($conn_r),
|
|
||||||
$this->buildOrderClause($conn_r),
|
|
||||||
$this->buildLimitClause($conn_r));
|
|
||||||
|
|
||||||
return $table->loadAllFromArray($rows);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function willFilterPage(array $page) {
|
protected function willFilterPage(array $page) {
|
||||||
@@ -99,61 +92,59 @@ final class PassphraseCredentialQuery
|
|||||||
return $page;
|
return $page;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function buildWhereClause(AphrontDatabaseConnection $conn_r) {
|
protected function buildWhereClauseParts(AphrontDatabaseConnection $conn) {
|
||||||
$where = array();
|
$where = parent::buildWhereClauseParts($conn);
|
||||||
|
|
||||||
$where[] = $this->buildPagingClause($conn_r);
|
if ($this->ids !== null) {
|
||||||
|
|
||||||
if ($this->ids) {
|
|
||||||
$where[] = qsprintf(
|
$where[] = qsprintf(
|
||||||
$conn_r,
|
$conn,
|
||||||
'id IN (%Ld)',
|
'id IN (%Ld)',
|
||||||
$this->ids);
|
$this->ids);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($this->phids) {
|
if ($this->phids !== null) {
|
||||||
$where[] = qsprintf(
|
$where[] = qsprintf(
|
||||||
$conn_r,
|
$conn,
|
||||||
'phid IN (%Ls)',
|
'phid IN (%Ls)',
|
||||||
$this->phids);
|
$this->phids);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($this->credentialTypes) {
|
if ($this->credentialTypes !== null) {
|
||||||
$where[] = qsprintf(
|
$where[] = qsprintf(
|
||||||
$conn_r,
|
$conn,
|
||||||
'credentialType in (%Ls)',
|
'credentialType in (%Ls)',
|
||||||
$this->credentialTypes);
|
$this->credentialTypes);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($this->providesTypes) {
|
if ($this->providesTypes !== null) {
|
||||||
$where[] = qsprintf(
|
$where[] = qsprintf(
|
||||||
$conn_r,
|
$conn,
|
||||||
'providesType IN (%Ls)',
|
'providesType IN (%Ls)',
|
||||||
$this->providesTypes);
|
$this->providesTypes);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($this->isDestroyed !== null) {
|
if ($this->isDestroyed !== null) {
|
||||||
$where[] = qsprintf(
|
$where[] = qsprintf(
|
||||||
$conn_r,
|
$conn,
|
||||||
'isDestroyed = %d',
|
'isDestroyed = %d',
|
||||||
(int)$this->isDestroyed);
|
(int)$this->isDestroyed);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($this->allowConduit !== null) {
|
if ($this->allowConduit !== null) {
|
||||||
$where[] = qsprintf(
|
$where[] = qsprintf(
|
||||||
$conn_r,
|
$conn,
|
||||||
'allowConduit = %d',
|
'allowConduit = %d',
|
||||||
(int)$this->allowConduit);
|
(int)$this->allowConduit);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (strlen($this->nameContains)) {
|
if (strlen($this->nameContains)) {
|
||||||
$where[] = qsprintf(
|
$where[] = qsprintf(
|
||||||
$conn_r,
|
$conn,
|
||||||
'name LIKE %~',
|
'LOWER(name) LIKE %~',
|
||||||
$this->nameContains);
|
phutil_utf8_strtolower($this->nameContains));
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this->formatWhereClause($where);
|
return $where;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getQueryApplicationClass() {
|
public function getQueryApplicationClass() {
|
||||||
|
|||||||
@@ -11,58 +11,39 @@ final class PassphraseCredentialSearchEngine
|
|||||||
return 'PhabricatorPassphraseApplication';
|
return 'PhabricatorPassphraseApplication';
|
||||||
}
|
}
|
||||||
|
|
||||||
public function buildSavedQueryFromRequest(AphrontRequest $request) {
|
public function newQuery() {
|
||||||
$saved = new PhabricatorSavedQuery();
|
return new PassphraseCredentialQuery();
|
||||||
|
|
||||||
$saved->setParameter(
|
|
||||||
'isDestroyed',
|
|
||||||
$this->readBoolFromRequest($request, 'isDestroyed'));
|
|
||||||
$saved->setParameter('name', $request->getStr('name'));
|
|
||||||
|
|
||||||
return $saved;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function buildQueryFromSavedQuery(PhabricatorSavedQuery $saved) {
|
protected function buildCustomSearchFields() {
|
||||||
$query = id(new PassphraseCredentialQuery());
|
return array(
|
||||||
|
id(new PhabricatorSearchThreeStateField())
|
||||||
|
->setLabel(pht('Status'))
|
||||||
|
->setKey('isDestroyed')
|
||||||
|
->setOptions(
|
||||||
|
pht('Show All'),
|
||||||
|
pht('Show Only Destroyed Credentials'),
|
||||||
|
pht('Show Only Active Credentials')),
|
||||||
|
id(new PhabricatorSearchTextField())
|
||||||
|
->setLabel(pht('Name Contains'))
|
||||||
|
->setKey('name'),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
$destroyed = $saved->getParameter('isDestroyed');
|
protected function buildQueryFromParameters(array $map) {
|
||||||
if ($destroyed !== null) {
|
$query = $this->newQuery();
|
||||||
$query->withIsDestroyed($destroyed);
|
|
||||||
|
if ($map['isDestroyed'] !== null) {
|
||||||
|
$query->withIsDestroyed($map['isDestroyed']);
|
||||||
}
|
}
|
||||||
|
|
||||||
$name = $saved->getParameter('name');
|
if (strlen($map['name'])) {
|
||||||
if (strlen($name)) {
|
$query->withNameContains($map['name']);
|
||||||
$query->withNameContains($name);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return $query;
|
return $query;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function buildSearchForm(
|
|
||||||
AphrontFormView $form,
|
|
||||||
PhabricatorSavedQuery $saved_query) {
|
|
||||||
|
|
||||||
$name = $saved_query->getParameter('name');
|
|
||||||
|
|
||||||
$form
|
|
||||||
->appendChild(
|
|
||||||
id(new AphrontFormSelectControl())
|
|
||||||
->setName('isDestroyed')
|
|
||||||
->setLabel(pht('Status'))
|
|
||||||
->setValue($this->getBoolFromQuery($saved_query, 'isDestroyed'))
|
|
||||||
->setOptions(
|
|
||||||
array(
|
|
||||||
'' => pht('Show All Credentials'),
|
|
||||||
'false' => pht('Show Only Active Credentials'),
|
|
||||||
'true' => pht('Show Only Destroyed Credentials'),
|
|
||||||
)))
|
|
||||||
->appendChild(
|
|
||||||
id(new AphrontFormTextControl())
|
|
||||||
->setName('name')
|
|
||||||
->setLabel(pht('Name Contains'))
|
|
||||||
->setValue($name));
|
|
||||||
}
|
|
||||||
|
|
||||||
protected function getURI($path) {
|
protected function getURI($path) {
|
||||||
return '/passphrase/'.$path;
|
return '/passphrase/'.$path;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,7 +4,8 @@ final class PassphraseCredential extends PassphraseDAO
|
|||||||
implements
|
implements
|
||||||
PhabricatorApplicationTransactionInterface,
|
PhabricatorApplicationTransactionInterface,
|
||||||
PhabricatorPolicyInterface,
|
PhabricatorPolicyInterface,
|
||||||
PhabricatorDestructibleInterface {
|
PhabricatorDestructibleInterface,
|
||||||
|
PhabricatorSpacesInterface {
|
||||||
|
|
||||||
protected $name;
|
protected $name;
|
||||||
protected $credentialType;
|
protected $credentialType;
|
||||||
@@ -17,17 +18,29 @@ final class PassphraseCredential extends PassphraseDAO
|
|||||||
protected $isDestroyed;
|
protected $isDestroyed;
|
||||||
protected $isLocked = 0;
|
protected $isLocked = 0;
|
||||||
protected $allowConduit = 0;
|
protected $allowConduit = 0;
|
||||||
|
protected $authorPHID;
|
||||||
|
protected $spacePHID;
|
||||||
|
|
||||||
private $secret = self::ATTACHABLE;
|
private $secret = self::ATTACHABLE;
|
||||||
|
|
||||||
public static function initializeNewCredential(PhabricatorUser $actor) {
|
public static function initializeNewCredential(PhabricatorUser $actor) {
|
||||||
|
$app = id(new PhabricatorApplicationQuery())
|
||||||
|
->setViewer($actor)
|
||||||
|
->withClasses(array('PhabricatorPassphraseApplication'))
|
||||||
|
->executeOne();
|
||||||
|
|
||||||
|
$view_policy = $app->getPolicy(PassphraseDefaultViewCapability::CAPABILITY);
|
||||||
|
$edit_policy = $app->getPolicy(PassphraseDefaultEditCapability::CAPABILITY);
|
||||||
|
|
||||||
return id(new PassphraseCredential())
|
return id(new PassphraseCredential())
|
||||||
->setName('')
|
->setName('')
|
||||||
->setUsername('')
|
->setUsername('')
|
||||||
->setDescription('')
|
->setDescription('')
|
||||||
->setIsDestroyed(0)
|
->setIsDestroyed(0)
|
||||||
->setViewPolicy($actor->getPHID())
|
->setAuthorPHID($actor->getPHID())
|
||||||
->setEditPolicy($actor->getPHID());
|
->setViewPolicy($view_policy)
|
||||||
|
->setEditPolicy($edit_policy)
|
||||||
|
->setSpacePHID($actor->getDefaultSpacePHID());
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getMonogram() {
|
public function getMonogram() {
|
||||||
@@ -148,4 +161,13 @@ final class PassphraseCredential extends PassphraseDAO
|
|||||||
$this->delete();
|
$this->delete();
|
||||||
$this->saveTransaction();
|
$this->saveTransaction();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* -( PhabricatorSpacesInterface )----------------------------------------- */
|
||||||
|
|
||||||
|
|
||||||
|
public function getSpacePHID() {
|
||||||
|
return $this->spacePHID;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -65,10 +65,12 @@ final class PhabricatorPasteApplication extends PhabricatorApplication {
|
|||||||
PasteDefaultViewCapability::CAPABILITY => array(
|
PasteDefaultViewCapability::CAPABILITY => array(
|
||||||
'caption' => pht('Default view policy for newly created pastes.'),
|
'caption' => pht('Default view policy for newly created pastes.'),
|
||||||
'template' => PhabricatorPastePastePHIDType::TYPECONST,
|
'template' => PhabricatorPastePastePHIDType::TYPECONST,
|
||||||
|
'capability' => PhabricatorPolicyCapability::CAN_VIEW,
|
||||||
),
|
),
|
||||||
PasteDefaultEditCapability::CAPABILITY => array(
|
PasteDefaultEditCapability::CAPABILITY => array(
|
||||||
'caption' => pht('Default edit policy for newly created pastes.'),
|
'caption' => pht('Default edit policy for newly created pastes.'),
|
||||||
'template' => PhabricatorPastePastePHIDType::TYPECONST,
|
'template' => PhabricatorPastePastePHIDType::TYPECONST,
|
||||||
|
'capability' => PhabricatorPolicyCapability::CAN_EDIT,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -73,9 +73,11 @@ final class PhabricatorPholioApplication extends PhabricatorApplication {
|
|||||||
return array(
|
return array(
|
||||||
PholioDefaultViewCapability::CAPABILITY => array(
|
PholioDefaultViewCapability::CAPABILITY => array(
|
||||||
'template' => PholioMockPHIDType::TYPECONST,
|
'template' => PholioMockPHIDType::TYPECONST,
|
||||||
|
'capability' => PhabricatorPolicyCapability::CAN_VIEW,
|
||||||
),
|
),
|
||||||
PholioDefaultEditCapability::CAPABILITY => array(
|
PholioDefaultEditCapability::CAPABILITY => array(
|
||||||
'template' => PholioMockPHIDType::TYPECONST,
|
'template' => PholioMockPHIDType::TYPECONST,
|
||||||
|
'capability' => PhabricatorPolicyCapability::CAN_EDIT,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,9 +6,6 @@ final class PhabricatorPolicyEditController
|
|||||||
public function handleRequest(AphrontRequest $request) {
|
public function handleRequest(AphrontRequest $request) {
|
||||||
$viewer = $this->getViewer();
|
$viewer = $this->getViewer();
|
||||||
|
|
||||||
// TODO: This doesn't do anything yet, but sets up template policies; see
|
|
||||||
// T6860.
|
|
||||||
$is_template = false;
|
|
||||||
|
|
||||||
$object_phid = $request->getURIData('objectPHID');
|
$object_phid = $request->getURIData('objectPHID');
|
||||||
if ($object_phid) {
|
if ($object_phid) {
|
||||||
@@ -23,7 +20,6 @@ final class PhabricatorPolicyEditController
|
|||||||
$object_type = $request->getURIData('objectType');
|
$object_type = $request->getURIData('objectType');
|
||||||
if (!$object_type) {
|
if (!$object_type) {
|
||||||
$object_type = $request->getURIData('templateType');
|
$object_type = $request->getURIData('templateType');
|
||||||
$is_template = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$phid_types = PhabricatorPHIDType::getAllInstalledTypes($viewer);
|
$phid_types = PhabricatorPHIDType::getAllInstalledTypes($viewer);
|
||||||
|
|||||||
@@ -3,24 +3,15 @@
|
|||||||
final class PhabricatorPolicyExplainController
|
final class PhabricatorPolicyExplainController
|
||||||
extends PhabricatorPolicyController {
|
extends PhabricatorPolicyController {
|
||||||
|
|
||||||
private $phid;
|
|
||||||
private $capability;
|
|
||||||
|
|
||||||
public function shouldAllowPublic() {
|
public function shouldAllowPublic() {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function willProcessRequest(array $data) {
|
public function handleRequest(AphrontRequest $request) {
|
||||||
$this->phid = $data['phid'];
|
$viewer = $this->getViewer();
|
||||||
$this->capability = $data['capability'];
|
|
||||||
}
|
|
||||||
|
|
||||||
public function processRequest() {
|
$phid = $request->getURIData('phid');
|
||||||
$request = $this->getRequest();
|
$capability = $request->getURIData('capability');
|
||||||
$viewer = $request->getUser();
|
|
||||||
|
|
||||||
$phid = $this->phid;
|
|
||||||
$capability = $this->capability;
|
|
||||||
|
|
||||||
$object = id(new PhabricatorObjectQuery())
|
$object = id(new PhabricatorObjectQuery())
|
||||||
->setViewer($viewer)
|
->setViewer($viewer)
|
||||||
@@ -84,11 +75,15 @@ final class PhabricatorPolicyExplainController
|
|||||||
$handle->getTypeName(),
|
$handle->getTypeName(),
|
||||||
$handle->getObjectName());
|
$handle->getObjectName());
|
||||||
|
|
||||||
return $dialog
|
$dialog
|
||||||
->setTitle(pht('Policy Details: %s', $object_name))
|
->setTitle(pht('Policy Details: %s', $object_name))
|
||||||
->appendParagraph($intro)
|
->appendParagraph($intro)
|
||||||
->appendChild($auto_info)
|
->appendChild($auto_info)
|
||||||
->addCancelButton($object_uri, pht('Done'));
|
->addCancelButton($object_uri, pht('Done'));
|
||||||
|
|
||||||
|
$this->appendStrengthInformation($dialog, $object, $policy, $capability);
|
||||||
|
|
||||||
|
return $dialog;
|
||||||
}
|
}
|
||||||
|
|
||||||
private function appendSpaceInformation(
|
private function appendSpaceInformation(
|
||||||
@@ -180,4 +175,46 @@ final class PhabricatorPolicyExplainController
|
|||||||
'object policy checks.'));
|
'object policy checks.'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function appendStrengthInformation(
|
||||||
|
AphrontDialogView $dialog,
|
||||||
|
PhabricatorPolicyInterface $object,
|
||||||
|
PhabricatorPolicy $policy,
|
||||||
|
$capability) {
|
||||||
|
$viewer = $this->getViewer();
|
||||||
|
|
||||||
|
$default_policy = PhabricatorPolicyQuery::getDefaultPolicyForObject(
|
||||||
|
$viewer,
|
||||||
|
$object,
|
||||||
|
$capability);
|
||||||
|
if (!$default_policy) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($default_policy->getPHID() == $policy->getPHID()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($default_policy->isStrongerThan($policy)) {
|
||||||
|
$info = pht(
|
||||||
|
'This object has a less restrictive policy ("%s") than the default '.
|
||||||
|
'policy for similar objects (which is "%s").',
|
||||||
|
$policy->getShortName(),
|
||||||
|
$default_policy->getShortName());
|
||||||
|
} else if ($policy->isStrongerThan($default_policy)) {
|
||||||
|
$info = pht(
|
||||||
|
'This object has a more restrictive policy ("%s") than the default '.
|
||||||
|
'policy for similar objects (which is "%s").',
|
||||||
|
$policy->getShortName(),
|
||||||
|
$default_policy->getShortName());
|
||||||
|
} else {
|
||||||
|
$info = pht(
|
||||||
|
'This object has a different policy ("%s") than the default policy '.
|
||||||
|
'for similar objects (which is "%s").',
|
||||||
|
$policy->getShortName(),
|
||||||
|
$default_policy->getShortName());
|
||||||
|
}
|
||||||
|
|
||||||
|
$dialog->appendParagraph($info);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -342,5 +342,46 @@ final class PhabricatorPolicyQuery
|
|||||||
return $results;
|
return $results;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static function getDefaultPolicyForObject(
|
||||||
|
PhabricatorUser $viewer,
|
||||||
|
PhabricatorPolicyInterface $object,
|
||||||
|
$capability) {
|
||||||
|
|
||||||
|
$phid = $object->getPHID();
|
||||||
|
if (!$phid) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$type = phid_get_type($phid);
|
||||||
|
|
||||||
|
$map = self::getDefaultObjectTypePolicyMap();
|
||||||
|
|
||||||
|
if (empty($map[$type][$capability])) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$policy_phid = $map[$type][$capability];
|
||||||
|
|
||||||
|
return id(new PhabricatorPolicyQuery())
|
||||||
|
->setViewer($viewer)
|
||||||
|
->withPHIDs(array($policy_phid))
|
||||||
|
->executeOne();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static function getDefaultObjectTypePolicyMap() {
|
||||||
|
static $map;
|
||||||
|
|
||||||
|
if ($map === null) {
|
||||||
|
$map = array();
|
||||||
|
|
||||||
|
$apps = PhabricatorApplication::getAllApplications();
|
||||||
|
foreach ($apps as $app) {
|
||||||
|
$map += $app->getDefaultObjectTypePolicyMap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $map;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -121,14 +121,17 @@ final class PhabricatorProjectApplication extends PhabricatorApplication {
|
|||||||
ProjectDefaultViewCapability::CAPABILITY => array(
|
ProjectDefaultViewCapability::CAPABILITY => array(
|
||||||
'caption' => pht('Default view policy for newly created projects.'),
|
'caption' => pht('Default view policy for newly created projects.'),
|
||||||
'template' => PhabricatorProjectProjectPHIDType::TYPECONST,
|
'template' => PhabricatorProjectProjectPHIDType::TYPECONST,
|
||||||
|
'capability' => PhabricatorPolicyCapability::CAN_VIEW,
|
||||||
),
|
),
|
||||||
ProjectDefaultEditCapability::CAPABILITY => array(
|
ProjectDefaultEditCapability::CAPABILITY => array(
|
||||||
'caption' => pht('Default edit policy for newly created projects.'),
|
'caption' => pht('Default edit policy for newly created projects.'),
|
||||||
'template' => PhabricatorProjectProjectPHIDType::TYPECONST,
|
'template' => PhabricatorProjectProjectPHIDType::TYPECONST,
|
||||||
|
'capability' => PhabricatorPolicyCapability::CAN_EDIT,
|
||||||
),
|
),
|
||||||
ProjectDefaultJoinCapability::CAPABILITY => array(
|
ProjectDefaultJoinCapability::CAPABILITY => array(
|
||||||
'caption' => pht('Default join policy for newly created projects.'),
|
'caption' => pht('Default join policy for newly created projects.'),
|
||||||
'template' => PhabricatorProjectProjectPHIDType::TYPECONST,
|
'template' => PhabricatorProjectProjectPHIDType::TYPECONST,
|
||||||
|
'capability' => PhabricatorPolicyCapability::CAN_JOIN,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -65,6 +65,7 @@ final class PhabricatorSlowvoteApplication extends PhabricatorApplication {
|
|||||||
PhabricatorSlowvoteDefaultViewCapability::CAPABILITY => array(
|
PhabricatorSlowvoteDefaultViewCapability::CAPABILITY => array(
|
||||||
'caption' => pht('Default view policy for new polls.'),
|
'caption' => pht('Default view policy for new polls.'),
|
||||||
'template' => PhabricatorSlowvotePollPHIDType::TYPECONST,
|
'template' => PhabricatorSlowvotePollPHIDType::TYPECONST,
|
||||||
|
'capability' => PhabricatorPolicyCapability::CAN_VIEW,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -74,11 +74,13 @@ final class PhabricatorSpacesApplication extends PhabricatorApplication {
|
|||||||
PhabricatorSpacesCapabilityDefaultView::CAPABILITY => array(
|
PhabricatorSpacesCapabilityDefaultView::CAPABILITY => array(
|
||||||
'caption' => pht('Default view policy for newly created spaces.'),
|
'caption' => pht('Default view policy for newly created spaces.'),
|
||||||
'template' => PhabricatorSpacesNamespacePHIDType::TYPECONST,
|
'template' => PhabricatorSpacesNamespacePHIDType::TYPECONST,
|
||||||
|
'capability' => PhabricatorPolicyCapability::CAN_VIEW,
|
||||||
),
|
),
|
||||||
PhabricatorSpacesCapabilityDefaultEdit::CAPABILITY => array(
|
PhabricatorSpacesCapabilityDefaultEdit::CAPABILITY => array(
|
||||||
'caption' => pht('Default edit policy for newly created spaces.'),
|
'caption' => pht('Default edit policy for newly created spaces.'),
|
||||||
'default' => PhabricatorPolicies::POLICY_ADMIN,
|
'default' => PhabricatorPolicies::POLICY_ADMIN,
|
||||||
'template' => PhabricatorSpacesNamespacePHIDType::TYPECONST,
|
'template' => PhabricatorSpacesNamespacePHIDType::TYPECONST,
|
||||||
|
'capability' => PhabricatorPolicyCapability::CAN_EDIT,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
247
src/docs/user/field/repository_imports.diviner
Normal file
247
src/docs/user/field/repository_imports.diviner
Normal file
@@ -0,0 +1,247 @@
|
|||||||
|
@title Troubleshooting Repository Imports
|
||||||
|
@group fieldmanual
|
||||||
|
|
||||||
|
Guide to the troubleshooting repositories which import incompletely.
|
||||||
|
|
||||||
|
Overview
|
||||||
|
========
|
||||||
|
|
||||||
|
When you first import an external source code repository (or push new commits to
|
||||||
|
a hosted repository), Phabricator imports those commits in the background.
|
||||||
|
|
||||||
|
While a repository is initially importing, some features won't work. While
|
||||||
|
individual commits are importing, some of their metadata won't be available in
|
||||||
|
the web UI.
|
||||||
|
|
||||||
|
Sometimes, the import process may hang or fail to complete. This document can
|
||||||
|
help you understand the import process and troubleshoot problems with it.
|
||||||
|
|
||||||
|
|
||||||
|
Understanding the Import Pipeline
|
||||||
|
=================================
|
||||||
|
|
||||||
|
Phabricator first performs commit discovery on repositories. This examines
|
||||||
|
a repository and identifies all the commits in it at a very shallow level,
|
||||||
|
then creates stub objects for them. These stub objects primarily serve to
|
||||||
|
assign various internal IDs to each commit.
|
||||||
|
|
||||||
|
Commit discovery occurs in the update phase, and you can learn more about
|
||||||
|
updates in @{article:Diffusion User Guide: Repository Updates}.
|
||||||
|
|
||||||
|
After commits are discovered, background tasks are queued to actually import
|
||||||
|
commits. These tasks do things like look at commit messages, trigger mentions
|
||||||
|
and autoclose rules, cache changes, trigger Herald, publish feed stories and
|
||||||
|
email, and apply Owners rules. You can learn more about some of these steps in
|
||||||
|
@{article:Diffusion User Guide: Autoclose}.
|
||||||
|
|
||||||
|
Specifically, the import pipeline has four steps:
|
||||||
|
|
||||||
|
- **Message**: Parses the commit message and author metadata.
|
||||||
|
- **Change**: Caches the paths the commit affected.
|
||||||
|
- **Owners**: Runs Owners rules.
|
||||||
|
- **Herald**: Runs Herald rules and publishes notifications.
|
||||||
|
|
||||||
|
These steps run in sequence for each commit, but all discovered commits import
|
||||||
|
in parallel.
|
||||||
|
|
||||||
|
|
||||||
|
Identifying Missing Steps
|
||||||
|
=========================
|
||||||
|
|
||||||
|
There are a few major pieces of information you can look at to understand where
|
||||||
|
the import process is stuck.
|
||||||
|
|
||||||
|
First, to identify which commits have missing import steps, run this command:
|
||||||
|
|
||||||
|
```
|
||||||
|
phabricator/ $ ./bin/repository importing rXYZ
|
||||||
|
```
|
||||||
|
|
||||||
|
That will show what work remains to be done. Each line shows a commit which
|
||||||
|
is discovered but not imported, and the import steps that are remaining for
|
||||||
|
that commit. Generally, the commit is stuck on the first step in the list.
|
||||||
|
|
||||||
|
Second, load the Daemon Console (at `/daemon/` in the web UI). This will show
|
||||||
|
what work is currently being done and waiting to complete. The most important
|
||||||
|
sections are "Queued Tasks" (work waiting in queue) and "Leased Tasks"
|
||||||
|
(work currently being done).
|
||||||
|
|
||||||
|
Third, run this command to look at the daemon logs:
|
||||||
|
|
||||||
|
```
|
||||||
|
phabricator/ $ ./bin/phd log
|
||||||
|
```
|
||||||
|
|
||||||
|
This can show you any errors the daemons have encountered recently.
|
||||||
|
|
||||||
|
The next sections will walk through how to use this information to understand
|
||||||
|
and resolve the issue.
|
||||||
|
|
||||||
|
|
||||||
|
Handling Permanent Failures
|
||||||
|
===========================
|
||||||
|
|
||||||
|
Some commits can not be imported, which will permanently stop a repository from
|
||||||
|
fully importing. These are rare, but can be caused by unusual data in a
|
||||||
|
repository, version peculiarities, or bugs in the importer.
|
||||||
|
|
||||||
|
Permanent failures usually look like a small number of commits stuck on the
|
||||||
|
"Message" or "Change" steps in the output of `repository importing`. If you
|
||||||
|
have a larger number of commits, it is less likely that there are any permanent
|
||||||
|
problems.
|
||||||
|
|
||||||
|
In the Daemon console, permanent failures usually look like a small number of
|
||||||
|
tasks in "Leased Tasks" with a large failure count. These tasks are retrying
|
||||||
|
until they succeed, but a bug is permanently preventing them from succeeding,
|
||||||
|
so they'll rack up a large number of retries over time.
|
||||||
|
|
||||||
|
In the daemon log, these commits usually emit specific errors showing why
|
||||||
|
they're failing to import.
|
||||||
|
|
||||||
|
These failures are the easiest to identify and understand, and can often be
|
||||||
|
resolved quickly. Choose some failing commit from the output of `bin/repository
|
||||||
|
importing` and use this command to re-run any missing steps manually in the
|
||||||
|
foreground:
|
||||||
|
|
||||||
|
```
|
||||||
|
phabricator/ $ ./bin/repository reparse --importing --trace rXYZabcdef012...
|
||||||
|
```
|
||||||
|
|
||||||
|
This command is always safe to run, no matter what the actual root cause of
|
||||||
|
the problem is.
|
||||||
|
|
||||||
|
If this fails with an error, you've likely identified a problem with
|
||||||
|
Phabricator. Collect as much information as you can about what makes the commit
|
||||||
|
special and file a bug in the upstream by following the instructions in
|
||||||
|
@{article:Contributing Bug Reports}.
|
||||||
|
|
||||||
|
If the commit imports cleanly, this is more likely to be caused by some other
|
||||||
|
issue.
|
||||||
|
|
||||||
|
|
||||||
|
Handling Temporary Failures
|
||||||
|
===========================
|
||||||
|
|
||||||
|
Some commits may temporarily fail to import: perhaps the network or services
|
||||||
|
may have briefly been down, or some configuration wasn't quite right, or the
|
||||||
|
daemons were killed halfway through the work.
|
||||||
|
|
||||||
|
These commits will retry eventually and usually succeed, but some of the retry
|
||||||
|
time limits are very conserative (up to 24 hours) and you might not want to
|
||||||
|
wait that long.
|
||||||
|
|
||||||
|
In the Daemon console, temporarily failures usually look like tasks in the
|
||||||
|
"Leased Tasks" column with a large "Expires" value but a low "Failures" count
|
||||||
|
(usually 0 or 1). The "Expires" column is showing how long Phabricator is
|
||||||
|
waiting to retry these tasks.
|
||||||
|
|
||||||
|
In the daemon log, these temporary failures might have created log entries, but
|
||||||
|
might also not have. For example, if the failure was rooted in a network issue
|
||||||
|
that probably will create a log entry, but if the faiulre was rooted in the
|
||||||
|
daemons being abruptly killed that may not create a log entry.
|
||||||
|
|
||||||
|
You can follow the instructions from "Handling Permanent Failures" above to
|
||||||
|
reparse steps individually to look for an error that represents a root cause,
|
||||||
|
but sometimes this can happen because of some transient issue which won't be
|
||||||
|
identifiable.
|
||||||
|
|
||||||
|
The easiest way to fix this is to restart the daemons. When you restart
|
||||||
|
daemons, all task leases are immediately expired, so any tasks waiting for a
|
||||||
|
long time will run right away:
|
||||||
|
|
||||||
|
```
|
||||||
|
phabricator/ $ ./bin/phd restart
|
||||||
|
```
|
||||||
|
|
||||||
|
This command is always safe to run, no matter what the actual root cause of
|
||||||
|
the problem is.
|
||||||
|
|
||||||
|
After restarting the daemons, any pending tasks should be able to retry
|
||||||
|
immediately.
|
||||||
|
|
||||||
|
For more information on managing the daemons, see
|
||||||
|
@{article:Managing Daemons with phd}.
|
||||||
|
|
||||||
|
|
||||||
|
Forced Parsing
|
||||||
|
==============
|
||||||
|
|
||||||
|
In rare cases, the actual tasks may be lost from the task queue. Usually, they
|
||||||
|
have been stolen by gremlins or spritied away by ghosts, or someone may have
|
||||||
|
been too ambitious with running manual SQL commands and deleted a bunch of
|
||||||
|
extra things they shouldn't have.
|
||||||
|
|
||||||
|
There is no normal set of conditions under which this should occur, but you can
|
||||||
|
force Phabricator to re-queue the tasks to recover from it if it does occur.
|
||||||
|
|
||||||
|
This will look like missing steps in `repository importing`, but nothing in the
|
||||||
|
"Queued Tasks" or "Leased Tasks" sections of the daemon console. The daemon
|
||||||
|
logs will also be empty, since the tasks have vanished.
|
||||||
|
|
||||||
|
To re-queue parse tasks for a repository, run this command, which will queue
|
||||||
|
up all of the missing work in `repository importing`:
|
||||||
|
|
||||||
|
```
|
||||||
|
phabricator/ $ ./bin/repository reparse --importing --all rXYZ
|
||||||
|
```
|
||||||
|
|
||||||
|
This command may cause duplicate work to occur if you have misdiagnosed the
|
||||||
|
problem and the tasks aren't actually lost. For example, it could queue a
|
||||||
|
second task to perform publishing, which could cause Phabricator to send a
|
||||||
|
second copy of email about the commit. Other than that, it is safe to run even
|
||||||
|
if this isn't the problem.
|
||||||
|
|
||||||
|
After running this command, you should see tasks in "Queued Tasks" and "Leased
|
||||||
|
Tasks" in the console which correspond to the commits in `repository
|
||||||
|
importing`, and progress should resume.
|
||||||
|
|
||||||
|
|
||||||
|
Forced Imports
|
||||||
|
==============
|
||||||
|
|
||||||
|
In some cases, you might want to force a repository to be flagged as imported
|
||||||
|
even though the import isn't complete. The most common and reasonable case
|
||||||
|
where you might want to do this is if you've identified a permanent failure
|
||||||
|
with a small number of commits (maybe just one) and reported it upstream, and
|
||||||
|
are waiting for a fix. You might want to start using the repository immediately,
|
||||||
|
even if a few things can't import yet.
|
||||||
|
|
||||||
|
You should be cautious about doing this. The "importing" flag controls
|
||||||
|
publishing of notifications and email, so if you flag a repository as imported
|
||||||
|
but it still has a lot of work queued, it may send an enormous amount of email
|
||||||
|
as that work completes.
|
||||||
|
|
||||||
|
To mark a repository as imported even though it really isn't, run this
|
||||||
|
command:
|
||||||
|
|
||||||
|
```
|
||||||
|
phabricator/ $ ./bin/repository mark-imported rXYZ
|
||||||
|
```
|
||||||
|
|
||||||
|
If you do this by mistake, you can reverse it later by using the
|
||||||
|
`--mark-not-imported` flag.
|
||||||
|
|
||||||
|
|
||||||
|
General Tips
|
||||||
|
============
|
||||||
|
|
||||||
|
Broadly, `bin/repository` contains several useful debugging commands which
|
||||||
|
let you figure out where failures are occuring. You can add the `--trace` flag
|
||||||
|
to any command to get more details about what it is doing. For any command,
|
||||||
|
you can use `help` to learn more about what it does and which flag it takes:
|
||||||
|
|
||||||
|
```
|
||||||
|
phabricator/ $ bin/repository help <command>
|
||||||
|
```
|
||||||
|
|
||||||
|
In particular, you can use flags with the the `repository reparse` command to
|
||||||
|
manually run parse steps in the foreground, including re-running steps and
|
||||||
|
running steps out of order.
|
||||||
|
|
||||||
|
|
||||||
|
Next Steps
|
||||||
|
==========
|
||||||
|
|
||||||
|
Continue by:
|
||||||
|
|
||||||
|
- returning to the @{article:Diffusion User Guide}.
|
||||||
@@ -94,9 +94,23 @@ repositories.
|
|||||||
|
|
||||||
= Next Steps =
|
= Next Steps =
|
||||||
|
|
||||||
- Learn about creating a symbol index at
|
Continue by:
|
||||||
|
|
||||||
|
- learning how to creating a symbol index at
|
||||||
@{article:Diffusion User Guide: Symbol Indexes}; or
|
@{article:Diffusion User Guide: Symbol Indexes}; or
|
||||||
- set up repository hosting with
|
- setting up repository hosting with
|
||||||
@{article:Diffusion User Guide: Repository Hosting}; or
|
@{article:Diffusion User Guide: Repository Hosting}; or
|
||||||
- understand daemons in detail with @{article:Managing Daemons with phd}; or
|
- managing repository hooks with
|
||||||
- give us feedback at @{article:Give Feedback! Get Support!}.
|
@{article:Diffusion User Guide: Commit Hooks}; or
|
||||||
|
- understanding daemons in more detail with
|
||||||
|
@{article:Managing Daemons with phd}.
|
||||||
|
|
||||||
|
If you're having trouble getting things working, these topic guides may be
|
||||||
|
helpful:
|
||||||
|
|
||||||
|
- get details about automatically closing tasks and revisions in response
|
||||||
|
to commits in @{article:Diffusion User Guide: Autoclose}; or
|
||||||
|
- understand how Phabricator updates repositories with
|
||||||
|
@{article:Diffusion User Guide: Repository Updates}; or
|
||||||
|
- fix issues with repository imports with
|
||||||
|
@{article:Troubleshooting Repository Imports}.
|
||||||
|
|||||||
@@ -58,3 +58,11 @@ not necessarily that the repository is still importing.
|
|||||||
no containing branch was configured to autoclose.
|
no containing branch was configured to autoclose.
|
||||||
- //Field Not Present// This commit was processed before we implemented
|
- //Field Not Present// This commit was processed before we implemented
|
||||||
this diagnostic feature, and no information is available.
|
this diagnostic feature, and no information is available.
|
||||||
|
|
||||||
|
Next Steps
|
||||||
|
==========
|
||||||
|
|
||||||
|
Continue by:
|
||||||
|
|
||||||
|
- troubleshooting in greater depth with
|
||||||
|
@{article:Troubleshooting Repository Imports}.
|
||||||
|
|||||||
@@ -113,3 +113,11 @@ issues, using the `--trace` flag to get full details:
|
|||||||
|
|
||||||
To catch potential issues with permissions, run this command as the same user
|
To catch potential issues with permissions, run this command as the same user
|
||||||
that the daemons run as.
|
that the daemons run as.
|
||||||
|
|
||||||
|
Next Steps
|
||||||
|
==========
|
||||||
|
|
||||||
|
Continue by:
|
||||||
|
|
||||||
|
- troubleshooting in greater depth with
|
||||||
|
@{article:Troubleshooting Repository Imports}.
|
||||||
|
|||||||
@@ -362,6 +362,7 @@ final class PHUIHeaderView extends AphrontTagView {
|
|||||||
// NOTE: We'll do this even if the viewer has access to only one space, and
|
// NOTE: We'll do this even if the viewer has access to only one space, and
|
||||||
// show them information about the existence of spaces if they click
|
// show them information about the existence of spaces if they click
|
||||||
// through.
|
// through.
|
||||||
|
$use_space_policy = false;
|
||||||
if ($object instanceof PhabricatorSpacesInterface) {
|
if ($object instanceof PhabricatorSpacesInterface) {
|
||||||
$space_phid = PhabricatorSpacesNamespaceQuery::getObjectSpacePHID(
|
$space_phid = PhabricatorSpacesNamespaceQuery::getObjectSpacePHID(
|
||||||
$object);
|
$object);
|
||||||
@@ -376,13 +377,46 @@ final class PHUIHeaderView extends AphrontTagView {
|
|||||||
if ($space_policy) {
|
if ($space_policy) {
|
||||||
if ($space_policy->isStrongerThan($policy)) {
|
if ($space_policy->isStrongerThan($policy)) {
|
||||||
$policy = $space_policy;
|
$policy = $space_policy;
|
||||||
|
$use_space_policy = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$container_classes = array();
|
||||||
|
$container_classes[] = 'policy-header-callout';
|
||||||
$phid = $object->getPHID();
|
$phid = $object->getPHID();
|
||||||
|
|
||||||
|
// If we're going to show the object policy, try to determine if the object
|
||||||
|
// policy differs from the default policy. If it does, we'll call it out
|
||||||
|
// as changed.
|
||||||
|
if (!$use_space_policy) {
|
||||||
|
$default_policy = PhabricatorPolicyQuery::getDefaultPolicyForObject(
|
||||||
|
$viewer,
|
||||||
|
$object,
|
||||||
|
$view_capability);
|
||||||
|
if ($default_policy) {
|
||||||
|
if ($default_policy->getPHID() != $policy->getPHID()) {
|
||||||
|
$container_classes[] = 'policy-adjusted';
|
||||||
|
if ($default_policy->isStrongerThan($policy)) {
|
||||||
|
// The policy has strictly been weakened. For example, the
|
||||||
|
// default might be "All Users" and the current policy is "Public".
|
||||||
|
$container_classes[] = 'policy-adjusted-weaker';
|
||||||
|
} else if ($policy->isStrongerThan($default_policy)) {
|
||||||
|
// The policy has strictly been strengthened, and is now more
|
||||||
|
// restrictive than the default. For example, "All Users" has
|
||||||
|
// been replaced with "No One".
|
||||||
|
$container_classes[] = 'policy-adjusted-stronger';
|
||||||
|
} else {
|
||||||
|
// The policy has been adjusted but not strictly strengthened
|
||||||
|
// or weakened. For example, "Members of X" has been replaced with
|
||||||
|
// "Members of Y".
|
||||||
|
$container_classes[] = 'policy-adjusted-different';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
$icon = id(new PHUIIconView())
|
$icon = id(new PHUIIconView())
|
||||||
->setIconFont($policy->getIcon().' bluegrey');
|
->setIconFont($policy->getIcon().' bluegrey');
|
||||||
|
|
||||||
@@ -395,7 +429,12 @@ final class PHUIHeaderView extends AphrontTagView {
|
|||||||
),
|
),
|
||||||
$policy->getShortName());
|
$policy->getShortName());
|
||||||
|
|
||||||
return array($icon, $link);
|
return phutil_tag(
|
||||||
|
'span',
|
||||||
|
array(
|
||||||
|
'class' => implode(' ', $container_classes),
|
||||||
|
),
|
||||||
|
array($icon, $link));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -144,6 +144,41 @@ body .phui-header-shell.phui-bleed-header
|
|||||||
color: {$darkbluetext};
|
color: {$darkbluetext};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.policy-header-callout.policy-adjusted {
|
||||||
|
padding: 0 4px;
|
||||||
|
border-radius: 3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.policy-header-callout.policy-adjusted-weaker {
|
||||||
|
background: {$lightgreen};
|
||||||
|
border: 1px solid {$green};
|
||||||
|
}
|
||||||
|
|
||||||
|
.policy-header-callout.policy-adjusted-weaker .policy-link,
|
||||||
|
.policy-header-callout.policy-adjusted-weaker .phui-icon-view {
|
||||||
|
color: {$green};
|
||||||
|
}
|
||||||
|
|
||||||
|
.policy-header-callout.policy-adjusted-stronger {
|
||||||
|
background: {$lightred};
|
||||||
|
border: 1px solid {$red};
|
||||||
|
}
|
||||||
|
|
||||||
|
.policy-header-callout.policy-adjusted-stronger .policy-link,
|
||||||
|
.policy-header-callout.policy-adjusted-stronger .phui-icon-view {
|
||||||
|
color: {$red};
|
||||||
|
}
|
||||||
|
|
||||||
|
.policy-header-callout.policy-adjusted-different {
|
||||||
|
background: {$lightorange};
|
||||||
|
border: 1px solid {$orange};
|
||||||
|
}
|
||||||
|
|
||||||
|
.policy-header-callout.policy-adjusted-different .policy-link,
|
||||||
|
.policy-header-callout.policy-adjusted-different .phui-icon-view {
|
||||||
|
color: {$orange};
|
||||||
|
}
|
||||||
|
|
||||||
.phui-header-subheader .phui-header-status-dark {
|
.phui-header-subheader .phui-header-status-dark {
|
||||||
color: {$sh-indigotext};
|
color: {$sh-indigotext};
|
||||||
background: {$sh-indigobackground};
|
background: {$sh-indigobackground};
|
||||||
|
|||||||
Reference in New Issue
Block a user