在预构建中调用 build.doStop() 停止得不够快

Calling build.doStop() in prebuild is not stopping fast enough

我正在尝试编写一个 Jenkins 插件,如果该构建在假期触发(或仅在给定输入 day/s 时触发),它可以自动中止构建。用户可以配置日期,每项工作都有一个复选框,允许用户决定他们是否希望他们的工作在假期中止。目前我的插件扩展 JobProperty 并利用全局配置,其中我有一个列入黑名单的日期列表。如果今天在我的黑名单日期列表中,那么我不希望我的工作运行。插件 "works" 但有一些烦人的注意事项。

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

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

下面是我的 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 个)仍然至少运行了一点。这是不可取的,因为我永远不会知道我的工作在中止时会处于什么状态(它可能已经在某个地方停止并杀死了一个进程......或者让一些东西活着等)

我错过了什么?我觉得我正在四处寻找我需要的东西。我希望有人能指出正确的方向,告诉我如何最好地做到这一点。

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

插件现在扩展了 BuildWrapper. This has both a setUp and preCheckout method that will run prior to build steps executing. These two methods can also throw InterruptedExceptions. Now if my checks pass and the date is blacklisted an InterruptedException is thrown from the interruptOnHoliday(...) method. The BuildWrapper also utilizes a BuildWrapperDescriptor,它将根据重写的 getDisplayName() 函数中提供的名称在作业配置中放置一个复选框(类似于码头可选块)。选中此框后,可以调用 setUp 函数,否则不会。这有效地使假期检查插件成为可选的(需要的)。

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

希望对大家有所帮助。下面是新杀法:

@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();
}