Add VCS import from Github

This commit is contained in:
rubenwardy 2018-05-11 15:04:17 +01:00
parent 5424f0aa34
commit 92717f31dd
No known key found for this signature in database
GPG Key ID: A1E29D52FF81513C
9 changed files with 158 additions and 63 deletions

View File

@ -322,6 +322,7 @@ class PackageRelease(db.Model):
releaseDate = db.Column(db.DateTime, nullable=False)
url = db.Column(db.String(100), nullable=False)
approved = db.Column(db.Boolean, nullable=False, default=False)
task_id = db.Column(db.String(32), nullable=True)
def getEditURL(self):

View File

@ -1,12 +1,18 @@
import flask
import flask, json
from flask.ext.sqlalchemy import SQLAlchemy
import urllib.request
from urllib.parse import urlparse
from urllib.parse import urlparse, quote_plus
from app import app
from app.models import *
from app.tasks import celery
class TaskError(Exception):
def __init__(self, value):
self.value = value
def __str__(self):
return repr(self.value)
class GithubURLMaker:
def __init__(self, url):
# Rewrite path
@ -18,6 +24,8 @@ class GithubURLMaker:
user = m.group(1)
repo = m.group(2)
self.baseUrl = "https://raw.githubusercontent.com/" + user + "/" + repo.replace(".git", "") + "/master"
self.user = user
self.repo = repo
def isValid(self):
return self.baseUrl is not None
@ -31,6 +39,13 @@ class GithubURLMaker:
def getScreenshotURL(self):
return self.baseUrl + "/screenshot.png"
def getCommitsURL(self, branch):
return "https://api.github.com/repos/" + self.user + "/" + self.repo + "/commits?sha" + urllib.parse.quote_plus(branch)
def getCommitDownload(self, commit):
return "https://github.com/" + self.user + "/" + self.repo + "/archive/" + commit + ".zip"
def parseConf(string):
retval = {}
for line in string.split("\n"):
@ -49,10 +64,11 @@ def getMeta(urlstr):
urlmaker = None
if url.netloc == "github.com":
urlmaker = GithubURLMaker(url)
else:
raise TaskError("Unsupported repo")
if not urlmaker.isValid():
print("Error! Url maker not valid")
return
raise TaskError("Error! Url maker not valid")
print(urlmaker.getModConfURL())
@ -79,3 +95,35 @@ def getMeta(urlstr):
print("description.txt does not exist!")
return result
@celery.task()
def makeVCSRelease(id, branch):
release = PackageRelease.query.get(id)
if release is None:
raise TaskError("No such release!")
if release.package is None:
raise TaskError("No package attached to release")
url = urlparse(release.package.repo)
urlmaker = None
if url.netloc == "github.com":
urlmaker = GithubURLMaker(url)
else:
raise TaskError("Unsupported repo")
if not urlmaker.isValid():
raise TaskError("Invalid github repo URL")
contents = urllib.request.urlopen(urlmaker.getCommitsURL(branch)).read().decode("utf-8")
commits = json.loads(contents)
if len(commits) == 0:
raise TaskError("No commits found")
release.url = urlmaker.getCommitDownload(commits[0]["sha"])
release.task_id = None
db.session.commit()
return release.url

View File

@ -7,6 +7,7 @@
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>{% block title %}title{% endblock %} - {{ config.USER_APP_NAME }}</title>
<link rel="stylesheet" type="text/css" href="/static/main.css">
{% block headextra %}{% endblock %}
</head>
<body>

View File

@ -78,25 +78,29 @@
<ul>
{% for rel in releases %}
<li>
{% if not rel.approved %}<i>{% endif %}
{% if rel.approved or package.checkPerm(current_user, "MAKE_RELEASE") or package.checkPerm(current_user, "APPROVE_RELEASE") %}
<li>
{% if not rel.approved %}<i>{% endif %}
<a href="{{ rel.url }}">{{ rel.title }}</a>,
created {{ rel.releaseDate }}.
{% if not rel.approved %}
Waiting for approval.
{% endif %}
{% if package.checkPerm(current_user, "MAKE_RELEASE") or package.checkPerm(current_user, "APPROVE_RELEASE") %}
<a href="{{ rel.getEditURL() }}">Edit
{% if not rel.approved and package.checkPerm(current_user, "APPROVE_RELEASE") %}
/ Approve
<a href="{{ rel.url }}">{{ rel.title }}</a>,
created {{ rel.releaseDate }}.
{% if rel.task_id %}
<a href="{{ url_for('check_task', id=rel.task_id, r=package.getDetailsURL()) }}">Importing</a>
{% elif not rel.approved %}
Waiting for approval.
{% endif %}
</a>
{% endif %}
{% if not rel.approved %}</i>{% endif %}
</li>
{% if not rel.task_id and (package.checkPerm(current_user, "MAKE_RELEASE") or package.checkPerm(current_user, "APPROVE_RELEASE")) %}
<a href="{{ rel.getEditURL() }}">Edit
{% if not rel.approved and package.checkPerm(current_user, "APPROVE_RELEASE") %}
/ Approve
{% endif %}
</a>
{% endif %}
{% if not rel.approved %}</i>{% endif %}
</li>
{% endif %}
{% else %}
<li>No releases available.</li>
{% endfor %}

View File

@ -0,0 +1,21 @@
{% extends "base.html" %}
{% block title %}
Working
{% endblock %}
{% block headextra %}
{% if not "error" in info %}
<meta http-equiv="refresh" content="1;URL=">
{% endif %}
{% endblock %}
{% block content %}
{% if "error" in info %}
<h1>Task Failed</h1>
<p>{{ info. error }}</p>
{% else %}
<h1>Working…</h1>
{% endif %}
{% endblock %}

View File

@ -30,4 +30,4 @@ def home_page():
packages = Package.query.filter_by(approved=True).all()
return render_template("index.html", packages=packages)
from . import users, githublogin, packages, sass, api
from . import users, githublogin, packages, sass, tasks

View File

@ -1,35 +0,0 @@
from flask import *
from flask_user import *
from flask.ext import menu
from app import app
from app.models import *
from app.tasks import celery
from app.tasks.importtasks import getMeta
# from celery.result import AsyncResult
from .utils import *
@app.route("/tasks/getmeta/new/")
def new_getmeta_page():
aresult = getMeta.delay(request.args.get("url"))
return jsonify({
"poll_url": url_for("check_task", id=aresult.id),
})
@app.route("/tasks/<id>/")
def check_task(id):
result = celery.AsyncResult(id)
status = result.status
traceback = result.traceback
result = result.result
if isinstance(result, Exception):
return jsonify({
'status': status,
'error': str(result),
# 'traceback': traceback,
})
else:
return jsonify({
'status': status,
'result': result,
})

View File

@ -3,6 +3,7 @@ from flask_user import *
from flask.ext import menu
from app import app
from app.models import *
from app.tasks.importtasks import makeVCSRelease
from .utils import *
@ -369,16 +370,17 @@ def create_release_page(type, author, name):
# Initial form class from post data and default data
form = CreatePackageReleaseForm()
if request.method == "POST" and form.validate():
for key, value in request.files.items() :
print (key, value)
if form["uploadOpt"].data == "vcs":
rel = PackageRelease()
rel.package = package
rel.title = form["title"].data
rel.url = form["vcsLabel"].data
# TODO: get URL to commit from branch name
rel.title = form["title"].data
rel.url = ""
db.session.commit()
return redirect(package.getDetailsURL())
rel.task_id = makeVCSRelease.delay(rel.id, form["vcsLabel"].data).id
db.session.commit()
return redirect(url_for("check_task", id=rel.task_id, r=package.getDetailsURL()))
else:
uploadedPath = doFileUpload(form.fileUpload.data, ["zip"], "a zip file")
if uploadedPath is not None:
@ -412,6 +414,9 @@ def edit_release_page(type, author, name, id):
if not (canEdit or canApprove):
return redirect(package.getDetailsURL())
if release.task_id is not None:
return redirect(url_for("check_task", id=release.task_id, r=release.getEditURL()))
# Initial form class from post data and default data
form = EditPackageReleaseForm(formdata=request.form, obj=release)
if request.method == "POST" and form.validate():

50
app/views/tasks.py Normal file
View File

@ -0,0 +1,50 @@
from flask import *
from flask_user import *
from flask.ext import menu
from app import app
from app.models import *
from app.tasks import celery
from app.tasks.importtasks import getMeta
from .utils import shouldReturnJson
# from celery.result import AsyncResult
from .utils import *
@app.route("/tasks/getmeta/new/")
def new_getmeta_page():
aresult = getMeta.delay(request.args.get("url"))
return jsonify({
"poll_url": url_for("check_task", id=aresult.id),
})
@app.route("/tasks/<id>/")
def check_task(id):
result = celery.AsyncResult(id)
status = result.status
traceback = result.traceback
result = result.result
info = None
if isinstance(result, Exception):
info = {
'status': status,
'error': str(result),
}
else:
info = {
'status': status,
'result': result,
}
if shouldReturnJson():
return jsonify(info)
else:
r = request.args.get("r")
if r is None:
abort(422)
if status == "SUCCESS":
flash("Task complete!", "success")
return redirect(r)
else:
return render_template("tasks/view.html", info=info)