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-39300] View.getDisplayName() is ignored when rendering tabs #2603

Merged
merged 15 commits into from
Dec 12, 2016

Conversation

stephenc
Copy link
Member

See JENKINS-39300

Also:

  • adds support for descriptor visibility filtering on views
  • fixes l10n of AllView
  • adds support for contextual create permission of specific view types
  • some other small code fixes spotted while touching the files

@jenkinsci/code-reviewers @reviewbybees

* Returns the {@link ViewDescriptor} instances that can be instantiated for the {@link ViewGroup} in the current
* {@link StaplerRequest}. <strong>NOTE: This method must be called from a {@link StaplerRequest}</strong>
* @return the list of instantiable {@link ViewDescriptor} instances for the current {@link StaplerRequest}
*/
Copy link
Member Author

Choose a reason for hiding this comment

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

Note: this is the javadoc that applied to the method before my changes as the method would have blown up with a NPE if invoked outside of the newView.jelly screen of a ViewGroup as soon as AllView.isInstantiable() was called

Copy link
Member

Choose a reason for hiding this comment

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

Perhaps just check owner == null and return all()?

Copy link
Member

Choose a reason for hiding this comment

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

Need to also check whether the StaplerRequest is null.

- Also while we are at it, modernise ViewDescriptor instantiation to allow for descriptor visibility filtering
@ghost
Copy link

ghost commented Oct 27, 2016

This pull request originates from a CloudBees employee. At CloudBees, we require that all pull requests be reviewed by other CloudBees employees before we seek to have the change accepted. If you want to learn more about our process please see this explanation.

@@ -3052,7 +3052,7 @@ public void run(Reactor session) throws Exception {
// initialize views by inserting the default view if necessary
// this is both for clean Jenkins and for backward compatibility.
if(views.size()==0 || primaryView==null) {
View v = new AllView(Messages.Hudson_ViewName());
View v = new AllView("all");
Copy link
Member

Choose a reason for hiding this comment

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

This looks like it fixes JENKINS-38606.

Copy link
Member

Choose a reason for hiding this comment

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

It is. But will it cause a fallout in upgrading Jenkins instances?

Copy link
Member Author

Choose a reason for hiding this comment

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

Will only affect new instances. Old instances can get the fix by recreating the All view (add new view, change default, delete all view, add back all view, change default, tidy up)

Copy link
Member Author

Choose a reason for hiding this comment

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

We could be more aggressive and rename the AllView to all but it is valid to give it whatever name you want... though perhaps we need some further tweaks

Copy link
Member

Choose a reason for hiding this comment

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

This looks like a reasonable default for new All views. No need to edit existing ones. Would just cause confusion and broken links.

Whether the tab is active or not
</st:attribute>
<st:attribute name="title">
The title of the tab
Copy link
Member

Choose a reason for hiding this comment

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

Do we have an @since equivalent for Jelly tags?

Copy link
Member Author

@stephenc stephenc Oct 28, 2016

Choose a reason for hiding this comment

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

I am restoring behaviour that was broken in this earlier commit (appears to be removed by omission as the old style documentation of parameters was retained)

Copy link
Member Author

Choose a reason for hiding this comment

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

jenkinsci/stapler#84 created for you ;-)

…ly if safe to fix

- Don't fix if there is already a view with the new default name
- Don't fix if the AllView is not the primary view
@stephenc
Copy link
Member Author

@daniel-beck @oleg-nenashev so I have added a fix for JENKINS-38606... and we need to be able to invoke that fix from plugins (e.g. folders plugin) so I cannot make that @Restricted before you ask!

@daniel-beck
Copy link
Member

have added a fix for JENKINS-38606

Not actually safe, as there are code paths that add the view name to the URL even if it's the default view.

I don't think we should fix JENKINS-38606 for existing installations. It modifies user data for a pretty weak reason.

@stephenc
Copy link
Member Author

@daniel-beck OK, I have made this opt-in. I still think we should have the ability for an admin to force the fix applied everywhere as it could be quite difficult to fix all the AllViews scattered everywhere otherwise

@daniel-beck
Copy link
Member

Is this really not trivial to take care of in a script console script with maybe five lines?

Do we really need a startup parameter (to be added in service configurations) for a one-time cleanup action here?

@stephenc
Copy link
Member Author

@daniel-beck really? show me the five lines that find every ViewGroup (including the User properties for all users) and the folders etc and does the fix-up? For most admins it should not be an issue... but if it is an issue it could be very painful to fix by script or manually. Much better to provide a hook to fix the issue that is available to everyone IMHO.

@oleg-nenashev oleg-nenashev added the needs-more-reviews Complex change, which would benefit from more eyes label Oct 29, 2016
@stephenc
Copy link
Member Author

@daniel-beck can you respond please? Would like to get the change at least merged before we hit one of the last likely candidates for the next LTS

@daniel-beck
Copy link
Member

I still have my doubt but I'd be happy to be outvoted. So far, nobody else has cared enough though @jenkinsci/code-reviewers Ping!). FWIW I would like to see other opinions on solving this using a new parameter.

@rsandell
Copy link
Member

rsandell commented Nov 1, 2016

🐝

Copy link
Member

@jglick jglick left a comment

Choose a reason for hiding this comment

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

Some minor inline comments, and tests are failing; 👍 on concept.

* @since FIXME
*/
@Nonnull
public static String applyJenkins38606Fixup(@Nonnull List<View> views, @Nonnull String primaryView) {
Copy link
Member

Choose a reason for hiding this comment

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

@Restricted(NoExternalUse.class)

(and remove @since) unless this is something you really expect plugins to use.

Copy link
Member Author

Choose a reason for hiding this comment

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

I expect plugins that implement ViewGroup will need to call into this method

Copy link
Member

Choose a reason for hiding this comment

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

Is there a proposed PR calling it? From cloudbees-folder? Then you should probably have a clearer name.

* fixing the view name by setting the system property {@code hudson.mode.AllView.JENKINS-38606} to {@code true}.
* Use this method to round-trip the primary view name, e.g.
* {@code primaryView = applyJenkins38606Fixup(views, primaryView)}
* NOTE: we can only fix the localized name of an {@link AllView} if it is the primary view as otherwise urls
Copy link
Member

Choose a reason for hiding this comment

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

<p>

* {@code primaryView = applyJenkins38606Fixup(views, primaryView)}
* NOTE: we can only fix the localized name of an {@link AllView} if it is the primary view as otherwise urls
* would change, whereas the primary view is special and does not normally get accessed by the
* {@code /view/_name_} url.
Copy link
Member

Choose a reason for hiding this comment

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

…though it can be, and those URLs will break. Right?

Copy link
Member

Choose a reason for hiding this comment

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

Yes, and there are links in Jenkins to the default view's /view/whatever URL.

Copy link
Member

Choose a reason for hiding this comment

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

Yes, actually the new item link has switched from /view/All/newJob to /view/all/newJob (note the lowercase in the default view name).

// modern name, we are safe
return primaryView;
}
if (SystemProperties.getBoolean(AllView.class.getName()+".JENKINS-38606", false)) {
Copy link
Member

Choose a reason for hiding this comment

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

getBoolean(String) suffices.

// name conflict, we cannot rename the all view anyway
return primaryView;
}
if (StringUtils.equals(v.getViewName(), primaryView)) {
Copy link
Member

Choose a reason for hiding this comment

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

AFAICT getViewName() should be marked @Nonnull.

Copy link
Member Author

Choose a reason for hiding this comment

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

Done

Copy link
Member

Choose a reason for hiding this comment

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

meaning you could use

if (v.getViewName().equals(primaryView)) {

* @return the validation result.
* @since FIXME
*/
@SuppressWarnings("unused") // expose utility check method to subclasses
Copy link
Member

Choose a reason for hiding this comment

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

Is there a particular subclass you had in mind? Not in this PR; some other linked one?

Copy link
Member Author

Choose a reason for hiding this comment

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

Yes but it needs to use the Referer header hack to resolve the View so probably waiting on dedicated support in stapler for that

Copy link
Member

Choose a reason for hiding this comment

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

So where is that subclass?

/**
* Returns true if this {@link View} type is applicable in the specific {@link ViewGroup}.
*
* @return true to indicate applicable, in which case the view will be instantiable within the given owner.
Copy link
Member

Choose a reason for hiding this comment

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

Specify default implementation.

/**
* Returns true if this {@link View} type is applicable to the given {@link ViewGroup} type.
*
* @return true to indicate applicable, in which case the view will be instantiable within the type of owner.
Copy link
Member

Choose a reason for hiding this comment

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

Specify default implementation.

@@ -32,7 +32,7 @@ THE SOFTWARE.
<st:include page="sidepanel.jelly" it="${it.user}"/>

<l:main-panel>
<j:invokeStatic var="views" className="hudson.model.View" method="allInstantiable" />
<j:invokeStatic var="views" className="hudson.model.View" method="allInstantiable"/>
Copy link
Member

Choose a reason for hiding this comment

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

Gratuitous diff hunk.

@@ -31,7 +31,7 @@ THE SOFTWARE.
<st:include page="sidepanel.jelly" />

<l:main-panel>
<j:invokeStatic var="views" className="hudson.model.View" method="allInstantiable" />
<j:invokeStatic var="views" className="hudson.model.View" method="allInstantiable"/>
Copy link
Member

Choose a reason for hiding this comment

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

ditto

Copy link
Member Author

@stephenc stephenc left a comment

Choose a reason for hiding this comment

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

@jglick I think i have addressed all your comments (in some way or other)

// name conflict, we cannot rename the all view anyway
return primaryView;
}
if (StringUtils.equals(v.getViewName(), primaryView)) {
Copy link
Member Author

Choose a reason for hiding this comment

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

Done

* @return the validation result.
* @since FIXME
*/
@SuppressWarnings("unused") // expose utility check method to subclasses
Copy link
Member Author

Choose a reason for hiding this comment

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

Yes but it needs to use the Referer header hack to resolve the View so probably waiting on dedicated support in stapler for that

Copy link
Member

@jglick jglick left a comment

Choose a reason for hiding this comment

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

Would like to discuss having better URL compatibility, and would like to see the downstream PR that various API methods here imply.

* @since FIXME
*/
@Nonnull
public static String applyJenkins38606Fixup(@Nonnull List<View> views, @Nonnull String primaryView) {
Copy link
Member

Choose a reason for hiding this comment

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

Is there a proposed PR calling it? From cloudbees-folder? Then you should probably have a clearer name.

// name conflict, we cannot rename the all view anyway
return primaryView;
}
if (StringUtils.equals(v.getViewName(), primaryView)) {
Copy link
Member

Choose a reason for hiding this comment

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

meaning you could use

if (v.getViewName().equals(primaryView)) {

* @return the validation result.
* @since FIXME
*/
@SuppressWarnings("unused") // expose utility check method to subclasses
Copy link
Member

Choose a reason for hiding this comment

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

So where is that subclass?

if (!lvc.shownByDefault()) continue; // skip this
if (!lvc.shownByDefault()) {
continue; // skip this
}
Copy link
Member

Choose a reason for hiding this comment

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

gratuitous reformatting

// modern name, we are safe
return primaryView;
}
if (SystemProperties.getBoolean(AllView.class.getName()+".JENKINS-38606")) {
Copy link
Member

Choose a reason for hiding this comment

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

Making this disabled by default makes it less than useful.

IIUC the concern is about compatibility for direct links to, say, http://jenkins/view/All/job/something/. But that is easily solved: amend ViewGroupMixIn.getView (called from Jenkins.getView(String), the Stapler URL binding) to fall back to searching by View.getDisplayName if no match is found via getViewName.

Copy link
Member Author

Choose a reason for hiding this comment

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

Actually no, so the concern here is that you had been using say the DE locale when you created the folder... thus you would have http://jenkins/jobs/MyFolder/view/Alle/job/something, the less likely concern is if you had started Jenkins in the IT locale (before changing it to something else) and you had http://jenkins/view/Tutto/job/something

Now what will happen with the fix-up is that it will spot these mistakes and say "Oh, those are localized names, that should really be all"

Now when a user with the LT locale configured for their browser clicks on either of those two links:

  • http://jenkins/jobs/MyFolder/view/Alle/job/something, well the primary AllView's displayName in LT is Visi so falling back to View.getDisplayName() will still not match
  • http://jenkins/view/Tutto/job/something again has the same issue.

But thanks to pointing out ViewGroupMixIn.getView what happens if we do not find a matching view name?

if (name != null && !name.equals(primaryView())) {
// Fallback to subview of primary view if it is a ViewGroup
View pv = getPrimaryView();
if (pv instanceof ViewGroup)
return ((ViewGroup)pv).getView(name);
}

So what will happen is, the name is not null and the name is not all and there was no other view with the name Visi... so we will display the primary view.

So actually I think we can default this to ON and stop worrying

Copy link
Member Author

Choose a reason for hiding this comment

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

Damn I read that wrong... but I think it does give us a solution instead

…r migration

- This means we can default the migration to enabled
@stephenc
Copy link
Member Author

stephenc commented Dec 7, 2016

See jenkinsci/cloudbees-folder-plugin#79 for example usage of migrateLegacyPrimaryAllViewLocalizedName method

@stephenc
Copy link
Member Author

stephenc commented Dec 7, 2016

@rsandell @daniel-beck @jglick PR has been updated

Copy link
Member

@jglick jglick left a comment

Choose a reason for hiding this comment

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

Sounds good to the extent I understand it.

@@ -99,6 +101,15 @@ public View getView(String name) {
View pv = getPrimaryView();
if (pv instanceof ViewGroup)
return ((ViewGroup)pv).getView(name);
if (pv instanceof AllView && AllView.DEFAULT_VIEW_NAME.equals(pv.name)) {
Copy link
Member

Choose a reason for hiding this comment

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

Sounds right but hard for me at least to follow how this will work in progress; recommend having some code coverage using @LocalData to prove it works.

* @param c the container of the item.
* @param d the descriptor of the view to be created.
* @throws AccessDeniedException if the user doesn't have the permission.
* @since 1.607
Copy link
Member

Choose a reason for hiding this comment

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

FIXME

Copy link
Member

@jglick jglick left a comment

Choose a reason for hiding this comment

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

Ah but lots of test failures.

@daniel-beck
Copy link
Member

One test still fails:

Expected: a string containing "ERROR: Jenkins does not allow to delete 'All' view"
     but: was "
ERROR: Jenkins does not allow to delete 'all' view
"

if (pv instanceof AllView && AllView.DEFAULT_VIEW_NAME.equals(pv.name)) {
// JENKINS-38606: primary view is the default AllView, is somebody using an old link to localized form?
for (Locale l : Locale.getAvailableLocales()) {
if (name.equals(Messages._Hudson_ViewName().toString(l))) {
Copy link
Member

@daniel-beck daniel-beck Dec 10, 2016

Choose a reason for hiding this comment

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

So changing the translations will break this compatibility measure for that language? Is this so rare to be irrelevant?

Copy link
Member Author

Choose a reason for hiding this comment

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

yes

@stephenc
Copy link
Member Author

I think we're good to merge now... i'll hold off until tomorrow and then merge just in case anyone has and issues with the test changes

// bingo JENKINS-38606 detected
LOGGER.log(Level.INFO,
"JENKINS-38606 detected for AllView in {0}; renaming view from {1} to {2}",
new Object[]{allView.owner.getUrl(), DEFAULT_VIEW_NAME});
Copy link
Member

Choose a reason for hiding this comment

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
needs-more-reviews Complex change, which would benefit from more eyes
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants