Make stage concept accessible from ui

This commit is contained in:
Sebastian Sdorra
2020-08-25 08:42:16 +02:00
parent 330f7c500e
commit 6c1a9f286f
7 changed files with 53 additions and 23 deletions

View File

@@ -25,31 +25,37 @@
import { createAttributesForTesting, isDevBuild } from "./devBuild";
describe("devbuild tests", () => {
let env: string | undefined;
let stage: string | undefined;
const setStage = (s?: string) => {
// @ts-ignore scmStage is set on the index page
window.scmStage = s;
};
beforeAll(() => {
env = process.env.NODE_ENV;
// @ts-ignore scmStage is set on the index page
stage = window.scmStage;
});
afterAll(() => {
process.env.NODE_ENV = env;
setStage(stage);
});
describe("isDevBuild tests", () => {
it("should return true for development", () => {
process.env.NODE_ENV = "development";
setStage("development");
expect(isDevBuild()).toBe(true);
});
it("should return false for production", () => {
process.env.NODE_ENV = "production";
setStage("production");
expect(isDevBuild()).toBe(false);
});
});
describe("createAttributesForTesting in non development mode", () => {
beforeAll(() => {
process.env.NODE_ENV = "production";
setStage("production");
});
it("should return undefined for non development", () => {
@@ -60,7 +66,7 @@ describe("devbuild tests", () => {
describe("createAttributesForTesting in development mode", () => {
beforeAll(() => {
process.env.NODE_ENV = "development";
setStage("development");
});
it("should return undefined for non development", () => {

View File

@@ -22,7 +22,8 @@
* SOFTWARE.
*/
export const isDevBuild = () => process.env.NODE_ENV === "development";
// @ts-ignore scmStage is set on the index page
export const isDevBuild = () => (window.scmStage || "").toUpperCase() === "DEVELOPMENT";
export const createAttributesForTesting = (testId?: string) => {
if (!testId || !isDevBuild()) {

View File

@@ -22,12 +22,13 @@
* SOFTWARE.
*/
const path = require("path");
const createIndexMiddleware = require("./middleware/IndexMiddleware");
const createContextPathMiddleware = require("./middleware/ContextPathMiddleware");
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const OptimizeCSSAssetsPlugin = require("optimize-css-assets-webpack-plugin");
const WorkerPlugin = require("worker-plugin");
const createIndexMiddleware = require("./middleware/IndexMiddleware");
const createContextPathMiddleware = require("./middleware/ContextPathMiddleware");
const isDevelopment = process.env.NODE_ENV === "development";
const root = path.resolve(process.cwd(), "scm-ui");
@@ -39,6 +40,8 @@ let mode = "production";
if (isDevelopment) {
mode = "development";
babelPlugins.push(require.resolve("react-refresh/babel"));
// it is ok to use require here, because we want to load the package conditionally
// eslint-disable-next-line global-require
const ReactRefreshWebpackPlugin = require("@pmmmwh/react-refresh-webpack-plugin");
webpackPlugins.push(new ReactRefreshWebpackPlugin());
}
@@ -113,13 +116,15 @@ module.exports = [
historyApiFallback: true,
overlay: true,
port: 3000,
before: function(app) {
before: app => {
app.use(createContextPathMiddleware("/scm"));
},
after: function(app) {
after: app => {
const templatePath = path.join(root, "ui-webapp", "public", "index.mustache");
const stage = process.env.NODE_ENV || "DEVELOPMENT";
const renderParams = {
contextPath: "/scm"
contextPath: "/scm",
scmStage: stage.toUpperCase()
};
app.use(createIndexMiddleware(templatePath, renderParams));
},

View File

@@ -47,6 +47,7 @@
-->
<script>
window.ctxPath = "{{ contextPath }}";
window.scmStage = "{{ scmStage }}";
</script>
<script src="{{ contextPath }}/assets/runtime.bundle.js"></script>
<script src="{{ contextPath }}/assets/vendors~webapp.bundle.js"></script>

View File

@@ -21,7 +21,7 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package sonia.scm;
import com.google.common.annotations.VisibleForTesting;
@@ -46,15 +46,17 @@ public class TemplatingPushStateDispatcher implements PushStateDispatcher {
static final String TEMPLATE = "/index.mustache";
private final TemplateEngine templateEngine;
private final SCMContextProvider context;
@Inject
public TemplatingPushStateDispatcher(TemplateEngineFactory templateEngineFactory) {
this(templateEngineFactory.getDefaultEngine());
public TemplatingPushStateDispatcher(TemplateEngineFactory templateEngineFactory, SCMContextProvider context) {
this(templateEngineFactory.getDefaultEngine(), context);
}
@VisibleForTesting
TemplatingPushStateDispatcher(TemplateEngine templateEngine) {
TemplatingPushStateDispatcher(TemplateEngine templateEngine, SCMContextProvider context) {
this.templateEngine = templateEngine;
this.context = context;
}
@Override
@@ -64,7 +66,7 @@ public class TemplatingPushStateDispatcher implements PushStateDispatcher {
Template template = templateEngine.getTemplate(TEMPLATE);
try (Writer writer = response.getWriter()) {
template.execute(writer, new IndexHtmlModel(request));
template.execute(writer, new IndexHtmlModel(request, context.getStage()));
}
}
@@ -72,15 +74,21 @@ public class TemplatingPushStateDispatcher implements PushStateDispatcher {
static class IndexHtmlModel {
private final HttpServletRequest request;
private final Stage scmStage;
private IndexHtmlModel(HttpServletRequest request) {
private IndexHtmlModel(HttpServletRequest request, Stage scmStage) {
this.request = request;
this.scmStage = scmStage;
}
public String getContextPath() {
return request.getContextPath();
}
public String getScmStage() {
return scmStage.name();
}
public String getLiveReloadURL() {
return System.getProperty("livereload.url");
}

View File

@@ -21,7 +21,7 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package sonia.scm;
import com.google.inject.util.Providers;
@@ -39,8 +39,11 @@ public class PushStateDispatcherProviderTest {
@Mock
private TemplateEngine templateEngine;
@Mock
private SCMContextProvider context;
private PushStateDispatcherProvider provider = new PushStateDispatcherProvider(
Providers.of(new TemplatingPushStateDispatcher(templateEngine))
Providers.of(new TemplatingPushStateDispatcher(templateEngine, context))
);
@Test

View File

@@ -21,7 +21,7 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package sonia.scm;
import org.junit.Before;
@@ -61,18 +61,24 @@ public class TemplatingPushStateDispatcherTest {
@Mock
private Template template;
@Mock
private SCMContextProvider context;
private TemplatingPushStateDispatcher dispatcher;
@Before
public void setUpMocks() {
dispatcher = new TemplatingPushStateDispatcher(templateEngine);
dispatcher = new TemplatingPushStateDispatcher(templateEngine, context);
}
@Test
public void testDispatch() throws IOException {
when(context.getStage()).thenReturn(Stage.DEVELOPMENT);
TemplatingPushStateDispatcher.IndexHtmlModel model = dispatch();
assertEquals("/scm", model.getContextPath());
assertNull(model.getLiveReloadURL());
assertEquals("DEVELOPMENT", model.getScmStage());
}
@Test