Create pipeline (#20)
CureNetMulti/pipeline/head There was a failure building this commit Details

update branches for deploy

move path to variables

deply backend fix

prepare for deploy

change database

fix syntax

change php version to 8.0

lint + pipeline

path

pipeline

Merge remote-tracking branch 'origin/dev' into 4-pipeline

Added Jenkinsfile

Co-authored-by: Sieciech <michal@fufle.net>
Co-authored-by: Sieciech <www.sieciech@gmail.com>
Co-authored-by: admin <jenkins@michal.sieciechowicz.pl>
Reviewed-on: http://git.fufle.net/Community/CureNet/pulls/20
Co-Authored-By: Sieciech <sieciech@noreply.fufle.net>
Co-Committed-By: Sieciech <sieciech@noreply.fufle.net>
This commit is contained in:
Michał Sieciechowicz 2021-07-27 20:35:53 +00:00
parent 6fcad220de
commit f0015a1961
12 changed files with 334 additions and 114 deletions

198
Jenkinsfile vendored Normal file
View File

@ -0,0 +1,198 @@
pipeline {
agent any
environment {
DatabaseUrl = sh(returnStdout: true, script: 'bash /var/lib/jenkins/variables/CureNet/var.sh ${BRANCH_NAME} DatabaseUrl').trim()
ProjectPath = sh(returnStdout: true, script: 'bash /var/lib/jenkins/variables/CureNet/var.sh ${BRANCH_NAME} ProjectPath').trim()
DatabaseUrlTesting = sh(returnStdout: true, script: 'bash /var/lib/jenkins/variables/CureNet/var.sh master DatabaseUrl').trim()
}
stages {
stage('Pull') {
steps {
git(url: 'http://git.fufle.net/Community/CureNet.git', branch: '${BRANCH_NAME}', credentialsId: '799188a2-c281-4e4c-b78f-c82132ea792b', poll: true)
}
}
stage('Approve') {
steps {
echo "http://git.fufle.net/Community/CureNet/commit/${env.GIT_COMMIT}"
script {
if (env.BRANCH_NAME == "prod") {
echo "http://git.fufle.net/Community/CureNet/compare/prod...staging"
input(message: 'Deploy to production?', id: 'A', ok: 'Yes', submitter: 'deploy', submitterParameter: 'a')
}
if (env.BRANCH_NAME == "staging") {
echo "http://git.fufle.net/Community/CureNet/compare/staging...beta"
input(message: 'Deploy to staging instance?', id: 'A', ok: 'Yes', submitter: 'deploy', submitterParameter: 'a')
}
if (env.BRANCH_NAME == "beta") {
echo "http://git.fufle.net/Community/CureNet/compare/beta...dev"
input(message: 'Deploy to beta instance?', id: 'A', ok: 'Yes', submitter: 'deploy', submitterParameter: 'a')
}
}
}
}
stage('Install') {
parallel {
stage('Frontend') {
steps {
dir(path: 'src/frontend') {
sh 'sed -i "s/-1001/${BUILD_ID}/g" src/environments/*.ts'
sh 'Timestamp=`php8.0 -r "echo time();"` && sed -i "s/-1002/${Timestamp}/g" src/environments/*.ts'
sh 'npm ci'
}
}
}
stage('Backend') {
steps {
dir(path: 'src/backend') {
sh 'php8.0 /bin/composer install'
}
}
}
}
}
stage('Configure for tests') {
parallel {
stage('Frontend') {
steps {
dir(path: 'src/frontend') {
sh 'echo skip'
}
}
}
stage('Backend') {
steps {
dir(path: 'src/backend') {
sh 'APP_SECRET=`php8.0 -r "echo md5(\\"branch=${BRANCH_NAME};\\");"` && sed -i "s/APP_SECRET=.*/APP_SECRET=${APP_SECRET}/g" .env'
sh '''sed -i 's/DATABASE_URL=.*/DATABASE_URL=${DatabaseUrlTesting}/g' .env.test'''
sh 'composer dump-env test'
sh 'php8.0 bin/console doctrine:schema:update --force';
}
}
}
}
}
stage('Test') {
parallel {
stage('Frontend') {
steps {
dir(path: 'src/frontend') {
sh 'ng lint'
}
}
}
stage('Backend') {
steps {
dir(path: 'src/backend') {
sh 'php8.0 vendor/bin/phpunit'
}
}
}
}
}
stage('Configure') {
parallel {
stage('Frontend') {
steps {
dir(path: 'src/frontend') {
sh 'echo skip'
}
}
}
stage('Backend') {
steps {
dir(path: 'src/backend') {
sh 'APP_SECRET=`php8.0 -r "echo md5(\\"branch=${BRANCH_NAME};\\");"` && sed -i "s/APP_SECRET=.*/APP_SECRET=${APP_SECRET}/g" .env'
sh 'sed -i "s/DATABASE_URL=.*/DATABASE_URL=${DatabaseUrl}/g" .env.dev'
sh 'composer dump-env dev'
}
}
}
}
}
stage('Build') {
parallel {
stage('Frontend') {
steps {
dir(path: 'src/frontend') {
sh 'ng b -c production'
}
}
}
stage('Backend') {
steps {
dir(path: 'src/backend') {
sh 'echo skip'
}
}
}
}
}
stage('Deploy') {
when {
anyOf {
branch 'master'
branch 'staging'
branch 'beta'
branch 'dev'
}
}
parallel {
stage('Frontend') {
steps {
dir(path: 'src/frontend') {
sh 'ssh web@fufle.net touch ${ProjectPath}/frontend/REMOVEME'
sh 'ssh web@fufle.net rm -rf ${ProjectPath}/frontend/*'
sh 'scp -r dist/* web@fufle.net:${ProjectPath}/frontend/'
}
}
}
stage('Backend') {
steps {
dir(path: 'src/backend') {
sh 'ssh web@fufle.net touch ${ProjectPath}/backend/REMOVEME'
sh 'ssh web@fufle.net rm -rf ${ProjectPath}/backend/*'
sh 'scp -r ./* web@fufle.net:${ProjectPath}/backend/'
}
}
}
}
}
}
}

View File

@ -4,3 +4,4 @@ APP_SECRET='$ecretf0rt3st'
SYMFONY_DEPRECATIONS_HELPER=999999 SYMFONY_DEPRECATIONS_HELPER=999999
PANTHER_APP_ENV=panther PANTHER_APP_ENV=panther
PANTHER_ERROR_SCREENSHOT_DIR=./var/error-screenshots PANTHER_ERROR_SCREENSHOT_DIR=./var/error-screenshots
DATABASE_URL="postgresql://db_user:db_password@127.0.0.1:5432/db_name?serverVersion=13&charset=utf8"

View File

@ -3,100 +3,111 @@ import { Route, RouterModule } from '@angular/router';
import { NotFoundComponent } from './modules/shared/components/not-found/not-found.component'; import { NotFoundComponent } from './modules/shared/components/not-found/not-found.component';
interface AppMenuEntry { interface AppMenuEntry {
label: string; label: string;
icon: string; icon: string;
path?: string; path?: string;
matchExact?: boolean; matchExact?: boolean;
level?: number; level?: number;
} }
interface AppRoute extends Route { interface AppRoute extends Route {
menuEntries?: AppMenuEntry[]; menuEntries?: AppMenuEntry[];
} }
export const appRoutes: AppRoute[] = [ export const appRoutes: AppRoute[] = [
{ {
path: '', path: '',
component: NotFoundComponent, component: NotFoundComponent,
menuEntries: [ menuEntries: [
{ {
label: 'MENU.HOME', label: 'MENU.HOME',
icon: 'fa fa-home', icon: 'fa fa-home',
matchExact: true, matchExact: true,
}, },
], ],
}, },
{ {
path: 'profile', path: 'profile',
component: NotFoundComponent, component: NotFoundComponent,
menuEntries: [ menuEntries: [
{ {
label: 'MENU.PROFILE', label: 'MENU.PROFILE',
icon: 'fa fa-user', icon: 'fa fa-user',
}, },
], ],
}, },
{ {
path: 'community', path: 'community',
component: NotFoundComponent, component: NotFoundComponent,
menuEntries: [ menuEntries: [
{ {
label: 'MENU.COMMUNITY', label: 'MENU.COMMUNITY',
icon: 'fa fa-users', icon: 'fa fa-users',
}, },
], ],
}, },
{ {
path: 'messages', path: 'questions',
component: NotFoundComponent, component: NotFoundComponent,
menuEntries: [ menuEntries: [
{ {
label: 'MENU.MESSAGES', label: 'MENU.QUESTIONS',
icon: 'fa fa-comments', icon: 'fa fa-question',
}, level: 1,
], }
}, ],
{ },
path: 'tests', {
component: NotFoundComponent, path: 'messages',
menuEntries: [ component: NotFoundComponent,
{ menuEntries: [
label: 'MENU.TESTS', {
icon: 'fa fa-heartbeat', label: 'MENU.MESSAGES',
}, icon: 'fa fa-comments',
], },
}, ],
{ },
path: 'research', {
component: NotFoundComponent, path: 'tests',
menuEntries: [ component: NotFoundComponent,
{ menuEntries: [
label: 'MENU.RESEARCH', {
icon: 'fa fa-flask', label: 'MENU.TESTS',
}, icon: 'fa fa-heartbeat',
], },
}, ],
{ },
path: 'admin', {
loadChildren: () => import('./modules/admin/admin.module').then(m => m.AdminModule), path: 'research',
menuEntries: [ component: NotFoundComponent,
{ menuEntries: [
label: 'MENU.ADMIN', {
icon: 'fa fa-id-card', label: 'MENU.RESEARCH',
matchExact: true, icon: 'fa fa-flask',
}, },
{ ],
path: 'admin/users', },
label: 'MENU.USERS', {
icon: 'fa fa-users', path: 'admin',
level: 1, loadChildren: () => import('./modules/admin/admin.module').then(m => m.AdminModule),
} menuEntries: [
], {
}, label: 'MENU.ADMIN',
icon: 'fa fa-id-card',
matchExact: true,
},
{
path: 'admin/users',
label: 'MENU.USERS',
icon: 'fa fa-users',
level: 1,
}
],
},
]; ];
@NgModule({ @NgModule({
imports: [RouterModule.forRoot(appRoutes)], imports: [RouterModule.forRoot(appRoutes)],
exports: [RouterModule] exports: [RouterModule]
}) })
export class AppRoutingModule { } export class AppRoutingModule { }

View File

@ -36,7 +36,7 @@ export class AppComponent {
avatar: 'https://www.gravatar.com/avatar/81b206a89f89d5b1123b87606075c6a8?s=514&d=robohash', avatar: 'https://www.gravatar.com/avatar/81b206a89f89d5b1123b87606075c6a8?s=514&d=robohash',
}; };
get isSidebarOpen() { get isSidebarOpen(): boolean {
switch (this.sidebarOpen) { switch (this.sidebarOpen) {
case SidebarOpenEnum.Open: case SidebarOpenEnum.Open:
return true; return true;
@ -86,7 +86,7 @@ export class AppComponent {
} }
} }
onThemeChanged(theme: string) { onThemeChanged(theme: string): void {
if (theme === undefined) { if (theme === undefined) {
return; return;
} }
@ -95,7 +95,7 @@ export class AppComponent {
this.isDark = theme.indexOf('dark') !== -1; this.isDark = theme.indexOf('dark') !== -1;
} }
onResize(size: WindowSize) { onResize(size: WindowSize): void {
if (size === undefined) { if (size === undefined) {
return; return;
} }
@ -104,7 +104,7 @@ export class AppComponent {
this.sidebarMode = this.isMobile ? 'over' : 'side'; this.sidebarMode = this.isMobile ? 'over' : 'side';
} }
onLangChanged(lang: string) { onLangChanged(lang: string): void {
if (lang === undefined) { if (lang === undefined) {
return; return;
} }
@ -112,16 +112,16 @@ export class AppComponent {
this.langControl.setValue(lang); this.langControl.setValue(lang);
} }
toggleSidebar() { toggleSidebar(): void {
this.sidebarOpen = this.isSidebarOpen ? SidebarOpenEnum.Closed : SidebarOpenEnum.Open; this.sidebarOpen = this.isSidebarOpen ? SidebarOpenEnum.Closed : SidebarOpenEnum.Open;
this.browserStorageService.setItem('sidebar.open', this.sidebarOpen); this.browserStorageService.setItem('sidebar.open', this.sidebarOpen);
} }
onSidebarOpenedChange(opened: boolean) { onSidebarOpenedChange(opened: boolean): void {
this.sidebarOpen = opened ? SidebarOpenEnum.Open : SidebarOpenEnum.Closed; this.sidebarOpen = opened ? SidebarOpenEnum.Open : SidebarOpenEnum.Closed;
} }
url(url: string): SafeStyle { url(url: string): SafeStyle {
return this.sanitizer.bypassSecurityTrustStyle(`url('${url}')`); return this.sanitizer.bypassSecurityTrustStyle(`url('${url}')`);
} }
} }

View File

@ -12,7 +12,7 @@ import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { TranslateLoader, TranslateModule } from '@ngx-translate/core'; import { TranslateLoader, TranslateModule } from '@ngx-translate/core';
import { TranslateHttpLoader } from '@ngx-translate/http-loader'; import { TranslateHttpLoader } from '@ngx-translate/http-loader';
export function HttpLoaderFactory(http: HttpClient) { export function HttpLoaderFactory(http: HttpClient): TranslateHttpLoader {
return new TranslateHttpLoader(http, '/assets/lang/', '.json'); return new TranslateHttpLoader(http, '/assets/lang/', '.json');
} }

View File

@ -13,13 +13,14 @@ export class WindowSize {
this.isMobile = this.width <= 700; this.isMobile = this.width <= 700;
} }
update() { static generate(): WindowSize {
this.width = window.innerWidth; return new WindowSize(window.innerWidth, window.innerHeight);
this.height = window.innerHeight;
} }
static generate() { update(): WindowSize {
return new WindowSize(window.innerWidth, window.innerHeight); this.width = window.innerWidth;
this.height = window.innerHeight;
return this;
} }
} }
@ -41,29 +42,29 @@ export class AppService {
}); });
this.sizeChange.subscribe(size => this.size = size); this.sizeChange.subscribe(size => this.size = size);
this.sizeChange.next(WindowSize.generate()); this.sizeChange.next(WindowSize.generate());
let lang = browserStorageService.getItem('language'); let language = browserStorageService.getItem('language');
if (!lang) { if (!language) {
lang = this.defaultLang; language = this.defaultLang;
} }
this.translate.setDefaultLang(this.defaultLang); this.translate.setDefaultLang(this.defaultLang);
this.changeLang(lang); this.changeLang(language);
fromEvent(window, 'resize').subscribe(e => { fromEvent(window, 'resize').subscribe(e => {
this.sizeChange.next(WindowSize.generate()); this.sizeChange.next(WindowSize.generate());
}) });
} }
changeLang(lang: string) { changeLang(lang: string): void {
if (lang !== this.lang) { if (lang !== this.lang) {
this.translate.use(lang); this.translate.use(lang);
this.langChange.next(lang); this.langChange.next(lang);
} }
} }
getLang() { getLang(): string {
return this.lang; return this.lang;
} }
getLangs() { getLangs(): string[] {
return [ return [
'pl', 'pl',
'en', 'en',

View File

@ -5,12 +5,13 @@ export class BrowserStorageService {
private storage: Storage; private storage: Storage;
private namespace: string; private namespace: string;
constructor() { constructor() {
this.storage = localStorage; this.storage = localStorage;
this.namespace = 'default'; this.namespace = 'default';
} }
setNamespace(namespace: string) { setNamespace(namespace: string): void {
this.namespace = namespace; this.namespace = namespace;
} }
@ -18,7 +19,7 @@ export class BrowserStorageService {
return namespace ?? this.namespace; return namespace ?? this.namespace;
} }
setItem(key: string, value: any, namespace: string | null = null) { setItem(key: string, value: any, namespace: string | null = null): void {
namespace = this.getNamespace(namespace); namespace = this.getNamespace(namespace);
const path = `${namespace}.${key}`; const path = `${namespace}.${key}`;
this.storage.setItem(path, JSON.stringify(value)); this.storage.setItem(path, JSON.stringify(value));

View File

@ -21,11 +21,11 @@ export class ThemeService {
this.setTheme(userTheme); this.setTheme(userTheme);
} }
getTheme() { getTheme(): string {
return this.theme; return this.theme;
} }
setTheme(theme: string) { setTheme(theme: string): void {
if (theme !== this.theme) { if (theme !== this.theme) {
this.themeChange.next(theme); this.themeChange.next(theme);
document.getElementById('current-theme').setAttribute('href', `/${theme}.css`); document.getElementById('current-theme').setAttribute('href', `/${theme}.css`);
@ -37,5 +37,5 @@ export class ThemeService {
'light', 'light',
'dark', 'dark',
]; ];
}; }
} }

View File

@ -19,7 +19,9 @@
"HOME": "Dashboard", "HOME": "Dashboard",
"PROFILE": "Profile", "PROFILE": "Profile",
"COMMUNITY": "Community", "COMMUNITY": "Community",
"GROUP": "My group",
"MESSAGES": "Messages", "MESSAGES": "Messages",
"QUESTIONS": "Q&A",
"TESTS": "Laboratory tests", "TESTS": "Laboratory tests",
"RESEARCH": "Research", "RESEARCH": "Research",
"ADMIN": "Admin", "ADMIN": "Admin",

View File

@ -19,7 +19,9 @@
"HOME": "Kokpit", "HOME": "Kokpit",
"PROFILE": "Profil", "PROFILE": "Profil",
"COMMUNITY": "Społeczność", "COMMUNITY": "Społeczność",
"GROUP": "Moja grupa",
"MESSAGES": "Wiadomości", "MESSAGES": "Wiadomości",
"QUESTIONS": "Pytania i odpowiedzi",
"TESTS": "Wyniki badań", "TESTS": "Wyniki badań",
"RESEARCH": "Badania naukowe", "RESEARCH": "Badania naukowe",
"ADMIN": "Panel administratora", "ADMIN": "Panel administratora",

View File

@ -1,3 +1,5 @@
export const environment = { export const environment = {
production: true production: true,
buildId: -1001,
buildTime: -1002,
}; };

View File

@ -3,7 +3,9 @@
// The list of file replacements can be found in `angular.json`. // The list of file replacements can be found in `angular.json`.
export const environment = { export const environment = {
production: false production: false,
buildId: -1001,
buildTime: -1002,
}; };
/* /*