Extend documentation
This commit is contained in:
parent
0e555d9e8a
commit
f356b1e65f
9 changed files with 160 additions and 98 deletions
63
doc/notes.md
63
doc/notes.md
|
@ -1,63 +0,0 @@
|
|||
# Programmieren [1,2] Gitlab
|
||||
|
||||
- https://docs.gitlab.com/omnibus/README.html
|
||||
|
||||
## Authentication
|
||||
|
||||
- use GITZ LDAP for login
|
||||
- not allow "create new repo"
|
||||
|
||||
|
||||
## Structure
|
||||
|
||||
- main repo
|
||||
+ publish example solutions
|
||||
+ CI config for checkstyle
|
||||
+ Protected Runner for JPlag
|
||||
+ restrict access to branches with example solutions
|
||||
|
||||
- student repos
|
||||
+ forked from main repo
|
||||
+ one repo per student
|
||||
+ student has *Developer* Access
|
||||
+ *tutors* group has *Master* access
|
||||
+ students can request access (Abgabepartner)
|
||||
+ *tutors* can grant access
|
||||
|
||||
## Checkstyle
|
||||
|
||||
- GitLab CI
|
||||
- [Docker](https://docs.gitlab.com/omnibus/docker/README.html)container
|
||||
- [Shared Runner](https://docs.gitlab.com/ce/ci/runners/README.html)
|
||||
- restrict Container to [checkstyle](http://checkstyle.sourceforge.net/)
|
||||
- disable internet access for container
|
||||
|
||||
## JPlag
|
||||
|
||||
- Deadline [at,cron]job or schedule via gitlab
|
||||
- triggers [Protected Runner](https://docs.gitlab.com/ee/ci/runners/README.html#protected-runners)
|
||||
- creates automatic protected TAG in each repo
|
||||
- checks out TAG from all repos into /tmp and runs [JPlag](https://jplag.ipd.kit.edu/)
|
||||
- replace with MOSS? https://github.com/soachishti/moss.py
|
||||
- deploy key in each repo
|
||||
|
||||
## (optional) sync script
|
||||
|
||||
- (one-way) sync students and groups from [Stud.IP REST API](http://docs.studip.de/develop/Entwickler/RESTAPI) to [Gitlab REST API](https://docs.gitlab.com/ce/api/)
|
||||
|
||||
# Replicate (TODO: ansible playbook)
|
||||
|
||||
- install gitlab
|
||||
- install docker
|
||||
- copy gitlab.rb
|
||||
- partially protected
|
||||
- default project limit = 0
|
||||
- shared runner for checkstyle
|
||||
|
||||
- protected runner for
|
||||
|
||||
+ setting protected tags
|
||||
+ running jplag
|
||||
|
||||
- script for creating repos and groups
|
||||
- SSH deploy key
|
|
@ -4,9 +4,8 @@
|
|||
# You can set these variables from the command line.
|
||||
SPHINXOPTS =
|
||||
SPHINXBUILD = sphinx-build
|
||||
SPHINXPROJ = abgabesystem
|
||||
SOURCEDIR = .
|
||||
BUILDDIR = _build
|
||||
SOURCEDIR = source
|
||||
BUILDDIR = build
|
||||
|
||||
# Put it first so that "make" without argument is like "make help".
|
||||
help:
|
|
@ -7,9 +7,8 @@ REM Command file for Sphinx documentation
|
|||
if "%SPHINXBUILD%" == "" (
|
||||
set SPHINXBUILD=sphinx-build
|
||||
)
|
||||
set SOURCEDIR=.
|
||||
set BUILDDIR=_build
|
||||
set SPHINXPROJ=abgabesystem
|
||||
set SOURCEDIR=source
|
||||
set BUILDDIR=build
|
||||
|
||||
if "%1" == "" goto help
|
||||
|
|
@ -12,9 +12,9 @@
|
|||
# add these directories to sys.path here. If the directory is relative to the
|
||||
# documentation root, use os.path.abspath to make it absolute, like shown here.
|
||||
#
|
||||
import os
|
||||
import sys
|
||||
sys.path.insert(0, os.path.abspath('../src'))
|
||||
# import os
|
||||
# import sys
|
||||
# sys.path.insert(0, os.path.abspath('.'))
|
||||
|
||||
|
||||
# -- Project information -----------------------------------------------------
|
||||
|
@ -26,7 +26,7 @@ author = 'Tim Schubert'
|
|||
# The short X.Y version
|
||||
version = ''
|
||||
# The full version, including alpha/beta/rc tags
|
||||
release = ''
|
||||
release = '1.0'
|
||||
|
||||
|
||||
# -- General configuration ---------------------------------------------------
|
||||
|
@ -42,7 +42,10 @@ extensions = [
|
|||
'sphinx.ext.autodoc',
|
||||
'sphinx.ext.doctest',
|
||||
'sphinx.ext.intersphinx',
|
||||
'sphinx.ext.todo',
|
||||
'sphinx.ext.coverage',
|
||||
'sphinx.ext.viewcode',
|
||||
'sphinx.ext.githubpages',
|
||||
]
|
||||
|
||||
# Add any paths that contain templates here, relative to this directory.
|
||||
|
@ -66,11 +69,11 @@ language = None
|
|||
|
||||
# List of patterns, relative to source directory, that match files and
|
||||
# directories to ignore when looking for source files.
|
||||
# This pattern also affects html_static_path and html_extra_path .
|
||||
exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store']
|
||||
# This pattern also affects html_static_path and html_extra_path.
|
||||
exclude_patterns = []
|
||||
|
||||
# The name of the Pygments (syntax highlighting) style to use.
|
||||
pygments_style = 'sphinx'
|
||||
pygments_style = None
|
||||
|
||||
|
||||
# -- Options for HTML output -------------------------------------------------
|
||||
|
@ -159,9 +162,32 @@ texinfo_documents = [
|
|||
]
|
||||
|
||||
|
||||
# -- Options for Epub output -------------------------------------------------
|
||||
|
||||
# Bibliographic Dublin Core info.
|
||||
epub_title = project
|
||||
|
||||
# The unique identifier of the text. This can be a ISBN number
|
||||
# or the project homepage.
|
||||
#
|
||||
# epub_identifier = ''
|
||||
|
||||
# A unique identification for the text.
|
||||
#
|
||||
# epub_uid = ''
|
||||
|
||||
# A list of files that should not be packed into the epub file.
|
||||
epub_exclude_files = ['search.html']
|
||||
|
||||
|
||||
# -- Extension configuration -------------------------------------------------
|
||||
|
||||
# -- Options for intersphinx extension ---------------------------------------
|
||||
|
||||
# Example configuration for intersphinx: refer to the Python standard library.
|
||||
intersphinx_mapping = {'https://docs.python.org/': None}
|
||||
|
||||
# -- Options for todo extension ----------------------------------------------
|
||||
|
||||
# If true, `todo` and `todoList` produce output, else they produce nothing.
|
||||
todo_include_todos = True
|
|
@ -1,5 +1,5 @@
|
|||
.. abgabesystem documentation master file, created by
|
||||
sphinx-quickstart on Fri Jun 1 13:35:35 2018.
|
||||
sphinx-quickstart on Fri Sep 28 14:59:39 2018.
|
||||
You can adapt this file completely to your liking, but it should at least
|
||||
contain the root `toctree` directive.
|
||||
|
||||
|
@ -18,18 +18,3 @@ Indices and tables
|
|||
* :ref:`genindex`
|
||||
* :ref:`modindex`
|
||||
* :ref:`search`
|
||||
|
||||
.. automodule:: abgabesystem
|
||||
:members:
|
||||
|
||||
.. automodule:: abgabesystem.projects
|
||||
:members:
|
||||
|
||||
.. automodule:: abgabesystem.students
|
||||
:members:
|
||||
|
||||
.. automodule:: abgabesystem.commands
|
||||
:members:
|
||||
|
||||
.. autoclass:: abgabesystem.students.Student
|
||||
:members:
|
|
@ -9,6 +9,10 @@ from gitlab.exceptions import GitlabCreateError, GitlabGetError
|
|||
|
||||
def enroll_students(gl, args):
|
||||
"""Creates Gitlab users from exported students list
|
||||
|
||||
Args:
|
||||
gl: API
|
||||
args: command line arguments
|
||||
"""
|
||||
|
||||
student_group = get_student_group(gl, args.course)
|
||||
|
@ -25,6 +29,10 @@ def enroll_students(gl, args):
|
|||
|
||||
def projects(gl, args):
|
||||
"""Creates the projects for all course participants
|
||||
|
||||
Args:
|
||||
gl: API
|
||||
args: command line arguments
|
||||
"""
|
||||
course = None
|
||||
for g in gl.groups.list(search=args.course):
|
||||
|
@ -39,7 +47,12 @@ def projects(gl, args):
|
|||
|
||||
|
||||
def deadline(gl, args):
|
||||
"""Checks deadlines for course and triggers deadline if it is reached"""
|
||||
"""Checks deadlines for course and triggers deadline if it is reached
|
||||
|
||||
Args:
|
||||
gl: API
|
||||
args: command line arguments
|
||||
"""
|
||||
|
||||
deadline_name = args.tag_name
|
||||
try:
|
||||
|
@ -63,6 +76,10 @@ def deadline(gl, args):
|
|||
|
||||
def plagiates(gl, args):
|
||||
"""Runs the plagiarism checker (JPlag) for the solutions with a certain tag
|
||||
|
||||
Args:
|
||||
gl: API
|
||||
args: command line arguments
|
||||
"""
|
||||
|
||||
solutions_dir = 'input'
|
||||
|
@ -90,6 +107,10 @@ def plagiates(gl, args):
|
|||
|
||||
def course(gl, args):
|
||||
"""Creates the group for the course
|
||||
|
||||
Args:
|
||||
gl: API
|
||||
args: command line arguments
|
||||
"""
|
||||
try:
|
||||
gl.groups.create({
|
||||
|
|
|
@ -2,10 +2,21 @@ import logging as log
|
|||
|
||||
|
||||
class InvalidCourse(Exception):
|
||||
"""Raised if the selected course is invalid.
|
||||
"""
|
||||
|
||||
pass
|
||||
|
||||
|
||||
def create_subgroup(gl, name, parent_group):
|
||||
"""Creates a group with `parent_group` as its parent.
|
||||
|
||||
Args:
|
||||
gl: gitlab API object
|
||||
name: name of the group to be created
|
||||
parent_group: parent group of the created group
|
||||
"""
|
||||
|
||||
log.info("Creating subgroup %s in group %s" % (name, parent_group.name))
|
||||
return gl.groups.create({
|
||||
"name": name,
|
||||
|
@ -23,6 +34,15 @@ def create_solutions_group(gl, parent_group):
|
|||
|
||||
|
||||
def create_course(gl, course_name):
|
||||
"""Creates a complete course as required by the `abgabesystem` including
|
||||
the students and solutions groups.
|
||||
|
||||
Args:
|
||||
gl: gitlab API object
|
||||
course_name: name of the course, may contain any characters from
|
||||
[0-9,a-z,A-Z,_, ]
|
||||
"""
|
||||
|
||||
group = gl.groups.create({
|
||||
"name": course_name,
|
||||
"path": course_name.lower().replace(" ", "_"),
|
||||
|
|
|
@ -10,7 +10,12 @@ def create_tag(project, tag, ref):
|
|||
"""Creates protected tag on ref
|
||||
|
||||
The tag is used by the abgabesystem to mark the state of a solution at the
|
||||
deadline
|
||||
deadline.
|
||||
|
||||
Args:
|
||||
project: GIT repository to create the tag in
|
||||
tag: name of the tag to be created
|
||||
ref: name of the red (branch / commit) to create the new tag on
|
||||
"""
|
||||
|
||||
print('Project %s. Creating tag %s' % (project.path, tag))
|
||||
|
@ -21,9 +26,17 @@ def create_tag(project, tag, ref):
|
|||
})
|
||||
|
||||
|
||||
|
||||
def fork_reference(gl, reference, namespace, deploy_key):
|
||||
"""Create fork of solutions for student.
|
||||
|
||||
Returns the created project.
|
||||
|
||||
Args:
|
||||
gl: gitlab API object
|
||||
reference: project to fork from
|
||||
namespace: namespace to place the created project into
|
||||
deploy_key: will be used by the abgabesystem to access the created
|
||||
project
|
||||
"""
|
||||
|
||||
fork = reference.forks.create({
|
||||
|
@ -46,6 +59,14 @@ def fork_reference(gl, reference, namespace, deploy_key):
|
|||
def create_project(gl, group, user, reference, deploy_key):
|
||||
"""Creates a namespace (subgroup) and forks the project with
|
||||
the reference solutions into that namespace
|
||||
|
||||
Args:
|
||||
gl: Gitlab API object
|
||||
group: project will be created in the namespace of this group
|
||||
user: user to add to the project as a developer
|
||||
reference: project to fork the new project from
|
||||
deploy_key: deploy key used by the `abgabesystem` to access the new
|
||||
project
|
||||
"""
|
||||
|
||||
subgroup = None
|
||||
|
@ -79,6 +100,14 @@ def create_project(gl, group, user, reference, deploy_key):
|
|||
|
||||
|
||||
def create_reference_solution(gl, namespace):
|
||||
"""Creates a new project for the reference solutions.
|
||||
|
||||
Args:
|
||||
gl: gitlab API object
|
||||
namespace: namespace to create the project in (that of the solutions for the course)
|
||||
"""
|
||||
|
||||
|
||||
reference_project = gl.projects.create({
|
||||
'name': 'solutions',
|
||||
'namespace_id': namespace,
|
||||
|
@ -100,7 +129,12 @@ def create_reference_solution(gl, namespace):
|
|||
|
||||
|
||||
def setup_projects(gl, course, deploy_key):
|
||||
"""Sets up the internal structure for the group for use with the course
|
||||
"""Sets up the internal structure for the group for use with the course.
|
||||
|
||||
Args:
|
||||
gl: gitlab API object
|
||||
course: course to set up projects for
|
||||
deploy_key: will be used to access the solutions from the abgabesystem
|
||||
"""
|
||||
|
||||
solutions = None
|
||||
|
|
|
@ -5,10 +5,17 @@ from gitlab import GUEST_ACCESS
|
|||
|
||||
|
||||
class MissingStudentsGroup(Exception):
|
||||
"""Raised if a the group for the students has not already been created
|
||||
inside the course.
|
||||
"""
|
||||
|
||||
pass
|
||||
|
||||
|
||||
class MissingCourseGroup(Exception):
|
||||
"""Raised if the group for the course is missing.
|
||||
"""
|
||||
|
||||
pass
|
||||
|
||||
|
||||
|
@ -18,6 +25,12 @@ class Student():
|
|||
Students are read from the CSV file that was exported from Stud.IP.
|
||||
For each user, a dummy LDAP user is created in Gitlab.
|
||||
Upon the first login Gitlab fetches the complete user using LDAP.
|
||||
|
||||
Args:
|
||||
user: user name
|
||||
mail: mail address of the user
|
||||
name: full name of the user
|
||||
group: tutorial group of the user
|
||||
"""
|
||||
|
||||
def __init__(self, user, mail, name, group):
|
||||
|
@ -27,7 +40,11 @@ class Student():
|
|||
self.group = group
|
||||
|
||||
def from_csv(csvfile):
|
||||
"""Creates an iterable containing the users"""
|
||||
"""Creates an iterable containing the users
|
||||
|
||||
Args:
|
||||
csvfile: CSV file from Stud.IP (latin-1)
|
||||
"""
|
||||
reader = csv.DictReader(csvfile, delimiter=';', quotechar='"')
|
||||
|
||||
for line in reader:
|
||||
|
@ -36,7 +53,12 @@ class Student():
|
|||
|
||||
|
||||
def get_students_csv(gl, students_csv):
|
||||
"""Returns already existing GitLab users for students from provided CSV file that have an account.
|
||||
"""Returns already existing GitLab users for students from provided CSV
|
||||
file that have an account.
|
||||
|
||||
Args:
|
||||
gl: Gitlab API object
|
||||
students_csv: CSV file from Stud.IP
|
||||
"""
|
||||
|
||||
for student in Student.from_csv(students_csv):
|
||||
|
@ -47,6 +69,10 @@ def get_students_csv(gl, students_csv):
|
|||
|
||||
def enrolled_students(gl, course):
|
||||
"""Returns the students enrolled in the course
|
||||
|
||||
Args:
|
||||
gl: Gitlab API object
|
||||
course: course the students are enrolled in
|
||||
"""
|
||||
|
||||
students = None
|
||||
|
@ -66,6 +92,12 @@ def enrolled_students(gl, course):
|
|||
def create_user(gl, student, ldap_base, ldap_provider):
|
||||
"""Creates a GitLab user account student.
|
||||
Requires admin privileges.
|
||||
|
||||
Args:
|
||||
gl: Gitlab API object
|
||||
student: student to create user for
|
||||
ldap_base: the search base string for the LDAP query
|
||||
ldap_provider: LDAP provider configured for Gitlab (usually `main`)
|
||||
"""
|
||||
|
||||
user = gl.users.create({
|
||||
|
@ -84,6 +116,10 @@ def create_user(gl, student, ldap_base, ldap_provider):
|
|||
|
||||
def get_student_group(gl, course_name):
|
||||
"""Gets the `students` subgroup for the course
|
||||
|
||||
Args:
|
||||
gl: Gitlab API objects
|
||||
course_name: name of the course
|
||||
"""
|
||||
|
||||
course = None
|
||||
|
@ -108,6 +144,11 @@ def get_student_group(gl, course_name):
|
|||
|
||||
def enroll_student(gl, user, subgroup):
|
||||
"""Adds a student to the course
|
||||
|
||||
Args:
|
||||
gl: Gitlab API object
|
||||
user: user to add to the course
|
||||
subgroup: student will become member of this group
|
||||
"""
|
||||
|
||||
subgroup.members.create({
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue