mirror of
https://github.com/minetest/contentdb.git
synced 2025-01-03 11:47:28 +01:00
Add package update configuration for polling
This commit is contained in:
parent
7461acdd1f
commit
14a67b99ba
@ -24,7 +24,7 @@ from wtforms.ext.sqlalchemy.fields import QuerySelectField
|
|||||||
from wtforms.validators import *
|
from wtforms.validators import *
|
||||||
|
|
||||||
from app.rediscache import has_key, set_key, make_download_key
|
from app.rediscache import has_key, set_key, make_download_key
|
||||||
from app.tasks.importtasks import makeVCSRelease, checkZipRelease
|
from app.tasks.importtasks import makeVCSRelease, checkZipRelease, updateMetaFromRelease, check_for_updates
|
||||||
from app.utils import *
|
from app.utils import *
|
||||||
from . import bp
|
from . import bp
|
||||||
|
|
||||||
@ -247,3 +247,34 @@ def delete_release(package, id):
|
|||||||
db.session.commit()
|
db.session.commit()
|
||||||
|
|
||||||
return redirect(package.getDetailsURL())
|
return redirect(package.getDetailsURL())
|
||||||
|
|
||||||
|
|
||||||
|
class PackageUpdateConfigFrom(FlaskForm):
|
||||||
|
trigger = SelectField("Trigger", [InputRequired()], choices=PackageUpdateTrigger.choices(), coerce=PackageUpdateTrigger.coerce,
|
||||||
|
default=PackageUpdateTrigger.COMMIT)
|
||||||
|
make_release = BooleanField("Create Release")
|
||||||
|
submit = SubmitField("Save")
|
||||||
|
|
||||||
|
|
||||||
|
@bp.route("/packages/<author>/<name>/update-config/", methods=["GET", "POST"])
|
||||||
|
@login_required
|
||||||
|
@is_package_page
|
||||||
|
def update_config(package):
|
||||||
|
package.update_config = package.update_config or PackageUpdateConfig()
|
||||||
|
|
||||||
|
if not package.checkPerm(current_user, Permission.MAKE_RELEASE):
|
||||||
|
return redirect(package.getDetailsURL())
|
||||||
|
|
||||||
|
form = PackageUpdateConfigFrom(obj=package.update_config)
|
||||||
|
if form.validate_on_submit():
|
||||||
|
flash("Changed update configuration", "success")
|
||||||
|
form.populate_obj(package.update_config)
|
||||||
|
db.session.add(package.update_config)
|
||||||
|
|
||||||
|
check_for_updates.delay()
|
||||||
|
|
||||||
|
db.session.commit()
|
||||||
|
|
||||||
|
return redirect(package.getDetailsURL())
|
||||||
|
|
||||||
|
return render_template("packages/update_config.html", package=package, form=form)
|
||||||
|
@ -317,7 +317,7 @@ class Package(db.Model):
|
|||||||
maintainers = db.relationship("User", secondary=maintainers)
|
maintainers = db.relationship("User", secondary=maintainers)
|
||||||
|
|
||||||
threads = db.relationship("Thread", back_populates="package", order_by=db.desc("thread_created_at"),
|
threads = db.relationship("Thread", back_populates="package", order_by=db.desc("thread_created_at"),
|
||||||
foreign_keys="Thread.package_id", cascade="all, delete, delete-orphan")
|
foreign_keys="Thread.package_id", cascade="all, delete, delete-orphan", lazy="dynamic")
|
||||||
|
|
||||||
reviews = db.relationship("PackageReview", back_populates="package", order_by=db.desc("package_review_created_at"),
|
reviews = db.relationship("PackageReview", back_populates="package", order_by=db.desc("package_review_created_at"),
|
||||||
cascade="all, delete, delete-orphan")
|
cascade="all, delete, delete-orphan")
|
||||||
@ -331,6 +331,9 @@ class Package(db.Model):
|
|||||||
tokens = db.relationship("APIToken", foreign_keys="APIToken.package_id", back_populates="package",
|
tokens = db.relationship("APIToken", foreign_keys="APIToken.package_id", back_populates="package",
|
||||||
cascade="all, delete, delete-orphan")
|
cascade="all, delete, delete-orphan")
|
||||||
|
|
||||||
|
update_config = db.relationship("PackageUpdateConfig", uselist=False, back_populates="package",
|
||||||
|
cascade="all, delete, delete-orphan")
|
||||||
|
|
||||||
def __init__(self, package=None):
|
def __init__(self, package=None):
|
||||||
if package is None:
|
if package is None:
|
||||||
return
|
return
|
||||||
@ -507,6 +510,10 @@ class Package(db.Model):
|
|||||||
return url_for("packages.bulk_change_release",
|
return url_for("packages.bulk_change_release",
|
||||||
author=self.author.username, name=self.name)
|
author=self.author.username, name=self.name)
|
||||||
|
|
||||||
|
def getUpdateConfigURL(self):
|
||||||
|
return url_for("packages.update_config",
|
||||||
|
author=self.author.username, name=self.name)
|
||||||
|
|
||||||
def getDownloadURL(self):
|
def getDownloadURL(self):
|
||||||
return url_for("packages.download",
|
return url_for("packages.download",
|
||||||
author=self.author.username, name=self.name)
|
author=self.author.username, name=self.name)
|
||||||
@ -790,7 +797,7 @@ class PackageRelease(db.Model):
|
|||||||
|
|
||||||
title = db.Column(db.String(100), nullable=False)
|
title = db.Column(db.String(100), nullable=False)
|
||||||
releaseDate = db.Column(db.DateTime, nullable=False)
|
releaseDate = db.Column(db.DateTime, nullable=False)
|
||||||
url = db.Column(db.String(200), nullable=False)
|
url = db.Column(db.String(200), nullable=False, default="")
|
||||||
approved = db.Column(db.Boolean, nullable=False, default=False)
|
approved = db.Column(db.Boolean, nullable=False, default=False)
|
||||||
task_id = db.Column(db.String(37), nullable=True)
|
task_id = db.Column(db.String(37), nullable=True)
|
||||||
commit_hash = db.Column(db.String(41), nullable=True, default=None)
|
commit_hash = db.Column(db.String(41), nullable=True, default=None)
|
||||||
@ -903,3 +910,39 @@ class PackageScreenshot(db.Model):
|
|||||||
|
|
||||||
def getThumbnailURL(self, level=2):
|
def getThumbnailURL(self, level=2):
|
||||||
return self.url.replace("/uploads/", "/thumbnails/{:d}/".format(level))
|
return self.url.replace("/uploads/", "/thumbnails/{:d}/".format(level))
|
||||||
|
|
||||||
|
|
||||||
|
class PackageUpdateTrigger(enum.Enum):
|
||||||
|
COMMIT = "New Commit"
|
||||||
|
TAG = "New Tag"
|
||||||
|
|
||||||
|
def toName(self):
|
||||||
|
return self.name.lower()
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return self.name
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get(cls, name):
|
||||||
|
try:
|
||||||
|
return PackageUpdateTrigger[name.upper()]
|
||||||
|
except KeyError:
|
||||||
|
return None
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def choices(cls):
|
||||||
|
return [(choice, choice.value) for choice in cls]
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def coerce(cls, item):
|
||||||
|
return item if type(item) == PackageUpdateTrigger else PackageUpdateTrigger[item]
|
||||||
|
|
||||||
|
|
||||||
|
class PackageUpdateConfig(db.Model):
|
||||||
|
package_id = db.Column(db.Integer, db.ForeignKey("package.id"), primary_key=True)
|
||||||
|
package = db.relationship("Package", back_populates="update_config", foreign_keys=[package_id])
|
||||||
|
|
||||||
|
last_commit = db.Column(db.String(41), nullable=True, default=None)
|
||||||
|
|
||||||
|
trigger = db.Column(db.Enum(PackageUpdateTrigger), nullable=False, default=PackageUpdateTrigger.COMMIT)
|
||||||
|
make_release = db.Column(db.Boolean, nullable=False, default=False)
|
||||||
|
@ -56,7 +56,7 @@ class Thread(db.Model):
|
|||||||
watchers = db.relationship("User", secondary=watchers, backref="watching")
|
watchers = db.relationship("User", secondary=watchers, backref="watching")
|
||||||
|
|
||||||
def getViewURL(self):
|
def getViewURL(self):
|
||||||
return url_for("threads.view", id=self.id)
|
return url_for("threads.view", id=self.id, _external=False)
|
||||||
|
|
||||||
def getSubscribeURL(self):
|
def getSubscribeURL(self):
|
||||||
return url_for("threads.subscribe", id=self.id)
|
return url_for("threads.subscribe", id=self.id)
|
||||||
|
@ -32,8 +32,9 @@ class UserRank(enum.Enum):
|
|||||||
MEMBER = 3
|
MEMBER = 3
|
||||||
TRUSTED_MEMBER = 4
|
TRUSTED_MEMBER = 4
|
||||||
EDITOR = 5
|
EDITOR = 5
|
||||||
MODERATOR = 6
|
BOT = 6
|
||||||
ADMIN = 7
|
MODERATOR = 7
|
||||||
|
ADMIN = 8
|
||||||
|
|
||||||
def atLeast(self, min):
|
def atLeast(self, min):
|
||||||
return self.value >= min.value
|
return self.value >= min.value
|
||||||
@ -192,6 +193,8 @@ class User(db.Model, UserMixin):
|
|||||||
def getProfilePicURL(self):
|
def getProfilePicURL(self):
|
||||||
if self.profile_pic:
|
if self.profile_pic:
|
||||||
return self.profile_pic
|
return self.profile_pic
|
||||||
|
elif self.rank == UserRank.BOT:
|
||||||
|
return "/static/bot_avatar.png"
|
||||||
else:
|
else:
|
||||||
return gravatar(self.email or "")
|
return gravatar(self.email or "")
|
||||||
|
|
||||||
|
BIN
app/public/static/bot_avatar.png
Normal file
BIN
app/public/static/bot_avatar.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 2.1 KiB |
@ -26,4 +26,10 @@
|
|||||||
border-width: 14px;
|
border-width: 14px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.user-photo {
|
||||||
|
width: 60px;
|
||||||
|
height: 60px;
|
||||||
|
object-fit: cover;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -81,6 +81,10 @@
|
|||||||
color: #2c2 !important;
|
color: #2c2 !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.BOT a, .BOT {
|
||||||
|
color: #FFDF00 !important;
|
||||||
|
}
|
||||||
|
|
||||||
.wiptopic a:not(.btn) {
|
.wiptopic a:not(.btn) {
|
||||||
color: #7ac;
|
color: #7ac;
|
||||||
}
|
}
|
||||||
|
@ -73,6 +73,11 @@ CELERYBEAT_SCHEDULE = {
|
|||||||
'task': 'app.tasks.pkgtasks.updatePackageScores',
|
'task': 'app.tasks.pkgtasks.updatePackageScores',
|
||||||
'schedule': crontab(minute=10, hour=1),
|
'schedule': crontab(minute=10, hour=1),
|
||||||
},
|
},
|
||||||
|
|
||||||
|
'package_score_update': {
|
||||||
|
'task': 'app.tasks.importtasks.check_for_updates',
|
||||||
|
'schedule': crontab(minute=10, hour=1),
|
||||||
|
},
|
||||||
'send_pending_notifications': {
|
'send_pending_notifications': {
|
||||||
'task': 'app.tasks.emails.send_pending_notifications',
|
'task': 'app.tasks.emails.send_pending_notifications',
|
||||||
'schedule': crontab(minute='*/5'),
|
'schedule': crontab(minute='*/5'),
|
||||||
|
@ -22,9 +22,12 @@ from urllib.error import HTTPError
|
|||||||
import urllib.request
|
import urllib.request
|
||||||
from urllib.parse import urlsplit
|
from urllib.parse import urlsplit
|
||||||
from zipfile import ZipFile
|
from zipfile import ZipFile
|
||||||
|
|
||||||
|
from kombu import uuid
|
||||||
|
|
||||||
from app.models import *
|
from app.models import *
|
||||||
from app.tasks import celery, TaskError
|
from app.tasks import celery, TaskError
|
||||||
from app.utils import randomString, getExtension
|
from app.utils import randomString, getExtension, post_system_thread
|
||||||
from .minetestcheck import build_tree, MinetestCheckError, ContentType
|
from .minetestcheck import build_tree, MinetestCheckError, ContentType
|
||||||
|
|
||||||
|
|
||||||
@ -85,6 +88,40 @@ def clone_repo(urlstr, ref=None, recursive=False):
|
|||||||
.strip())
|
.strip())
|
||||||
|
|
||||||
|
|
||||||
|
def get_commit_hash(urlstr, ref=None):
|
||||||
|
gitDir = os.path.join(tempfile.gettempdir(), randomString(10))
|
||||||
|
|
||||||
|
err = None
|
||||||
|
try:
|
||||||
|
gitUrl = generateGitURL(urlstr)
|
||||||
|
print("Cloning from " + gitUrl)
|
||||||
|
|
||||||
|
assert ref != ""
|
||||||
|
|
||||||
|
repo = git.Repo.init(gitDir)
|
||||||
|
origin: git.Remote = repo.create_remote("origin", url=gitUrl)
|
||||||
|
assert origin.exists()
|
||||||
|
origin.fetch()
|
||||||
|
|
||||||
|
if ref:
|
||||||
|
ref: git.Reference = origin.refs[ref]
|
||||||
|
else:
|
||||||
|
ref: git.Reference = origin.refs[0]
|
||||||
|
|
||||||
|
return ref.commit.hexsha
|
||||||
|
|
||||||
|
except GitCommandError as e:
|
||||||
|
# This is needed to stop the backtrace being weird
|
||||||
|
err = e.stderr
|
||||||
|
|
||||||
|
except gitdb.exc.BadName as e:
|
||||||
|
err = "Unable to find the reference " + (ref or "?") + "\n" + e.stderr
|
||||||
|
|
||||||
|
raise TaskError(err.replace("stderr: ", "") \
|
||||||
|
.replace("Cloning into '" + gitDir + "'...", "") \
|
||||||
|
.strip())
|
||||||
|
|
||||||
|
|
||||||
@celery.task()
|
@celery.task()
|
||||||
def getMeta(urlstr, author):
|
def getMeta(urlstr, author):
|
||||||
with clone_repo(urlstr, recursive=True) as repo:
|
with clone_repo(urlstr, recursive=True) as repo:
|
||||||
@ -274,3 +311,50 @@ def importForeignDownloads(self, id):
|
|||||||
release.task_id = self.request.id
|
release.task_id = self.request.id
|
||||||
release.approved = False
|
release.approved = False
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
|
|
||||||
|
|
||||||
|
@celery.task
|
||||||
|
def check_update_config(package_id):
|
||||||
|
package: Package = Package.query.get(package_id)
|
||||||
|
if package is None:
|
||||||
|
raise TaskError("No such package!")
|
||||||
|
elif package.update_config is None:
|
||||||
|
raise TaskError("No update config attached to package")
|
||||||
|
|
||||||
|
config = package.update_config
|
||||||
|
ref = None
|
||||||
|
hash = get_commit_hash(package.repo, ref)
|
||||||
|
|
||||||
|
if config.last_commit != hash:
|
||||||
|
if config.make_release:
|
||||||
|
rel = PackageRelease()
|
||||||
|
rel.package = package
|
||||||
|
rel.title = hash[0:5]
|
||||||
|
rel.url = ""
|
||||||
|
rel.task_id = uuid()
|
||||||
|
db.session.add(rel)
|
||||||
|
db.session.commit()
|
||||||
|
|
||||||
|
makeVCSRelease.apply_async((rel.id, ref), task_id=rel.task_id)
|
||||||
|
|
||||||
|
else:
|
||||||
|
post_system_thread(package, "New commit detected, package outdated?",
|
||||||
|
"Commit {} was detected on the Git repository.\n\n[Change update configuration]({})" \
|
||||||
|
.format(hash[0:5], package.getUpdateConfigURL()))
|
||||||
|
|
||||||
|
config.last_commit = hash
|
||||||
|
db.session.commit()
|
||||||
|
|
||||||
|
|
||||||
|
@celery.task
|
||||||
|
def check_for_updates():
|
||||||
|
for update_config in PackageUpdateConfig.query.all():
|
||||||
|
update_config: PackageUpdateConfig
|
||||||
|
|
||||||
|
if update_config.package.repo is None:
|
||||||
|
db.session.delete(update_config)
|
||||||
|
continue
|
||||||
|
|
||||||
|
check_update_config.delay(update_config.package_id)
|
||||||
|
|
||||||
|
db.session.commit()
|
||||||
|
@ -11,10 +11,22 @@
|
|||||||
<div class="col pr-0">
|
<div class="col pr-0">
|
||||||
<div class="card">
|
<div class="card">
|
||||||
<div class="card-header">
|
<div class="card-header">
|
||||||
<a class="author {{ r.author.rank.name }}"
|
<a class="author {{ r.author.rank.name }} mr-3"
|
||||||
href="{{ url_for('users.profile', username=r.author.username) }}">
|
href="{{ url_for('users.profile', username=r.author.username) }}">
|
||||||
{{ r.author.display_name }}
|
{{ r.author.display_name }}
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
|
{% if r.author in thread.package.maintainers %}
|
||||||
|
<span class="badge badge-dark">
|
||||||
|
{{ _("Maintainer") }}
|
||||||
|
</span>
|
||||||
|
{% endif %}
|
||||||
|
{% if r.author.rank == r.author.rank.BOT %}
|
||||||
|
<span class="badge badge-dark">
|
||||||
|
{{ r.author.rank.getTitle() }}
|
||||||
|
</span>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
<a name="reply-{{ r.id }}" class="text-muted float-right"
|
<a name="reply-{{ r.id }}" class="text-muted float-right"
|
||||||
href="{{ url_for('threads.view', id=thread.id) }}#reply-{{ r.id }}">
|
href="{{ url_for('threads.view', id=thread.id) }}#reply-{{ r.id }}">
|
||||||
{{ r.created_at | datetime }}
|
{{ r.created_at | datetime }}
|
||||||
|
29
app/templates/packages/update_config.html
Normal file
29
app/templates/packages/update_config.html
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
{% extends "base.html" %}
|
||||||
|
|
||||||
|
{% block title %}
|
||||||
|
Configure Update Detection | {{ package.title }}
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<h1>{{ _("Configure Update Detection") }}</h1>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
{{ _("ContentDB will poll your Git repository at 2am UTC every day.") }}
|
||||||
|
{{ _("You should consider using webhooks or the API for faster rollouts.") }}
|
||||||
|
</p>
|
||||||
|
|
||||||
|
{% from "macros/forms.html" import render_field, render_submit_field, render_checkbox_field %}
|
||||||
|
<form method="POST" action="">
|
||||||
|
{{ form.hidden_tag() }}
|
||||||
|
|
||||||
|
<h3>Triggers</h3>
|
||||||
|
{{ render_field(form.trigger) }}
|
||||||
|
|
||||||
|
<h3 class="mt-5">Actions</h3>
|
||||||
|
{{ render_checkbox_field(form.make_release) }}
|
||||||
|
|
||||||
|
<p class="mt-5">
|
||||||
|
{{ render_submit_field(form.submit) }}
|
||||||
|
</p>
|
||||||
|
</form>
|
||||||
|
{% endblock %}
|
@ -38,6 +38,8 @@
|
|||||||
<i class="fas fa-user-shield mr-2"></i>
|
<i class="fas fa-user-shield mr-2"></i>
|
||||||
{% elif user.rank == user.rank.EDITOR %}
|
{% elif user.rank == user.rank.EDITOR %}
|
||||||
<i class="fas fa-user-edit mr-2"></i>
|
<i class="fas fa-user-edit mr-2"></i>
|
||||||
|
{% elif user.rank == user.rank.BOT %}
|
||||||
|
<i class="fas fa-robot mr-2"></i>
|
||||||
{% else %}
|
{% else %}
|
||||||
<i class="fas fa-user mr-2"></i>
|
<i class="fas fa-user mr-2"></i>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
@ -23,7 +23,7 @@
|
|||||||
</a>
|
</a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
<h1 class="ml-3 my-0">
|
<h1 class="ml-3 my-0 {{ user.rank.name }}">
|
||||||
{{ user.display_name }}
|
{{ user.display_name }}
|
||||||
</h1>
|
</h1>
|
||||||
|
|
||||||
|
27
app/utils.py
27
app/utils.py
@ -253,3 +253,30 @@ def nonEmptyOrNone(str):
|
|||||||
return None
|
return None
|
||||||
|
|
||||||
return str
|
return str
|
||||||
|
|
||||||
|
|
||||||
|
def post_system_thread(package: Package, title: str, message: str):
|
||||||
|
system_user = User.query.filter_by(username="ContentDB").first()
|
||||||
|
assert system_user
|
||||||
|
|
||||||
|
thread = package.threads.filter_by(author=system_user).first()
|
||||||
|
if not thread:
|
||||||
|
thread = Thread()
|
||||||
|
thread.package = package
|
||||||
|
thread.title = "System Notifications"
|
||||||
|
thread.author = system_user
|
||||||
|
thread.private = True
|
||||||
|
thread.watchers.append(package.author)
|
||||||
|
db.session.add(thread)
|
||||||
|
db.session.flush()
|
||||||
|
|
||||||
|
reply = ThreadReply()
|
||||||
|
reply.thread = thread
|
||||||
|
reply.author = system_user
|
||||||
|
reply.comment = "# {}\n\n{}".format(title, message)
|
||||||
|
db.session.add(reply)
|
||||||
|
|
||||||
|
addNotification(thread.watchers, system_user, NotificationType.THREAD_REPLY,
|
||||||
|
title, thread.getViewURL(), thread.package)
|
||||||
|
|
||||||
|
thread.replies.append(reply)
|
||||||
|
36
migrations/versions/105d4c740ad6_.py
Normal file
36
migrations/versions/105d4c740ad6_.py
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
"""empty message
|
||||||
|
|
||||||
|
Revision ID: 105d4c740ad6
|
||||||
|
Revises: 886c92dc6eaa
|
||||||
|
Create Date: 2020-12-15 17:28:56.559801
|
||||||
|
|
||||||
|
"""
|
||||||
|
from alembic import op
|
||||||
|
import sqlalchemy as sa
|
||||||
|
|
||||||
|
|
||||||
|
# revision identifiers, used by Alembic.
|
||||||
|
from sqlalchemy import orm
|
||||||
|
from app.models import User, UserRank
|
||||||
|
|
||||||
|
revision = '105d4c740ad6'
|
||||||
|
down_revision = '886c92dc6eaa'
|
||||||
|
branch_labels = None
|
||||||
|
depends_on = None
|
||||||
|
|
||||||
|
|
||||||
|
def upgrade():
|
||||||
|
op.execute("COMMIT")
|
||||||
|
op.execute("ALTER TYPE userrank ADD VALUE 'BOT' AFTER 'EDITOR'")
|
||||||
|
|
||||||
|
conn = op.get_bind()
|
||||||
|
system_user = User("ContentDB", active=False)
|
||||||
|
system_user.rank = UserRank.BOT
|
||||||
|
|
||||||
|
session = orm.Session(bind=conn)
|
||||||
|
session.add(system_user)
|
||||||
|
session.commit()
|
||||||
|
|
||||||
|
|
||||||
|
def downgrade():
|
||||||
|
pass
|
35
migrations/versions/886c92dc6eaa_.py
Normal file
35
migrations/versions/886c92dc6eaa_.py
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
"""empty message
|
||||||
|
|
||||||
|
Revision ID: 886c92dc6eaa
|
||||||
|
Revises: 8d22def23c8b
|
||||||
|
Create Date: 2020-12-15 16:38:54.114559
|
||||||
|
|
||||||
|
"""
|
||||||
|
from alembic import op
|
||||||
|
import sqlalchemy as sa
|
||||||
|
from sqlalchemy.dialects import postgresql
|
||||||
|
|
||||||
|
# revision identifiers, used by Alembic.
|
||||||
|
revision = '886c92dc6eaa'
|
||||||
|
down_revision = '8d22def23c8b'
|
||||||
|
branch_labels = None
|
||||||
|
depends_on = None
|
||||||
|
|
||||||
|
|
||||||
|
def upgrade():
|
||||||
|
# ### commands auto generated by Alembic - please adjust! ###
|
||||||
|
op.create_table('package_update_config',
|
||||||
|
sa.Column('package_id', sa.Integer(), nullable=False),
|
||||||
|
sa.Column('last_commit', sa.String(length=41), nullable=True),
|
||||||
|
sa.Column('trigger', sa.Enum('COMMIT', 'TAG', name='packageupdatetrigger'), nullable=False),
|
||||||
|
sa.Column('make_release', sa.Boolean(), nullable=False),
|
||||||
|
sa.ForeignKeyConstraint(['package_id'], ['package.id'], ),
|
||||||
|
sa.PrimaryKeyConstraint('package_id')
|
||||||
|
)
|
||||||
|
# ### end Alembic commands ###
|
||||||
|
|
||||||
|
|
||||||
|
def downgrade():
|
||||||
|
# ### commands auto generated by Alembic - please adjust! ###
|
||||||
|
op.drop_table('package_update_config')
|
||||||
|
# ### end Alembic commands ###
|
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
# Create a database migration, and copy it back to the host.
|
# Create a database migration, and copy it back to the host.
|
||||||
|
|
||||||
docker exec contentdb_app_1 sh -c "FLASK_CONFIG=../config.cfg FLASK_APP=app/__init__.py flask db migrate"
|
docker exec contentdb_app_1 sh -c "FLASK_CONFIG=../config.cfg FLASK_APP=app/__init__.py flask db revision"
|
||||||
docker exec -u root contentdb_app_1 sh -c "cp /home/cdb/migrations/versions/* /source/migrations/versions/"
|
docker exec -u root contentdb_app_1 sh -c "cp /home/cdb/migrations/versions/* /source/migrations/versions/"
|
||||||
|
|
||||||
USER=$(whoami)
|
USER=$(whoami)
|
||||||
|
Loading…
Reference in New Issue
Block a user