在prebuild中调用build.doStop()并没有足够快地停止

时间:2015-01-06 20:25:51

标签: jenkins jenkins-plugins

我正在尝试编写一个Jenkins插件,如果在假期(或仅在给定的输入日/ s)触发该构建,则该插件可以自动中止构建。用户可以配置日期,每个作业都会有一个复选框,允许用户决定他们是否希望他们的工作在假期中止。目前我的插件扩展 JobProperty 并利用全局配置,其中列出了黑名单日期。如果今天列入我列入黑名单的日子,那么我不想让我的工作继续下去。该插件“有效”,但有一些恼人的警告。

我的主要问题是,如果碰巧是在我列入黑名单的日子之一的某一天触发,我只能对构建失败。这对我来说是一个问题,因为没有实际的错误。工作正在按预期运行,我不想收到充满错误的电子邮件,因为工作在我不想让它运行的那天停止(例如:假期)

当我的插件决定中止构建时,我希望能够以“已中止”状态结束作业。 (事实上​​ - 我希望能够控制状态并将其作为潜在参数。)

下面是我的prebuild()代码。

@Override
public boolean prebuild(AbstractBuild build, BuildListener listener) {
    boolean stopped = false;
    if(checkIfClosed) {
        LocalDate today = LocalDate.now();
        listener.getLogger().println("Checking the date for " + DateFormats.yyyyMMdd.print(today));
        if (getDescriptor().getUseCalculatedDateChecker()) {
            if (!NyseHolidayChecker.isMarketOpen(today)) {
                listener.getLogger().println("Closed (From auto calculation)!");
                stopped = true;
            }
        }
        if (getDescriptor().getListOfClosedDates() != null && !getDescriptor().getListOfClosedDates().isEmpty()) {
            if (getDescriptor().getListOfClosedDates().contains(DateFormats.yyyyMMdd.print(today))) {
                listener.getLogger().println("Closed. Date is in the Closed Date List. " +
                        "If this is wrong check global configuration.");
                stopped = true;
            }
        }
    }
    if(stopped) {
        try {
            if(build.doStop() == null) {
                return false;
            }
        } catch (IOException e) {
            listener.getLogger().println(e.getMessage());
            return false;
        } catch (ServletException e) {
            listener.getLogger().println(e.getMessage());
            return false;
        }
        //throw new RuntimeException("This job has been told not to run when marked as Closed!");
        //throw new AbortException("This job has been told not to run when marked as Closed!");
    }
    return true;
}

我尝试了几种不同的方法让工作立即中止,而不是将构建标记为失败。

  1. doc告诉我,我应该抛出一个AbortException,但是我所覆盖的函数似乎不支持它。

  2. 我也尝试调用doStop(),但是我的第一个构建步骤(总共2个)仍然至少运行一次。这是不可取的,因为我永远不会知道我的工作将会在什么状态下中止(它可能已经在某个地方被摧毁并杀死了一个进程......或者做了一些活动等等)

  3. 我错过了什么?我觉得我正在乱砍以获得我需要的东西。我希望有人能指出我如何最好地做到这一点的正确方向。

1 个答案:

答案 0 :(得分:2)

进一步深入研究Jenkins代码,结果显示Build.doRun()方法将在do while循环中执行构建步骤,这允许一小部分构建步骤通过。 Jenkins文档建议的AbortException也会将构建标记为失败(不合需要)。我发现取消作业并将其正确标记为中止的唯一方法是抛出InterruptedException。 JobProperties prebuild()函数不允许任何抛出(运行时除外,它将标记为失败)。

该插件现在扩展BuildWrapper。这有一个setUp和preCheckout方法,它将在构建步骤执行之前运行。这两种方法也可以抛出InterruptedExceptions。现在,如果我的检查通过并且日期被列入黑名单,则会从interruptOnHoliday(...)方法中抛出InterruptedException。 BuildWrapper还使用BuildWrapperDescriptor,它将根据重写的getDisplayName()函数中提供的名称在作业配置中放置一个复选框(Acts排序为jetty optionalBlock)。选中此框后,可以调用setUp函数,否则不会调用。这有效地使假日检查插件可选(所需)。

为了向用户提供插件的帮助,在插件的资源中包含一个help.html文件,这将允许程序员向用户解释如何以及为何使用插件。 BuildWrapperDescriptor类将以编程方式知道如何使用该文件。

希望这有助于每个人。以下是杀人的新方法:

@Override
public void preCheckout(AbstractBuild build, Launcher launcher, BuildListener listener)
        throws InterruptedException, IOException {
    interruptOnHoliday(build, listener);
}

/**
 * Run a check against todays date and dates from the {@link NyseHolidayChecker}
 * which is an automatic calculator for New York Stock Exchange holidays and also a check against the manually
 * created user date list. If either one is not checked to be used, then they will be ignored.
 *
 * @param build {@link hudson.model.AbstractBuild} that we are on, will kill the executor
 * @param listener  {@link hudson.model.BuildListener} that we will log to
 *
 * @throws InterruptedException
 */
private void interruptOnHoliday(AbstractBuild build, BuildListener listener) throws InterruptedException {
    boolean stopped = false;
    LocalDate today = LocalDate.now();
    listener.getLogger().println("Checking the date for " + DateFormats.yyyyMMdd.print(today));
    //if the NYSE calculator is checked then let's use it
    if (getDescriptor().getUseNyseCalculatedDateChecker()) {
        if (!NyseHolidayChecker.isMarketOpen(today)) {
            listener.getLogger().println("The NYSE is not Open today (From auto calculation)" +
                    " and this job is marked to abort. Stopping the build!");
            stopped = true;
        }
    }
    //If we have inserted manual dates into the list we want to check them
    if (getDescriptor().getListOfClosedDates() != null && !getDescriptor().getListOfClosedDates().isEmpty()) {
        if (getDescriptor().getListOfClosedDates().contains(DateFormats.yyyyMMdd.print(today))) {
            listener.getLogger().println("This date is blacklisted, and this job is marked to abort. " +
                    "Stopping the job! If this date should not be on the list check Jenkins Settings.");
            stopped = true;
        }
    }
    //if we should stop the job then we call doStop() on the build and we also throw an InterruptedException
    //The InterruptedException is the only way to abort a build without it failing.
    if (stopped) {
        try {
            build.doStop();
            throw new InterruptedException(DateFormats.yyyyMMdd.print(today) + " is a blacklisted date.");
        } catch (IOException e) {
            listener.getLogger().println(e.getMessage());
        } catch (ServletException e) {
            listener.getLogger().println(e.getMessage());
        }
    }

}

@Override
public BuildWrapper.Environment setUp(AbstractBuild build, Launcher launcher, BuildListener listener)
        throws InterruptedException, IOException {
    interruptOnHoliday(build, listener);
    return new CloseCheckerEnvironment();
}