Failed Conditions
Pull Request — master (#15)
by Raphael
03:58 queued 01:16
created

Scripts::getGuardedGitDirectory()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 11
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 11
rs 9.4285
cc 2
eloc 6
nc 2
nop 2
1
<?php
2
declare(strict_types = 1);
3
namespace PurpleBooth\GitLintValidators\Composer;
4
5
use Composer\IO\IOInterface;
6
use Composer\Script\Event;
7
8
class Scripts
9
{
10
    const BACKUP_EXTENSION  = '.bak';
11
    const GIT_PATH          = '.git';
12
    const HOOKS_PATH        = 'hooks';
13
    const HOOK_FILENAME     = 'commit-msg';
14
    const TEMPLATE_FILENAME = '.gitmessage';
15
16
    /**
17
     * Default Permissions (Copied from example hooks)
18
     *
19
     * User: Read, Write, Execute
20
     * Group: Read, Execute
21
     * Other: Execute
22
     */
23
    const EXECUTABLE_PERMISSIONS = 0751;
24
    const HOOK_CONTENTS          = <<<CONTENT
25
#!/bin/sh
26
27
vendor/bin/git-lint-validators git-lint-validator:hook $1
28
CONTENT;
29
30
    const TEMPLATE_CONTENTS = <<<CONTENT
31
Subject line
32
33
# - Capitalise the subject line and do not end it with a period
34
# - Use the imperative mood in the subject line
35
# - Summarise changes in around 50 (soft limit, hard limit at 69)
36
#   characters or less in the subject line
37
# - Separate subject line from body with a blank line
38
Subject body
39
# - Use the subject body to explain what and why vs. how
40
# - Wrap the subject body at 72 characters
41
42
CONTENT;
43
44
    /**
45
     * Installs and activates the Git commit message
46
     * hook when confirmed by the user. An existing hook
47
     * is backed with the .bak extension.
48
     *
49
     * @param  Event $event The script event.
50
     *
51
     * @return boolean
52
     */
53
    public static function installGitMessageHook(Event $event)
54
    {
55
        $hookContent = self::HOOK_CONTENTS;
56
        $inputOutput = $event->getIO();
57
        $question    = "Do you want to install and activate the Git ";
58
        $question   .= "commit message hook? ";
59
60
        if ($inputOutput->askConfirmation($question, false)) {
61
            $errorMessage  = "Couldn't locate the .git directory. ";
62
            $errorMessage .= "Aborting the Git hook installation.";
63
64
            $gitDirectory = self::getGuardedGitDirectory($errorMessage, $inputOutput);
65
66
            if (!$gitDirectory) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $gitDirectory of type false|string is loosely compared to false; this is ambiguous if the string can be empty. You might want to explicitly use === false instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
67
                return false;
68
            }
69
70
            $hookFile         = implode(DIRECTORY_SEPARATOR, [$gitDirectory, self::HOOKS_PATH, self::HOOK_FILENAME]);
71
            $existingHookFile = false;
72
73
            if (file_exists($hookFile)) {
74
                $existingHookFile = copy(
75
                    $hookFile,
76
                    $hookFile . self::BACKUP_EXTENSION
77
                );
78
            }
79
80
            file_put_contents($hookFile, $hookContent);
81
            chmod($hookFile, self::EXECUTABLE_PERMISSIONS);
82
83
            $inputOutput->write("Installed and activated the Git commit message hook.");
84
85
            if ($existingHookFile) {
86
                $inputOutput->write("Backed previous Git commit message hook.");
87
            }
88
89
            if ($inputOutput->isVerbose()) {
90
                $inputOutput->write("Wrote");
91
                $inputOutput->write("<comment>$hookContent</comment>");
92
                $inputOutput->write("into <info>$hookFile</info> and made it executable.");
93
            }
94
95
            return true;
96
        }
97
98
        $inputOutput->write("Aborted installation and activation of the Git commit message hook.");
99
100
        return false;
101
    }
102
103
    /**
104
     * Installs and configures the Git commit message
105
     * template when confirmed by the user.
106
     *
107
     * @param  Event $event The script event.
108
     *
109
     * @return boolean
110
     */
111
    public static function installGitCommitMessageTemplate(Event $event)
112
    {
113
        $templateContent = self::TEMPLATE_CONTENTS;
114
        $inputOutput     = $event->getIO();
115
        $question        = "Do you want to install and configure the Git ";
116
        $question       .= "commit message template? ";
117
118
        if ($inputOutput->askConfirmation($question, false)) {
119
            $errorMessage  = "Couldn't locate the .git directory. ";
120
            $errorMessage .= "Aborting the Git commit message template installation.";
121
122
            $gitDirectory = self::getGuardedGitDirectory($errorMessage, $inputOutput);
123
124
            if (!$gitDirectory) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $gitDirectory of type false|string is loosely compared to false; this is ambiguous if the string can be empty. You might want to explicitly use === false instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
125
                return false;
126
            }
127
128
            $templateFile = implode(DIRECTORY_SEPARATOR, [$gitDirectory, self::TEMPLATE_FILENAME]);
129
130
            file_put_contents($templateFile, $templateContent);
131
            $gitConfigureCommand = "git config --add commit.template $templateFile";
132
            exec($gitConfigureCommand);
133
134
            $inputOutput->write("Installed and configured the Git commit message template.");
135
136
            if ($inputOutput->isVerbose()) {
137
                $inputOutput->write("Wrote");
138
                $inputOutput->write("<comment>$templateContent</comment>");
139
                $inputOutput->write("into <info>$templateFile</info> and configured the Git commit message template ");
140
                $inputOutput->write("via <comment>$gitConfigureCommand</comment>.");
141
            }
142
143
            return true;
144
        }
145
146
        $inputOutput->write("Aborted installation and configuration of the Git commit message template.");
147
148
        return false;
149
    }
150
151
    /**
152
     * Returns the .git directory if present. Errors the given
153
     * message if not.
154
     *
155
     * @param  string      $message The message to error.
156
     * @param  IOInterface $io      The Input/Output helper interface.
157
     *
158
     * @return mixed
0 ignored issues
show
Documentation introduced by
Consider making the return type a bit more specific; maybe use false|string.

This check looks for the generic type array as a return type and suggests a more specific type. This type is inferred from the actual code.

Loading history...
159
     */
160
    private static function getGuardedGitDirectory($message, IOInterface $io)
0 ignored issues
show
Comprehensibility introduced by
Avoid variables with short names like $io. Configured minimum length is 3.

Short variable names may make your code harder to understand. Variable names should be self-descriptive. This check looks for variable names who are shorter than a configured minimum.

Loading history...
161
    {
162
        $gitDirectory = implode(DIRECTORY_SEPARATOR, [dirname(dirname(dirname(dirname(__DIR__)))), self::GIT_PATH]);
163
164
        if (!is_dir($gitDirectory)) {
165
            $io->error($message);
166
            return false;
167
        }
168
169
        return $gitDirectory;
170
    }
171
}
172