From d7484b7b5963016b6fb96702d4c24e1aa2266d31 Mon Sep 17 00:00:00 2001 From: Jon Pugh Date: Mon, 21 Sep 2020 10:46:00 -0400 Subject: [PATCH] CH36 / Little Bugs (#596) * Use --ci option instead of --volumes for indicating that we don't want to use docker volumes. * Fix for commit 23c51d3a9aa2b20b40c3a9326aa87212f8d1298f. In the create wizard, site nodes don't exist for a time, so the query must include environments with site == null. * Test using devshop-composer-template instead * Fix broken class arrays. * Improve admin section for Server Access. * Improve project templates admin section. * Give create.js the data it expects, for now. * On "project/add/settings" page, don't show the checkbox. * Make checks for no_verify consistent with "empty()". * Accidentally lost $output[] setting. * Squashed cherry-pick of dab79688fafd5558116e334387b3280f8456a8e5...ffa7621a45e16672101089ea5925eebf37f69770 * Include unverified sites in project query. Rewrite OR query to one condition per line * change to empty to avoid notices. * Add gcp as an alias for git cherry-pick. * Clean up behat error reporting, including printing last drush output. * Avoid PHP notices. It slows things down quite a bit when DBLog is active. * Add a "Run in Terminal" button that outputs the command to trigger the task! * Cleanup run in terminal button with kbd alert. * Check more options to avoid printing in the wrong place. * Create separate "View Logs" and "Retry" buttons. Make the Retry button go right to the confirm form. * Let the hosting-queue-runner clear drush caches by itself, try to avoid strange missing module message: > Command hosting-task needs the following extension(s) enabled to run: [error] > The drush command 'hosting-task 197' could not be executed. [error] * Use devshop-log, not log. * Removing devshop_support_network_client from devmaster install profile and adding an update hook to disable it. * Add --reinstall option to robo test. * Bad update number. * Use all git projects in devmaster dev and remove distro_update * Bump to Drupal 7.73 * Build full drupal and makefile for now to reduce confusion until the rest of the integration work is done. * Keep break step commented. * Rename tested project to compose. * Stopgap: pass future git platform properties to context so that latest provision 3.x works with devshop in soon-to-be-legacy * Delete duplicate test file. * Remove test for support widget. * Ensure github PR queues respect the project settings by removing complex pull_request_create_policy feature that is impossible to calculate. Improve the form. * Improve the github PR settings form and messaging. * Fix create project form so that: - GitHub PR environments are included in the main form, so that they get created on the spot just like ad-hoc environments. - GitHub PR environments only show up when enabled. - Show number of PRs and link to PRs even if disabled. - * Fix create project form so that: - GitHub PR environments are included in the main form, so that they get created on submit of the form just like ad-hoc environments. - GitHub PR environments only show up when enabled. - Show number of PRs and link to PRs even if disabled. * Remove dsm and unneeded UI. * Fix error reporting about environment names already in use: highlight the right element and include the duplicate name in the error message. * Fix incorrect link back to project settings from errored environments page. * Update hosting_create_environment() to be used by the create site wizard by allowing it to skip site nodes, and replace ad-hoc code that did the same thing. * Remove the extra environments list from the project create page. * Save boolean for pr_environment in env settings so we know which envs to load PR data into later. * Handle forked repos in new project wizard with alternate URLs and branches. * Fix project name validation. * Remove loading.gif reference that isn't there. * Catch bad data exceptions when trying to load PR data. * If environment/platform was already created, re-insert environment DB record on Step 3 submit. this function was lost when converting to hosting_create_environment(). * Remove mentions of master branch from behat tests. --- .config.fish | 1 + .github/workflows/build.yml | 2 +- RoboFile.php | 24 +- bin/hosting-queue-runner | 5 +- bin/wait-site | 2 +- build-devmaster-dev.make.yml | 13 +- build-devmaster.make | 2 +- devmaster/devmaster.info | 1 - devmaster/drupal-org-core.make | 2 +- devmaster/drupal-org.make | 1 - .../devshop_bitbucket/includes/admin.inc | 2 +- .../devshop_github/devshop_github.module | 229 +++++++----------- .../devshop/devshop_github/includes/admin.inc | 4 +- .../devshop/devshop_github/includes/queue.inc | 2 +- .../modules/devshop/devshop_hosting.install | 7 + .../devshop_projects/drush/contexts.inc | 6 + .../devshop/devshop_projects/inc/admin.inc | 28 ++- .../devshop_projects/inc/create/step-1.inc | 21 +- .../devshop_projects/inc/create/step-2.inc | 9 + .../devshop_projects/inc/create/step-3.inc | 97 +++----- .../devshop_projects/inc/create/step-4.inc | 2 +- .../devshop/devshop_projects/inc/forms.inc | 5 + .../devshop/devshop_projects/inc/nodes.inc | 4 +- .../devshop_projects/inc/tasks-ajax.inc | 2 + .../devshop/devshop_projects/inc/ui.inc | 26 +- .../devshop/devshop_projects/projects.inc | 12 +- .../devshop/devshop_projects/tasks/create.inc | 54 +++-- .../devshop_remotes/devshop_remotes.module | 2 +- .../features/bootstrap/FeatureContext.php | 3 + .../tests/features/project.create.feature | 36 ++- .../tests/features/project.docroot.feature | 86 ------- devmaster/tests/features/support.feature | 2 +- devmaster/themes/boots/boots.css | 6 +- devmaster/themes/boots/environment.tpl.php | 8 +- devmaster/themes/boots/node--task.tpl.php | 41 +++- devmaster/themes/boots/template.php | 33 ++- 36 files changed, 386 insertions(+), 394 deletions(-) delete mode 100644 devmaster/tests/features/project.docroot.feature diff --git a/.config.fish b/.config.fish index 109d2ffbbd..2b2f5baf1c 100644 --- a/.config.fish +++ b/.config.fish @@ -12,6 +12,7 @@ abbr -a -- gd git diff abbr -a -- gs git status abbr -a -- gt git tag abbr -a -- gco git checkout +abbr -a -- gcp git cherry-pick abbr -a -- gp git push abbr -a -- gpl git pull abbr -a -- r bin/robo diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 919d858896..dfc372794d 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -101,7 +101,7 @@ jobs: --vars "${ANSIBLE_VARS}" \ --tags "${ANSIBLE_TAGS}" \ --skip-tags "${ANSIBLE_SKIP_TAGS}" \ - --volumes 0 \ + --ci \ && bin/github deployment:update --state=in_progress --description="Preparing Containers with robo up... Done." --log_url=${GITHUB_RUN_LOG_URL}#step:8:1 \ || ( bin/github deployment:update --state=failure --description="Preparing Containers with robo up... Failed." --log_url=${GITHUB_RUN_LOG_URL}#step:8:1 && exit 1 ) diff --git a/RoboFile.php b/RoboFile.php index a44ce17683..379c68d2fe 100644 --- a/RoboFile.php +++ b/RoboFile.php @@ -79,6 +79,7 @@ class RoboFile extends \Robo\Tasks { 'from' => 'FROM_IMAGE', 'os' => 'OS_VERSION', 'dockerfile' => 'DOCKERFILE', + 'compose-file' => 'COMPOSE_FILE', ]; /** @@ -219,7 +220,6 @@ public function prepareSourcecode($opts = [ 'no-dev' => FALSE, 'devshop-version' => '1.x', 'test-upgrade' => FALSE, - 'make' => 'profile', ]) { if (empty($this->git_ref)) { @@ -268,7 +268,7 @@ public function prepareSourcecode($opts = [ } // If we want to just populate modules into /devmaster folder... - if ($opts['make'] == 'profile') { + // MAKE inside the devmaster profile // Populate devmaster install profile with contrib code. $makefile_path = 'build-devmaster-dev.make.yml'; $make_destination = 'devmaster/'; @@ -282,10 +282,8 @@ public function prepareSourcecode($opts = [ throw new \RuntimeException("Drush make failed with the exit code " . $result->getExitCode()); } } - } - // Or if a whole Drupal build is needed. - elseif ($opts['make'] == 'drupal') { + // Also MAKE the entire drupal stack. // Run drush make to build the devmaster stack. $makefile_path = $opts['no-dev']? 'build-devmaster.make': "build-devmaster-dev.make.yml"; $make_destination = $this->devshop_root_path . "/aegir-home/devmaster-" . $opts['devshop-version']; @@ -305,7 +303,6 @@ public function prepareSourcecode($opts = [ throw new \RuntimeException("Drush make failed with the exit code " . $result->getExitCode()); } } - } // Set git remote urls if ($opts['no-dev'] == FALSE) { @@ -474,7 +471,7 @@ public function prepareContainers($user_uid = NULL, $hostname = 'devshop.local.c * @option $build Run `robo prepare:containers` to rebuild the container first. * @option os-version An OS "slug" for any of the geerlingguy/docker-*-ansible images: https://hub.docker.com/u/geerlingguy/ * @option environment pass an environment variable to docker-compose in the form --environment NAME=VALUE - * @option volumes Set to TRUE to use the docker-compose.volumes.yml file to map local folders into the container. + * @option ci Set to TRUE when run in CI, such as in build.yml. If not set, docker-compose.volumes.yml will be included to produce a development environment. * @option install-at-runtime Launch bare containers and then install devshop. */ public function up($docker_command = 'devshop-ansible-playbook', $opts = [ @@ -503,7 +500,7 @@ public function up($docker_command = 'devshop-ansible-playbook', $opts = [ 'config' => '/usr/share/devshop/ansible.cfg', 'local' => FALSE, 'environment' => [], - 'volumes' => true, + 'ci' => FALSE, 'install-at-runtime' => FALSE, 'build-command' => NULL, ]) { @@ -573,13 +570,13 @@ public function up($docker_command = 'devshop-ansible-playbook', $opts = [ if ($opts['mode'] == 'docker-compose') { // Volumes - if ($opts['volumes']) { + if (!$opts['ci']) { $this->yell('Volume mounts requested. Adding docker-compose.volumes.yml'); $this->say(' - ' . __DIR__ . '/aegir-home to /var/aegir'); $this->say(' - ' . __DIR__ . '/devmaster to /var/aegir/devmaster-1.x/profiles/devmaster'); // Set COMPOSE_FILE to include volumes. - putenv('COMPOSE_FILE=docker-compose.yml:docker-compose.volumes.yml'); + $opts['compose-file'] = 'docker-compose.yml:docker-compose.volumes.yml'; if (!file_exists('aegir-home/devmaster-' . $this::DEVSHOP_LOCAL_VERSION) && !$opts['skip-source-prep']) { $this->io()->warning('The aegir-home folder not present. Running prepare source code command.'); @@ -945,7 +942,8 @@ public function shell($user = 'aegir') { * Run all devshop tests on the containers. */ public function test($user = 'aegir', $opts = array( - 'compose-file' => 'docker-compose.yml', + 'compose-file' => 'docker-compose.yml:docker-compose.volumes.yml', + 'reinstall' => FALSE )) { $is_tty = !empty($_SERVER['XDG_SESSION_TYPE']) && $_SERVER['XDG_SESSION_TYPE'] == 'tty'; $no_tty = !$is_tty? '-T': ''; @@ -958,6 +956,10 @@ public function test($user = 'aegir', $opts = array( $commands[] = "docker-compose exec $no_tty devshop chmod 777 /var/aegir/test-artifacts -R"; } + if ($opts['reinstall']) { + $commands[] = "docker-compose exec $no_tty --user $user devshop drush @hostmaster provision-install --force-reinstall"; + } + $commands[] = "docker-compose exec $no_tty --user $user devshop /usr/share/devshop/tests/devshop-tests.sh"; $provision_io = new \DevShop\Component\PowerProcess\PowerProcessStyle($this->input, $this->output); foreach ($commands as $command) { diff --git a/bin/hosting-queue-runner b/bin/hosting-queue-runner index c5f1e4818e..d28ee91a37 100755 --- a/bin/hosting-queue-runner +++ b/bin/hosting-queue-runner @@ -10,5 +10,8 @@ PATH="$DIR:$PATH" export TIMEOUT=300 wait-site @hostmaster -log "Running drush @hostmaster hosting-queued ..." +devshop-log "Clearing drush caches ..." +drush cc drush + +devshop-log "Running drush @hostmaster hosting-queued ..." drush @hostmaster hosting-queued diff --git a/bin/wait-site b/bin/wait-site index eba9adee59..aa987b6c44 100755 --- a/bin/wait-site +++ b/bin/wait-site @@ -32,7 +32,7 @@ if [ -z "${ALIAS}" ]; then exit 1 fi -OPTIONS=-n log "Checking database... " +OPTIONS=-n devshop-log "Checking database... " # Returns true once mysql can connect. # Thanks to http://askubuntu.com/questions/697798/shell-script-how-to-run-script-after-mysql-is-ready diff --git a/build-devmaster-dev.make.yml b/build-devmaster-dev.make.yml index 2cca8ca642..731a7b7a24 100644 --- a/build-devmaster-dev.make.yml +++ b/build-devmaster-dev.make.yml @@ -9,7 +9,9 @@ defaults: projects: drupal: type: core - version: 7.72 + download: + type: git + tag: 7.73 # DEVELOPERS: If submitting a Pull Request, CHANGE THE URL or BRANCH here, if you need to test devshop and devmaster repos. devmaster: @@ -20,7 +22,9 @@ projects: url: devmaster devel: - version: 1 + download: + type: git + tag: 7.x-1.7 # The modules listed below override the settings in devmaster/drupal-org.make # Each module is downloaded and checked out to the version specified here. @@ -30,6 +34,11 @@ projects: type: git tag: 7.x-3.180-devshop + eldir: + download: + type: git + tag: 7.x-3.180 + hosting_git: download: type: git diff --git a/build-devmaster.make b/build-devmaster.make index e65cd447ef..ad567b598e 100644 --- a/build-devmaster.make +++ b/build-devmaster.make @@ -14,7 +14,7 @@ core = 7.x api = 2 projects[drupal][type] = core -projects[drupal][version] = 7.72 +projects[drupal][version] = 7.73 ; RELEASE ; Leave in place for replacement by release process. diff --git a/devmaster/devmaster.info b/devmaster/devmaster.info index 713f7d7c28..f30d0703ff 100644 --- a/devmaster/devmaster.info +++ b/devmaster/devmaster.info @@ -75,5 +75,4 @@ dependencies[] = aegir_config dependencies[] = devshop_permissions dependencies[] = devshop_stats dependencies[] = devshop_remotes -dependencies[] = devshop_support_network_client diff --git a/devmaster/drupal-org-core.make b/devmaster/drupal-org-core.make index 5d1739b731..8f85348467 100644 --- a/devmaster/drupal-org-core.make +++ b/devmaster/drupal-org-core.make @@ -8,4 +8,4 @@ api = 2 ; - https://github.com/opendevshop/devshop/blob/1.x/build-devmaster-dev.yml ; - https://github.com/opendevshop/devshop/blob/1.x/build-devmaster-travis-forks.make.yml projects[drupal][type] = core -projects[drupal][version] = 7.72 +projects[drupal][version] = 7.73 diff --git a/devmaster/drupal-org.make b/devmaster/drupal-org.make index 8db2798aa3..3bdf1fde03 100644 --- a/devmaster/drupal-org.make +++ b/devmaster/drupal-org.make @@ -59,7 +59,6 @@ projects[views][version] = "3.24" projects[views_bulk_operations][version] = "3.6" projects[ctools][version] = "1.15" projects[features][version] = "2.11" -projects[distro_update][version] = "1" projects[module_filter][version] = "2.2" projects[libraries][version] = 2.5 projects[token][version] = 1.7 diff --git a/devmaster/modules/devshop/devshop_bitbucket/includes/admin.inc b/devmaster/modules/devshop/devshop_bitbucket/includes/admin.inc index bf5d52a23c..1b14ecf67a 100644 --- a/devmaster/modules/devshop/devshop_bitbucket/includes/admin.inc +++ b/devmaster/modules/devshop/devshop_bitbucket/includes/admin.inc @@ -48,7 +48,7 @@ function devshop_bitbucket_settings_form($form, &$form_state) { $form['bitbucket_public_keys']['#prefix'] = '
'; $form['bitbucket_public_keys']['#suffix'] = l(' ' . t('Add devshop public key to your bitbucket account'), 'admin/devshop/bitbucket/add-key', array( 'attributes' => array( - 'class' => 'btn btn-primary btn-large' + 'class' => array('btn btn-primary btn-large'), ), 'html' => TRUE, )) . '
'; diff --git a/devmaster/modules/devshop/devshop_github/devshop_github.module b/devmaster/modules/devshop/devshop_github/devshop_github.module index 48f40f8cb6..bbfba9fc26 100644 --- a/devmaster/modules/devshop/devshop_github/devshop_github.module +++ b/devmaster/modules/devshop/devshop_github/devshop_github.module @@ -135,7 +135,8 @@ function devshop_github_menu() { */ function devshop_github_form_project_node_form_alter(&$form, &$form_state, $form_id) { $node = $form['#node']; - + $project = &$form_state['project']; + $prs_url = $project->git_repo_url . '/pulls'; if ($node->project->git_provider != 'github') { return; } @@ -153,59 +154,57 @@ function devshop_github_form_project_node_form_alter(&$form, &$form_state, $form // If Pull Requests were found in the environment, enable PR environments by default. - if (!empty(variable_get('devshop_github_token', ''))) { - $prs = devshop_github_client()->pullRequests()->all($node->project->github_owner, $node->project->github_repo); + if (devshop_github_token()) { + try { + $prs = devshop_github_client()->pullRequests()->all($node->project->github_owner, $node->project->github_repo); + } + catch (\Exception $e) { + drupal_set_message(t("Something went wrong when looking up PRs: for the GitHub repo !link: %message", array( + '!link' => l("{$node->project->github_owner}/{$node->project->github_repo}", $node->project->git_repo_url), + '%message' => $e->getMessage(), + )), 'error'); + $prs = []; + } } else { $prs = []; } $pr_count = count($prs); - if ($pr_count > 0) { - $form['project']['settings']['github']['found_prs'] = array( - '#type' => 'markup', - '#prefix' => '
', - '#suffix' => '
', - '#markup' => t('Pull Request Environments are enabled because !link. Please confirm your desired settings below.', array( - '!link' => l(format_plural($pr_count, t('there is 1 open Pull Request in your project'), t('there are @number open Pull Requests in your project', array('@number' => $pr_count))), $node->project->git_repo_url . '/pulls', array( - 'attributes' => array( - 'target' => '_blank', - ), - )), - )), - ); - $pr_envs_default_value = 1; - } - else { - $pr_envs_default_value = isset($node->project->settings->github) ? $node->project->settings->github['pull_request_environments'] : 0; - } - - $form['project']['settings']['github']['pull_request_environments'] = array( - '#type' => 'checkbox', - '#title' => t('Enable Pull Request Environments
Automatically create a copy of your site with the code from a Pull Request\'s branch.
'), - '#default_value' => $pr_envs_default_value, + $form['found_prs'] = array( + '#type' => 'markup', + '#prefix' => '
', + '#suffix' => '
', + '#weight' => -1000, + '#markup' => implode(' ', array( + format_plural($pr_count, t('There is 1 open Pull Request in your project'), t('There are @number open Pull Requests in your project', array('@number' => $pr_count))), + t('Confirm your desired behavior in the "GitHub Integration" section.'), + l(t('View Pull Requests on GitHub.com'), $node->project->git_repo_url . '/pulls', array( + 'attributes' => array( + 'target' => '_blank', + ), + )) + )), ); - $form['project']['settings']['github']['pull_request_create_policy'] = array( - '#title' => t('Environment Creation Policy'), - '#type' => 'radios', + $form['project']['settings']['github']['pull_request_environments'] = array( + '#title' => t('Pull Request Environments'), + '#description' => t('Maintain an environment for every !open_pull_request.', array( + '!open_pull_request' => l(t('open Pull Request (@count)', array( + '@count' => $pr_count, + )), $prs_url, array( + 'attributes' => array( + 'target' => '_blank', + ), + )), + )), + '#type' => 'checkbox', '#field_prefix' => '' . format_plural($pr_count, t('The project has one open Pull Request'), t('The project has @number open Pull Requests', array( '@number' => $pr_count, )) . '' ), - '#options' => array( - 'all' => t('Create Environments for all open Pull Requests.
Environments will be created and deleted as Pull Requests are opened, closed, and re-opened.
'), - 'create' => t('Only Create Environments when Pull Requests are opened or re-opened.
Recommended if you have a large number of open Pull Requests or if PRs have unstable or unknown code.
'), - ), - '#default_value' => !empty($node->project->settings->github['pull_request_create_policy'])? - $node->project->settings->github['pull_request_create_policy']: - 'all', - '#states' => array( - 'visible' => array( - ':input[name="project[settings][github][pull_request_environments]"]' => array('checked' => TRUE), - ), - ), + '#default_value' => $project->settings->github['pull_request_environments'], ); // Delete Pull Request environments? @@ -775,100 +774,95 @@ function devshop_github_create_project_form_set_values($element, &$form_state, & */ function devshop_github_form_devshop_project_create_step_environments_alter(&$form, &$form_state, $form_id) { - // Don't try to load PRs if there isn't even a token. - if (empty(variable_get('devshop_github_token', ''))) { - return; - } - $project = &$form_state['project']; - $form['pr_environments'] = array( - '#type' => 'container', - '#prefix' => '

' . t('Pull Request Environments') . '

', - '#weight' => -100, - ); - $form['pr_environments']['environments_table'] = array( - '#tree' => TRUE, - '#theme' => 'devshop_projects_create_settings_form', - ); + $prs_url = $project->git_repo_url . '/pulls'; // Load the PRs. - try{ + try { $prs = devshop_github_client()->pullRequests()->all($project->github_owner, $project->github_repo); - foreach ($prs as $pr) {// '#type' => 'fieldset', - - - // Prepare environment objects - $environment = new stdClass(); - $environment->name = "pr{$pr['number']}"; - $environment->git_ref = $pr['head']['ref']; - $project->environments[$environment->name] = $environment; + $environment_forms = array(); + if (!empty($project->settings->github['pull_request_environments'])) { - // Prepare form element. - $element = devshop_project_environment_create_form_element($project, $environment); - $element['name']['#attributes']['readonly'] = 1; - $element['git_ref']['#type'] = 'value'; - $element['git_ref']['#value'] = $environment->git_ref; - $element['git_ref']['git_ref_display'] = array( - '#type' => 'markup', - '#markup' => " {$environment->git_ref}", - ); + foreach ($prs as $pr) { + // Prepare environment objects + $environment = new stdClass(); + $environment->name = "pr{$pr['number']}"; + $environment->git_ref = $pr['head']['ref']; + $project->environments[$environment->name] = $environment; + + // Use NEW form elements as the template. + $environment_forms[$environment->name] = $form['project']['environments']['NEW']; + + // Create a disabled textfield for display to user, and convert original element to "value" type so the info is passed. + $environment_forms[$environment->name]['name']['#default_value'] = $environment->name; + $environment_forms[$environment->name]['name']['#attributes']['disabled'] = true; + + $environment_forms[$environment->name]['git_ref']['#default_value'] = $environment->git_ref; + $environment_forms[$environment->name]['git_ref']['#attributes']['disabled'] = true; + + // Handle forked environments with branches not in main repo. + $environment_forms[$environment->name]['git_ref']['#options'][$environment->git_ref] = $environment->git_ref; + + // If PR has different remote URL, set it. + if ($pr->head->repo->fork) { + // Try to match project URL scheme + if (strpos($project->git_url, 'git://') === 0){ + $remote_url = $pr->head->repo->git_url; + } + elseif (strpos($project->git_url, 'git@') === 0){ + $remote_url = $pr->head->repo->ssh_url; + } + else { + $remote_url = $pr->head->repo->clone_url; + } + $environment_forms[$environment->name]['git_remote'] = array( + '#value' => $remote_url, + ); + } - // Only add to $form if configured to keep all environments. - if ($project->settings->github['pull_request_create_policy'] == 'all') { - $form['pr_environments']['environments_table'][$environment->name] = $element; + // Save a flag that this is a pr_environment, so that the site knows to load the PR data later. + $environment_forms[$environment->name]['pr_environment'] = array( + '#value' => TRUE, + ); } - } - // Push "new" to the bottom. - $new_element = $form['project']['environments']['NEW']; - unset($form['project']['environments']['NEW']); - $form['project']['environments']['NEW'] = $new_element; + // Merge environments fields together to put PRs on top. + $form['project']['environments'] = array_merge($environment_forms, $form['project']['environments']); + } $settings_link = l(t('Change Project Settings'), 'projects/add/settings', array( 'fragment' => 'edit-project-settings-github', )); - $prs_link = l(t('Pull Requests for @repo', array( + $prs_link = l(t('Pull Requests for @repo: @count', array( '@repo' => $project->github_owner . '/' . $project->github_repo, - )), $project->git_repo_url . '/pulls', array( + '@count' => count($prs), + )), $prs_url, array( 'attributes' => array('target' => '_blank') )); // Project with PR environments disabled. - if (!$project->settings->github['pull_request_environments']) { + if (empty($project->settings->github['pull_request_environments'])) { $help_display['help'] = array( '#theme' => 'item_list', '#items' => array( t('Pull Request environments are disabled for this project.'), - $settings_link, $prs_link, + $settings_link, ), '#prefix' => '
', '#suffix' => '
', ); } // Project configured to maintain all PR environments. - elseif ($project->settings->github['pull_request_create_policy'] == 'all') { + elseif (!empty($project->settings->github['pull_request_environments'])) { $help_display['help'] = array( '#theme' => 'item_list', '#items' => array( - t('Project is configured to create environments for all Pull Requests.'), - $settings_link, + t('Project is configured to create environments for every open Pull Request.'), $prs_link, - ), - '#prefix' => '
', - '#suffix' => '
', - ); - } - // Project configured to only create environments on PR open or re-open. - elseif ($project->settings->github['pull_request_create_policy'] == 'create') { - $help_display['help'] = array( - '#theme' => 'item_list', - '#items' => array( - t('Project is configured to create environments only for new or reopened Pull Requests.'), $settings_link, - $prs_link, ), '#prefix' => '
', '#suffix' => '
', @@ -891,10 +885,6 @@ function devshop_github_form_devshop_project_create_step_environments_alter(&$fo } $form['pr_environments']['help'] = $help_display; $form['pr_environments']['help']['#weight'] = -1; - - // Add a header to distinguish from PRs - $form['project']['#prefix'] = '

' . t('Create Additional Environments') . '

'; - } /** @@ -983,37 +973,6 @@ function devshop_github_form_devshop_project_create_step_sites_alter(&$form, &$f 'fragment' => 'edit-project-settings-github', )); - // Load the PRs. - try { - $prs = devshop_github_client() - ->pullRequests() - ->all($project->github_owner, $project->github_repo); - - foreach ($prs as $pr) { - $form['platforms']['#rows'][] = array( - 'name' => "pr{$pr['number']}", - 'branch' => $pr['head']['ref'], - 'version' => array( - 'colspan' => 3, - 'data' => " {$pr['title']}", - ), - ); - } - } - catch (\Exception $e) { - drupal_set_message(theme('item_list', array( - 'items' => array( - t('GitHub authentication failed. Check your token at !link. The error was: %message', array( - '%message' => $e->getMessage(), - '!link' => l('DevShop GitHub Settings', 'admin/devshop/github'), - )), - $settings_link, - ), - )), 'error'); - - drupal_set_message(get_class($e)); - } - // Return if deploy method is not webhook. if ($project->settings->deploy['method'] != 'webhook') { return; diff --git a/devmaster/modules/devshop/devshop_github/includes/admin.inc b/devmaster/modules/devshop/devshop_github/includes/admin.inc index a005751a5e..69b7e9a5ad 100644 --- a/devmaster/modules/devshop/devshop_github/includes/admin.inc +++ b/devmaster/modules/devshop/devshop_github/includes/admin.inc @@ -102,7 +102,7 @@ function devshop_github_settings_form($form, &$form_state) { 'destination' => $_GET['q'], ), 'attributes' => array( - 'class' => 'btn btn-info' + 'class' => array('btn btn-info'), ), )); $form['devshop_github_ssh_key']['ssh_key_status_buttons'] ['#markup'] .= l(t('Configure Public Key'), 'admin/devshop', array( @@ -110,7 +110,7 @@ function devshop_github_settings_form($form, &$form_state) { 'destination' => $_GET['q'], ), 'attributes' => array( - 'class' => 'btn btn-default' + 'class' => array('btn btn-default') ), )) . ''; $form['devshop_github_ssh_key']['ssh_key_status'] ['#prefix'] = '
'; diff --git a/devmaster/modules/devshop/devshop_github/includes/queue.inc b/devmaster/modules/devshop/devshop_github/includes/queue.inc index d03c410c1a..1929d5cb53 100644 --- a/devmaster/modules/devshop/devshop_github/includes/queue.inc +++ b/devmaster/modules/devshop/devshop_github/includes/queue.inc @@ -47,7 +47,7 @@ function hosting_github_queue($count) { drush_log("Checking project {$project->name}...", "success"); // Check ones that have PR envs enabled - if ($project->settings->github['pull_request_create_policy'] == 'all') { + if (!empty($project->settings->github['pull_request_environments'])) { drush_log("Project {$project->name} is configured to maintain environments for all pull requests. Preparing environments...", "success"); $message = devshop_github_create_all_pr_environments($project_node); drush_log($message, "success"); diff --git a/devmaster/modules/devshop/devshop_hosting.install b/devmaster/modules/devshop/devshop_hosting.install index 4e0ce7c191..0288137a84 100644 --- a/devmaster/modules/devshop/devshop_hosting.install +++ b/devmaster/modules/devshop/devshop_hosting.install @@ -302,3 +302,10 @@ function devshop_hosting_update_7106() { variable_set('chosen_minimum_single', 0); variable_set('chosen_minimum_multiple', 0); } + +/** + * Disable DevShop.Support Client! + */ +function devshop_hosting_update_7107() { + module_disable(array('devshop_support_network_client')); +} diff --git a/devmaster/modules/devshop/devshop_projects/drush/contexts.inc b/devmaster/modules/devshop/devshop_projects/drush/contexts.inc index ca066134cf..d49166e800 100644 --- a/devmaster/modules/devshop/devshop_projects/drush/contexts.inc +++ b/devmaster/modules/devshop/devshop_projects/drush/contexts.inc @@ -161,6 +161,12 @@ function devshop_projects_hosting_platform_context_options(&$task) { $task->context_options['environment'] = $task->ref->environment->name; $task->context_options['project'] = $task->ref->project->name; $task->context_options['git_ref'] = $task->ref->environment->git_ref; + + // BRIDGE TO MODERNIZATION + // These are the new provision platform options. See + $task->context_options['git_remote'] = $task->ref->git['repo_url']; + $task->context_options['git_root'] = $task->ref->git['repo_path']; + $task->context_options['git_reference'] = $task->ref->git['git_ref']; } } diff --git a/devmaster/modules/devshop/devshop_projects/inc/admin.inc b/devmaster/modules/devshop/devshop_projects/inc/admin.inc index 4896a0ab25..7e076e2f04 100644 --- a/devmaster/modules/devshop/devshop_projects/inc/admin.inc +++ b/devmaster/modules/devshop/devshop_projects/inc/admin.inc @@ -27,11 +27,11 @@ function devshop_projects_settings_form($form, &$form_state) { $form['projects'] = array( '#type' => 'fieldset', - '#title' => t('Projects'), + '#title' => t('Project Templates'), ); $form['projects']['devshop_git_repo_suggestions'] = array( - '#title' => t('Suggested Git Repositories'), - '#description' => t('Enter Git URLs, one per line. When creating a new project, these Git Repositories will available to use as a starting codebase.'), + '#title' => t('Available Git Repositories'), + '#description' => t('Enter Git repository URLs, one per line. When creating a new project, these Git repositories are available to clone into new projects.'), '#type' => 'textarea', '#default_value' => implode(PHP_EOL, variable_get('devshop_git_repo_suggestions', array( 'git@github.com:opendevshop/devshop-composer-template.git' @@ -39,8 +39,8 @@ function devshop_projects_settings_form($form, &$form_state) { '#element_validate' => array('devshop_element_validate_explode_array'), ); $form['projects']['devshop_composer_project_suggestions'] = array( - '#title' => t('Suggested Composer Project'), - '#description' => t('Enter composer project names, one per line. These projects will be available to users creating new DevShop Project Git repositories.'), + '#title' => t('Available Composer Projects'), + '#description' => t('Enter Composer project names, one per line. These projects are available when creating new projects.'), '#type' => 'textarea', '#default_value' => implode(PHP_EOL, variable_get('devshop_composer_project_suggestions', array( 'devshop/composer-template:8.x-dev' @@ -112,12 +112,20 @@ function devshop_projects_settings_form($form, &$form_state) { // Server settings. $form['server'] = array( - '#type' => 'fieldset', - '#title' => t('DevShop Server'), + '#type' => 'fieldset', + '#title' => t('DevShop Server Access'), + '#weight' => -1, ); $form['server']['devshop_public_key'] = array( - '#title' => t('Aegir User Public Key'), - '#description' => t('The public key of the aegir user on this server. If you change the SSH keys located at /var/aegir/.ssh/id_rsa.pub, then you should update this variable. This variable is for user reference only. If using GitHub API, then devshop will check to make sure the server has access using this public key.'), + '#title' => t('Public Key'), + '#description' => theme('item_list', array( + 'items' => array( + t('The public key for this server. This key will be used when cloning code and syncing data from remote servers.'), + t('Add this key to your git host to allow this DevShop to clone protected code.'), + t('Add this key to other hosts to authorize this DevShop to connect and copy data from your existing sites.'), + t('Warning: If you authorize this key on a production server, any user who can access this DevShop will be able to access that server.') + ), + )), '#type' => 'textarea', '#default_value' => variable_get('devshop_public_key', ''), ); @@ -131,4 +139,4 @@ function devshop_project_settings_validate_environment_url_pattern($element, &$f if (strpos($form_state['values']['devshop_project_environment_url_pattern'], '@environment') === FALSE || strpos($form_state['values']['devshop_project_environment_url_pattern'], '@project') === FALSE) { form_error($element, t('The placeholders @project and @environment must be in the Environment Domain Name Pattern.')); } -} \ No newline at end of file +} diff --git a/devmaster/modules/devshop/devshop_projects/inc/create/step-1.inc b/devmaster/modules/devshop/devshop_projects/inc/create/step-1.inc index 49dbc77194..000cf33d24 100644 --- a/devmaster/modules/devshop/devshop_projects/inc/create/step-1.inc +++ b/devmaster/modules/devshop/devshop_projects/inc/create/step-1.inc @@ -50,6 +50,9 @@ function devshop_project_create_step_git($form, $form_state) { '#attributes'=> array( 'placeholder' => t('myproject') ), + '#element_validate' => array( + 'devshop_project_wizard_title_validate', + ), '#weight' => 1, ); } @@ -114,7 +117,7 @@ function devshop_project_create_step_git($form, $form_state) { 'destination' => $_GET['q'], ), 'attributes' => array( - 'class' => 'btn btn-default' + 'class' => array('btn btn-default') ), )); $output = << $project_name, + )), 'warning'); + } + + // If still contains spaces, throw error. + if (strpos($project_name, ' ') !== FALSE) { + form_set_error('title', t('Project name cannot contain any spaces or non-alphanumeric characters.')); + } } /** @@ -330,5 +345,5 @@ function devshop_project_create_step_git_submit(&$from, &$form_state) { } // Remove default "task" messages. - drupal_get_messages(); + // drupal_get_messages(); } diff --git a/devmaster/modules/devshop/devshop_projects/inc/create/step-2.inc b/devmaster/modules/devshop/devshop_projects/inc/create/step-2.inc index 00ca82ab7c..4a2c01c962 100644 --- a/devmaster/modules/devshop/devshop_projects/inc/create/step-2.inc +++ b/devmaster/modules/devshop/devshop_projects/inc/create/step-2.inc @@ -57,7 +57,16 @@ function devshop_project_create_step_settings($form, &$form_state) { $form['buttons']['next']['#submit'] = $actions['submit']['#submit']; $form['buttons']['next']['#submit'][] = 'ctools_wizard_submit'; + // Add create.js script and pass an object. drupal_add_js(drupal_get_path('module', 'devshop_projects') . '/inc/create/create.js'); + // @TODO This is only here because create.js is currently coded to expect the array. + // I tried, I really tried to check for this prop in create.js. + drupal_add_js(array( + 'devshop' => array( + 'projectNameSourceElements' => array( + ), + ), + ), 'setting'); // Remove "live environment" selector. $form['project']['codebase']['live_environment']['#type'] = 'value'; diff --git a/devmaster/modules/devshop/devshop_projects/inc/create/step-3.inc b/devmaster/modules/devshop/devshop_projects/inc/create/step-3.inc index 3813e95831..fb373fadbe 100644 --- a/devmaster/modules/devshop/devshop_projects/inc/create/step-3.inc +++ b/devmaster/modules/devshop/devshop_projects/inc/create/step-3.inc @@ -98,21 +98,18 @@ function devshop_project_create_step_environments_validate(&$form, &$form_state) // Check for illegal chars if ($env != 'NEW' && !empty($env_settings['name'])) { if (!preg_match('!^[a-z0-9_]+$!', $env_settings['name'])) { - $form_item = 'environments][' . $env . '][name'; + $form_item = 'project][environments][' . $env . '][name'; form_set_error($form_item, t('The environment name must contain only lowercase letters, numbers, and underscores.')); } } - // Check for unique names. + // Ensure NEW env name does not already exist in the environments array. if ($env == 'NEW' && array_key_exists($env_settings['name'], $values['project']['environments'])) { - $form_item = 'environments][' . $env . '][name'; - form_set_error($form_item, t('The environment name must be unique.')); + $form_item = 'project][environments][' . $env . '][name'; + form_set_error($form_item, t('The environment name must be unique. %name is already in use.', array( + '%name' => $env_settings['name'], + ))); } - if ($env != $env_settings['name'] && array_key_exists($env_settings['name'], $values['project']['environments'])) { - $form_item = 'environments][' . $env . '][name'; - form_set_error($form_item, t('The environment name must be unique.')); - } - } // Reject if empty @@ -185,12 +182,15 @@ function devshop_project_create_step_environments_submit(&$form, &$form_state) { // Save environments data $environments = $form_state['values']['project']['environments']; + + // If NEW environment name was submitted, add it to the env array with name as key, then unset NEW environment. if (!empty($environments['NEW']['name'])) { $new_environment_name = $environments['NEW']['name']; $environments[$new_environment_name] = $environments['NEW']; } unset($environments['NEW']); + // Rebuild $environments array ensuring "name" field is used as array key. foreach ($environments as $name => $environment) { if ($name != $environment['name']) { $environments[$environment['name']] = $environment; @@ -209,68 +209,33 @@ function devshop_project_create_step_environments_submit(&$form, &$form_state) { $environment->settings = (object) $environment->settings; $name = trim($environment->name); + // @TODO: VALIDATE CONTEXT DOES NOT EXIST!! if (!empty($name)) { - $id = db_insert('hosting_devshop_project_environment') - ->fields(array( - 'project_nid' => $form_state['values']['nid'], - 'name' => $environment->name, - 'platform' => $environment->platform, - 'settings' => serialize($environment->settings), - )) - ->execute(); - } - // Create platform node if we don't have one. - if (empty($environment->platform)) { - //If platform hasn't been created yet, build platform node - $platform = new stdClass; - $platform->type = 'platform'; - $platform->title = $project->name . '_' . $name; - - // Platform publish_path - - // If drupal path is set, repo path and platform path are different. Append drupal_path to repo path to create publish path. - if ($project->drupal_path) { - $platform->git['repo_path'] = $project->code_path . '/' . $environment->name; - $platform->publish_path = $project->code_path . '/' . $environment->name . '/' . $project->drupal_path; - } - else { - $platform->git['repo_path'] = $project->code_path . '/' . $environment->name; - $platform->publish_path = $project->code_path . '/' . $environment->name; + if (!empty($environment->git_remote)) { + $git_remote = $environment->git_remote; + } else { + $git_remote = null; } - // Git information - $platform->git['repo_url'] = $project->git_url; - $platform->git['git_ref'] = $environment->git_ref; - - // Other attributes - $platform->web_server = $environment->settings->web_server; - $platform->db_server = $environment->settings->db_server; - - // Save the node - global $user; - node_object_prepare($platform); - $platform->language = LANGUAGE_NONE; // Or e.g. 'en' if locale is enabled - $platform->uid = $user->uid; - $platform->status = 1; - $platform->promote = 0; - $platform->comment = 0; - $platform = node_submit($platform); - node_save($platform); - - if (!$platform->nid) { - form_set_error('projects', t('An unknown problem has occured: the platform node was not created for the %env environment.', array('%env' => $environment->name))); + if (!empty($environment->platform)) { + // RECREATE the env RECORD in the database if platform NID already exists. + $id = db_insert('hosting_devshop_project_environment') + ->fields(array( + 'project_nid' => $form_state['values']['nid'], + 'name' => $environment->name, + 'platform' => $environment->platform, + 'settings' => serialize($environment->settings), + )) + ->execute(); + } + else { + // CREATE the environment OBJECT, including a new platform and DB record. + drupal_set_message(t('Creating environment %name', array( + '%name' => $name, + ))); + hosting_create_environment($project, $name, $environment->git_ref, NULL, $environment->settings, 'create', $git_remote, FALSE); ; } - $environment->platform = $platform->nid; - - // Update environment with our platform - db_update('hosting_devshop_project_environment') - ->fields(array( - 'platform' => $environment->platform, - )) - ->condition('project_nid', $form_state['values']['nid']) - ->condition('name', $environment->name) - ->execute(); } } diff --git a/devmaster/modules/devshop/devshop_projects/inc/create/step-4.inc b/devmaster/modules/devshop/devshop_projects/inc/create/step-4.inc index 9503b52471..fbe802a384 100644 --- a/devmaster/modules/devshop/devshop_projects/inc/create/step-4.inc +++ b/devmaster/modules/devshop/devshop_projects/inc/create/step-4.inc @@ -203,7 +203,7 @@ HTML; if (strpos($errors_rendered, 'Check the Publish Path of the platform') !== FALSE) { if (empty($project->drupal_path)) { $message = t("Drupal was not found in the project at the root. !link and try again.", array( - '!link' => l(t('Change Document Root in Project Settings'), '/project/add/settings'), + '!link' => l(t('Change Document Root in Project Settings'), '/projects/add/settings'), )); } else { diff --git a/devmaster/modules/devshop/devshop_projects/inc/forms.inc b/devmaster/modules/devshop/devshop_projects/inc/forms.inc index 257c03dc20..7a31607c87 100644 --- a/devmaster/modules/devshop/devshop_projects/inc/forms.inc +++ b/devmaster/modules/devshop/devshop_projects/inc/forms.inc @@ -461,6 +461,11 @@ function devshop_projects_form_alter(&$form, &$form_state, $form_id) { $form['options']['status']['#title'] = t('Active'); $form['options']['status']['#description'] = t('Uncheck this box to hide the project from the main dashboard. Users who have permission to "view unpublished nodes" will still be able to view inactive projects.'); + // On "project/add/settings" page, don't show the checkbox. + if (current_path() == 'projects/add/settings') { + $form['options']['status']['#access'] = 0; + } + unset($form['actions']['delete']); unset($form['actions']['preview']); if (isset($form['retry']['#value'])) { diff --git a/devmaster/modules/devshop/devshop_projects/inc/nodes.inc b/devmaster/modules/devshop/devshop_projects/inc/nodes.inc index f022cad44a..b9fbfa1173 100644 --- a/devmaster/modules/devshop/devshop_projects/inc/nodes.inc +++ b/devmaster/modules/devshop/devshop_projects/inc/nodes.inc @@ -178,7 +178,7 @@ function devshop_projects_node_insert($node) { return; } - if (!isset($node->no_verify)) { + if (empty($node->no_verify)) { hosting_add_task($node->nid, 'verify'); } @@ -274,7 +274,7 @@ function devshop_projects_node_update($node) { // Write project record. drupal_write_record('hosting_devshop_project', $info, 'nid'); - if (!isset($node->no_verify) || $node->no_verify == FALSE) { + if (empty($node->no_verify)) { hosting_add_task($node->nid, 'verify'); } diff --git a/devmaster/modules/devshop/devshop_projects/inc/tasks-ajax.inc b/devmaster/modules/devshop/devshop_projects/inc/tasks-ajax.inc index 4aa3169d7f..e55d770dab 100644 --- a/devmaster/modules/devshop/devshop_projects/inc/tasks-ajax.inc +++ b/devmaster/modules/devshop/devshop_projects/inc/tasks-ajax.inc @@ -81,6 +81,8 @@ function devshop_projects_tasks_status_json() { // Output a rendered task node $task_node->rendered = theme('devshop_task', array('task' => $task_node)); + + $output[] = $task_node; } print json_encode($output); diff --git a/devmaster/modules/devshop/devshop_projects/inc/ui.inc b/devmaster/modules/devshop/devshop_projects/inc/ui.inc index 5054046bc9..dcefeae99f 100644 --- a/devmaster/modules/devshop/devshop_projects/inc/ui.inc +++ b/devmaster/modules/devshop/devshop_projects/inc/ui.inc @@ -155,15 +155,24 @@ HTML; // No Projects if (empty($rows)) { - $link = url('projects/add'); - $welcome = t('Welcome to DevShop!'); - $text = t('Create your first project to get started.'); - $button = t('Start a Project'); + $link = url('admin/devshop'); + $welcome = t('Welcome to your DevShop!'); + $subtitle = t("You are almost ready to start working."); + $text = t("Check your DevShop settings or get started with a new Project."); + $button = t('DevShop Settings'); + + $link_create = url('projects/add'); + $button_create = t('Create your first Project'); + $output = <<

$welcome

-

$text

-

$button

+

$subtitle

+

$text

+

+ $button + $button_create +

HTML; @@ -201,9 +210,12 @@ function devshop_projects_inactive_tab_title() { } /** - * + * Access check for "inactive projects" tab. */ function devshop_projects_inactive_tab_access() { + if (arg(0) == 'projects' && arg(1) == 'add') { + return FALSE; + } static $count; if (!isset($count)) { $count = devshop_projects_count(NODE_NOT_PUBLISHED); diff --git a/devmaster/modules/devshop/devshop_projects/projects.inc b/devmaster/modules/devshop/devshop_projects/projects.inc index 116db4495f..f6222fdcf0 100644 --- a/devmaster/modules/devshop/devshop_projects/projects.inc +++ b/devmaster/modules/devshop/devshop_projects/projects.inc @@ -172,12 +172,18 @@ function devshop_project_load($node) { LEFT JOIN {node} db ON s.db_server = db.nid LEFT JOIN {node} pn ON e.project_nid = pn.nid LEFT JOIN {hosting_site_alias} a ON a.vid = s.vid - WHERE project_nid = :nid AND - e.name != '' AND - s.status IN (:site_status) + WHERE project_nid = :nid + AND e.name != '' + AND ( + s.status IN (:site_status) + OR s.verified = 0 + OR s.nid IS NULL + ) ORDER BY name; ", array( ':nid' => $node->nid, + + // Query includes sites that are either enabled, queued, unverified, or have no site NID. ':site_status' => [HOSTING_SITE_QUEUED, HOSTING_SITE_ENABLED] )); foreach ($environment_data as $environment) { diff --git a/devmaster/modules/devshop/devshop_projects/tasks/create.inc b/devmaster/modules/devshop/devshop_projects/tasks/create.inc index 8444e3b6b9..124dcbb778 100644 --- a/devmaster/modules/devshop/devshop_projects/tasks/create.inc +++ b/devmaster/modules/devshop/devshop_projects/tasks/create.inc @@ -17,22 +17,10 @@ * @param $source_environment * If desired, the environment to clone. (Copy the database and create a new branch from) */ -function hosting_create_environment($project, $new_environment_name, $new_environment_branch = NULL, $source_environment = NULL, $settings = NULL, $action = 'create', $git_remote_url = NULL) { +function hosting_create_environment($project, $new_environment_name, $new_environment_branch = NULL, $source_environment = NULL, $settings = NULL, $action = 'create', $git_remote_url = NULL, $create_site = TRUE) { $settings = (object) $settings; global $user; - // Create site node. - $site = new stdClass(); - $site->type = 'site'; - $site->title = devshop_environment_url($project, $new_environment_name); - $site->status = 1; - $site->uid = $user->uid; - $site->name = $user->name; - $site->client = HOSTING_DEFAULT_CLIENT; - - // Attach a new platform node. - $site->platform_node = devshop_prepare_platform_node($project, $new_environment_name, $new_environment_branch, $settings->web_server, $git_remote_url); - // Set db server to the project default, if none was set. if (empty($settings->db_server) && !empty($project->settings->default_environment['db_server'])) { $settings->db_server = $project->settings->default_environment['db_server']; @@ -50,13 +38,34 @@ function hosting_create_environment($project, $new_environment_name, $new_enviro $settings->web_server = $project->settings->default_environment['web_server']; } - // Now that desired servers have been determined, save to their respective nodes. - $site->db_server = $settings->db_server; - - // Save the site node, along with the platform. - // This is possible thanks to the patch in https://www.drupal.org/node/2824731 - if ($site = node_submit($site)) { - node_save($site); + // Always prepare platform node. That part is required. + $platform = devshop_prepare_platform_node($project, $new_environment_name, $new_environment_branch, $settings->web_server, $git_remote_url); + + // Create site node, unless blocked by setting $create_site = FALSE. + if ($create_site) { + $site = new stdClass(); + $site->type = 'site'; + $site->title = devshop_environment_url($project, $new_environment_name); + $site->status = 1; + $site->uid = $user->uid; + $site->name = $user->name; + $site->client = HOSTING_DEFAULT_CLIENT; + + // Attach a new platform node. + $site->platform_node = $platform; + $site->db_server = $settings->db_server; + + // Save the site node, along with the platform. + // This is possible thanks to the patch in https://www.drupal.org/node/2824731 + if ($site = node_submit($site)) { + node_save($site); + } + } + else { + // If site doesn't get saved, platform doesn't either, so save it directly. + if ($platform = node_submit($platform)) { + node_save($platform); + } } // // If no new branch specified and fork source is present, set branch to forked environment's branch. @@ -111,7 +120,8 @@ function hosting_create_environment($project, $new_environment_name, $new_enviro // Next, add the environment record. $environment = new stdClass(); $environment->name = $new_environment_name; - $environment->site = $site->nid; + $environment->site = $site->nid?: NULL; + $environment->platform = $platform->nid; // Use settings passed in to this function. $environment->settings = $settings; @@ -132,7 +142,7 @@ function hosting_create_environment($project, $new_environment_name, $new_enviro 'project_nid' => $environment->project_nid, 'name' => $environment->name, 'site' => $environment->site, - 'platform' => $site->platform_node->nid, + 'platform' => $environment->platform, 'settings' => serialize($environment->settings), 'last_task' => $environment->last_task, )) diff --git a/devmaster/modules/devshop/devshop_remotes/devshop_remotes.module b/devmaster/modules/devshop/devshop_remotes/devshop_remotes.module index 86bf162891..c7fd28df5e 100644 --- a/devmaster/modules/devshop/devshop_remotes/devshop_remotes.module +++ b/devmaster/modules/devshop/devshop_remotes/devshop_remotes.module @@ -362,7 +362,7 @@ function devshop_remotes_node_load($nodes, $types) { if (count(array_intersect(array('project'), $types))) { foreach ($nodes as &$node) { - if (isset($node->project->settings) && !is_array($node->project->settings->aliases)) { + if (isset($node->project->settings) && empty($node->project->settings->aliases)) { $node->project->settings->aliases = array(); } diff --git a/devmaster/tests/features/bootstrap/FeatureContext.php b/devmaster/tests/features/bootstrap/FeatureContext.php index 2126ea3d79..493ca41952 100644 --- a/devmaster/tests/features/bootstrap/FeatureContext.php +++ b/devmaster/tests/features/bootstrap/FeatureContext.php @@ -119,6 +119,9 @@ public function logAfterFailedStep($event) echo "\nWatchdog Errors:\n"; $this->drushContext->assertDrushCommand('wd-show'); $this->drushContext->printLastDrushOutput(); + + echo "\n\nLast Drush Output\n"; + $this->drushContext->printLastDrushOutput(); } } diff --git a/devmaster/tests/features/project.create.feature b/devmaster/tests/features/project.create.feature index fcd9b5a7c8..491dd97329 100644 --- a/devmaster/tests/features/project.create.feature +++ b/devmaster/tests/features/project.create.feature @@ -11,21 +11,21 @@ Feature: Create a project and check settings When I click "Projects" And I click "Start a new Project" Then I should see "Step 1" - Then I fill in "drpl8" for "Project Code Name" - And I fill in "http://github.com/opendevshop/drupal_docroot.git" for "Git Repository URL" + Then I fill in "composer" for "Project Code Name" + And I fill in "http://github.com/opendevshop/devshop-composer-template.git" for "Git Repository URL" When I press "Next" # Step 2 - Then I should see "drpl8" - And I should see "http://github.com/opendevshop/drupal_docroot.git" + Then I should see "composer" + And I should see "http://github.com/opendevshop/devshop-composer-template.git" Then I should see "Please wait while we connect and analyze your repository." When I run drush "hosting-tasks --force --fork=0 --strict=0" # Then print last drush output And I reload the page - Then I fill in "docroot" for "Document Root" + Then I fill in "web" for "Document Root" When I press "Next" - And I should see "DOCUMENT ROOT docroot" + And I should see "DOCUMENT ROOT web" When I run drush "hosting-tasks --force --fork=0 --strict=0" And I reload the page @@ -33,18 +33,18 @@ Feature: Create a project and check settings Then I should see "Create as many new environments as you would like." When I fill in "dev" for "project[environments][NEW][name]" - And I select "master" from "project[environments][NEW][git_ref]" + And I select "8.x" from "project[environments][NEW][git_ref]" And I press "Add environment" And I fill in "live" for "project[environments][NEW][name]" - And I select "master" from "project[environments][NEW][git_ref]" + And I select "8.x" from "project[environments][NEW][git_ref]" And I press "Add environment" Then I press "Next" # Step 4 And I should see "dev" And I should see "live" - And I should see "master" + And I should see "8.x" When I run drush "hosting-tasks --force --fork=0 --strict=0" # Then print last drush output @@ -52,9 +52,7 @@ Feature: Create a project and check settings Then I should see "dev" And I should see "live" - And I should see "master" - And I should see "master" And I reload the page # When I click "Process Failed" Then I should see "8." @@ -75,8 +73,7 @@ Feature: Create a project and check settings And I should see the link "dev" And I should see the link "live" -# Then I break - And I should see the link "http://drpl8.dev.devshop.local.computer" + And I should see the link "http://composer.dev.devshop.local.computer" And I should see the link "Aegir Site" When I run drush "hosting-tasks --force --fork=0 --strict=0" @@ -86,7 +83,7 @@ Feature: Create a project and check settings And I reload the page Then I should see the link "dev" Then I should see the link "live" -# Given I go to "http://dev.drpl8.devshop.travis" +# Given I go to "http://dev.composer.devshop.travis" # When I click "Visit Environment" # @TODO: Fix our site installation. @@ -94,7 +91,6 @@ Feature: Create a project and check settings When I click "Create New Environment" And I fill in "testenv" for "Environment Name" - And I select "master" from "Branch or Tag" And I select the radio button "Drupal Profile" Then I select the radio button "Standard Install with commonly used features pre-configured." @@ -105,7 +101,7 @@ Feature: Create a project and check settings And I fill in "What's the password?" for "Message" Then I press "Create New Environment" - Then I should see "Environment testenv created in project drpl8." + Then I should see "Environment testenv created in project composer." When I run drush "hosting-tasks --force --fork=0 --strict=0" @@ -122,13 +118,13 @@ Feature: Create a project and check settings Then I select "testenv" from "Primary Environment" And I press "Save" - Then I should see "DevShop Project drpl8 has been updated." + Then I should see "DevShop Project composer has been updated." And I should see an ".environment-link .fa-bolt" element # When I click "Visit Site" - Given I am on "http://drpl8.testenv.devshop.local.computer" + Given I am on "http://composer.testenv.devshop.local.computer" # TODO: Figure out how to test this in travis! # Then the response status code should be 401 - Given I am on "http://testuser:testpassword@drpl8.testenv.devshop.local.computer" - Then I should see "Welcome to drpl8.testenv" + Given I am on "http://testuser:testpassword@composer.testenv.devshop.local.computer" + Then I should see "Welcome to composer.testenv" diff --git a/devmaster/tests/features/project.docroot.feature b/devmaster/tests/features/project.docroot.feature deleted file mode 100644 index 9949c2f64e..0000000000 --- a/devmaster/tests/features/project.docroot.feature +++ /dev/null @@ -1,86 +0,0 @@ -@api -Feature: Create a project with Drupal in the docroot. - - In order to start developing a drupal site - As a project admin - I need to create a new project - - Scenario: Create a new drupal 8 project with drupal in docroot folder - - When I run drush "en dblog -y" - Given I am logged in as a user with the "administrator" role - And I am on the homepage - When I click "Projects" - And I click "Start a new Project" - Then I should see "Step 1" - Then I fill in "rootproject" for "Project Code Name" - And I fill in "http://github.com/opendevshop/drupal_docroot" for "Git Repository URL" - When I press "Next" - - # Step 2 - Then I should see "rootproject" - And I should not see "The name rootproject is in use. Please try again." - And I should see "http://github.com/opendevshop/drupal_docroot" - - When I run drush "hosting-tasks --force --fork=0 --strict=0" - # Then print last drush output - And I reload the page - - When I fill in "docroot" for "Document Root" - - # Step 3 - When I press "Next" - # Users no longer see this, we wait for verify before showing step 2. -# Then I should see "Please wait while we connect to your repository and determine any branches." - And I should see "Document Root" - And I should see "rootproject" - - When I run drush "hosting-tasks --force --fork=0 --strict=0" - # Then print last drush output - And I reload the page - And I reload the page - - Then I should see "Create as many new environments as you would like." - When I fill in "dev" for "project[environments][NEW][name]" - And I select "master" from "project[environments][NEW][git_ref]" - - Then I press "Next" - # Step 4 - And I should see "dev" - And I should see "master" - - When I run drush "hosting-tasks --force --fork=0 --strict=0" - # Then print last drush output - And I reload the page - - Then I should see "dev" - And I should see "master" - And I reload the page -# When I click "Process Failed" - Then I should see "8." - Then I should not see "Platform verification failed" - When I select "standard" from "install_profile" - And I press "Create Project & Environments" - - # FINISH! - Then print current URL - When I run drush "wd-show" - # Then print last drush output - - Then I should see "Your project has been created. Your sites are being installed." - And I should see "Dashboard" - And I should see "Settings" - And I should see "Logs" - And I should see "standard" -# And I should see "http://github.com/opendevshop/drupal" - And I should see the link "dev" - - When I run drush "hosting-tasks --force --fork=0 --strict=0" - # Then print last drush output - Then drush output should not contain "This task is already running, use --force" - - And I reload the page - Then I should see the link "dev" - -# When I click "Visit Site" -# Then I should see "Welcome to" diff --git a/devmaster/tests/features/support.feature b/devmaster/tests/features/support.feature index ed261a7a3a..9b24eaa72a 100644 --- a/devmaster/tests/features/support.feature +++ b/devmaster/tests/features/support.feature @@ -10,9 +10,9 @@ Feature: Anonymous Homepage And I should not see the link "Sign in with DevShop.Cloud" When I am logged in as a user with the "authenticated user" role - Then I should see "Your DevShop server is currently unsupported." # @TODO: When finalizing the devshop cloud client module, re-implement these tests. +# Then I should see "Your DevShop server is currently unsupported." # When I run drush "vset devshop_support_license_key automated_testing_license_key" # # Then print last drush output # When I run drush "vset devshop_support_license_key_status active" diff --git a/devmaster/themes/boots/boots.css b/devmaster/themes/boots/boots.css index 1c5d8ddc89..0e30d992dc 100644 --- a/devmaster/themes/boots/boots.css +++ b/devmaster/themes/boots/boots.css @@ -1035,7 +1035,6 @@ pre.ansi_box { p.wait { text-align: center; padding: 32px 0px 52px; - background: bottom center no-repeat url(images/loading.gif); } p.error { @@ -1339,3 +1338,8 @@ form .well .form-type-radios .form-type-radio .form-control.chosen-container.chosen-container-single .chosen-single { height: 34px; } + + +kbd.alert { + display: block; +} diff --git a/devmaster/themes/boots/environment.tpl.php b/devmaster/themes/boots/environment.tpl.php index 999c2abb46..d9d81df1ff 100644 --- a/devmaster/themes/boots/environment.tpl.php +++ b/devmaster/themes/boots/environment.tpl.php @@ -277,13 +277,15 @@ } ?>
-
- -
+ +
+ +
+
diff --git a/devmaster/themes/boots/node--task.tpl.php b/devmaster/themes/boots/node--task.tpl.php index 9dfe6bcf57..cbcd7aed97 100644 --- a/devmaster/themes/boots/node--task.tpl.php +++ b/devmaster/themes/boots/node--task.tpl.php @@ -94,12 +94,17 @@

+ + + - @@ -133,6 +138,40 @@ + +

diff --git a/devmaster/themes/boots/template.php b/devmaster/themes/boots/template.php index 4ff7b30112..f1612c7c16 100644 --- a/devmaster/themes/boots/template.php +++ b/devmaster/themes/boots/template.php @@ -178,7 +178,7 @@ function boots_preprocess_environment(&$vars) { // Determine Environment State. Only one of these may be active at a time. // State: Platform verify failed. - if (current($environment->tasks['verify'])->ref_type == 'platform' && current($environment->tasks['verify'])->task_status == HOSTING_TASK_ERROR) { + if (!empty($environment->tasks['verify']) && current($environment->tasks['verify'])->ref_type == 'platform' && current($environment->tasks['verify'])->task_status == HOSTING_TASK_ERROR) { $verify_task = current($environment->tasks['verify']); $buttons = l( ' ' . t('Retry'), @@ -211,13 +211,26 @@ function boots_preprocess_environment(&$vars) { } // State: Site install failed. - elseif (isset($environment->tasks) && is_array($environment->tasks['install']) && current($environment->tasks['install'])->task_status == HOSTING_TASK_ERROR) { + elseif (!empty($environment->tasks['install']) && current($environment->tasks['install'])->task_status == HOSTING_TASK_ERROR) { $install_task = current($environment->tasks['install']); $buttons = l( - ' ' . t('Retry'), + ' ' . t('View Logs'), "node/{$install_task->nid}", array( 'html' => TRUE, + 'attributes' => array( + 'class' => array('btn btn-sm text-primary'), + ), + ) + ); + $buttons .= l( + ' ' . t('Retry'), + "hosting_confirm/{$install_task->rid}/site_{$install_task->task_type}", + array( + 'html' => TRUE, + 'query' => array( + 'token' => drupal_get_token($user->uid), + ), 'attributes' => array( 'class' => array('btn btn-sm text-success'), ), @@ -367,15 +380,19 @@ function boots_preprocess_environment(&$vars) { $environment->git_sha = trim(shell_exec("cd {$environment->repo_path}; git rev-parse HEAD 2> /dev/null")); // Determine the type of git ref the stored version is - $stored_git_ref_type = $project->settings->git['refs'][$environment->git_ref_stored]; + $stored_git_ref_type = !empty($project->settings->git['refs'][$environment->git_ref_stored]) + ? $project->settings->git['refs'][$environment->git_ref_stored] + : 'branch'; $stored_git_sha = trim(shell_exec("cd {$environment->repo_path}; git rev-parse {$environment->git_ref_stored} 2> /dev/null")); // Get the actual tag or branch. If a branch and tag have the same SHA, the tag will be output here. // "2> /dev/null" ensures errors don't get printed like "fatal: no tag exactly matches". $environment->git_ref = trim(str_replace('refs/heads/', '', shell_exec("cd {$environment->repo_path}; git describe --tags --exact-match 2> /dev/null || git symbolic-ref -q HEAD 2> /dev/null"))); - $environment->git_ref_type = $project->settings->git['refs'][$environment->git_ref]; - + $environment->git_ref_type = !empty($project->settings->git['refs'][$environment->git_ref]) + ? $project->settings->git['refs'][$environment->git_ref] + : 'branch'; + // If the git sha for stored branch are the same, but the type is different, detect if HEAD is detached so we know if this is on a branch or a tag. if ($stored_git_sha == $environment->git_sha && $stored_git_ref_type != $environment->git_ref_type) { $git_status = shell_exec("cd {$environment->repo_path}; git status"); @@ -810,8 +827,8 @@ function boots_preprocess_page(&$vars){ $vars['sidebar_first_rendered'] = render($vars['page']['sidebar_first']); // Indicate the project is inactive. - if ((int) $vars['node']->status == NODE_NOT_PUBLISHED) { - $vars['subtitle'] .= ' ' . t('Inactive') . ''; + if (isset($project_node) && isset($project_node->nid) && (int) $project_node->status == NODE_NOT_PUBLISHED) { + $vars['subtitle'] .= ' ' . t('Inactive Project') . ''; } }