Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[JENKINS-71737] Fix redirect when submitting cloud changes #8310

Closed
wants to merge 31 commits into from
Closed
Show file tree
Hide file tree
Changes from 17 commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
081cadd
Fix redirect when submitting cloud changes
car-roll Jul 28, 2023
cb2a5fd
update comment
car-roll Jul 29, 2023
1741953
test cloud name change
car-roll Aug 11, 2023
a0a3e9c
add separate page for cloud rename
car-roll Aug 15, 2023
3d50865
tests cloud name change
car-roll Aug 15, 2023
29ad035
block using apply in cloud rename
car-roll Aug 15, 2023
ff3cbba
fix comments
car-roll Aug 15, 2023
dbf61fd
Merge branch 'master' into redirect-cloud-name-change
car-roll Aug 15, 2023
108bc22
Remove rename change, block apply when changing name
car-roll Aug 16, 2023
cc7c4e1
Revert "Remove rename change, block apply when changing name"
car-roll Aug 17, 2023
e3ef831
Add Renamable interface, generalize TransientActionFactoryImpl
car-roll Aug 26, 2023
7a96cd6
change isNameEditable default to true
car-roll Aug 30, 2023
b8e7f84
update jelly
car-roll Aug 30, 2023
aec2de1
add check for improper name change
car-roll Aug 31, 2023
d5b6dcd
hide sidepanel link if name not editable
car-roll Aug 31, 2023
a57343c
remove unnecessary sidepanel link
car-roll Sep 1, 2023
73f451e
Merge branch 'master' into redirect-cloud-name-change
car-roll Sep 6, 2023
b7eed6f
update Renamable javadoc
car-roll Sep 7, 2023
6c561f7
silently block renaming in config page
car-roll Sep 8, 2023
10ea3dd
Merge branch 'master' into redirect-cloud-name-change
car-roll Sep 8, 2023
92489f1
update test
car-roll Sep 8, 2023
b6e2fde
pass name field during cloud creation
car-roll Sep 9, 2023
5bb029f
chnage cloudName to name in _new.jelly
car-roll Sep 9, 2023
63c3633
change to invisible text box
car-roll Sep 11, 2023
bf62fc2
remove cloudName from Cloud formdata
car-roll Sep 11, 2023
1024b9e
add cloudName back to formData
car-roll Sep 12, 2023
4b89c49
cleanup
car-roll Sep 12, 2023
8c3d6c6
add name fields to config form data
car-roll Sep 12, 2023
231db94
remove cloudName from new cloud form data
car-roll Sep 13, 2023
13bab6c
save to disk when changing name
car-roll Sep 19, 2023
e933c51
Merge branch 'master' into redirect-cloud-name-change
car-roll Sep 20, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion core/src/main/java/hudson/model/AbstractItem.java
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@
// Item doesn't necessarily have to be Actionable, but
// Java doesn't let multiple inheritance.
@ExportedBean
public abstract class AbstractItem extends Actionable implements Item, HttpDeletable, AccessControlled, DescriptorByNameOwner, StaplerProxy {
public abstract class AbstractItem extends Actionable implements Item, HttpDeletable, AccessControlled, DescriptorByNameOwner, StaplerProxy, Renamable {

private static final Logger LOGGER = Logger.getLogger(AbstractItem.class.getName());

Expand Down Expand Up @@ -245,6 +245,7 @@ protected void doSetName(String name) {
* @see #renameTo
* @since 2.110
*/
@Override
public boolean isNameEditable() {
return false;
}
Expand All @@ -254,6 +255,7 @@ public boolean isNameEditable() {
*/
@RequirePOST
@Restricted(NoExternalUse.class)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note that these restrictions become easily bypassable via casting to Renamable with the new changes. Perhaps the new interface should be marked as @Restricted(ProtectedExternally.class)? Even then there would be some issues though, see jenkinsci/lib-access-modifier#22 and jenkinsci/lib-access-modifier#21.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

added @Restricted(ProtectedExternally.class) in b7eed6f

@Override
public HttpResponse doConfirmRename(@QueryParameter String newName) throws IOException {
newName = newName == null ? null : newName.trim();
FormValidation validationError = doCheckNewName(newName);
Expand All @@ -274,6 +276,7 @@ public HttpResponse doConfirmRename(@QueryParameter String newName) throws IOExc
* {@link FormValidation#error} with a message explaining the problem.
*/
@Restricted(NoExternalUse.class)
@Override
public @NonNull FormValidation doCheckNewName(@QueryParameter String newName) {

if (!isNameEditable()) {
Expand Down
57 changes: 57 additions & 0 deletions core/src/main/java/hudson/model/Renamable.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
/*
* The MIT License
*
* Copyright 2023 CloudBees, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/

package hudson.model;

import edu.umd.cs.findbugs.annotations.NonNull;
import hudson.util.FormValidation;
import org.kohsuke.stapler.HttpResponse;
import org.kohsuke.stapler.QueryParameter;

public interface Renamable {
dwnusbaum marked this conversation as resolved.
Show resolved Hide resolved
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Having a hard time understanding the relationship between this interface and Node/Slave. Should they implement this interface or not? If so, why don't they? If not, why does renaming work without issue there?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The idea was to make them implement this interface as well: #8310 (comment)

I had originally tried to do it the same way as Computer, but it always failed testing it in other plugins such as ec2 and azure-vm-agents.
Looking back now, I realize the problem was always the cloudName vs name issue that was finally identified and corrected. I have just pushed up a second, simpler, version of a fix for this bug. See #8505

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@timja reminded me that one of the big issues was that apply does not work correctly when changing names and other config parts: #8505 (review)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To fully answer the original comment, I guess it is more a matter of being consistent across our UIs? Changing the name of a Node isn't an issue because there is no Apply button. Should we implement this interface in Node, the apply button could be added back in.
Given how this PR affected a bunch of downstream PRs, it's probably best to implement this interface one component at a time.

Copy link
Member

@basil basil Sep 19, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

On the flip side, why not remove the Apply button from Cloud to make it consistent with Node? That's inconsistent with AbstractItem, but so is the status quo where Node is inconsistent with AbstractItem. And at least it fixes the bug.

A request to defer implementing this interface in Node is effectively a request to introduce debt. I would not automatically reject such a request, but I think it needs to be justified, and merely mentioning "how this PR affected a bunch of downstream PRs" does not seem like a valid justification to me. And I think the intention behind the request is to implement in stages (which is fine, if the rest of the stages are actually finished in a timely fashion, something which almost never happens in my experience whenever someone makes such a request), but an unintentional consequence is that the design of the interface might turn out worse.

When defining a new interface, it is important to consume it in at least three places before shipping it to ensure the design is correct. If you implement it only once, it probably won't support a second implementation. If you implement it only twice, it will probably support a third implementation with difficulty. If you implement it three or more times, the interface will probably work fine. Will Tracz calls this "The Rule of Threes" (Confessions of a Used Program Salesman, Addison-Wesley, 1995).

So my perspective is that the third implementation should be in scope for this PR not only in order to make the implementation complete but also to validate the design of the interface.


/**
* Controls whether the default rename action is available for this object.
*
* @return whether the name can be modified by a user
* @since TODO
*/
boolean isNameEditable();

/**
* Renames the object
*
* @since TODO
*/
HttpResponse doConfirmRename(@QueryParameter String newName) throws Exception;

/**
* Controls whether the default rename action is available.
*
* @return whether object name can be modified by a user
* @since TODO
*/
@NonNull
FormValidation doCheckNewName(@QueryParameter String newName);
}
77 changes: 71 additions & 6 deletions core/src/main/java/hudson/slaves/Cloud.java
Original file line number Diff line number Diff line change
Expand Up @@ -30,15 +30,18 @@
import hudson.DescriptorExtensionList;
import hudson.Extension;
import hudson.ExtensionPoint;
import hudson.Functions;
import hudson.Util;
import hudson.init.InitMilestone;
import hudson.init.Initializer;
import hudson.model.Actionable;
import hudson.model.Computer;
import hudson.model.Describable;
import hudson.model.Descriptor;
import hudson.model.Failure;
import hudson.model.Label;
import hudson.model.Node;
import hudson.model.Renamable;
import hudson.model.Slave;
import hudson.security.ACL;
import hudson.security.AccessControlled;
Expand All @@ -47,6 +50,7 @@
import hudson.slaves.NodeProvisioner.PlannedNode;
import hudson.util.DescriptorList;
import hudson.util.FormApply;
import hudson.util.FormValidation;
import java.io.IOException;
import java.util.Collection;
import java.util.Objects;
Expand All @@ -57,9 +61,12 @@
import org.apache.commons.lang.Validate;
import org.kohsuke.accmod.Restricted;
import org.kohsuke.accmod.restrictions.DoNotUse;
import org.kohsuke.accmod.restrictions.NoExternalUse;
import org.kohsuke.stapler.DataBoundConstructor;
import org.kohsuke.stapler.HttpRedirect;
import org.kohsuke.stapler.HttpResponse;
import org.kohsuke.stapler.HttpResponses;
import org.kohsuke.stapler.QueryParameter;
import org.kohsuke.stapler.StaplerRequest;
import org.kohsuke.stapler.StaplerResponse;
import org.kohsuke.stapler.interceptor.RequirePOST;
Expand Down Expand Up @@ -107,7 +114,7 @@
* @see NodeProvisioner
* @see AbstractCloudImpl
*/
public abstract class Cloud extends Actionable implements ExtensionPoint, Describable<Cloud>, AccessControlled {
public abstract class Cloud extends Actionable implements ExtensionPoint, Describable<Cloud>, AccessControlled, Renamable {

/**
* Uniquely identifies this {@link Cloud} instance among other instances in {@link jenkins.model.Jenkins#clouds}.
Expand Down Expand Up @@ -310,8 +317,68 @@
return new HttpRedirect("..");
}


@Override
public boolean isNameEditable() {
return true;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I must be missing something, because I can't see how renaming is exposed in the GUI for, say, the Docker plugin. I have a Docker cloud created against a core before this PR and the current release of Docker plugin, and I have another Docker cloud created against a core after this PR and jenkinsci/docker-plugin#1016. I can visit confirm-rename manually and rename the cloud there, but I can't get the link to show up anywhere in the GUI for either of my two clouds. Please forgive me if I am doing something wrong on my side.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The rename page gets exposed via TransientActionFactoryImpl, which is hidden in RenameAction. I had to get pointed in the right direction as well when I was first looking into this.
I was able to create an old docker cloud and then when I changed to jenkinsci/docker-plugin#1016, was able to see the old docker cloud name and then rename it though. But to be fair, I didn't really have any parameters filled in my cloud.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I still couldn't find where RenameAction is visible in the UI on Cloud with these changes even after looking on several pages. I must be missing something.

}

@RequirePOST
@Restricted(NoExternalUse.class)
@Override
public HttpResponse doConfirmRename(@QueryParameter String newName) throws IOException, ServletException, Descriptor.FormException {
newName = newName == null ? null : newName.trim();

Check warning on line 330 in core/src/main/java/hudson/slaves/Cloud.java

View check run for this annotation

ci.jenkins.io / Code Coverage

Partially covered line

Line 330 is only partially covered, one branch is missing
FormValidation validationError = doCheckNewName(newName);
if (validationError.kind != FormValidation.Kind.OK) {

Check warning on line 332 in core/src/main/java/hudson/slaves/Cloud.java

View check run for this annotation

ci.jenkins.io / Code Coverage

Partially covered line

Line 332 is only partially covered, one branch is missing
throw new Failure(validationError.getMessage());

Check warning on line 333 in core/src/main/java/hudson/slaves/Cloud.java

View check run for this annotation

ci.jenkins.io / Code Coverage

Not covered line

Line 333 is not covered by tests
}
this.name = newName;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't we be doing something to persist this change to disk, the same way it would be persisted immediately if we changed it via the configure page?


// take the user to the renamed cloud top page.
return HttpResponses.redirectTo("../" + Functions.encode(newName));
}

@NonNull
@Restricted(NoExternalUse.class)
@Override
public FormValidation doCheckNewName(String newName) {
if (!isNameEditable()) {

Check warning on line 345 in core/src/main/java/hudson/slaves/Cloud.java

View check run for this annotation

ci.jenkins.io / Code Coverage

Partially covered line

Line 345 is only partially covered, one branch is missing
return FormValidation.error("Trying to rename an item that does not support this operation.");

Check warning on line 346 in core/src/main/java/hudson/slaves/Cloud.java

View check run for this annotation

ci.jenkins.io / Code Coverage

Not covered line

Line 346 is not covered by tests
}
checkPermission(Jenkins.ADMINISTER);

newName = newName == null ? null : newName.trim();

Check warning on line 350 in core/src/main/java/hudson/slaves/Cloud.java

View check run for this annotation

ci.jenkins.io / Code Coverage

Partially covered line

Line 350 is only partially covered, one branch is missing

try {
Jenkins.checkGoodName(newName);
assert newName != null; // Would have thrown Failure

Check warning on line 354 in core/src/main/java/hudson/slaves/Cloud.java

View check run for this annotation

ci.jenkins.io / Code Coverage

Partially covered line

Line 354 is only partially covered, one branch is missing
if (newName.equals(name)) {
return FormValidation.warning(hudson.model.Messages.AbstractItem_NewNameUnchanged());
}
if (Jenkins.get().getCloud(newName) != null) {

Check warning on line 358 in core/src/main/java/hudson/slaves/Cloud.java

View check run for this annotation

ci.jenkins.io / Code Coverage

Partially covered line

Line 358 is only partially covered, one branch is missing
return FormValidation.warning(jenkins.agents.Messages.CloudSet_CloudAlreadyExists(newName));

Check warning on line 359 in core/src/main/java/hudson/slaves/Cloud.java

View check run for this annotation

ci.jenkins.io / Code Coverage

Not covered line

Line 359 is not covered by tests
}
checkRename(newName);
} catch (Failure e) {

Check warning on line 362 in core/src/main/java/hudson/slaves/Cloud.java

View check run for this annotation

ci.jenkins.io / Code Coverage

Not covered line

Line 362 is not covered by tests
return FormValidation.error(e.getMessage());

Check warning on line 363 in core/src/main/java/hudson/slaves/Cloud.java

View check run for this annotation

ci.jenkins.io / Code Coverage

Not covered line

Line 363 is not covered by tests
}
return FormValidation.ok();
}

/**
* Allows subclasses to block renames for domain-specific reasons. Generic validation of the new name
* (e.g., null checking, checking for illegal characters, and checking that the name is not in use)
* always happens prior to calling this method.
*
* @param newName the new name for the item
* @throws Failure if the rename should be blocked
*/
protected void checkRename(@NonNull String newName) throws Failure {

}

/**
* Accepts the update to the node configuration.
* Accepts the update to the node configuration. To change node name see {@link #doConfirmRename(String)}.
*/
@POST
public HttpResponse doConfigSubmit(StaplerRequest req, StaplerResponse rsp) throws IOException, ServletException, Descriptor.FormException {
Expand All @@ -323,10 +390,8 @@
throw new ServletException("No such cloud " + this.name);
}
Cloud result = cloud.reconfigure(req, req.getSubmittedForm());
String proposedName = result.name;
timja marked this conversation as resolved.
Show resolved Hide resolved
if (!proposedName.equals(this.name)
&& j.getCloud(proposedName) != null) {
throw new Descriptor.FormException(jenkins.agents.Messages.CloudSet_CloudAlreadyExists(proposedName), "name");
if (!(result.name).equals(this.name)) {

Check warning on line 393 in core/src/main/java/hudson/slaves/Cloud.java

View check run for this annotation

ci.jenkins.io / Code Coverage

Partially covered line

Line 393 is only partially covered, one branch is missing
throw new Descriptor.FormException(jenkins.agents.Messages.Cloud_DoNotRename(), "name");
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Another option was to just ignore any name changes, i.e. result.name = this.name

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will this case get triggered by some existing cloud plugins until they override isNameEditable and update their form configurations to remove the related field?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess that is the case described in #8310 (comment). Any idea how widespread that kind of problem will be? Should we prepare downstream PRs?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, this exception will be thrown by existing cloud nodes from plugins that do not have the form updated. I'll take a look to see what plugins are affected.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

On an initial search of "extends Cloud " and "exnteds AbstractCloudImpl" , I see around 50+ plugins that need to be checked.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ideally, I'd like to just throw a warning dialogue box and block the save/apply action until then name change is reverted in the form. I'm just not sure how to do that.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, yeah I'm not sure how to pop a warning dialog here without having to update config.jelly in all the plugins.

For now I would be tempted to just ignore name changes in this context. It would be pretty frustrating to reconfigure various things and attempt to rename an object at the same time, hit save, get an exception, and then have to reconfigure things again. IDK though how common it is to rename and reconfigure things at the same time. If people normally do them separately then the current behavior at least gives you clear feedback on why the rename did not happen vs just silently ignoring the rename.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(or file PRs into the major cloud plugins)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I tried without any success to get the submit button to be blocked if the name is changed. Looks like I would have to use the button tag instead, but I think I was getting too lost in the weeds.

I think I'll go ahead and just block the name change without the exception. I don't think name changes happen that much as this bug has only been discovered now. I think the fact that the rename page exists should be enough of a clue. I'll also go ahead and try and file some downstream PRs based off of this incremental.

}
j.clouds.replace(this, result);
j.save();
Expand Down
10 changes: 5 additions & 5 deletions core/src/main/java/jenkins/model/RenameAction.java
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,8 @@
package jenkins.model;

import hudson.Extension;
import hudson.model.AbstractItem;
import hudson.model.Action;
import hudson.model.Renamable;
import java.util.Collection;
import java.util.Collections;
import java.util.Set;
Expand All @@ -52,15 +52,15 @@ public String getUrlName() {
}

@Extension
public static class TransientActionFactoryImpl extends TransientActionFactory<AbstractItem> {
public static class TransientActionFactoryImpl extends TransientActionFactory<Renamable> {

@Override
public Class<AbstractItem> type() {
return AbstractItem.class;
public Class<Renamable> type() {
return Renamable.class;
}

@Override
public Collection<? extends Action> createFor(AbstractItem target) {
public Collection<? extends Action> createFor(Renamable target) {
if (target.isNameEditable()) {
return Set.of(new RenameAction());
} else {
Expand Down
43 changes: 43 additions & 0 deletions core/src/main/resources/hudson/slaves/Cloud/confirm-rename.jelly
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
<!--
The MIT License

Copyright 2018 CloudBees, Inc.

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
-->

<?jelly escape-by-default='true'?>
<j:jelly xmlns:j="jelly:core" xmlns:st="jelly:stapler" xmlns:d="jelly:define" xmlns:l="/lib/layout" xmlns:t="/lib/hudson" xmlns:f="/lib/form" xmlns:i="jelly:fmt">
<l:layout title="${%Rename}">
<st:include page="sidepanel.jelly" />
<l:breadcrumb title="${%Rename}" />
<l:main-panel>
<h1>${%DescribeRename(it.name)}</h1>
<f:form method="post" action="confirmRename" name="config" tableClass="config-table scrollspy">
<f:entry title="${%NewName}">
<f:textbox name="newName" value="${it.name}" autocomplete="on" checkUrl="checkNewName" checkDependsOn="newName"/>
</f:entry>
<f:bottomButtonBar>
<f:submit value="${%Rename}" />
</f:bottomButtonBar>
</f:form>
<st:adjunct includes="lib.form.confirm" />
</l:main-panel>
</l:layout>
</j:jelly>
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# The MIT License
#
# Copyright (c) 2018 CloudBees, Inc.
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.

DescribeRename=Rename {0}
NewName=New Name
Rename=Rename
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
DescribeRename={0} umbenennen
NewName=Neuer Name
Rename=Umbenennen
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Rename=Renommer
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# The MIT License
#
# Italian localization plugin for Jenkins
# Copyright © 2020 Alessandro Menti
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.

DescribeRename=Rinomina {0}
NewName=Nuovo nome
Rename=Rinomina
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# The MIT License
#
# Copyright (c) 2021 Takashi Harano
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.

DescribeRename=名前の変更 {0}
NewName=新しい名前
Rename=名前の変更
Loading
Loading