Merge branch '11_Redirect_to_edit_vehicle_page_if_no_consumable_is_configured' into 'development'
11 redirect to edit vehicle page if no consumable is configured See merge request !28
This commit is contained in:
commit
bb7c2780e8
|
@ -1,4 +1,6 @@
|
|||
.idea/
|
||||
tests/results/
|
||||
**.DS_Store
|
||||
**.swp
|
||||
**.pyc
|
||||
*.sqlite
|
|
@ -1,6 +1,4 @@
|
|||
from datetime import date
|
||||
|
||||
from flask import Flask
|
||||
from flask import Flask, flash
|
||||
from flask import redirect, g
|
||||
from flask import render_template
|
||||
from flask import url_for
|
||||
|
@ -58,6 +56,10 @@ def user_registered_sighandler(app, user, confirm_token):
|
|||
"""
|
||||
role = user_datastore.find_role('user')
|
||||
user_datastore.add_role_to_user(user, role)
|
||||
if user.email == app.config['ADMIN_MAIL']:
|
||||
# if the user selected the preconfigured email for the admin account
|
||||
role = user_datastore.find_role('admin')
|
||||
user_datastore.add_role_to_user(user, role)
|
||||
new_vehicle = Vehicle('default vehicle')
|
||||
db.session.add(new_vehicle)
|
||||
user.vehicles.append(new_vehicle)
|
||||
|
@ -237,6 +239,10 @@ def select_consumable_for_new_pitstop(vid):
|
|||
if vehicle is None or vehicle not in current_user.vehicles:
|
||||
return redirect(url_for('select_vehicle_for_new_pitstop'))
|
||||
|
||||
if len(vehicle.consumables) == 0:
|
||||
flash('Please choose at least one consumable!', 'warning')
|
||||
return redirect(url_for('edit_vehicle', vid=vid))
|
||||
|
||||
if len(vehicle.consumables) == 1:
|
||||
return redirect(url_for('create_pit_stop_form', vid=vid, cid=vehicle.consumables[0].id))
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@ body {
|
|||
}
|
||||
|
||||
.starter-template {
|
||||
padding-top: 30px;
|
||||
padding-top: 0px;
|
||||
padding-bottom: 60px;
|
||||
text-align: center;
|
||||
}
|
||||
|
@ -59,6 +59,14 @@ h3:after{
|
|||
text-align: left;
|
||||
}
|
||||
|
||||
.alert {
|
||||
margin-bottom:0px;
|
||||
}
|
||||
|
||||
.topspace {
|
||||
margin-top: 5px;
|
||||
}
|
||||
|
||||
// for small devices
|
||||
@media only screen
|
||||
and (min-device-width : 320px)
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<div class="panel panel-default">
|
||||
<div class="panel-heading">Password</div>
|
||||
<div class="panel-body">
|
||||
<a href='{{ url_for('security.change_password') }}' class="btn btn-primary " role="button">
|
||||
<a href="{{ url_for('security.change_password') }}" id="change_password" class="btn btn-primary " role="button">
|
||||
<span class="glyphicon glyphicon-pencil" aria-hidden="true"></span> Change
|
||||
</a>
|
||||
</div>
|
||||
|
@ -13,7 +13,7 @@
|
|||
<div class="panel panel-default">
|
||||
<div class="panel-heading">Vehicles</div>
|
||||
<div class="panel-body">
|
||||
<a href="{{ url_for('create_vehicle') }}" class="btn btn-primary " role="button">
|
||||
<a href="{{ url_for('create_vehicle') }}" id="create_vehicle" class="btn btn-primary " role="button">
|
||||
<span class="glyphicon glyphicon-plus" aria-hidden="true"></span> create
|
||||
</a>
|
||||
</div>
|
||||
|
@ -40,11 +40,11 @@
|
|||
{{ vehicle.consumables | length }} consumables
|
||||
</td>
|
||||
<td>
|
||||
<a href="{{ url_for('edit_vehicle', vid=vehicle.id) }}" class="btn btn-primary " role="button">
|
||||
<a href="{{ url_for('edit_vehicle', vid=vehicle.id) }}" id="edit_vehicle_{{loop.index}}" class="btn btn-primary " role="button">
|
||||
<span class="glyphicon glyphicon-pencil" aria-hidden="true"></span> edit
|
||||
</a>
|
||||
{% if current_user.vehicles | length > 1 %}
|
||||
<a href="{{ url_for('delete_vehicle', vid=vehicle.id) }}" class="btn btn-primary btn-warning " role="button">
|
||||
<a href="{{ url_for('delete_vehicle', vid=vehicle.id) }}" id="delete_vehicle_{{loop.index}}" class="btn btn-primary btn-warning " role="button">
|
||||
<span class="glyphicon glyphicon-trash" aria-hidden="true"></span> delete
|
||||
</a>
|
||||
{% else %}
|
||||
|
@ -59,7 +59,7 @@
|
|||
<div class="panel panel-default">
|
||||
<div class="panel-heading">Account</div>
|
||||
<div class="panel-body">
|
||||
<a href='{{ url_for('delete_account') }}' class="btn btn-primary " role="button">
|
||||
<a href="{{ url_for('delete_account') }}" id="delete_account" class="btn btn-primary " role="button">
|
||||
<span class="glyphicon glyphicon-remove" aria-hidden="true"></span> Delete
|
||||
</a>
|
||||
</div>
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
<div class="panel panel-default">
|
||||
<div class="panel-heading">Consumables</div>
|
||||
<div class="panel-body">
|
||||
<a href="{{ url_for('create_consumable') }}" class="btn btn-primary " role="button">
|
||||
<a href="{{ url_for('create_consumable') }}" id="create_consumable" class="btn btn-primary " role="button">
|
||||
<span class="glyphicon glyphicon-plus" aria-hidden="true"></span> create
|
||||
</a>
|
||||
</div>
|
||||
|
@ -38,22 +38,16 @@
|
|||
</tr>
|
||||
{% for consumable in consumables %}
|
||||
<tr>
|
||||
<td>
|
||||
{{ consumable.name }}
|
||||
</td>
|
||||
<td>
|
||||
{{ consumable.unit }}
|
||||
</td>
|
||||
<td>
|
||||
{{ consumable.vehicles | length }} vehicles
|
||||
</td>
|
||||
<td id="name_{{loop.index}}">{{ consumable.name }}</td>
|
||||
<td id="unit_{{loop.index}}">{{ consumable.unit }}</td>
|
||||
<td id="count_{{loop.index}}">{{ consumable.vehicles | length }} vehicles</td>
|
||||
<td>
|
||||
{% if not consumable.in_use %}
|
||||
<a href="{{ url_for('delete_consumable', cid=consumable.id) }}" class="btn btn-primary btn-warning " role="button">
|
||||
<a href="{{ url_for('delete_consumable', cid=consumable.id) }}" id="delete_consumable{{loop.index}}" class="btn btn-primary btn-warning " role="button">
|
||||
<span class="glyphicon glyphicon-trash" aria-hidden="true"></span> delete
|
||||
</a>
|
||||
{% endif %}
|
||||
<a href="{{ url_for('edit_consumable', cid=consumable.id) }}" class="btn btn-primary " role="button">
|
||||
<a href="{{ url_for('edit_consumable', cid=consumable.id) }}" id="edit_consumable{{loop.index}}" class="btn btn-primary " role="button">
|
||||
<span class="glyphicon glyphicon-pencil" aria-hidden="true"></span> edit
|
||||
</a>
|
||||
</td>
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<div class="col-md-8">
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-body">
|
||||
<h3>Delete vehicle '{{consumable.name}}'?</h3>
|
||||
<h3>Delete consumable '{{consumable.name}}'?</h3>
|
||||
<form class='form-horizontal' method="POST">
|
||||
{{ form.hidden_tag() }}
|
||||
{{ render_field_with_errors(form.submit) }}
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<div class="col-md-8">
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-body">
|
||||
<h3>Edit vehicle</h3>
|
||||
<h3>Edit vehicle '{{vehicle.name}}'</h3>
|
||||
<form class='form-horizontal' method="POST">
|
||||
{{ form.hidden_tag() }}
|
||||
{{ render_field_with_errors(form.name) }}
|
||||
|
|
|
@ -1,15 +1,15 @@
|
|||
{% macro navigation() -%}
|
||||
{% if current_user.email %}
|
||||
<li><a href='{{ url_for('select_vehicle_for_new_pitstop') }}'>Create Pitstop</a></li>
|
||||
<li><a href='{{ url_for('get_statistics') }}'>Statistics</a></li>
|
||||
<li><a href='{{ url_for('get_account_page') }}'>Account</a></li>
|
||||
<li><a id='new_pitstop_link' href='{{ url_for('select_vehicle_for_new_pitstop') }}'>Create Pitstop</a></li>
|
||||
<li><a id='statistics_limk' href='{{ url_for('get_statistics') }}'>Statistics</a></li>
|
||||
<li><a id='account_link' href='{{ url_for('get_account_page') }}'>Account</a></li>
|
||||
{% if current_user.has_role('admin') %}
|
||||
<li><a href='{{ url_for('get_admin_page') }}'>Admin</a></li>
|
||||
<li><a id='admin_link' href='{{ url_for('get_admin_page') }}'>Admin</a></li>
|
||||
{% endif %}
|
||||
<li><a href='{{ url_for('security.logout') }}'>Logout</a></li>
|
||||
<li><a id='logout_link' href='{{ url_for('security.logout') }}'>Logout</a></li>
|
||||
{% else %}
|
||||
<li><a href='{{ url_for('security.login') }}'>Login</a></li>
|
||||
<li><a href='{{ url_for('security.register') }}'>Register</a></li>
|
||||
<li><a id='login_link' href='{{ url_for('security.login') }}'>Login</a></li>
|
||||
<li><a id='register_link' href='{{ url_for('security.register') }}'>Register</a></li>
|
||||
{% endif %}
|
||||
{%- endmacro %}
|
||||
|
||||
|
@ -151,8 +151,23 @@
|
|||
</div><!--/.nav-collapse -->
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<div class="container">
|
||||
{% with messages = get_flashed_messages(with_categories=true) %}
|
||||
{% if messages %}
|
||||
{% for category, message in messages %}
|
||||
<div class="row topspace">
|
||||
<div class="col-md-4" ></div>
|
||||
<div class="col-md-4">
|
||||
<div class="alert alert-{{category}} alert-dismissible" role="alert">
|
||||
<button type="button" class="close" data-dismiss="alert" aria-label="Close"><span aria-hidden="true">×</span></button>
|
||||
{{ message }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-4" ></div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
{% endwith %}
|
||||
<div class="container topspace">
|
||||
<div class="starter-template">
|
||||
{% block body %}
|
||||
{% endblock %}
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
</ul>
|
||||
<div id="my-tab-content" class="tab-content">
|
||||
{% for vehicle in current_user.vehicles %}
|
||||
{% set vehicleloop = loop %}
|
||||
<div class="tab-pane {% if loop.first %}active{% endif %}" id="v{{vehicle.id}}">
|
||||
<h3>{{vehicle.name}}</h3>
|
||||
{% if vehicle.pitstops %}
|
||||
|
@ -22,19 +23,19 @@
|
|||
<table class="table table-striped table-bordered table-condensed">
|
||||
<tr>
|
||||
<th>Date</th>
|
||||
<td>{{pitstop.date}}</td>
|
||||
<td id="vehicle_{{vehicleloop.index}}_pitstop_{{loop.index}}_date">{{pitstop.date}}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Odometer</th>
|
||||
<td>{{pitstop.odometer}} km</td>
|
||||
<td id="vehicle_{{vehicleloop.index}}_pitstop_{{loop.index}}_odo">{{pitstop.odometer}} km</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>{{ pitstop.consumable.name }}</th>
|
||||
<td>{{pitstop.amount}} {{ pitstop.consumable.unit }}</td>
|
||||
<td id="vehicle_{{vehicleloop.index}}_pitstop_{{loop.index}}_anmount">{{pitstop.amount}} {{ pitstop.consumable.unit }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Costs</th>
|
||||
<td>
|
||||
<td id="vehicle_{{vehicleloop.index}}_pitstop_{{loop.index}}_cost">
|
||||
{% if pitstop.costs %}
|
||||
{{pitstop.costs}} €
|
||||
{% else %}
|
||||
|
@ -44,10 +45,10 @@
|
|||
</tr>
|
||||
</table>
|
||||
{% if loop.first %}
|
||||
<a href="{{ url_for('edit_pit_stop_form', pid=pitstop.id) }}" class="btn btn-primary">
|
||||
<a id="vehicle_{{vehicleloop.index}}_edit_pitstop_{{loop.index}}" href="{{ url_for('edit_pit_stop_form', pid=pitstop.id) }}" class="btn btn-primary">
|
||||
<span class="glyphicon glyphicon-pencil" aria-hidden="true"></span> edit
|
||||
</a>
|
||||
<a href="{{ url_for('delete_pit_stop_form', pid=pitstop.id) }}" class="btn btn-primary btn-warning ">
|
||||
<a id="vehicle_{{vehicleloop.index}}_delete_pitstop_{{loop.index}}" href="{{ url_for('delete_pit_stop_form', pid=pitstop.id) }}" class="btn btn-primary btn-warning ">
|
||||
<span class="glyphicon glyphicon-trash" aria-hidden="true"></span> delete
|
||||
</a>
|
||||
{% endif %}
|
||||
|
|
|
@ -17,6 +17,7 @@ class Config:
|
|||
MAIL_USE_SSL = False
|
||||
MAIL_USERNAME = os.environ.get('MAIL_USERNAME')
|
||||
MAIL_PASSWORD = os.environ.get('MAIL_PASSWORD')
|
||||
ADMIN_MAIL = 'joachim@lusiardi.de'
|
||||
|
||||
@staticmethod
|
||||
def init_app(app):
|
||||
|
@ -26,7 +27,7 @@ class Config:
|
|||
class DevelopmentConfig(Config):
|
||||
SECURITY_SEND_REGISTER_EMAIL = False
|
||||
DEBUG = True
|
||||
SQLALCHEMY_DATABASE_URI = 'mysql+pymysql://root:%s@database/pitstops' % (os.environ['DATABASE_ENV_MYSQL_ROOT_PASSWORD'])
|
||||
SQLALCHEMY_DATABASE_URI = 'mysql+pymysql://root:%s@database/pitstops' % (os.environ.get('DATABASE_ENV_MYSQL_ROOT_PASSWORD'))
|
||||
|
||||
|
||||
class TestingConfig(Config):
|
||||
|
|
|
@ -2,19 +2,11 @@ version: '2'
|
|||
services:
|
||||
rollerverbrauch:
|
||||
build: .
|
||||
depends_on:
|
||||
- database
|
||||
volumes:
|
||||
- ./compose_config/:/config
|
||||
environment:
|
||||
- config=/config/config.py
|
||||
- DATABASE_ENV_MYSQL_ROOT_PASSWORD=foobar123
|
||||
- FLASK_CONFIG=testing
|
||||
ports:
|
||||
- 5000
|
||||
database:
|
||||
image: mysql
|
||||
environment:
|
||||
- MYSQL_ROOT_PASSWORD=foobar123
|
||||
- MYSQL_DATABASE=pitstops
|
||||
ports:
|
||||
- 3306
|
||||
- 5000:5000
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
FROM debian8_python3
|
||||
|
||||
COPY app/requirements.txt /requirements.txt
|
||||
RUN pip3 install -r /requirements.txt; \
|
||||
mkdir /data
|
||||
|
||||
ADD app /app
|
||||
|
||||
VOLUME ["/data"]
|
||||
VOLUME ["/app/config]
|
||||
EXPOSE 5000
|
||||
ENTRYPOINT python3 /app/main.py
|
|
@ -0,0 +1,137 @@
|
|||
import unittest
|
||||
import inspect
|
||||
from selenium import webdriver
|
||||
from selenium.webdriver.common.keys import Keys
|
||||
from selenium.webdriver.common.desired_capabilities import DesiredCapabilities
|
||||
from selenium.webdriver.common.by import By
|
||||
from selenium.webdriver.support.ui import WebDriverWait
|
||||
from selenium.webdriver.support import expected_conditions
|
||||
|
||||
|
||||
def wait_net_service(server, port, timeout=None):
|
||||
""" Wait for network service to appear
|
||||
@param timeout: in seconds, if None or 0 wait forever
|
||||
@return: True of False, if timeout is None may return only True or
|
||||
throw unhandled network exception
|
||||
"""
|
||||
import socket
|
||||
import errno
|
||||
|
||||
s = socket.socket()
|
||||
if timeout:
|
||||
from time import time as now
|
||||
# time module is needed to calc timeout shared between two exceptions
|
||||
end = now() + timeout
|
||||
|
||||
while True:
|
||||
try:
|
||||
if timeout:
|
||||
next_timeout = end - now()
|
||||
if next_timeout < 0:
|
||||
return False
|
||||
else:
|
||||
s.settimeout(next_timeout)
|
||||
|
||||
s.connect((server, port))
|
||||
|
||||
except socket.timeout as err:
|
||||
# this exception occurs only if timeout is set
|
||||
if timeout:
|
||||
return False
|
||||
|
||||
except socket.error as err:
|
||||
# catch timeout exception from underlying network library
|
||||
# this one is different from socket.timeout
|
||||
if type(err.args) != tuple or err[0] != errno.ETIMEDOUT:
|
||||
raise
|
||||
else:
|
||||
s.close()
|
||||
return True
|
||||
|
||||
|
||||
class BaseTestCase(unittest.TestCase):
|
||||
def setUp(self):
|
||||
self.screen_shot_counter = 0
|
||||
self.driver = webdriver.Remote(
|
||||
command_executor='http://selenium:4444/wd/hub',
|
||||
desired_capabilities=DesiredCapabilities.FIREFOX)
|
||||
self.driver.get("http://rollerverbrauch:5000")
|
||||
WebDriverWait(self.driver, 10).until(expected_conditions.presence_of_element_located((By.ID, "email")))
|
||||
|
||||
def create_screenshot(self):
|
||||
self.driver.get_screenshot_as_file(
|
||||
'/results/%s_%s_%s.png' % (self.__class__.__name__, inspect.stack()[1][3], str(self.screen_shot_counter)))
|
||||
self.screen_shot_counter += 1
|
||||
|
||||
def tearDown(self):
|
||||
self.driver.close()
|
||||
|
||||
|
||||
class RegisterCheck(BaseTestCase):
|
||||
def setUp(self):
|
||||
self.screen_shot_counter = 0
|
||||
self.driver = webdriver.Remote(
|
||||
command_executor='http://selenium:4444/wd/hub',
|
||||
desired_capabilities=DesiredCapabilities.FIREFOX)
|
||||
self.driver.get("http://rollerverbrauch:5000")
|
||||
WebDriverWait(self.driver, 10).until(expected_conditions.presence_of_element_located((By.ID, "email")))
|
||||
|
||||
def test_page_loads(self):
|
||||
self.driver.get("http://rollerverbrauch:5000")
|
||||
self.create_screenshot()
|
||||
self.assertIn("refuel", self.driver.title, "Title must contain reload")
|
||||
|
||||
def test_can_register(self):
|
||||
self.driver.get("http://rollerverbrauch:5000")
|
||||
self.driver.find_element_by_partial_link_text('Register').click()
|
||||
self.create_screenshot()
|
||||
WebDriverWait(self.driver, 10).until(expected_conditions.presence_of_element_located((By.ID, "submit")))
|
||||
self.create_screenshot()
|
||||
self.driver.find_element_by_id('email').send_keys('test@test.com')
|
||||
self.driver.find_element_by_id('password').send_keys('test123')
|
||||
self.driver.find_element_by_id('password_confirm').send_keys('test123')
|
||||
self.create_screenshot()
|
||||
self.driver.find_element_by_id('submit').click()
|
||||
WebDriverWait(self.driver, 10).until(expected_conditions.presence_of_element_located((By.ID, "i1")))
|
||||
self.create_screenshot()
|
||||
|
||||
def test_register_must_repeat_pwd(self):
|
||||
self.driver.get("http://rollerverbrauch:5000")
|
||||
self.driver.find_element_by_partial_link_text('Register').click()
|
||||
self.create_screenshot()
|
||||
WebDriverWait(self.driver, 10).until(expected_conditions.presence_of_element_located((By.ID, "submit")))
|
||||
self.create_screenshot()
|
||||
self.driver.find_element_by_id('email').send_keys('test1@test.com')
|
||||
self.driver.find_element_by_id('password').send_keys('test123')
|
||||
self.create_screenshot()
|
||||
self.driver.find_element_by_id('submit').click()
|
||||
self.create_screenshot()
|
||||
error = self.driver.find_elements_by_class_name('error')
|
||||
self.assertIsNotNone(error[0], 'we expect an error')
|
||||
self.assertIn('Passwords do not match', error[0].text, 'wrong error message')
|
||||
|
||||
def test_register_must_be_equal_pwd(self):
|
||||
self.driver.get("http://rollerverbrauch:5000")
|
||||
self.driver.find_element_by_partial_link_text('Register').click()
|
||||
self.create_screenshot()
|
||||
WebDriverWait(self.driver, 10).until(expected_conditions.presence_of_element_located((By.ID, "submit")))
|
||||
self.create_screenshot()
|
||||
self.driver.find_element_by_id('email').send_keys('test1@test.com')
|
||||
self.driver.find_element_by_id('password').send_keys('test123')
|
||||
self.driver.find_element_by_id('password_confirm').send_keys('test1234')
|
||||
self.create_screenshot()
|
||||
self.driver.find_element_by_id('submit').click()
|
||||
self.create_screenshot()
|
||||
error = self.driver.find_elements_by_class_name('error')
|
||||
self.assertIsNotNone(error[0], 'we expect an error')
|
||||
self.assertIn('Passwords do not match', error[0].text, 'wrong error message')
|
||||
|
||||
|
||||
class LoginCheck(BaseTestCase):
|
||||
|
||||
def can_login(self):
|
||||
pass
|
||||
|
||||
if __name__ == "__main__":
|
||||
wait_net_service('selenium', 4444)
|
||||
unittest.main()
|
|
@ -0,0 +1 @@
|
|||
selenium
|
|
@ -0,0 +1,16 @@
|
|||
import os
|
||||
|
||||
#SQLALCHEMY_DATABASE_URI = 'mysql+pymysql://root:%s@database/pitstops' % (os.environ['DATABASE_ENV_MYSQL_ROOT_PASSWORD'])
|
||||
SQLALCHEMY_DATABASE_URI = 'sqlite:////data/rollerverbrauch.db'
|
||||
|
||||
MAIL_SERVER = ''
|
||||
MAIL_PORT= 25
|
||||
MAIL_USE_TLS = True
|
||||
MAIL_USE_SSL = False
|
||||
MAIL_USERNAME = ''
|
||||
MAIL_PASSWORD = ''
|
||||
SECURITY_EMAIL_SENDER = ''
|
||||
SECURITY_PASSWORD_SALT = 'SecretSalt'
|
||||
SECRET_KEY = 'SecretKey'
|
||||
|
||||
SECURITY_SEND_REGISTER_EMAIL = False
|
|
@ -0,0 +1,22 @@
|
|||
version: '2'
|
||||
services:
|
||||
tests:
|
||||
build: .
|
||||
depends_on:
|
||||
- selenium
|
||||
volumes:
|
||||
- ./results:/results
|
||||
selenium:
|
||||
image: selenium/standalone-firefox
|
||||
depends_on:
|
||||
- rollerverbrauch
|
||||
rollerverbrauch:
|
||||
build: ..
|
||||
volumes:
|
||||
- ./compose_config/:/config
|
||||
environment:
|
||||
- config=/config/config.py
|
||||
- DATABASE_ENV_MYSQL_ROOT_PASSWORD=foobar123
|
||||
ports:
|
||||
- 5000
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
#!/bin/bash
|
||||
|
||||
rm -f results/*
|
||||
docker-compose build
|
||||
docker-compose up --abort-on-container-exit
|
||||
docker-compose down
|
||||
docker-compose rm --all
|
Loading…
Reference in New Issue