mirror of https://github.com/jenkinsci/jenkins.git
Merge branch 'master' into add-groups-to-command-palette
This commit is contained in:
commit
428e826fcd
|
@ -70,7 +70,7 @@ THE SOFTWARE.
|
|||
<!-- https://docs.spring.io/spring-security/reference/6.3/getting-spring-security.html#getting-maven-no-boot -->
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<artifactId>spring-security-bom</artifactId>
|
||||
<version>6.4.1</version>
|
||||
<version>6.4.2</version>
|
||||
<type>pom</type>
|
||||
<scope>import</scope>
|
||||
</dependency>
|
||||
|
|
|
@ -58,6 +58,8 @@ import java.util.logging.Logger;
|
|||
import java.util.regex.Pattern;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipOutputStream;
|
||||
import jenkins.model.Jenkins;
|
||||
import jenkins.security.MasterToSlaveCallable;
|
||||
import jenkins.security.ResourceDomainConfiguration;
|
||||
|
@ -65,8 +67,6 @@ import jenkins.security.ResourceDomainRootAction;
|
|||
import jenkins.util.SystemProperties;
|
||||
import jenkins.util.VirtualFile;
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.apache.tools.zip.ZipEntry;
|
||||
import org.apache.tools.zip.ZipOutputStream;
|
||||
import org.kohsuke.accmod.Restricted;
|
||||
import org.kohsuke.accmod.restrictions.NoExternalUse;
|
||||
import org.kohsuke.stapler.HttpResponse;
|
||||
|
@ -530,8 +530,8 @@ public final class DirectoryBrowserSupport implements HttpResponse {
|
|||
|
||||
private static void zip(StaplerResponse2 rsp, VirtualFile root, VirtualFile dir, String glob) throws IOException, InterruptedException {
|
||||
OutputStream outputStream = rsp.getOutputStream();
|
||||
try (ZipOutputStream zos = new ZipOutputStream(outputStream)) {
|
||||
zos.setEncoding(Charset.defaultCharset().displayName()); // TODO JENKINS-20663 make this overridable via query parameter
|
||||
// TODO JENKINS-20663 make encoding overridable via query parameter
|
||||
try (ZipOutputStream zos = new ZipOutputStream(outputStream, Charset.defaultCharset())) {
|
||||
// TODO consider using run(Callable) here
|
||||
|
||||
if (glob.isEmpty()) {
|
||||
|
|
|
@ -4,6 +4,8 @@ import edu.umd.cs.findbugs.annotations.CheckForNull;
|
|||
import edu.umd.cs.findbugs.annotations.NonNull;
|
||||
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
|
||||
import hudson.Extension;
|
||||
import hudson.ExtensionList;
|
||||
import hudson.ExtensionPoint;
|
||||
import hudson.Util;
|
||||
import hudson.model.Job;
|
||||
import hudson.model.PermalinkProjectAction.Permalink;
|
||||
|
@ -14,6 +16,7 @@ import hudson.model.listeners.RunListener;
|
|||
import hudson.util.AtomicFileWriter;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.Serializable;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
import java.util.HashMap;
|
||||
|
@ -24,6 +27,7 @@ import java.util.logging.Level;
|
|||
import java.util.logging.Logger;
|
||||
import java.util.stream.Stream;
|
||||
import org.kohsuke.accmod.Restricted;
|
||||
import org.kohsuke.accmod.restrictions.Beta;
|
||||
import org.kohsuke.accmod.restrictions.NoExternalUse;
|
||||
|
||||
/**
|
||||
|
@ -63,14 +67,6 @@ import org.kohsuke.accmod.restrictions.NoExternalUse;
|
|||
*/
|
||||
public abstract class PeepholePermalink extends Permalink implements Predicate<Run<?, ?>> {
|
||||
|
||||
/**
|
||||
* JENKINS-22822: avoids rereading caches.
|
||||
* Top map keys are {@code builds} directories.
|
||||
* Inner maps are from permalink name to build number.
|
||||
* Synchronization is first on the outer map, then on the inner.
|
||||
*/
|
||||
private static final Map<File, Map<String, Integer>> caches = new HashMap<>();
|
||||
|
||||
/**
|
||||
* Checks if the given build satisfies the peep-hole criteria.
|
||||
*
|
||||
|
@ -94,115 +90,216 @@ public abstract class PeepholePermalink extends Permalink implements Predicate<R
|
|||
*/
|
||||
@Override
|
||||
public Run<?, ?> resolve(Job<?, ?> job) {
|
||||
Map<String, Integer> cache = cacheFor(job.getBuildDir());
|
||||
int n;
|
||||
synchronized (cache) {
|
||||
n = cache.getOrDefault(getId(), 0);
|
||||
}
|
||||
if (n == RESOLVES_TO_NONE) {
|
||||
return null;
|
||||
}
|
||||
Run<?, ?> b;
|
||||
if (n > 0) {
|
||||
b = job.getBuildByNumber(n);
|
||||
if (b != null && apply(b)) {
|
||||
return b; // found it (in the most efficient way possible)
|
||||
}
|
||||
} else {
|
||||
b = null;
|
||||
}
|
||||
|
||||
// the cache is stale. start the search
|
||||
if (b == null) {
|
||||
b = job.getNearestOldBuild(n);
|
||||
}
|
||||
|
||||
if (b == null) {
|
||||
// no cache
|
||||
b = job.getLastBuild();
|
||||
}
|
||||
|
||||
// start from the build 'b' and locate the build that matches the criteria going back in time
|
||||
b = find(b);
|
||||
|
||||
updateCache(job, b);
|
||||
return b;
|
||||
return ExtensionList.lookupFirst(Cache.class).get(job, getId()).resolve(this, job, getId());
|
||||
}
|
||||
|
||||
/**
|
||||
* Start from the build 'b' and locate the build that matches the criteria going back in time
|
||||
*/
|
||||
private Run<?, ?> find(Run<?, ?> b) {
|
||||
//noinspection StatementWithEmptyBody
|
||||
for ( ; b != null && !apply(b); b = b.getPreviousBuild())
|
||||
;
|
||||
@CheckForNull
|
||||
private Run<?, ?> find(@CheckForNull Run<?, ?> b) {
|
||||
while (b != null && !apply(b)) {
|
||||
b = b.getPreviousBuild();
|
||||
}
|
||||
return b;
|
||||
}
|
||||
|
||||
private static @NonNull Map<String, Integer> cacheFor(@NonNull File buildDir) {
|
||||
synchronized (caches) {
|
||||
Map<String, Integer> cache = caches.get(buildDir);
|
||||
if (cache == null) {
|
||||
cache = load(buildDir);
|
||||
caches.put(buildDir, cache);
|
||||
}
|
||||
return cache;
|
||||
}
|
||||
}
|
||||
|
||||
private static @NonNull Map<String, Integer> load(@NonNull File buildDir) {
|
||||
Map<String, Integer> cache = new TreeMap<>();
|
||||
File storage = storageFor(buildDir);
|
||||
if (storage.isFile()) {
|
||||
try (Stream<String> lines = Files.lines(storage.toPath(), StandardCharsets.UTF_8)) {
|
||||
lines.forEach(line -> {
|
||||
int idx = line.indexOf(' ');
|
||||
if (idx == -1) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
cache.put(line.substring(0, idx), Integer.parseInt(line.substring(idx + 1)));
|
||||
} catch (NumberFormatException x) {
|
||||
LOGGER.log(Level.WARNING, "failed to read " + storage, x);
|
||||
}
|
||||
});
|
||||
} catch (IOException x) {
|
||||
LOGGER.log(Level.WARNING, "failed to read " + storage, x);
|
||||
}
|
||||
LOGGER.fine(() -> "loading from " + storage + ": " + cache);
|
||||
}
|
||||
return cache;
|
||||
}
|
||||
|
||||
static @NonNull File storageFor(@NonNull File buildDir) {
|
||||
return new File(buildDir, "permalinks");
|
||||
}
|
||||
|
||||
/**
|
||||
* Remembers the value 'n' in the cache for future {@link #resolve(Job)}.
|
||||
*/
|
||||
protected void updateCache(@NonNull Job<?, ?> job, @CheckForNull Run<?, ?> b) {
|
||||
File buildDir = job.getBuildDir();
|
||||
Map<String, Integer> cache = cacheFor(buildDir);
|
||||
synchronized (cache) {
|
||||
cache.put(getId(), b == null ? RESOLVES_TO_NONE : b.getNumber());
|
||||
File storage = storageFor(buildDir);
|
||||
LOGGER.fine(() -> "saving to " + storage + ": " + cache);
|
||||
try (AtomicFileWriter cw = new AtomicFileWriter(storage)) {
|
||||
try {
|
||||
for (Map.Entry<String, Integer> entry : cache.entrySet()) {
|
||||
cw.write(entry.getKey());
|
||||
cw.write(' ');
|
||||
cw.write(Integer.toString(entry.getValue()));
|
||||
cw.write('\n');
|
||||
}
|
||||
cw.commit();
|
||||
} finally {
|
||||
cw.abort();
|
||||
ExtensionList.lookupFirst(Cache.class).put(job, getId(), b != null ? new Cache.Some(b.getNumber()) : Cache.NONE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Persistable cache of peephole permalink targets.
|
||||
*/
|
||||
@Restricted(Beta.class)
|
||||
public interface Cache extends ExtensionPoint {
|
||||
|
||||
/** Cacheable target of a permalink. */
|
||||
sealed interface PermalinkTarget extends Serializable {
|
||||
|
||||
/**
|
||||
* Implementation of {@link #resolve(Job)}.
|
||||
* This may update the cache if it was missing or found to be invalid.
|
||||
*/
|
||||
@Restricted(NoExternalUse.class)
|
||||
@CheckForNull
|
||||
Run<?, ?> resolve(@NonNull PeepholePermalink pp, @NonNull Job<?, ?> job, @NonNull String id);
|
||||
|
||||
/**
|
||||
* Partial implementation of {@link #resolve(PeepholePermalink, Job, String)} when searching.
|
||||
* @param b if set, the newest build to even consider when searching
|
||||
*/
|
||||
@Restricted(NoExternalUse.class)
|
||||
@CheckForNull
|
||||
default Run<?, ?> search(@NonNull PeepholePermalink pp, @NonNull Job<?, ?> job, @NonNull String id, @CheckForNull Run<?, ?> b) {
|
||||
if (b == null) {
|
||||
// no cache
|
||||
b = job.getLastBuild();
|
||||
}
|
||||
} catch (IOException x) {
|
||||
LOGGER.log(Level.WARNING, "failed to update " + storage, x);
|
||||
// start from the build 'b' and locate the build that matches the criteria going back in time
|
||||
b = pp.find(b);
|
||||
pp.updateCache(job, b);
|
||||
return b;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* The cache entry for this target is missing.
|
||||
*/
|
||||
record Unknown() implements PermalinkTarget {
|
||||
@Override
|
||||
public Run<?, ?> resolve(PeepholePermalink pp, Job<?, ?> job, String id) {
|
||||
return search(pp, job, id, null);
|
||||
}
|
||||
}
|
||||
|
||||
Unknown UNKNOWN = new Unknown();
|
||||
|
||||
/**
|
||||
* The cache entry for this target is present.
|
||||
*/
|
||||
sealed interface Known extends PermalinkTarget {}
|
||||
|
||||
/** There is known to be no matching build. */
|
||||
record None() implements Known {
|
||||
@Override
|
||||
public Run<?, ?> resolve(PeepholePermalink pp, Job<?, ?> job, String id) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/** Singleton of {@link None}. */
|
||||
None NONE = new None();
|
||||
|
||||
/** A matching build, indicated by {@link Run#getNumber}. */
|
||||
record Some(int number) implements Known {
|
||||
@Override
|
||||
public Run<?, ?> resolve(PeepholePermalink pp, Job<?, ?> job, String id) {
|
||||
Run<?, ?> b = job.getBuildByNumber(number);
|
||||
if (b != null && pp.apply(b)) {
|
||||
return b; // found it (in the most efficient way possible)
|
||||
}
|
||||
// the cache is stale. start the search
|
||||
if (b == null) {
|
||||
b = job.getNearestOldBuild(number);
|
||||
}
|
||||
return search(pp, job, id, b);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Looks for any existing cache hit.
|
||||
* @param id {@link #getId}
|
||||
* @return {@link Some} or {@link #NONE} or {@link #UNKNOWN}
|
||||
*/
|
||||
@NonNull PermalinkTarget get(@NonNull Job<?, ?> job, @NonNull String id);
|
||||
|
||||
/**
|
||||
* Updates the cache.
|
||||
* Note that this may be called not just when a build completes or is deleted
|
||||
* (meaning that the logical value of the cache has changed),
|
||||
* but also when {@link #resolve} has failed to find a cached value
|
||||
* (or determined that a previously cached value is in fact invalid).
|
||||
* @param id {@link #getId}
|
||||
* @param target {@link Some} or {@link #NONE}
|
||||
*/
|
||||
void put(@NonNull Job<?, ?> job, @NonNull String id, @NonNull Known target);
|
||||
}
|
||||
|
||||
/**
|
||||
* Default cache based on a {@code permalinks} file in the build directory.
|
||||
* There is one line per cached permalink, in the format {@code lastStableBuild 123}
|
||||
* or (for a negative cache) {@code lastFailedBuild -1}.
|
||||
*/
|
||||
@Restricted(NoExternalUse.class)
|
||||
@Extension(ordinal = -1000)
|
||||
public static final class DefaultCache implements Cache {
|
||||
|
||||
/**
|
||||
* JENKINS-22822: avoids rereading caches.
|
||||
* Top map keys are {@code builds} directories.
|
||||
* Inner maps are from permalink name to target.
|
||||
* Synchronization is first on the outer map, then on the inner.
|
||||
*/
|
||||
private final Map<File, Map<String, Known>> caches = new HashMap<>();
|
||||
|
||||
@Override
|
||||
public PermalinkTarget get(Job<?, ?> job, String id) {
|
||||
var cache = cacheFor(job.getBuildDir());
|
||||
synchronized (cache) {
|
||||
var cached = cache.get(id);
|
||||
return cached != null ? cached : UNKNOWN;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void put(Job<?, ?> job, String id, Known target) {
|
||||
File buildDir = job.getBuildDir();
|
||||
var cache = cacheFor(buildDir);
|
||||
synchronized (cache) {
|
||||
cache.put(id, target);
|
||||
File storage = storageFor(buildDir);
|
||||
LOGGER.fine(() -> "saving to " + storage + ": " + cache);
|
||||
try (AtomicFileWriter cw = new AtomicFileWriter(storage)) {
|
||||
try {
|
||||
for (var entry : cache.entrySet()) {
|
||||
cw.write(entry.getKey());
|
||||
cw.write(' ');
|
||||
cw.write(Integer.toString(entry.getValue() instanceof Cache.Some some ? some.number : -1));
|
||||
cw.write('\n');
|
||||
}
|
||||
cw.commit();
|
||||
} finally {
|
||||
cw.abort();
|
||||
}
|
||||
} catch (IOException x) {
|
||||
LOGGER.log(Level.WARNING, "failed to update " + storage, x);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private @NonNull Map<String, Known> cacheFor(@NonNull File buildDir) {
|
||||
synchronized (caches) {
|
||||
var cache = caches.get(buildDir);
|
||||
if (cache == null) {
|
||||
cache = load(buildDir);
|
||||
caches.put(buildDir, cache);
|
||||
}
|
||||
return cache;
|
||||
}
|
||||
}
|
||||
|
||||
private static @NonNull Map<String, Known> load(@NonNull File buildDir) {
|
||||
Map<String, Known> cache = new TreeMap<>();
|
||||
File storage = storageFor(buildDir);
|
||||
if (storage.isFile()) {
|
||||
try (Stream<String> lines = Files.lines(storage.toPath(), StandardCharsets.UTF_8)) {
|
||||
lines.forEach(line -> {
|
||||
int idx = line.indexOf(' ');
|
||||
if (idx == -1) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
int number = Integer.parseInt(line.substring(idx + 1));
|
||||
cache.put(line.substring(0, idx), number == -1 ? Cache.NONE : new Cache.Some(number));
|
||||
} catch (NumberFormatException x) {
|
||||
LOGGER.log(Level.WARNING, "failed to read " + storage, x);
|
||||
}
|
||||
});
|
||||
} catch (IOException x) {
|
||||
LOGGER.log(Level.WARNING, "failed to read " + storage, x);
|
||||
}
|
||||
LOGGER.fine(() -> "loading from " + storage + ": " + cache);
|
||||
}
|
||||
return cache;
|
||||
}
|
||||
|
||||
static @NonNull File storageFor(@NonNull File buildDir) {
|
||||
return new File(buildDir, "permalinks");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -380,7 +477,5 @@ public abstract class PeepholePermalink extends Permalink implements Predicate<R
|
|||
@Restricted(NoExternalUse.class)
|
||||
public static void initialized() {}
|
||||
|
||||
private static final int RESOLVES_TO_NONE = -1;
|
||||
|
||||
private static final Logger LOGGER = Logger.getLogger(PeepholePermalink.class.getName());
|
||||
}
|
||||
|
|
|
@ -60,6 +60,8 @@ import java.util.Objects;
|
|||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipOutputStream;
|
||||
import jenkins.MasterToSlaveFileCallable;
|
||||
import jenkins.model.ArtifactManager;
|
||||
import jenkins.security.MasterToSlaveCallable;
|
||||
|
@ -68,8 +70,6 @@ import org.apache.tools.ant.types.AbstractFileSet;
|
|||
import org.apache.tools.ant.types.selectors.SelectorUtils;
|
||||
import org.apache.tools.ant.types.selectors.TokenizedPath;
|
||||
import org.apache.tools.ant.types.selectors.TokenizedPattern;
|
||||
import org.apache.tools.zip.ZipEntry;
|
||||
import org.apache.tools.zip.ZipOutputStream;
|
||||
import org.kohsuke.accmod.Restricted;
|
||||
import org.kohsuke.accmod.restrictions.NoExternalUse;
|
||||
|
||||
|
@ -375,8 +375,8 @@ public abstract class VirtualFile implements Comparable<VirtualFile>, Serializab
|
|||
}
|
||||
|
||||
Collection<String> files = list(includes, excludes, useDefaultExcludes, openOptions);
|
||||
try (ZipOutputStream zos = new ZipOutputStream(outputStream)) {
|
||||
zos.setEncoding(Charset.defaultCharset().displayName()); // TODO JENKINS-20663 make this overridable via query parameter
|
||||
// TODO JENKINS-20663 make encoding overridable via query parameter
|
||||
try (ZipOutputStream zos = new ZipOutputStream(outputStream, Charset.defaultCharset())) {
|
||||
|
||||
for (String relativePath : files) {
|
||||
VirtualFile virtualFile = this.child(relativePath);
|
||||
|
|
|
@ -39,10 +39,10 @@
|
|||
"mini-css-extract-plugin": "2.9.2",
|
||||
"postcss": "8.4.49",
|
||||
"postcss-loader": "8.1.1",
|
||||
"postcss-preset-env": "10.1.1",
|
||||
"postcss-preset-env": "10.1.2",
|
||||
"postcss-scss": "4.0.9",
|
||||
"prettier": "3.4.2",
|
||||
"sass": "1.82.0",
|
||||
"sass": "1.83.0",
|
||||
"sass-loader": "16.0.4",
|
||||
"style-loader": "4.0.0",
|
||||
"stylelint": "16.11.0",
|
||||
|
@ -54,7 +54,7 @@
|
|||
},
|
||||
"dependencies": {
|
||||
"handlebars": "4.7.8",
|
||||
"hotkeys-js": "3.12.2",
|
||||
"hotkeys-js": "3.13.9",
|
||||
"jquery": "3.7.1",
|
||||
"lodash": "4.17.21",
|
||||
"sortablejs": "1.15.6",
|
||||
|
|
2
pom.xml
2
pom.xml
|
@ -97,7 +97,7 @@ THE SOFTWARE.
|
|||
<bridge-method-injector.version>1.30</bridge-method-injector.version>
|
||||
<spotless.check.skip>false</spotless.check.skip>
|
||||
<!-- Make sure to keep the jetty-ee9-maven-plugin version in war/pom.xml in sync with the Jetty release in Winstone: -->
|
||||
<winstone.version>8.2</winstone.version>
|
||||
<winstone.version>8.4</winstone.version>
|
||||
<node.version>20.18.1</node.version>
|
||||
</properties>
|
||||
|
||||
|
|
|
@ -33,6 +33,8 @@ function init() {
|
|||
searchResultsContainer,
|
||||
() => searchResults.querySelectorAll("a"),
|
||||
hoverClass,
|
||||
() => {},
|
||||
() => commandPalette.open,
|
||||
);
|
||||
|
||||
// Events
|
||||
|
|
|
@ -81,7 +81,7 @@ export default function makeKeyboardNavigable(
|
|||
}
|
||||
|
||||
function scrollAndSelect(selectedItem, selectedClass, items) {
|
||||
if (selectedItem !== null) {
|
||||
if (selectedItem) {
|
||||
if (!isInViewport(selectedItem)) {
|
||||
selectedItem.scrollIntoView(false);
|
||||
}
|
||||
|
|
|
@ -218,7 +218,7 @@ THE SOFTWARE.
|
|||
<dependency>
|
||||
<groupId>org.jenkins-ci.plugins</groupId>
|
||||
<artifactId>cloudbees-folder</artifactId>
|
||||
<version>6.973.vc9b_85a_61e4fc</version>
|
||||
<version>6.975.v4161e479479f</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
|
|
|
@ -664,6 +664,8 @@ public class AbstractProjectTest {
|
|||
JSONObject o = new JSONObject();
|
||||
o.put("name", p);
|
||||
o.put("url", JSONObject.fromObject(null));
|
||||
o.put("icon", JSONObject.fromObject(null));
|
||||
o.put("type", "symbol");
|
||||
expected.add(o);
|
||||
}
|
||||
assertThat(suggestions.containsAll(expected), is(true));
|
||||
|
|
|
@ -82,7 +82,7 @@ public class PeepholePermalinkTest {
|
|||
}
|
||||
|
||||
private void assertStorage(String id, Job<?, ?> job, Run<?, ?> build) throws Exception {
|
||||
assertThat(Files.readAllLines(PeepholePermalink.storageFor(job.getBuildDir()).toPath(), StandardCharsets.UTF_8),
|
||||
assertThat(Files.readAllLines(PeepholePermalink.DefaultCache.storageFor(job.getBuildDir()).toPath(), StandardCharsets.UTF_8),
|
||||
hasItem(id + " " + (build == null ? -1 : build.getNumber())));
|
||||
}
|
||||
|
||||
|
|
|
@ -24,6 +24,9 @@
|
|||
|
||||
package jenkins.model.lazy;
|
||||
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.hamcrest.Matchers.is;
|
||||
import static org.hamcrest.Matchers.nullValue;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotSame;
|
||||
import static org.junit.Assert.assertNull;
|
||||
|
@ -87,6 +90,40 @@ public class LazyBuildMixInTest {
|
|||
assertEquals(b3, b1a.getNextBuild());
|
||||
}
|
||||
|
||||
@Test public void numericLookups() throws Exception {
|
||||
var p = r.createFreeStyleProject();
|
||||
var b1 = r.buildAndAssertSuccess(p);
|
||||
var b2 = r.buildAndAssertSuccess(p);
|
||||
var b3 = r.buildAndAssertSuccess(p);
|
||||
var b4 = r.buildAndAssertSuccess(p);
|
||||
var b5 = r.buildAndAssertSuccess(p);
|
||||
var b6 = r.buildAndAssertSuccess(p);
|
||||
b1.delete();
|
||||
b3.delete();
|
||||
b6.delete();
|
||||
// leaving 2, 4, 5
|
||||
assertThat(p.getFirstBuild(), is(b2));
|
||||
assertThat(p.getLastBuild(), is(b5));
|
||||
assertThat(p.getNearestBuild(-1), is(b2));
|
||||
assertThat(p.getNearestBuild(0), is(b2));
|
||||
assertThat(p.getNearestBuild(1), is(b2));
|
||||
assertThat(p.getNearestBuild(2), is(b2));
|
||||
assertThat(p.getNearestBuild(3), is(b4));
|
||||
assertThat(p.getNearestBuild(4), is(b4));
|
||||
assertThat(p.getNearestBuild(5), is(b5));
|
||||
assertThat(p.getNearestBuild(6), nullValue());
|
||||
assertThat(p.getNearestBuild(7), nullValue());
|
||||
assertThat(p.getNearestOldBuild(-1), nullValue());
|
||||
assertThat(p.getNearestOldBuild(0), nullValue());
|
||||
assertThat(p.getNearestOldBuild(1), nullValue());
|
||||
assertThat(p.getNearestOldBuild(2), is(b2));
|
||||
assertThat(p.getNearestOldBuild(3), is(b2));
|
||||
assertThat(p.getNearestOldBuild(4), is(b4));
|
||||
assertThat(p.getNearestOldBuild(5), is(b5));
|
||||
assertThat(p.getNearestOldBuild(6), is(b5));
|
||||
assertThat(p.getNearestOldBuild(7), is(b5));
|
||||
}
|
||||
|
||||
@Issue("JENKINS-20662")
|
||||
@Test public void newRunningBuildRelationFromPrevious() throws Exception {
|
||||
FreeStyleProject p = r.createFreeStyleProject();
|
||||
|
|
|
@ -645,7 +645,7 @@ THE SOFTWARE.
|
|||
<plugin>
|
||||
<groupId>org.eclipse.jetty.ee9</groupId>
|
||||
<artifactId>jetty-ee9-maven-plugin</artifactId>
|
||||
<version>12.0.14</version>
|
||||
<version>12.0.16</version>
|
||||
<configuration>
|
||||
<!--
|
||||
Reload webapp when you hit ENTER. (See JETTY-282 for more)
|
||||
|
|
50
yarn.lock
50
yarn.lock
|
@ -3040,16 +3040,16 @@ __metadata:
|
|||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"css-has-pseudo@npm:^7.0.1":
|
||||
version: 7.0.1
|
||||
resolution: "css-has-pseudo@npm:7.0.1"
|
||||
"css-has-pseudo@npm:^7.0.2":
|
||||
version: 7.0.2
|
||||
resolution: "css-has-pseudo@npm:7.0.2"
|
||||
dependencies:
|
||||
"@csstools/selector-specificity": "npm:^5.0.0"
|
||||
postcss-selector-parser: "npm:^7.0.0"
|
||||
postcss-value-parser: "npm:^4.2.0"
|
||||
peerDependencies:
|
||||
postcss: ^8.4
|
||||
checksum: 10c0/13789b08b70169204be786d652190356ace9313099d3656bd2fc38afbdd28f3d9620f0e0b07425480961b7a1ec789794961d0472f205b959d3f64c9a78ce511c
|
||||
checksum: 10c0/456e9ce1eec8a535683c329956acfe53ce5a208345d7f2fcbe662626be8b3c98681e9041d7f4980316714397b0c1c3defde25653d629c396df17803d599c4edf
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
|
@ -3165,10 +3165,10 @@ __metadata:
|
|||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"cssdb@npm:^8.2.1":
|
||||
version: 8.2.1
|
||||
resolution: "cssdb@npm:8.2.1"
|
||||
checksum: 10c0/d27d7db0a39e1105181aac119a98d6c92cd5ceba2e8bd349cdf2ba4a8d9ead149b685a1dba9542ca24f094cc70eca4a3e02973fe1f74c11a373b508606e5e1c0
|
||||
"cssdb@npm:^8.2.3":
|
||||
version: 8.2.3
|
||||
resolution: "cssdb@npm:8.2.3"
|
||||
checksum: 10c0/17c3ca6432ed02431db6b44bed74649ccef7d7b7b900ccbc7297525f030722c441dd67c71f28aef3cfa0814ba7b254a24adfb0dcd5728937da179ff437cdcd0c
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
|
@ -4071,10 +4071,10 @@ __metadata:
|
|||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"hotkeys-js@npm:3.12.2":
|
||||
version: 3.12.2
|
||||
resolution: "hotkeys-js@npm:3.12.2"
|
||||
checksum: 10c0/67f19a01de9d1a6ad4ce1055734a7adc0a52fef81ccb1f61f4930a58ad93fca9c382f16647ef0abd9e1610814caddb0d3ca6ce7a8e6fcc43e26275423de617a9
|
||||
"hotkeys-js@npm:3.13.9":
|
||||
version: 3.13.9
|
||||
resolution: "hotkeys-js@npm:3.13.9"
|
||||
checksum: 10c0/83511e7e812395289231605f6c50974f85c270de0316b21ffc4b794d29f2a1aa927a29644c77f1f77ac6e3228fa91fb4bc5f01fb5b27e00196af4d8c5a4a6693
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
|
@ -4383,16 +4383,16 @@ __metadata:
|
|||
globals: "npm:15.13.0"
|
||||
handlebars: "npm:4.7.8"
|
||||
handlebars-loader: "npm:1.7.3"
|
||||
hotkeys-js: "npm:3.12.2"
|
||||
hotkeys-js: "npm:3.13.9"
|
||||
jquery: "npm:3.7.1"
|
||||
lodash: "npm:4.17.21"
|
||||
mini-css-extract-plugin: "npm:2.9.2"
|
||||
postcss: "npm:8.4.49"
|
||||
postcss-loader: "npm:8.1.1"
|
||||
postcss-preset-env: "npm:10.1.1"
|
||||
postcss-preset-env: "npm:10.1.2"
|
||||
postcss-scss: "npm:4.0.9"
|
||||
prettier: "npm:3.4.2"
|
||||
sass: "npm:1.82.0"
|
||||
sass: "npm:1.83.0"
|
||||
sass-loader: "npm:16.0.4"
|
||||
sortablejs: "npm:1.15.6"
|
||||
style-loader: "npm:4.0.0"
|
||||
|
@ -5893,9 +5893,9 @@ __metadata:
|
|||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"postcss-preset-env@npm:10.1.1":
|
||||
version: 10.1.1
|
||||
resolution: "postcss-preset-env@npm:10.1.1"
|
||||
"postcss-preset-env@npm:10.1.2":
|
||||
version: 10.1.2
|
||||
resolution: "postcss-preset-env@npm:10.1.2"
|
||||
dependencies:
|
||||
"@csstools/postcss-cascade-layers": "npm:^5.0.1"
|
||||
"@csstools/postcss-color-function": "npm:^4.0.6"
|
||||
|
@ -5932,9 +5932,9 @@ __metadata:
|
|||
autoprefixer: "npm:^10.4.19"
|
||||
browserslist: "npm:^4.23.1"
|
||||
css-blank-pseudo: "npm:^7.0.1"
|
||||
css-has-pseudo: "npm:^7.0.1"
|
||||
css-has-pseudo: "npm:^7.0.2"
|
||||
css-prefers-color-scheme: "npm:^10.0.0"
|
||||
cssdb: "npm:^8.2.1"
|
||||
cssdb: "npm:^8.2.3"
|
||||
postcss-attribute-case-insensitive: "npm:^7.0.1"
|
||||
postcss-clamp: "npm:^4.1.0"
|
||||
postcss-color-functional-notation: "npm:^7.0.6"
|
||||
|
@ -5962,7 +5962,7 @@ __metadata:
|
|||
postcss-selector-not: "npm:^8.0.1"
|
||||
peerDependencies:
|
||||
postcss: ^8.4
|
||||
checksum: 10c0/99931117735a66827c7318be023ddb614990457617ccbe7fd2fdc1f10345554652df180d4842768d68d57e14fc0be4d86d0b413c65e77e02db5511e57ed07c4f
|
||||
checksum: 10c0/bd40330867a525679d434ff9602efbf229da9e745a3759c2d0b3cff166dd0f17bf99b44673ebb316df1906c2bf2edef97aeef1840aa6be170b43a34404df396d
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
|
@ -6381,9 +6381,9 @@ __metadata:
|
|||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"sass@npm:1.82.0":
|
||||
version: 1.82.0
|
||||
resolution: "sass@npm:1.82.0"
|
||||
"sass@npm:1.83.0":
|
||||
version: 1.83.0
|
||||
resolution: "sass@npm:1.83.0"
|
||||
dependencies:
|
||||
"@parcel/watcher": "npm:^2.4.1"
|
||||
chokidar: "npm:^4.0.0"
|
||||
|
@ -6394,7 +6394,7 @@ __metadata:
|
|||
optional: true
|
||||
bin:
|
||||
sass: sass.js
|
||||
checksum: 10c0/7f86fe6ade4f6018862c448ed69d5c52f485b0125c9dab24e63f679739a04cc7c56562d588e3cf16b5efb4d2c4d0530e62740e1cfd273e2e3707d04d11011736
|
||||
checksum: 10c0/4415361229879a9041d77c953da85482e89032aa4321ba13250a9987d39c80fac6c88af3777f2a2d76a4e8b0c8afbd21c1970fdbe84e0b3ec25fb26741f92beb
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
|
|
Loading…
Reference in New Issue