Skip to content

Commit

Permalink
Added a feature to load the server build details [#578]
Browse files Browse the repository at this point in the history
 * Added the frontend feature to retrieve the details.
 * Refactored the REST APIs and repackaged the classes.
 * Added the page to display the build details.
  • Loading branch information
mcpierce committed Mar 1, 2021
1 parent 6b9fa1f commit 23bd654
Show file tree
Hide file tree
Showing 31 changed files with 913 additions and 32 deletions.
Expand Up @@ -16,12 +16,14 @@
* along with this program. If not, see <http://www.gnu.org/licenses>
*/

package org.comixedproject.model.core;
package org.comixedproject.model.app;

import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonView;
import java.util.Date;
import lombok.Getter;
import lombok.Setter;
import org.comixedproject.views.View;

/**
* <code>BuildDetails</code> holds the know details for the currently running build.
Expand All @@ -30,61 +32,73 @@
*/
public class BuildDetails {
@JsonProperty("branch")
@JsonView(View.BuildDetails.class)
@Getter
@Setter
private String branch;

@JsonProperty("buildTime")
@JsonView(View.BuildDetails.class)
@Getter
@Setter
private Date buildTime;

@JsonProperty("buildHost")
@JsonView(View.BuildDetails.class)
@Getter
@Setter
private String buildHost;

@JsonProperty("buildVersion")
@JsonView(View.BuildDetails.class)
@Getter
@Setter
private String buildVersion;

@JsonProperty("commitId")
@JsonView(View.BuildDetails.class)
@Getter
@Setter
private String commitId;

@JsonProperty("commitTime")
@JsonView(View.BuildDetails.class)
@Getter
@Setter
private Date commitTime;

@JsonProperty("commitMessage")
@JsonView(View.BuildDetails.class)
@Getter
@Setter
private String commitMessage;

@JsonProperty("commitUser")
@JsonView(View.BuildDetails.class)
@Getter
@Setter
private String commitUser;

@JsonProperty("commitEmail")
@JsonView(View.BuildDetails.class)
@Getter
@Setter
private String commitEmail;

@JsonProperty("dirty")
@JsonView(View.BuildDetails.class)
@Getter
@Setter
private boolean dirty;

@JsonProperty("remoteOriginURL")
@JsonView(View.BuildDetails.class)
@Getter
@Setter
private String remoteOriginURL;

@JsonProperty("jdbcUrl")
@JsonView(View.BuildDetails.class)
@Getter
@Setter
private String jdbcUrl;
Expand Down
Expand Up @@ -71,4 +71,7 @@ public interface ComicFileList {}

/** Used when retrieving a session update. */
public interface SessionUpdateView {}

/** Uses when viewing the build details for the server. */
public interface BuildDetails {}
}
Expand Up @@ -16,27 +16,28 @@
* along with this program. If not, see <http://www.gnu.org/licenses>
*/

package org.comixedproject.controller.core;
package org.comixedproject.controller.app;

import com.fasterxml.jackson.annotation.JsonView;
import java.text.ParseException;
import lombok.extern.log4j.Log4j2;
import org.comixedproject.auditlog.AuditableEndpoint;
import org.comixedproject.model.core.BuildDetails;
import org.comixedproject.service.core.DetailsService;
import org.comixedproject.model.app.BuildDetails;
import org.comixedproject.service.app.DetailsService;
import org.comixedproject.views.View;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

/**
* <code>DetailsController</code> handles requests for build details.
* <code>BuildDetailsController</code> handles requests for build details.
*
* @author Darryl L. Pierce
*/
@RestController
@RequestMapping("/api/core")
@Log4j2
public class DetailsController {
public class BuildDetailsController {
@Autowired private DetailsService detailsService;

/**
Expand All @@ -45,8 +46,9 @@ public class DetailsController {
* @return the build details
* @throws ParseException if an error occurs
*/
@GetMapping("/build-details")
@GetMapping(value = "/api/build-details", produces = MediaType.APPLICATION_JSON_VALUE)
@AuditableEndpoint
@JsonView(View.BuildDetails.class)
public BuildDetails getBuildDetails() throws ParseException {
log.info("Getting application build details");
return this.detailsService.getBuildDetails();
Expand Down
Expand Up @@ -22,8 +22,9 @@
import static junit.framework.TestCase.assertSame;

import java.text.ParseException;
import org.comixedproject.model.core.BuildDetails;
import org.comixedproject.service.core.DetailsService;
import org.comixedproject.controller.app.BuildDetailsController;
import org.comixedproject.model.app.BuildDetails;
import org.comixedproject.service.app.DetailsService;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
Expand All @@ -34,10 +35,10 @@

@RunWith(MockitoJUnitRunner.class)
@SpringBootTest
public class DetailsControllerTest {
public class BuildDetailsControllerTest {
private static final String TEST_STACKTRACE = "The error message";

@InjectMocks private DetailsController detailsController;
@InjectMocks private BuildDetailsController buildDetailsController;
@Mock private DetailsService detailsService;
@Mock private BuildDetails buildDetails;

Expand All @@ -46,7 +47,7 @@ public void testGetBuildDetailsParsingException() throws ParseException {
Mockito.when(detailsService.getBuildDetails()).thenThrow(ParseException.class);

try {
detailsController.getBuildDetails();
buildDetailsController.getBuildDetails();
} finally {
Mockito.verify(detailsService, Mockito.times(1)).getBuildDetails();
}
Expand All @@ -56,7 +57,7 @@ public void testGetBuildDetailsParsingException() throws ParseException {
public void testGetBuildDetails() throws ParseException {
Mockito.when(detailsService.getBuildDetails()).thenReturn(buildDetails);

final BuildDetails result = detailsController.getBuildDetails();
final BuildDetails result = buildDetailsController.getBuildDetails();

assertNotNull(result);
assertSame(buildDetails, result);
Expand Down
Expand Up @@ -16,12 +16,12 @@
* along with this program. If not, see <http://www.gnu.org/licenses>
*/

package org.comixedproject.service.core;
package org.comixedproject.service.app;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import lombok.extern.log4j.Log4j2;
import org.comixedproject.model.core.BuildDetails;
import org.comixedproject.model.app.BuildDetails;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.PropertySource;
import org.springframework.stereotype.Service;
Expand Down
Expand Up @@ -16,14 +16,14 @@
* along with this program. If not, see <http://www.gnu.org/licenses>
*/

package org.comixedproject.service.core;
package org.comixedproject.service.app;

import static junit.framework.TestCase.assertEquals;
import static junit.framework.TestCase.assertNotNull;

import java.text.ParseException;
import java.util.Calendar;
import org.comixedproject.model.core.BuildDetails;
import org.comixedproject.model.app.BuildDetails;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
Expand Down
33 changes: 33 additions & 0 deletions comixed-web/src/app/actions/build-details.actions.ts
@@ -0,0 +1,33 @@
/*
* ComiXed - A digital comic book library management application.
* Copyright (C) 2021, The ComiXed Project
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses>
*/

import { createAction, props } from '@ngrx/store';
import { BuildDetails } from '@app/models/build-details';

export const loadBuildDetails = createAction(
'[Build Details] Load the build details'
);

export const buildDetailsLoaded = createAction(
'[Build Details] Build details loaded',
props<{ details: BuildDetails }>()
);

export const loadBuildDetailsFailed = createAction(
'[Build Details] Load build details failed'
);
1 change: 1 addition & 0 deletions comixed-web/src/app/app.constants.ts
Expand Up @@ -23,3 +23,4 @@ export const HTTP_REQUESTED_WITH_HEADER = 'X-Requested-With';
export const HTTP_XML_REQUEST = 'XMLHttpRequest';

export const LOAD_SESSION_UPDATE_URL = `${API_ROOT_URL}/session/updates`;
export const LOAD_BUILD_DETAILS_URL = `${API_ROOT_URL}/build-details`;
34 changes: 34 additions & 0 deletions comixed-web/src/app/app.fixtures.ts
@@ -0,0 +1,34 @@
/*
* ComiXed - A digital comic book library management application.
* Copyright (C) 2020, The ComiXed Project
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses>
*/

import { BuildDetails } from './models/build-details';

export const BUILD_DETAILS: BuildDetails = {
branch: 'branch-name',
buildTime: new Date().getTime(),
buildHost: 'build-host',
buildVersion: 'build-version',
commitId: 'commit-id',
commitTime: new Date().getTime(),
commitMessage: 'commit-message',
commitUser: 'commit-user',
commitEmail: 'commit@email.com',
dirty: Math.random() > 0.5,
remoteOriginURL: 'http://remote.origin.url',
jdbcUrl: 'jdbc:h2:mem://localhost/comixed'
};
15 changes: 12 additions & 3 deletions comixed-web/src/app/app.module.ts
Expand Up @@ -50,9 +50,17 @@ import { APP_REDUCERS } from '@app/app.reducers';
import { SessionEffects } from '@app/effects/session.effects';
import { environment } from '../environments/environment';
import { StoreDevtoolsModule } from '@ngrx/store-devtools';
import { BuildDetailsEffects } from '@app/effects/build-details.effects';
import { BuildDetailsComponent } from './pages/build-details/build-details.component';
import { MatCardModule } from '@angular/material/card';

@NgModule({
declarations: [AppComponent, HomeComponent, NavigationBarComponent],
declarations: [
AppComponent,
HomeComponent,
NavigationBarComponent,
BuildDetailsComponent
],
imports: [
UserModule,
LibraryModule,
Expand All @@ -62,7 +70,7 @@ import { StoreDevtoolsModule } from '@ngrx/store-devtools';
MatToolbarModule,
MatIconModule,
StoreModule.forRoot(APP_REDUCERS, {}),
EffectsModule.forRoot([AppEffects, SessionEffects]),
EffectsModule.forRoot([AppEffects, SessionEffects, BuildDetailsEffects]),
StoreRouterConnectingModule.forRoot(),
LoggerModule.forRoot({ useLevelGroup: true }),
TranslateModule.forRoot({
Expand All @@ -86,7 +94,8 @@ import { StoreDevtoolsModule } from '@ngrx/store-devtools';
MatFormFieldModule,
MatTooltipModule,
MatProgressSpinnerModule,
MatMenuModule
MatMenuModule,
MatCardModule
],
providers: [
[{ provide: HTTP_INTERCEPTORS, useClass: HttpInterceptor, multi: true }]
Expand Down
9 changes: 8 additions & 1 deletion comixed-web/src/app/app.reducers.ts
Expand Up @@ -22,13 +22,20 @@ import {
SESSION_FEATURE_KEY,
SessionState
} from '@app/reducers/session.reducer';
import {
BUILD_DETAILS_FEATURE_KEY,
BuildDetailsState,
reducer as buildDetailsReducer
} from '@app/reducers/build-details.reducer';

export interface AppState {
[SESSION_FEATURE_KEY]: SessionState;
[BUILD_DETAILS_FEATURE_KEY]: BuildDetailsState;
}

export type State = AppState;

export const APP_REDUCERS: ActionReducerMap<State> = {
[SESSION_FEATURE_KEY]: sessionReducer
[SESSION_FEATURE_KEY]: sessionReducer,
[BUILD_DETAILS_FEATURE_KEY]: buildDetailsReducer
};
5 changes: 5 additions & 0 deletions comixed-web/src/app/app.routing.ts
Expand Up @@ -19,12 +19,17 @@
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { HomeComponent } from '@app/pages/home/home.component';
import { BuildDetailsComponent } from '@app/pages/build-details/build-details.component';

const routes: Routes = [
{
path: 'home',
component: HomeComponent
},
{
path: 'build',
component: BuildDetailsComponent
},
{
path: '**',
redirectTo: '/home'
Expand Down

0 comments on commit 23bd654

Please sign in to comment.