Статьи

Реализация моего первого плагина Jenkins: AnsiColor


Я установил Jenkins на прошлой неделе в самый первый раз.
Пару дней спустя я смог опубликовать свой первый плагин, названный
AnsiColor , который раскрашивает вывод ANSI. Это
плагин, который вы все так долго ждали .

Дженкинс плагина учебник довольно хорошо, я рекомендую вам просто следовать за ним. У него есть кулинарная книга на основе Maven для создания нового проекта. Но если вы похожи на меня, вы будете реконструировать плагин с нуля (и, возможно, обменять время на лучшее понимание). Я просто упомяну несколько вещей, которые могли бы быть полезными для меня.

основы

Плагин расширяет Гудзон . Плагин . Этот класс даже не нужен, но это хорошая возможность настроить регистратор, который сообщит нам, что плагин действительно загружается. Независимо от того, тестируете ли вы плагин локально или запускаете производственный экземпляр Jenkins, это пригодится.

    public class PluginImpl extends Plugin {
        private final static Logger LOG = Logger.getLogger(PluginImpl.class.getName());
     
        public void start() throws Exception {
            LOG.info("starting ansicolor plugin");
        }
    }


Обработка вывода сборки

Наша цель — обработать результаты сборки и вставить разметку HTML. Итак, первая задача — найти отсюда точку расширения Jenkins, которая предоставляет данные журнала сборки. Я нашел очень многообещающий ConsoleLogFilter . Простое расширение помечено @Extension, и я подумал, что все готово.

    @Extension
    public class AnsiColorConsoleLogFilter extends ConsoleLogFilter {
     
        @SuppressWarnings("unchecked")
        @Override
        public OutputStream decorateLogger(AbstractBuild build, OutputStream logger)
                throws IOException, InterruptedException {
            return new AnsiColorizer(logger, build.getCharset());
        }
     
    }


Что это за AnsiColorizer ? Это класс обработки потока, который наследуется от hudson.console.LineTransformationOutputStream, который переопределяет метод eol , вызываемый для каждой строки вывода. Он украшает наш регистратор. Обратите внимание, что байты, переданные в метод eol , предварительно выделены, следовательно, параметр len . Вы получаете намного больше байтов, чем в текущей строке, но это мусор из предыдущего вывода после len .

Следующий код удалит всю разметку ANSI.

    @Override
    protected void eol(byte[] b, int len) throws IOException {
        String ansiEncodedString = new String(b, 0, len);
        AnsiString ansiString = new AnsiString(ansiEncodedString);
        String plainString = ansiString.getPlain().toString();
        byte[] plainBytes = plainString.getBytes();
        out.write(plainBytes, 0, plainBytes.length);
    }

Довольно просто, правда? Ну, это работает, только если мы хотим удалить материал или добавить текст, и не работает для HTML. Вывод на консоль кодируется в HTML-формате, поскольку он проходит через последующую фильтрацию, поэтому вставка HTML-кода, такого как цвет, также будет кодироваться. Грустное лицо.

Консольные заметки

У Дженкинса есть еще одна точка расширения, BuildWrapper . Он добавит опцию в каждый проект сборки, чтобы включить оформление регистратора сборки, к которому мы можем присоединить ConsoleAnnotationDescriptor . Все это довольно запутанно, но построено с благими намерениями возможности потоковой передачи данных. Как недавний Rubyist я снова и снова поднимал брови — я забыл, как сильно люди любят фабрики на Java. В любом случае, это позволяет вставлять элементы ConsoleNote до и после строки вывода журнала. Примечание HTML. Но символы ANSI могут быть где угодно в строке, так как это полезно?

Давайте использовать лишние клетки мозга, которые не умирали при сортировке упаковщиков, фабрик, декораторов и аннотаторов. Учитывая строку, такую ​​как «Hello] 32mCruel Java World», как мы можем заставить ее отображать «Hello <span style =» color: green »> Cruel Java World </ span>», учитывая, что мы можем только добавлять и добавлять текст? Как это.

    Hello <span style=”color: green”>Cruel Java World</span>
    <span style="display: none">Hello ]32mCruel Java World</span>

Я знаю, это полный взлом, но это работает, и никто не будет жаловаться.

    String colorizedData = colorize(this.data);
    if (! colorizedData.contentEquals(this.data)) {
        text.addMarkup(charPos, colorizedData);
        text.addMarkup(charPos, charPos + text.length(), "<span style=\"display: none;\">", "</span>");
    }

ansicolor

Исходный код

Полный исходный код плагина находится здесь, на Github .