Perl - ловушка commit-msg не останавливает коммит при выходе 1 - PullRequest
0 голосов
/ 25 февраля 2019

Контекст:

Я использую некоторые git-хуки для автоматического применения некоторых опций форматирования в скриптах Perl.На крючке перед фиксацией я очищаю и переформатирую свои скрипты, используя perltidy.Я хочу проверить, что пользователь поместил в сообщение фиксации, и если оно пустое или эквивалентно «abort», мы хотим предотвратить фиксацию и отменить изменения форматирования.

Проблема:

Я удалил расширение .sample из git hook и сделал его исполняемым, используя chmod u+x .git/hooks/commit-msg, но когда мой скрипт exit 1, коммит не останавливается, как должен.

commit-msg

Этот хук вызывается git-commit [1] и git-merge [1] и может быть обойден с опцией --no-verify.Он принимает единственный параметр - имя файла, в котором хранится предлагаемое сообщение в журнале фиксации.Выход с ненулевым состоянием приводит к прерыванию команды.

source: https://git -scm.com / docs / githooks # _commit_msg

#!/usr/bin/perl -w

use strict;
use warnings;

# Get the path to the files in which we have the commit message
my $commit_file = $ARGV[0];

# Read the file and extract the commit message (lines which don't start with #) 
my @commit_msg;
open(my $fh, "<", "$commit_file");
while (my $line = <$fh>) {
    if (substr($line, 0, 1) ne "#") {
        push(@commit_msg, $line);
    }
}

# Check the message isn't empty or we don't have a "abort" line
my $boolean = 0;
foreach my $line (@commit_msg) {
    if ($line ne "abort" && $line ne "") {
        $boolean = 1;
    }
}

if ($boolean == 0) {
    print "We should commit the modifications\n";
    exit 0; # Don't prevent commit
}
else {
    print "We shouldn't commit the modifications\n";
    exit 1; # Prevent commit
}

Сценарий исполняемый и работает!Если я ввожу «abort» при фиксации чего-либо, выводится «Мы не должны фиксировать изменения», а фиксируем их без выхода 1 ...

Я надеюсь, что кто-то сможет помочь!Я новичок в git-hook и не могу найти решение.Возможно, я что-то упустил в Stackoverflow, но я не нашел сообщения, отвечающего на этот вопрос.

Best,

Antoine

Редактировать: Не знаюсовершить, используя: --no-verify

Ответы [ 2 ]

0 голосов
/ 25 февраля 2019

Я думаю, что логика в вашем скрипте обратная, то есть слово abort не приводит к коду выхода 1.

Я думаю, что должно работать следующее:

#!/usr/bin/perl
use strict;
use warnings;
use autodie;

my($commit_msg_file) = @ARGV
    or die "usage: $0 <commit message file>\n";

open(my $fh, '<', $commit_msg_file);
my $do_commit;
while (<$fh>) {
    # skip comment or empty lines
    next if /^#/ || /^\s*$/;

    # check for the word "abort" on its own line
    last if (/^abort$/);

    # at least one non-empty non-comment line detected
    $do_commit++;
    last;
}
close($fh);

if ($do_commit) {
    print "We should commit the modifications\n";
    exit 0; # Don't prevent commit
}

print "We shouldn't commit the modifications\n";
exit 1; # Prevent commit
0 голосов
/ 25 февраля 2019

Когда я впервые установил ваш хук, я не смог заставить его совершить что-нибудь , но это потому, что у хука слишком много негативов.Предупреждения вашего преподавателя языка, чтобы избежать двойных негативов, помогут вам при написании программного обеспечения.Хук пытается найти допустимое условие, проверяя в отрицательном смысле, если строка выглядит хорошо, установите $boolean в 1, если это так, но тогда exit 0 (указывает на успех), только если $boolean было 0.

Неописанное имя $boolean, вероятно, частично ответственно.Возможно, вы потеряли отслеживание вашего предполагаемого значения между его настройкой и тем статусом выхода, который вы хотели создать.Кроме того, ваше намерение за логикой не будет выполнено, пока последняя строка сообщения фиксации верна.

Приведенный ниже код работает так, как вам нужно с git 2.17.1.

#! /usr/bin/perl -w

use strict;
use warnings;

die "Usage: $0 commit-log-message\n" unless @ARGV == 1; # (1)

# Get the path to the files in which we have the commit message
my $commit_file = shift; # (2)

# Read the file and extract the commit message (lines which don't start with #) 
my $commit_msg = "";
open my $fh, "<", $commit_file or die "$0: open $commit_file: $!"; # (3)
while (<$fh>) {        # (4)
    next if /^#/;      # (5)
    $commit_msg .= $_;
}

# Check the message isn't empty or we don't have an "abort" line
my $valid_commit_msg = $commit_msg ne "" && $commit_msg !~ /^abort$/m; # (6)

if ($valid_commit_msg) { # (7)
    print "We should commit the modifications\n";
    exit 0; # Don't prevent commit
}
else {
    print "We shouldn't commit the modifications\n";
    exit 1; # Prevent commit
}

(1) Да, предполагается, что git предоставляет имя файла с сообщением журнала, но проверяет его работоспособность в случае, если код скопирован или иным образом установлен в неправильном хуке.

(2) Соберите аргумент из @ARGV с shift.

(3) Всегда, всегда , всегда проверьте возвращаемое значение с open.Обратите внимание, что сообщение об ошибке, если оно терпит неудачу, содержит имя программы, в которой произошла ошибка ($0), что она пыталась сделать ("open $commit_file") и ошибка ($!).Развивайте эту привычку.Это избавит вас от многих неприятностей в один прекрасный день.

(4) Вместо того, чтобы копировать строки в массив, объедините их все в один скаляр.Используйте while (<$fh>) { ... }, чтобы увидеть каждую строку в $_, что является более идиоматическим Perl и обезвреживает ваш код.

(5) Пропуск строк комментариев становится простым next if /^#/;.

(6) Скажите, что вы имеете в виду.Вместо механизма ($boolean) назовите свое намерение.Вы хотите знать, что сообщение коммита является действительным, прежде чем пропустить его.Допустимое сообщение фиксации должно соответствовать двум условиям:

  • Сообщение фиксации не является пустым.
  • Сообщение фиксации не содержит строки, единственное содержимое которой равно abort.

В Perl это

my $valid_commit_msg = $commit_msg ne "" && $commit_msg !~ /^abort$/m;

Пара замечаний:

  • Оператор !~ инвертирует смысл соответствия регулярному выражению, т.е. , $commit_msg должен не содержать abort.
  • Переключатель /m в конце шаблона предназначен для многострочного режима.При этом якоря ^ и $ совпадают в начале и конце строк в пределах цели, а не только с левыми и самыми правыми символами.

(7) Использование$valid_commit_msg как логическое значение, которое читается естественным образом.

if ($valid_commit_msg) { ... }

предпочтительнее if ($valid_commit_msg == 0) { ... }, потому что значение 0 было неправильным, повторение правильного значения избыточно, а значение висит наконец легко не заметить.

...