mirror of
https://github.com/YunoHost/tartiflette.git
synced 2024-09-03 20:06:08 +02:00
Port the pullrequest dashboard as well
This commit is contained in:
parent
7e14e5860f
commit
6970387bad
13 changed files with 337 additions and 55 deletions
20
app/app.py
20
app/app.py
|
@ -1,5 +1,6 @@
|
|||
from flask import render_template, Blueprint
|
||||
from .models import App, AppCI, AppCIBranch
|
||||
from .models.pr import PullRequest
|
||||
from .models.appci import App, AppCI, AppCIBranch
|
||||
from .settings import SITE_ROOT
|
||||
|
||||
main = Blueprint('main', __name__, url_prefix=SITE_ROOT)
|
||||
|
@ -21,6 +22,23 @@ def index():
|
|||
return render_template('index.html')
|
||||
|
||||
|
||||
@main.route('/pullrequests')
|
||||
def pullrequests():
|
||||
|
||||
prs = PullRequest.query.all()
|
||||
|
||||
prs = sorted(prs, key=lambda pr: (pr.review_priority, pr.created), reverse=True)
|
||||
|
||||
active_prs = [ pr for pr in prs if pr.review_priority >= 0]
|
||||
count_by_team = { "all": len(active_prs),
|
||||
"core": len([pr for pr in active_prs if pr.repo.team == "core"]),
|
||||
"apps": len([pr for pr in active_prs if pr.repo.team == "apps"]),
|
||||
"infra": len([pr for pr in active_prs if pr.repo.team == "infra"]),
|
||||
"doc": len([pr for pr in active_prs if pr.repo.team == "doc"]) }
|
||||
|
||||
return render_template("pullrequests.html", prs=prs, count_by_team=count_by_team)
|
||||
|
||||
|
||||
@main.route('/appci/branch/<branch>')
|
||||
def appci_branch(branch):
|
||||
|
||||
|
|
1
app/models/__init__.py
Normal file
1
app/models/__init__.py
Normal file
|
@ -0,0 +1 @@
|
|||
from . import appci, pr
|
|
@ -1,12 +1,10 @@
|
|||
import os
|
||||
import time
|
||||
import json
|
||||
import requests
|
||||
import dateutil.parser
|
||||
|
||||
from flask_sqlalchemy import SQLAlchemy
|
||||
from .. import db
|
||||
|
||||
from . import db
|
||||
|
||||
class AppList(db.Model):
|
||||
|
||||
|
@ -293,7 +291,7 @@ class Github():
|
|||
|
||||
def __init__(self):
|
||||
|
||||
from .settings import GITHUB_USER, GITHUB_TOKEN
|
||||
from ..settings import GITHUB_USER, GITHUB_TOKEN
|
||||
|
||||
self.user = GITHUB_USER
|
||||
self.token = GITHUB_TOKEN
|
133
app/models/pr.py
Normal file
133
app/models/pr.py
Normal file
|
@ -0,0 +1,133 @@
|
|||
import json
|
||||
import requests
|
||||
import datetime
|
||||
|
||||
from .. import db
|
||||
|
||||
|
||||
class Repo(db.Model):
|
||||
|
||||
id = db.Column(db.Integer, primary_key=True)
|
||||
|
||||
name = db.Column(db.String(64), unique=True, nullable=False)
|
||||
team = db.Column(db.String(64), nullable=False)
|
||||
|
||||
def __repr__(self):
|
||||
return '<Repo %r>' % self.name
|
||||
|
||||
def init():
|
||||
|
||||
d = {
|
||||
"core": ["yunohost",
|
||||
"yunohost-admin",
|
||||
"SSOwat",
|
||||
"moulinette",
|
||||
"Vagrantfile",
|
||||
"ynh-dev"],
|
||||
|
||||
"doc": ["doc",
|
||||
"Simone",
|
||||
"project-organization"],
|
||||
|
||||
"apps": ["apps",
|
||||
"CI_package_check",
|
||||
"example_ynh",
|
||||
"package_linter",
|
||||
"package_check"],
|
||||
|
||||
"infra": ["build.yunohost.org",
|
||||
"dynette",
|
||||
"YunoPorts",
|
||||
"cd_build",
|
||||
"install_script",
|
||||
"trotinette",
|
||||
"bicyclette",
|
||||
"install-app",
|
||||
"tartiflette",
|
||||
"vinaigrette"]
|
||||
}
|
||||
|
||||
for team, repos in d.items():
|
||||
for repo in repos:
|
||||
yield Repo(name=repo, team=team)
|
||||
|
||||
def update(self):
|
||||
|
||||
print("Updating PRs for repo %s ..." % self.name)
|
||||
|
||||
PullRequest.query.filter_by(repo=self).delete()
|
||||
|
||||
issues = requests.get("https://api.github.com/repos/yunohost/%s/issues?per_page=100" % self.name)
|
||||
issues = json.loads(issues.text)
|
||||
issues = [i for i in issues if "pull_request" in i.keys()]
|
||||
|
||||
for issue in issues:
|
||||
print(" > Analyzing %s-%s" % (self.name, issue["number"]))
|
||||
db.session.add(PullRequest(self, issue))
|
||||
|
||||
db.session.commit()
|
||||
|
||||
|
||||
class PullRequest(db.Model):
|
||||
|
||||
id = db.Column(db.Integer, primary_key=True)
|
||||
|
||||
id_ = db.Column(db.String(64), unique=True, nullable=False)
|
||||
title = db.Column(db.String(256), nullable=False)
|
||||
labels = db.Column(db.PickleType)
|
||||
url = db.Column(db.String(128), nullable=False)
|
||||
milestone = db.Column(db.String(32), nullable=False)
|
||||
|
||||
review_priority = db.Column(db.Integer)
|
||||
|
||||
created = db.Column(db.DateTime)
|
||||
updated = db.Column(db.DateTime)
|
||||
|
||||
repo = db.relationship(Repo, backref='prs', lazy=True, uselist=False)
|
||||
repo_id = db.Column(db.ForeignKey(Repo.id))
|
||||
|
||||
def __init__(self, repo, issue):
|
||||
|
||||
self.repo = repo
|
||||
self.title = issue["title"]
|
||||
self.labels = [label["name"] for label in issue["labels"]]
|
||||
self.milestone = issue["milestone"]["title"] if issue["milestone"] else ""
|
||||
|
||||
self.id_ = "%s-%s" % (repo.name, issue["number"])
|
||||
|
||||
self.created = datetime.datetime.strptime(issue["created_at"], "%Y-%m-%dT%H:%M:%SZ")
|
||||
self.updated = datetime.datetime.strptime(issue["updated_at"], "%Y-%m-%dT%H:%M:%SZ")
|
||||
self.url = issue["pull_request"]["html_url"]
|
||||
|
||||
for size in ["small", "medium", "big"]:
|
||||
if "%s decision" % size in self.labels:
|
||||
self.labels.remove("%s decision" % size)
|
||||
self.labels.insert(0, size)
|
||||
|
||||
now = datetime.datetime.now()
|
||||
if (now - self.created).days > 60 and (now - self.updated).days > 30:
|
||||
self.labels.append("dying")
|
||||
|
||||
self.review_priority = self.get_review_priority()
|
||||
|
||||
def get_review_priority(self):
|
||||
if "important" in self.labels:
|
||||
base_priority = 100
|
||||
elif "opinion needed" in self.labels:
|
||||
base_priority = 50
|
||||
elif "postponed" in self.labels or "inactive" in self.labels:
|
||||
base_priority = -100
|
||||
else:
|
||||
base_priority = 0
|
||||
|
||||
if "work needed" in self.labels:
|
||||
base_priority += -5
|
||||
|
||||
if "dying" in self.labels and base_priority > -100:
|
||||
base_priority += 5
|
||||
|
||||
return base_priority
|
||||
|
||||
def init():
|
||||
pass
|
||||
|
15
app/static/css/bootstrap.min.css
vendored
15
app/static/css/bootstrap.min.css
vendored
File diff suppressed because one or more lines are too long
|
@ -8,15 +8,11 @@
|
|||
margin-top:4em;
|
||||
}
|
||||
|
||||
#app-ci-test-results
|
||||
{
|
||||
margin-left:auto;
|
||||
margin-right:auto;
|
||||
/*width:1000px;*/
|
||||
}
|
||||
a { color:#007bff; }
|
||||
|
||||
table, thead, tbody { display: block; width: 100%;}
|
||||
table.ci-app { margin: 0 auto; margin-top: 100px; max-width: 1070px; overflow-x: visible; }
|
||||
.ci-app-table > thead, .ci-app-table > tbody { display: block; width: 100%;}
|
||||
.ci-app-table { margin: 0 auto; margin-top: 100px; max-width: 1070px; overflow-x: visible; }
|
||||
.ci-app-table th, .ci-app-table td { display: block; border: none; padding; 0px;float: left; height:33px; width: 33px; margin: 5px; }
|
||||
|
||||
th.ci-app-test-title
|
||||
{
|
||||
|
@ -40,24 +36,32 @@ th.ci-app-test-title > div > span
|
|||
border:none;
|
||||
}
|
||||
|
||||
|
||||
th, td { display: block; border: none; padding; 0px;float: left; height:33px; width: 33px; margin: 5px; }
|
||||
|
||||
.ci-app-row-title { text-align: center; width:150px; }
|
||||
td.ci-app-test-result { text-align:center; padding: 14px 8px 8px 8px; }
|
||||
td.ci-app-test-result > div { position:relative; background-color: #bdc3c7; border-radius:5px; width: 18px; height: 18px;}
|
||||
td.ci-app-test-result > div.success { background-color: rgb(46,204,83); }
|
||||
td.ci-app-test-result > div.danger { background-color: rgb(225,80,62); }
|
||||
|
||||
.table > thead > tr > th { border : none; }
|
||||
.table > tbody > tr > td { border : none; }
|
||||
.ci-app-table > thead > tr > th { border : none; }
|
||||
.ci-app-table > tbody > tr > td { border : none; }
|
||||
.ci-app-table .ci-app-row-title { text-align: center; width:150px; }
|
||||
.ci-app-table .ci-app-test-info { width:150px; font-size: 12px; }
|
||||
|
||||
.canvasjs-chart-credit { display: none; }
|
||||
|
||||
.ci-app-test-info { width:150px; font-size: 12px; }
|
||||
.daysAgo a { color: #777; }
|
||||
.official-star { color: #f0ad4e; }
|
||||
.level-improvement { color: #2d2; }
|
||||
.level-regression { color: #f22; }
|
||||
.level-unknown { color: #aaa; }
|
||||
.text-warning { color: #f0ad0e !important; }
|
||||
|
||||
.table th { border-top: none; }
|
||||
|
||||
.table-pullrequests { width: 1250px; font-family: sans-serif; border: none; }
|
||||
|
||||
.column-pr-title {
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
max-width:400px;
|
||||
}
|
||||
|
|
|
@ -2,21 +2,18 @@
|
|||
function daysAgo(timestamp) {
|
||||
var difference = Math.round(+new Date()/1000) - timestamp;
|
||||
var daysDifference = Math.round(difference/60/60/24);
|
||||
//return (new Date(timestamp*1000));
|
||||
return "(" + daysDifference + " days ago)";
|
||||
}
|
||||
|
||||
$(".daysAgo").each(function () {
|
||||
var t = $(this).attr("timestamp");
|
||||
var console = $(this).attr("console");
|
||||
var href = $(this).attr("href");
|
||||
if (t) {
|
||||
link = document.createElement('a');
|
||||
link.setAttribute('href', console);
|
||||
link.setAttribute('href', href);
|
||||
link.innerHTML = daysAgo(t);
|
||||
this.appendChild(link);
|
||||
}
|
||||
// $(this).text(daysAgo(t));
|
||||
//}
|
||||
});
|
||||
|
||||
$(".ci-app-test-result div[value=True]").addClass("success")
|
||||
|
|
|
@ -1,15 +1,15 @@
|
|||
{% extends "base.html" %}
|
||||
{% block content %}
|
||||
|
||||
<h2 class="text-center">{{ app.name.title() }}</h2>
|
||||
<h2 class="text-center my-3">{{ app.name.title() }}</h2>
|
||||
|
||||
<div class="row">
|
||||
<div id="app-ci-test-results">
|
||||
<div class="mx-auto">
|
||||
<div>
|
||||
<table class="table table-responsive ci-app">
|
||||
<table class="table table-responsive ci-app-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="ci-app-row-title"><div></div></th>
|
||||
<th class="ci-app-row-title"></th>
|
||||
<th class="ci-app-test-title"><div>Level</div></th>
|
||||
{% for test in tests %}
|
||||
<th class="ci-app-test-title"><div><span>{{ test }}</span></div></th>
|
||||
|
@ -36,9 +36,9 @@
|
|||
{% endfor %}
|
||||
<td class="ci-app-test-info">
|
||||
{% if result.date == None %}
|
||||
<span class="daysAgo" console="{{ result.url }}">???</span>
|
||||
<span class="daysAgo" href="{{ result.url }}">???</span>
|
||||
{% else %}
|
||||
<span class="daysAgo" timestamp="{{ result.date.timestamp() }}" console="{{ result.url }}"></span>
|
||||
<span class="daysAgo" timestamp="{{ result.date.timestamp() }}" href="{{ result.url }}"></span>
|
||||
{% endif %}
|
||||
{% if result.commit != result.app.master_commit %}
|
||||
<span class="oi oi-clock text-warning"
|
||||
|
|
|
@ -1,16 +1,16 @@
|
|||
{% extends "base.html" %}
|
||||
{% block content %}
|
||||
|
||||
<h2 class="text-center">{{ branch.display_name }}</h2>
|
||||
<div id="levelSummary" style="height: 270px;" class="col-sm-6 offset-sm-3"></div>
|
||||
<h2 class="text-center my-3">{{ branch.display_name }}</h2>
|
||||
<div id="levelSummary" style="height: 270px;" class="col-sm-6 offset-sm-3 my-3"></div>
|
||||
|
||||
<div class="row">
|
||||
<div id="app-ci-test-results">
|
||||
<div class="mx-auto">
|
||||
<div>
|
||||
<table class="table table-responsive ci-app">
|
||||
<table class="table table-responsive ci-app-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="ci-app-row-title"><div></div></th>
|
||||
<th class="ci-app-row-title"></th>
|
||||
<th class="ci-app-test-title"><div>Level</div></th>
|
||||
{% for test in tests %}
|
||||
<th class="ci-app-test-title"><div><span>{{ test }}</span></div></th>
|
||||
|
@ -40,9 +40,9 @@
|
|||
{% endfor %}
|
||||
<td class="ci-app-test-info">
|
||||
{% if result.date == None %}
|
||||
<span class="daysAgo" console="{{ result.url }}">???</span>
|
||||
<span class="daysAgo" href="{{ result.url }}">???</span>
|
||||
{% else %}
|
||||
<span class="daysAgo" timestamp="{{ result.date.timestamp() }}" console="{{ result.url }}"></span>
|
||||
<span class="daysAgo" timestamp="{{ result.date.timestamp() }}" href="{{ result.url }}"></span>
|
||||
{% endif %}
|
||||
{% if result.commit != result.app.master_commit %}
|
||||
<span class="oi oi-clock text-warning"
|
||||
|
|
|
@ -1,15 +1,15 @@
|
|||
{% extends "base.html" %}
|
||||
{% block content %}
|
||||
|
||||
<h2 class="text-center">{{ ref.display_name }} vs. {{ target.display_name }}</h2>
|
||||
<h2 class="text-center my-3">{{ ref.display_name }} vs. {{ target.display_name }}</h2>
|
||||
|
||||
<div class="row">
|
||||
<div id="app-ci-test-results">
|
||||
<div class="mx-auto">
|
||||
<div>
|
||||
<table class="table table-responsive ci-app">
|
||||
<table class="table table-responsive ci-app-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="ci-app-row-title"><div></div></th>
|
||||
<th class="ci-app-row-title"></th>
|
||||
<th class="ci-app-test-title"><div>{{ ref.display_name }} </div></th>
|
||||
<th class="ci-app-test-title"><div>{{ target.display_name }} </div></th>
|
||||
<th class="ci-app-test-title"></th>
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
</head>
|
||||
<body>
|
||||
|
||||
<nav class="navbar navbar-expand-lg navbar-dark bg-dark">
|
||||
<nav class="navbar navbar-expand-lg navbar-dark bg-primary">
|
||||
<a class="navbar-brand" href="#">YunoHost Dev Dashboard</a>
|
||||
<button class="navbar-toggler" type="button" data-toggle="collapse"
|
||||
data-target="#navbarColor01">
|
||||
|
|
107
app/templates/pullrequests.html
Normal file
107
app/templates/pullrequests.html
Normal file
|
@ -0,0 +1,107 @@
|
|||
{% extends "base.html" %}
|
||||
{% block content %}
|
||||
|
||||
|
||||
<h3 class="text-center my-5">What should you review today ?</h3>
|
||||
|
||||
<div class="row">
|
||||
|
||||
<div class="mx-auto mb-5">
|
||||
<ul id="select-team" class="nav nav-pills">
|
||||
<li class="nav-item">
|
||||
<a id="select-team-all" class="nav-link active" href="javascript:void(0)" onclick="filter('')">All <span class="badge badge-secondary badge-pill">{{ count_by_team["all"] }}</span></a>
|
||||
</li>
|
||||
<li class="nav-item"><a id="select-team-core" class="nav-link" href="javascript:void(0)" onclick="filter('team-core')">Core <span class="badge badge-secondary badge-pill">{{ count_by_team["core"] }}</span></a></li>
|
||||
<li class="nav-item"><a id="select-team-apps" class="nav-link" href="javascript:void(0)" onclick="filter('team-apps')">Apps <span class="badge badge-secondary badge-pill">{{ count_by_team["apps"] }}</span></a/li>
|
||||
<li class="nav-item"><a id="select-team-infra" class="nav-link" href="javascript:void(0)" onclick="filter('team-infra')">Infra / dist <span class="badge badge-secondary badge-pill">{{ count_by_team["infra"] }}</span></a></li>
|
||||
<li class="nav-item"><a id="select-team-doc" class="nav-link" href="javascript:void(0)" onclick="filter('team-doc')">Doc <span class="badge badge-secondary badge-pill">{{ count_by_team["doc"] }}</span></a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="mx-auto">
|
||||
<table id="pullrequests" class="table table-responsive table-sm table-pullrequests">
|
||||
<thead>
|
||||
<tr>
|
||||
<th></th>
|
||||
<th>Title</th>
|
||||
<th>Created</th>
|
||||
<th>Labels</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for pr in prs %}
|
||||
<tr class="team-{{ pr.repo.team }}">
|
||||
<td class="col-md-2 text-center">
|
||||
<a class="btn btn-sm mx-4 py-2 px-3
|
||||
{% if pr.review_priority >= 90 %}btn-warning{% else %}
|
||||
{% if pr.review_priority >= 40 %}btn-success{% else %}
|
||||
{% if pr.review_priority >= -10 %}btn-info{% else %}
|
||||
{% if pr.review_priority >= -60 %}btn-secondary{% else %}
|
||||
btn-link{% endif %}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% endif %} text-uppercase font-weight-bold"
|
||||
href="{{ pr.url }}">{{ pr.id_ }}</a>
|
||||
</td>
|
||||
<td class="column-pr-title font-weight-bold"><strong>{{ pr.title }}</strong></td>
|
||||
<td class="col-md-1 daysAgo" timestamp="{{ pr.created.timestamp() }}"
|
||||
style="font-size: 12px;" ></td>
|
||||
<td class="col-md-4">
|
||||
{% for label in pr.labels %}
|
||||
<span class="badge ml-1
|
||||
{% if label == "important" %}badge-danger{%else%}
|
||||
{% if label == "opinion needed" %}badge-warning{%else%}
|
||||
{% if label == "small" %}badge-info{%else%}
|
||||
{% if label == "medium" %}badge-info{%else%}
|
||||
{% if label == "big" %}badge-info{%else%}
|
||||
{% if label == "ready to merge" %}badge-success{%else%}
|
||||
{% if label == "work needed" %}badge-primary{%else%}
|
||||
{% if label == "inactive" %}badge-secondary{%else%}
|
||||
{% if label == "postponed" %}badge-secondary{%else%}
|
||||
{% if label == "dying" %}badge-danger{%else%}
|
||||
badge-secondary
|
||||
{%endif%}{%endif%}{%endif%}{%endif%}{%endif%}{%endif%}{%endif%}{%endif%}{%endif%}{%endif%}
|
||||
">{{ label }}</span>
|
||||
{% endfor %}
|
||||
</td>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<script>
|
||||
function filter(team) {
|
||||
// Declare variables
|
||||
var input, filter, table, tr, td, i;
|
||||
table = document.getElementById("pullrequests");
|
||||
tr = table.getElementsByTagName("tr");
|
||||
// Loop through all table rows, and hide those who don't match the search query
|
||||
for (i = 0; i < tr.length; i++)
|
||||
{
|
||||
if (team == '') { tr[i].style.display = ""; }
|
||||
else if (tr[i].classList == "") { tr[i].style.display = ""; }
|
||||
else if (tr[i].classList.contains(team)) { tr[i].style.display = ""; }
|
||||
else { tr[i].style.display = "none"; }
|
||||
}
|
||||
selector = document.getElementById("select-team");
|
||||
a = selector.getElementsByTagName("a");
|
||||
if (team == "") { team = "team-all"; }
|
||||
for (i = 0; i < a.length; i++)
|
||||
{
|
||||
if (a[i].getAttribute("id") == "select-".concat(team))
|
||||
{
|
||||
a[i].classList.add("active");
|
||||
}
|
||||
else
|
||||
{
|
||||
a[i].classList.remove("active");
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
{% endblock %}
|
33
manage.py
33
manage.py
|
@ -5,23 +5,34 @@ from app import db, create_app
|
|||
|
||||
app = create_app()
|
||||
|
||||
|
||||
def main():
|
||||
manager = Manager(app)
|
||||
manager.add_command('shell', Shell(make_context=lambda:{"app":app, "db":db}))
|
||||
manager.add_command('nuke', Nuke(db))
|
||||
manager.add_command('init', Init(db))
|
||||
manager.add_command('update', Update(db))
|
||||
manager.add_command('update-appci', Update(db, "appci"))
|
||||
manager.add_command('update-pr', Update(db, "pr"))
|
||||
manager.run()
|
||||
|
||||
|
||||
class Update(Command):
|
||||
|
||||
def __init__(self, db):
|
||||
def __init__(self, db, what):
|
||||
self.db = db
|
||||
self.what = what
|
||||
|
||||
def run(self):
|
||||
|
||||
from app.models import AppCI
|
||||
AppCI.update()
|
||||
if self.what == "appci":
|
||||
from app.models.appci import AppCI
|
||||
AppCI.update()
|
||||
elif self.what == "pr":
|
||||
from app.models.pr import Repo
|
||||
for repo in Repo.query.all():
|
||||
repo.update()
|
||||
else:
|
||||
pass
|
||||
|
||||
|
||||
class Nuke(Command):
|
||||
|
@ -32,7 +43,9 @@ class Nuke(Command):
|
|||
|
||||
def run(self):
|
||||
|
||||
import app.models
|
||||
import app.models.appci
|
||||
import app.models.pr
|
||||
|
||||
print("> Droping tables...")
|
||||
self.db.drop_all()
|
||||
print("> Creating tables...")
|
||||
|
@ -40,6 +53,7 @@ class Nuke(Command):
|
|||
print("> Comitting sessions...")
|
||||
self.db.session.commit()
|
||||
|
||||
|
||||
class Init(Command):
|
||||
|
||||
def __init__(self, db):
|
||||
|
@ -48,8 +62,12 @@ class Init(Command):
|
|||
def run(self):
|
||||
import app.models
|
||||
|
||||
stuff_in_module = [ app.models.__dict__.get(s) for s in dir(app.models) ]
|
||||
models = [ m for m in stuff_in_module if isinstance(m, type(db.Model)) ]
|
||||
# Black magic to extract list of models from 'models' folder
|
||||
submodules = [ app.models.__dict__.get(m) for m in dir(app.models) if not m.startswith('__') ]
|
||||
stuff = []
|
||||
for submodule in submodules:
|
||||
stuff.extend([submodule.__dict__.get(s) for s in dir(submodule)])
|
||||
models = [s for s in stuff if isinstance(s, type(db.Model))]
|
||||
|
||||
for model in models:
|
||||
objs = model.init()
|
||||
|
@ -59,5 +77,6 @@ class Init(Command):
|
|||
db.session.add(obj)
|
||||
db.session.commit()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
|
|
Loading…
Add table
Reference in a new issue