Fix issue #513 - Show incompatibilies to admin after update

This commit is contained in:
Robin Shen 2022-01-05 13:18:39 +08:00
parent ac86cf97a6
commit 9816fcc1f7
8 changed files with 168 additions and 21 deletions

View File

@ -50,6 +50,10 @@ public class Upgrade extends DefaultPersistManager {
private static final Pattern PRODUCT_FILE_NAME_PATTERN = Pattern.compile("io\\.onedev\\.server-product-(.*?)\\.jar"); private static final Pattern PRODUCT_FILE_NAME_PATTERN = Pattern.compile("io\\.onedev\\.server-product-(.*?)\\.jar");
public static final String FILE_INCOMPATIBILITIES = "incompatibilities.md";
public static final String FILE_INCOMPATIBILITIES_SINCE_UPGRADED_VERSION = "incompatibilities-since-upgraded-version.md";
@Inject @Inject
public Upgrade(PhysicalNamingStrategy physicalNamingStrategy, public Upgrade(PhysicalNamingStrategy physicalNamingStrategy,
HibernateProperties properties, Interceptor interceptor, HibernateProperties properties, Interceptor interceptor,
@ -585,6 +589,24 @@ public class Upgrade extends DefaultPersistManager {
FileUtils.copyFile(new File(Bootstrap.installDir, "license.txt"), new File(upgradeDir, "license.txt")); FileUtils.copyFile(new File(Bootstrap.installDir, "license.txt"), new File(upgradeDir, "license.txt"));
FileUtils.copyFile(new File(Bootstrap.installDir, "version.txt"), new File(upgradeDir, "version.txt")); FileUtils.copyFile(new File(Bootstrap.installDir, "version.txt"), new File(upgradeDir, "version.txt"));
FileUtils.copyFile(new File(Bootstrap.installDir, "build.txt"), new File(upgradeDir, "build.txt")); FileUtils.copyFile(new File(Bootstrap.installDir, "build.txt"), new File(upgradeDir, "build.txt"));
String incompatibilities = FileUtils.readFileToString(
new File(Bootstrap.installDir, FILE_INCOMPATIBILITIES), StandardCharsets.UTF_8);
if (new File(upgradeDir, FILE_INCOMPATIBILITIES).exists()) {
String incompatibilitiesOfUpgradedVersion = FileUtils.readFileToString(
new File(upgradeDir, FILE_INCOMPATIBILITIES), StandardCharsets.UTF_8);
if (incompatibilities.startsWith(incompatibilitiesOfUpgradedVersion)) {
String incompatibilitiesSinceUpgradedVersion =
incompatibilities.substring(incompatibilitiesOfUpgradedVersion.length());
if (StringUtils.isNotBlank(incompatibilitiesSinceUpgradedVersion)) {
FileUtils.writeFile(
new File(upgradeDir, FILE_INCOMPATIBILITIES_SINCE_UPGRADED_VERSION),
incompatibilitiesSinceUpgradedVersion);
}
}
}
FileUtils.copyFile(new File(Bootstrap.installDir, FILE_INCOMPATIBILITIES),
new File(upgradeDir, FILE_INCOMPATIBILITIES));
} catch (IOException e) { } catch (IOException e) {
throw new RuntimeException(e); throw new RuntimeException(e);
} }

View File

@ -56,6 +56,7 @@ import io.onedev.server.web.page.admin.user.password.UserPasswordPage;
import io.onedev.server.web.page.admin.user.profile.UserProfilePage; import io.onedev.server.web.page.admin.user.profile.UserProfilePage;
import io.onedev.server.web.page.admin.user.ssh.UserSshKeysPage; import io.onedev.server.web.page.admin.user.ssh.UserSshKeysPage;
import io.onedev.server.web.page.builds.BuildListPage; import io.onedev.server.web.page.builds.BuildListPage;
import io.onedev.server.web.page.help.IncompatibilitiesPage;
import io.onedev.server.web.page.help.MethodDetailPage; import io.onedev.server.web.page.help.MethodDetailPage;
import io.onedev.server.web.page.help.ResourceDetailPage; import io.onedev.server.web.page.help.ResourceDetailPage;
import io.onedev.server.web.page.help.ResourceListPage; import io.onedev.server.web.page.help.ResourceListPage;
@ -161,6 +162,7 @@ public class OneUrlMapper extends CompoundRequestMapper {
} }
private void addHelpPages() { private void addHelpPages() {
add(new DynamicPathPageMapper("help/incompatibilities", IncompatibilitiesPage.class));
add(new DynamicPathPageMapper("help/api", ResourceListPage.class)); add(new DynamicPathPageMapper("help/api", ResourceListPage.class));
add(new DynamicPathPageMapper("help/api/${resource}", ResourceDetailPage.class)); add(new DynamicPathPageMapper("help/api/${resource}", ResourceDetailPage.class));
add(new DynamicPathPageMapper("help/api/${resource}/${method}", MethodDetailPage.class)); add(new DynamicPathPageMapper("help/api/${resource}/${method}", MethodDetailPage.class));

View File

@ -2,6 +2,7 @@ package io.onedev.server.web.page.base;
import static org.apache.wicket.ajax.attributes.CallbackParameter.explicit; import static org.apache.wicket.ajax.attributes.CallbackParameter.explicit;
import java.io.File;
import java.io.Serializable; import java.io.Serializable;
import java.util.Collection; import java.util.Collection;
import java.util.HashSet; import java.util.HashSet;
@ -45,8 +46,10 @@ import org.unbescape.javascript.JavaScriptEscape;
import com.google.common.base.Splitter; import com.google.common.base.Splitter;
import io.onedev.commons.bootstrap.Bootstrap;
import io.onedev.commons.loader.AppLoader; import io.onedev.commons.loader.AppLoader;
import io.onedev.server.OneDev; import io.onedev.server.OneDev;
import io.onedev.server.maintenance.Upgrade;
import io.onedev.server.model.User; import io.onedev.server.model.User;
import io.onedev.server.security.SecurityUtils; import io.onedev.server.security.SecurityUtils;
import io.onedev.server.util.CryptoUtils; import io.onedev.server.util.CryptoUtils;
@ -56,6 +59,7 @@ import io.onedev.server.web.behavior.ForceOrdinaryStyleBehavior;
import io.onedev.server.web.behavior.WebSocketObserver; import io.onedev.server.web.behavior.WebSocketObserver;
import io.onedev.server.web.component.svg.SpriteImage; import io.onedev.server.web.component.svg.SpriteImage;
import io.onedev.server.web.editable.BeanEditor; import io.onedev.server.web.editable.BeanEditor;
import io.onedev.server.web.page.help.IncompatibilitiesPage;
import io.onedev.server.web.page.simple.SimplePage; import io.onedev.server.web.page.simple.SimplePage;
import io.onedev.server.web.page.simple.security.LoginPage; import io.onedev.server.web.page.simple.security.LoginPage;
import io.onedev.server.web.page.simple.serverinit.ServerInitPage; import io.onedev.server.web.page.simple.serverinit.ServerInitPage;
@ -80,6 +84,12 @@ public abstract class BasePage extends WebPage {
if (!isPermitted()) if (!isPermitted())
unauthorized(); unauthorized();
if (SecurityUtils.isAdministrator()
&& !(getPage() instanceof IncompatibilitiesPage)
&& new File(Bootstrap.installDir, Upgrade.FILE_INCOMPATIBILITIES_SINCE_UPGRADED_VERSION).exists()) {
throw new RestartResponseAtInterceptPageException(IncompatibilitiesPage.class);
}
AbstractPostAjaxBehavior popStateBehavior; AbstractPostAjaxBehavior popStateBehavior;
add(popStateBehavior = new AbstractPostAjaxBehavior() { add(popStateBehavior = new AbstractPostAjaxBehavior() {

View File

@ -0,0 +1,18 @@
<wicket:extend>
<div class="m-2 m-sm-5 card">
<div class="card-body">
<div wicket:id="warning" class="alert alert-warning mb-5">
There are incompatibilities since your upgraded version.
</div>
<div wicket:id="incompatibilities"></div>
<wicket:enclosure>
<div class="text-center mt-5">
<a wicket:id="back" class="btn btn-primary">Go Back</a>
<p class="text-muted mt-4">
you may show this page later via incompatibilities link in help menu
</p>
</div>
</wicket:enclosure>
</div>
</div>
</wicket:extend>

View File

@ -0,0 +1,112 @@
package io.onedev.server.web.page.help;
import java.io.File;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import org.apache.wicket.Component;
import org.apache.wicket.RestartResponseAtInterceptPageException;
import org.apache.wicket.markup.html.WebMarkupContainer;
import org.apache.wicket.markup.html.basic.Label;
import org.apache.wicket.markup.html.link.Link;
import org.apache.wicket.model.IModel;
import org.apache.wicket.model.LoadableDetachableModel;
import org.apache.wicket.request.mapper.parameter.PageParameters;
import io.onedev.commons.bootstrap.Bootstrap;
import io.onedev.commons.utils.FileUtils;
import io.onedev.server.maintenance.Upgrade;
import io.onedev.server.web.component.markdown.MarkdownViewer;
import io.onedev.server.web.page.layout.LayoutPage;
@SuppressWarnings("serial")
public class IncompatibilitiesPage extends LayoutPage {
private final IModel<String> incompatibilitiesSinceUpgradedVersionModel = new LoadableDetachableModel<String>() {
@Override
protected String load() {
File incompatibilitiesSinceUpgradedVersionFile =
new File(Bootstrap.installDir, Upgrade.FILE_INCOMPATIBILITIES_SINCE_UPGRADED_VERSION);
if (incompatibilitiesSinceUpgradedVersionFile.exists()) {
try {
String incompatibilitiesSinceUpgradedVersion = FileUtils.readFileToString(
incompatibilitiesSinceUpgradedVersionFile, StandardCharsets.UTF_8);
FileUtils.deleteFile(incompatibilitiesSinceUpgradedVersionFile);
return incompatibilitiesSinceUpgradedVersion;
} catch (IOException e) {
throw new RuntimeException(e);
}
} else {
return null;
}
}
};
public IncompatibilitiesPage(PageParameters params) {
super(params);
}
@Override
protected void onDetach() {
incompatibilitiesSinceUpgradedVersionModel.detach();
super.onDetach();
}
@Override
protected void onInitialize() {
super.onInitialize();
add(new WebMarkupContainer("warning") {
@Override
protected void onConfigure() {
super.onConfigure();
setVisible(incompatibilitiesSinceUpgradedVersionModel.getObject() != null);
}
});
add(new MarkdownViewer("incompatibilities", new LoadableDetachableModel<String>() {
@Override
protected String load() {
try {
if (incompatibilitiesSinceUpgradedVersionModel.getObject() != null) {
return incompatibilitiesSinceUpgradedVersionModel.getObject();
} else {
return FileUtils.readFileToString(
new File(Bootstrap.installDir, Upgrade.FILE_INCOMPATIBILITIES),
StandardCharsets.UTF_8);
}
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}, null));
add(new Link<Void>("back") {
@Override
public void onClick() {
continueToOriginalDestination();
}
@Override
protected void onConfigure() {
super.onConfigure();
setVisible(RestartResponseAtInterceptPageException.getOriginalUrl() != null);
}
});
}
@Override
protected Component newTopbarTitle(String componentId) {
return new Label(componentId, "Incompatibilities");
}
}

View File

@ -24,7 +24,7 @@
<a wicket:id="docLink" class="dropdown-item" target="_blank">Documentation</a> <a wicket:id="docLink" class="dropdown-item" target="_blank">Documentation</a>
<a href="https://code.onedev.io/projects/160/issues?query=%22State%22+is+%22Open%22" class="dropdown-item" target="_blank">Support &amp; Bug Report</a> <a href="https://code.onedev.io/projects/160/issues?query=%22State%22+is+%22Open%22" class="dropdown-item" target="_blank">Support &amp; Bug Report</a>
<a href="/help/api" class="dropdown-item" target="_blank">RESTful API</a> <a href="/help/api" class="dropdown-item" target="_blank">RESTful API</a>
<a wicket:id="incompatibilities" class="dropdown-item" target="_blank">Incompatibilities</a> <a wicket:id="incompatibilities" class="dropdown-item">Incompatibilities</a>
</div> </div>
</div> </div>
</div> </div>

View File

@ -1,15 +1,11 @@
package io.onedev.server.web.page.layout; package io.onedev.server.web.page.layout;
import java.io.File;
import java.io.IOException;
import java.io.Serializable; import java.io.Serializable;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import javax.servlet.http.Cookie; import javax.servlet.http.Cookie;
import org.apache.commons.io.FileUtils;
import org.apache.shiro.subject.PrincipalCollection; import org.apache.shiro.subject.PrincipalCollection;
import org.apache.wicket.Component; import org.apache.wicket.Component;
import org.apache.wicket.RestartResponseAtInterceptPageException; import org.apache.wicket.RestartResponseAtInterceptPageException;
@ -36,7 +32,6 @@ import org.apache.wicket.request.mapper.parameter.PageParameters;
import com.google.common.collect.Lists; import com.google.common.collect.Lists;
import io.onedev.commons.bootstrap.Bootstrap;
import io.onedev.commons.loader.AppLoader; import io.onedev.commons.loader.AppLoader;
import io.onedev.commons.loader.Plugin; import io.onedev.commons.loader.Plugin;
import io.onedev.server.OneDev; import io.onedev.server.OneDev;
@ -83,6 +78,7 @@ import io.onedev.server.web.page.admin.user.UserListPage;
import io.onedev.server.web.page.admin.user.UserPage; import io.onedev.server.web.page.admin.user.UserPage;
import io.onedev.server.web.page.admin.user.create.NewUserPage; import io.onedev.server.web.page.admin.user.create.NewUserPage;
import io.onedev.server.web.page.base.BasePage; import io.onedev.server.web.page.base.BasePage;
import io.onedev.server.web.page.help.IncompatibilitiesPage;
import io.onedev.server.web.page.my.MyPage; import io.onedev.server.web.page.my.MyPage;
import io.onedev.server.web.page.my.accesstoken.MyAccessTokenPage; import io.onedev.server.web.page.my.accesstoken.MyAccessTokenPage;
import io.onedev.server.web.page.my.avatar.MyAvatarPage; import io.onedev.server.web.page.my.avatar.MyAvatarPage;
@ -306,20 +302,7 @@ public abstract class LayoutPage extends BasePage {
Plugin product = AppLoader.getProduct(); Plugin product = AppLoader.getProduct();
sidebar.add(new Label("productVersion", "Ver. " + product.getVersion())); sidebar.add(new Label("productVersion", "Ver. " + product.getVersion()));
sidebar.add(new ExternalLink("docLink", OneDev.getInstance().getDocRoot() + "/")); sidebar.add(new ExternalLink("docLink", OneDev.getInstance().getDocRoot() + "/"));
try { sidebar.add(new BookmarkablePageLink<Void>("incompatibilities", IncompatibilitiesPage.class));
String buildNumber = FileUtils.readFileToString(
new File(Bootstrap.installDir, "build.txt"),
StandardCharsets.UTF_8);
if (buildNumber.length() != 0) {
sidebar.add(new ExternalLink("incompatibilities",
"https://code.onedev.io/projects/160/builds/" + buildNumber.trim()
+ "/markdown/Incompatibilities/doc/incompatibilities.md"));
} else {
sidebar.add(new WebMarkupContainer("incompatibilities").setVisible(false));
}
} catch (IOException e) {
throw new RuntimeException(e);
}
WebMarkupContainer topbar = new WebMarkupContainer("topbar"); WebMarkupContainer topbar = new WebMarkupContainer("topbar");
add(topbar); add(topbar);

View File

@ -50,7 +50,7 @@ consideration. As a result of this, password authentication specified previously
1. Submodule authentication 1. Submodule authentication
You will need to use custom http/ssh clone credential with permission to access submodule projects to retrieve source. Refer to [usage scenario](https://code.onedev.io/projects/onedev-manual/blob/master/pages/clone-submodules-via-ssh.md) for an example. You will need to use custom http/ssh clone credential with permission to access submodule projects to retrieve source. Refer to [usage scenario](https://code.onedev.io/projects/162/blob/main/pages/clone-submodules-via-ssh.md) for an example.
2. Project dependency authentication 2. Project dependency authentication