@Override /** * Called after the user has changed the project name of a job and then clicked on submit. * * @param item The item that has been renamed. The new project name is already in item.getName() * @param oldName the old name * @param newName the new name */ public void onRenamed(Item item, String oldName, String newName) { // bug 5077308 - Display name field should be cleared when you rename a job. if (item instanceof AbstractItem) { AbstractItem abstractItem = (AbstractItem) item; if (oldName.equals(abstractItem.getDisplayName())) { // the user renamed the job, but the old project name which is shown as the // displayname if no displayname was set, has been set into the displayname field. // This means that the displayname was never set, so we want to set it // to null as it was before try { LOGGER.info( String.format( "onRenamed():Setting displayname to null for item.name=%s", item.getName())); abstractItem.setDisplayName(null); } catch (IOException ioe) { LOGGER.log( Level.WARNING, String.format( "onRenamed():Exception while trying to clear the displayName for Item.name:%s", item.getName()), ioe); } } } }
@Override public List<? extends ItemGroup<?>> validDestinations(Item item) { List<DirectlyModifiableTopLevelItemGroup> result = new ArrayList<DirectlyModifiableTopLevelItemGroup>(); Jenkins instance = Jenkins.getActiveInstance(); if (permitted(item, instance)) { result.add(instance); } ITEM: for (Item g : instance.getAllItems()) { if (g instanceof DirectlyModifiableTopLevelItemGroup) { DirectlyModifiableTopLevelItemGroup itemGroup = (DirectlyModifiableTopLevelItemGroup) g; if (!permitted(item, itemGroup)) { continue; } ItemGroup<?> p = itemGroup; while (p instanceof Item) { Item i = (Item) p; if (i == item) { // Cannot move a folder into itself or a descendant. continue ITEM; } p = i.getParent(); } result.add(itemGroup); } } return result; }
@Override protected void compute() throws Exception { int itemCount = 0; for (Item item : items) { for (Job<?, ?> job : item.getAllJobs()) { if (job instanceof AbstractProject) { AbstractProject<?, ?> p = (AbstractProject) job; RunList<? extends AbstractBuild<?, ?>> builds = p.getBuilds(); int buildCount = 0; for (AbstractBuild<?, ?> build : builds) { if (canceled()) { return; } for (ChangeLogSet.Entry entry : build.getChangeSet()) { User user = entry.getAuthor(); UserInfo info = users.get(user); if (info == null) { UserInfo userInfo = new UserInfo(user, p, build.getTimestamp()); userInfo.avatar = UserAvatarResolver.resolveOrNull(user, iconSize); synchronized (this) { users.put(user, userInfo); modified.add(user); } } else if (info.getLastChange().before(build.getTimestamp())) { synchronized (this) { info.project = p; info.lastChange = build.getTimestamp(); modified.add(user); } } } // TODO consider also adding the user of the UserCause when applicable buildCount++; progress((itemCount + 1.0 * buildCount / builds.size()) / (items.size() + 1)); } } } itemCount++; progress(1.0 * itemCount / (items.size() + /* handling User.getAll */ 1)); } if (unknown != null) { if (canceled()) { return; } for (User u : User.getAll()) { // TODO nice to have a method to iterate these lazily if (u == unknown) { continue; } if (!users.containsKey(u)) { UserInfo userInfo = new UserInfo(u, null, null); userInfo.avatar = UserAvatarResolver.resolveOrNull(u, iconSize); synchronized (this) { users.put(u, userInfo); modified.add(u); } } } } }
/** * Loads a {@link Item} from a config file. * * @param dir The directory that contains the config file, not the config file itself. * @param loadLazy true if return a LazyTopLevelItem without actually loading; false to actually * load the file and return a real item. * @throws IOException */ public static Item load(ItemGroup parent, File dir, boolean loadLazy) throws IOException { if (loadLazy) { return newLazyTopLevelItem(parent, dir, null); } else { Item item = (Item) getConfigFile(dir).read(); item.onLoad(parent, dir.getName()); return item; } }
public Item doCreateItem(StaplerRequest req, StaplerResponse rsp) throws IOException, ServletException { Item item = Hudson.getInstance().doCreateItem(req, rsp); if (item != null) { jobNames.add(item.getName()); owner.save(); } return item; }
/** Converts a list of items into a comma-separated list of full names. */ public static String toNameList(Collection<? extends Item> items) { StringBuilder buf = new StringBuilder(); for (Item item : items) { if (buf.length() > 0) { buf.append(", "); } buf.append(item.getFullName()); } return buf.toString(); }
/** * Cancels the item in the queue. If the item is scheduled more than once, cancels the first * occurrence. * * @return true if the project was indeed in the queue and was removed. false if this was no-op. */ public synchronized boolean cancel(Task p) { LOGGER.fine("Cancelling " + p.getFullDisplayName()); for (Iterator<WaitingItem> itr = waitingList.iterator(); itr.hasNext(); ) { Item item = itr.next(); if (item.task.equals(p)) { itr.remove(); item.onCancelled(); return true; } } // use bitwise-OR to make sure that both branches get evaluated all the time return blockedProjects.cancel(p) != null | buildables.cancel(p) != null; }
public static boolean isApplicable(Collection<? extends Item> items) { for (Item item : items) { for (Job job : item.getAllJobs()) { if (job instanceof AbstractProject) { AbstractProject<?, ?> p = (AbstractProject) job; for (AbstractBuild<?, ?> build : p.getBuilds()) { for (Entry entry : build.getChangeSet()) { User user = entry.getAuthor(); if (user != null) return true; } } } } } return false; }
/** * Returns true if {@link BuildPtr} points to the given job or one of its subordinates. * * <p>This is useful to check if an artifact in MavenModule belongs to MavenModuleSet. */ public boolean belongsTo(Job job) { Item p = Jenkins.getInstance().getItemByFullName(name); while (p != null) { if (p == job) return true; // go up the chain while we ItemGroup<? extends Item> parent = p.getParent(); if (!(parent instanceof Item)) { return false; } p = (Item) parent; } return false; }
public FormValidation doCheckUrl( @AncestorInPath Item project, @QueryParameter String credentialsId, @QueryParameter String value) throws IOException, InterruptedException { if (project == null || !project.hasPermission(Item.CONFIGURE)) { return FormValidation.ok(); } String url = Util.fixEmptyAndTrim(value); if (url == null) return FormValidation.error("Please enter repository url."); // get git executable on master final EnvVars environment = new EnvVars(EnvVars.masterEnvVars); GitClient git = Git.with(TaskListener.NULL, environment) .using(GitTool.getDefaultInstallation().getGitExe()) .getClient(); if (credentialsId != null) { StandardCredentials credentials = lookupCredentials(project, credentialsId, url); if (credentials != null) git.addDefaultCredentials(credentials); } // attempt to connect the provided URL try { git.getHeadRev(url, "HEAD"); } catch (GitException e) { return FormValidation.error(Messages.UserRemoteConfig_FailedToConnect(e.getMessage())); } return FormValidation.ok(); }
public HandlingMode applicability(Item item) { if (item instanceof TopLevelItem && item instanceof AbstractItem && item.getParent() instanceof DirectlyModifiableTopLevelItemGroup) { return HandlingMode.HANDLE; } else { return HandlingMode.SKIP; } }
@Override public HttpResponse handle( Item item, ItemGroup<?> destination, AtomicReference<Item> newItem, List<? extends RelocationHandler> chain) throws IOException, InterruptedException { if (!(destination instanceof DirectlyModifiableTopLevelItemGroup)) { return chain.isEmpty() ? null : chain.get(0).handle(item, destination, newItem, chain.subList(1, chain.size())); } Item result = doMove(item, (DirectlyModifiableTopLevelItemGroup) destination); newItem.set(result); // AbstractItem.getUrl does weird magic here which winds up making it redirect to the old // location, so inline the correct part of this method. return HttpResponses.redirectViaContextPath(result.getParent().getUrl() + result.getShortUrl()); }
public synchronized boolean cancel(Item item) { LOGGER.fine("Cancelling " + item.task.getFullDisplayName() + " item#" + item.id); // use bitwise-OR to make sure that all the branches get evaluated all the time boolean r = (item instanceof WaitingItem && waitingList.remove(item)) | blockedProjects.remove(item) | buildables.remove(item); if (r) item.onCancelled(); return r; }
private void updateGeneratedJobs( final AbstractBuild<?, ?> build, BuildListener listener, Set<GeneratedJob> freshJobs) throws IOException { // Update Project Set<GeneratedJob> generatedJobs = extractGeneratedObjects(build.getProject(), GeneratedJobsAction.class); Set<GeneratedJob> added = Sets.difference(freshJobs, generatedJobs); Set<GeneratedJob> existing = Sets.intersection(generatedJobs, freshJobs); Set<GeneratedJob> removed = Sets.difference(generatedJobs, freshJobs); logItems(listener, "Adding items", added); logItems(listener, "Existing items", existing); logItems(listener, "Removing items", removed); // Update unreferenced jobs for (GeneratedJob removedJob : removed) { Item removedItem = getLookupStrategy().getItem(build.getProject(), removedJob.getJobName(), Item.class); if (removedItem != null && removedJobAction != RemovedJobAction.IGNORE) { if (removedJobAction == RemovedJobAction.DELETE) { try { removedItem.delete(); } catch (InterruptedException e) { listener.getLogger().println(String.format("Delete item failed: %s", removedJob)); if (removedItem instanceof AbstractProject) { listener.getLogger().println(String.format("Disabling item instead: %s", removedJob)); ((AbstractProject) removedItem).disable(); } } } else { if (removedItem instanceof AbstractProject) { ((AbstractProject) removedItem).disable(); } } } } updateGeneratedJobMap(build.getProject(), Sets.union(added, existing), removed); }
@Override public OwnershipInfo getOwnershipInfo(AbstractFolder<?> item) { if (item == null) { // Handle renames, etc. return OwnershipInfo.DISABLED_INFO; } // Retrieve Ownership from the Folder property FolderOwnershipProperty prop = getOwnerProperty(item); if (prop != null) { OwnershipDescription d = prop.getOwnership(); if (d.isOwnershipEnabled()) { return new OwnershipInfo(prop.getOwnership(), new FolderOwnershipDescriptionSource(item)); } } // We go to upper items in order to get the ownership description if (!OwnershipPluginConfiguration.get() .getInheritanceOptions() .isBlockInheritanceFromItemGroups()) { ItemGroup parent = item.getParent(); AbstractOwnershipHelper<ItemGroup> located = OwnershipHelperLocator.locate(parent); while (located != null) { OwnershipInfo fromParent = located.getOwnershipInfo(parent); if (fromParent.getDescription().isOwnershipEnabled()) { return fromParent; } if (parent instanceof Item) { Item parentItem = (Item) parent; parent = parentItem.getParent(); located = OwnershipHelperLocator.locate(parent); } else { located = null; } } } return OwnershipInfo.DISABLED_INFO; }
private Map<User, UserInfo> getUserInfo(Collection<? extends Item> items) { Map<User, UserInfo> users = new HashMap<User, UserInfo>(); for (Item item : items) { for (Job job : item.getAllJobs()) { if (job instanceof AbstractProject) { AbstractProject<?, ?> p = (AbstractProject) job; for (AbstractBuild<?, ?> build : p.getBuilds()) { for (Entry entry : build.getChangeSet()) { User user = entry.getAuthor(); UserInfo info = users.get(user); if (info == null) users.put(user, new UserInfo(user, p, build.getTimestamp())); else if (info.getLastChange().before(build.getTimestamp())) { info.project = p; info.lastChange = build.getTimestamp(); } } } } } } return users; }
/** Erase aliases from newly created projects by copying. */ @Override public void onCopied(Item src, Item item) { if (!(item instanceof Job)) return; Job<?, ?> job = (Job<?, ?>) item; PermalinkStorage storage = job.getProperty(PermalinkStorage.class); if (storage == null) return; try { job.removeProperty(storage); } catch (IOException ex) { LOGGER.log(Level.SEVERE, "Unable to erase aliases when coppying " + item.getFullName(), ex); } }
/** Computes the relative path from the current page to the given item. */ public static String getRelativeLinkTo(Item p) { Map<Object, String> ancestors = new HashMap<Object, String>(); View view = null; StaplerRequest request = Stapler.getCurrentRequest(); for (Ancestor a : request.getAncestors()) { ancestors.put(a.getObject(), a.getRelativePath()); if (a.getObject() instanceof View) view = (View) a.getObject(); } String path = ancestors.get(p); if (path != null) return path; Item i = p; String url = ""; while (true) { ItemGroup ig = i.getParent(); url = i.getShortUrl() + url; if (ig == Hudson.getInstance()) { assert i instanceof TopLevelItem; if (view != null && view.contains((TopLevelItem) i)) { // if p and the current page belongs to the same view, then return a relative path return ancestors.get(view) + '/' + url; } else { // otherwise return a path from the root Hudson return request.getContextPath() + '/' + p.getUrl(); } } path = ancestors.get(ig); if (path != null) return path + '/' + url; assert ig instanceof Item; // if not, ig must have been the Hudson instance i = (Item) ig; } }
public ListBoxModel doFillCredentialsIdItems( @AncestorInPath Item project, @QueryParameter String url) { if (project == null || !project.hasPermission(Item.CONFIGURE)) { return new StandardListBoxModel(); } return new StandardListBoxModel() .withEmptySelection() .withMatching( GitClient.CREDENTIALS_MATCHER, CredentialsProvider.lookupCredentials( StandardCredentials.class, project, ACL.SYSTEM, GitURIRequirementsBuilder.fromUri(url).build())); }
public void observe(Item item) { if (item instanceof Folder) { // only interested in non-folders in order to prevent double counting return; } HealthReport report = getHealthReport(item); if (report != null && (worst == null || report.getScore() < worst.getScore())) { worst = new HealthReport( report.getScore(), report.getIconUrl(), Messages._Folder_HealthWrap( item.getFullDisplayName(), report.getLocalizableDescription())); } }
@Override /** * Called after the user has clicked OK in the New Job page when Copy existing job has been * selected. The fields in item will be displayed in when the config page is loaded displayed. */ public void onCopied(Item src, Item item) { // bug 5056825 - Display name field should be cleared when you copy a job. if (item instanceof AbstractItem) { AbstractItem dest = (AbstractItem) item; try { dest.setDisplayName(null); } catch (IOException ioe) { LOGGER.log( Level.WARNING, String.format( "onCopied():Exception while trying to clear the displayName for Item.name:%s", item.getName()), ioe); } } }
private void updateGeneratedJobMap( AbstractProject<?, ?> seedJob, Set<GeneratedJob> createdOrUpdatedJobs, Set<GeneratedJob> removedJobs) throws IOException { DescriptorImpl descriptor = Jenkins.getInstance().getDescriptorByType(DescriptorImpl.class); boolean descriptorMutated = false; Map<String, SeedReference> generatedJobMap = descriptor.getGeneratedJobMap(); for (GeneratedJob generatedJob : createdOrUpdatedJobs) { Item item = getLookupStrategy().getItem(seedJob, generatedJob.getJobName(), Item.class); if (item != null) { SeedReference newSeedReference = new SeedReference(seedJob.getFullName()); if (generatedJob.getTemplateName() != null) { Item template = getLookupStrategy().getItem(seedJob, generatedJob.getTemplateName(), Item.class); newSeedReference.setTemplateJobName(template.getFullName()); } newSeedReference.setDigest(Util.getDigestOf(Items.getConfigFile(item).getFile())); SeedReference oldSeedReference = generatedJobMap.get(item.getFullName()); if (!newSeedReference.equals(oldSeedReference)) { generatedJobMap.put(item.getFullName(), newSeedReference); descriptorMutated = true; } } } for (GeneratedJob removedJob : removedJobs) { Item removedItem = getLookupStrategy().getItem(seedJob, removedJob.getJobName(), Item.class); if (removedItem != null) { generatedJobMap.remove(removedItem.getFullName()); descriptorMutated = true; } } if (descriptorMutated) { descriptor.save(); } }
private boolean permitted(Item item, DirectlyModifiableTopLevelItemGroup itemGroup) { return itemGroup == item.getParent() || itemGroup.canAdd((TopLevelItem) item) && ((AccessControlled) itemGroup).hasPermission(Job.CREATE); }
public String getRelativeNameFrom(Item item) { return getRelativeNameFrom(item.getParent()); }
/** * Schedules an execution of a task. * * @since 1.311 * @return null if this task is already in the queue and therefore the add operation was no-op. * Otherwise indicates the {@link WaitingItem} object added, although the nature of the queue * is that such {@link Item} only captures the state of the item at a particular moment, and * by the time you inspect the object, some of its information can be already stale. * <p>That said, one can still look at {@link WaitingItem#future}, {@link WaitingItem#id}, * etc. */ private synchronized WaitingItem scheduleInternal(Task p, int quietPeriod, List<Action> actions) { WaitingItem added = null; List<Item> items = getItems(p); Calendar due = new GregorianCalendar(); due.add(Calendar.SECOND, quietPeriod); List<Item> duplicatesInQueue = new ArrayList<Item>(); for (Item item : items) { boolean shouldScheduleItem = false; for (Action action : item.getActions()) { if (action instanceof QueueAction) shouldScheduleItem |= ((QueueAction) action).shouldSchedule(actions); } for (Action action : actions) { if (action instanceof QueueAction) { shouldScheduleItem |= ((QueueAction) action).shouldSchedule(item.getActions()); } } if (!shouldScheduleItem) { duplicatesInQueue.add(item); } } if (duplicatesInQueue.size() == 0) { LOGGER.fine(p.getFullDisplayName() + " added to queue"); // put the item in the queue waitingList.add(added = new WaitingItem(due, p, actions)); } else { // the requested build is already queued, so will not be added List<WaitingItem> waitingDuplicates = new ArrayList<WaitingItem>(); for (Item item : duplicatesInQueue) { for (Action a : actions) { if (a instanceof FoldableAction) { ((FoldableAction) a).foldIntoExisting(item.task, item.getActions()); } } if ((item instanceof WaitingItem)) waitingDuplicates.add((WaitingItem) item); } if (duplicatesInQueue.size() == 0) { // all duplicates in the queue are already in the blocked or // buildable stage no need to requeue return null; } // TODO: avoid calling scheduleMaintenance() if none of the waiting items // actually change for (WaitingItem wi : waitingDuplicates) { if (quietPeriod <= 0) { // the user really wants to build now, and they mean NOW. // so let's pull in the timestamp if we can. if (wi.timestamp.before(due)) continue; } else { // otherwise we do the normal quiet period implementation if (wi.timestamp.after(due)) continue; // quiet period timer reset. start the period over again } // waitingList is sorted, so when we change a timestamp we need to maintain order waitingList.remove(wi); wi.timestamp = due; waitingList.add(wi); } } scheduleMaintenance(); // let an executor know that a new item is in the queue. return added; }
/** Works like {@link #remove(Object)} but also marks the {@link Item} as cancelled. */ public boolean cancel(Item t) { boolean r = remove(t); if (r) t.onCancelled(); return r; }
protected Item(Item item) { this(item.task, item.getActions(), item.id, item.future); }
public String call(Item item) { return item.getName(); }
@Override protected void compute() throws Exception { int itemCount = 0; for (Item item : items) { for (Job<?, ?> job : item.getAllJobs()) { if (job instanceof AbstractProject) { AbstractProject<?, ?> p = (AbstractProject) job; RunList<? extends AbstractBuild<?, ?>> builds = p.getBuilds(); int buildCount = 0; for (AbstractBuild<?, ?> build : builds) { if (canceled()) { return; } for (ChangeLogSet.Entry entry : build.getChangeSet()) { User user = entry.getAuthor(); UserInfo info = users.get(user); if (info == null) { UserInfo userInfo = new UserInfo(user, p, build.getTimestamp()); userInfo.avatar = UserAvatarResolver.resolveOrNull(user, iconSize); synchronized (this) { users.put(user, userInfo); modified.add(user); } } else if (info.getLastChange().before(build.getTimestamp())) { synchronized (this) { info.project = p; info.lastChange = build.getTimestamp(); modified.add(user); } } } // TODO consider also adding the user of the UserCause when applicable buildCount++; // TODO this defeats lazy-loading. Should rather do a breadth-first search, as in // hudson.plugins.view.dashboard.builds.LatestBuilds // (though currently there is no quick implementation of RunMap.size() ~ // idOnDisk.size(), which would be needed for proper progress) progress((itemCount + 1.0 * buildCount / builds.size()) / (items.size() + 1)); } } } itemCount++; progress(1.0 * itemCount / (items.size() + /* handling User.getAll */ 1)); } if (unknown != null) { if (canceled()) { return; } for (User u : User.getAll()) { // TODO nice to have a method to iterate these lazily if (canceled()) { return; } if (u == unknown) { continue; } if (!users.containsKey(u)) { UserInfo userInfo = new UserInfo(u, null, null); userInfo.avatar = UserAvatarResolver.resolveOrNull(u, iconSize); synchronized (this) { users.put(u, userInfo); modified.add(u); } } } } }
/** The file we save our configuration. */ public static XmlFile getConfigFile(Item item) { return getConfigFile(item.getRootDir()); }