diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d86d2fc4c32..175bf2522e0 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -926,12 +926,23 @@ jobs: ssh -T localhost sudo systemctl start postgresql - - name: Run ansible script + - name: Run ansible scripts shell: bash run: | + SEMESTER=$(python3 -c 'from datetime import datetime; today = datetime.today(); semester = ("s" if today.month < 7 else "f") + str(today.year)[-2:]; print(semester)') cd .setup/ansible ansible-playbook --private-key /home/runner/.ssh/id_rsa -e 'ansible_user=runner submitty_install_submitty_version=${{ github.sha }} submitty_install_github_url=https://github.com/${{ github.repository }}.git' -i inventory/submitty playbooks/submitty_install.yml ansible-playbook --private-key /home/runner/.ssh/id_rsa -e 'ansible_user=runner' -i inventory/submitty playbooks/submitty_course_creation.yml + + - name: Get API key + shell: bash + run: | + echo 'RESPONSE=(curl -s -X POST http://localhost:1511/api/token -H "Content-Type: application/x-www-form-urlencoded" -d "user_id=instructor&password=instructor")' >> $GITHUB_ENV' + + - name: Create Homework + shell: bash + run: + ansible-playbook --private-key /home/runner/.ssh/id_rsa -e 'ansible_user=runner' -i inventory/submitty playbooks/submitty_homework_creation.yml -e "localhost/api/${SEMESTER}/course/upload" -e "${{ fromJson(env.RESPONSE).token }}" - name: Set perms shell: bash diff --git a/.setup/ansible/playbooks/submitty_homework_creation.yml b/.setup/ansible/playbooks/submitty_homework_creation.yml new file mode 100644 index 00000000000..95738afd859 --- /dev/null +++ b/.setup/ansible/playbooks/submitty_homework_creation.yml @@ -0,0 +1,18 @@ +--- +- name: Submitty Homework Creation + hosts: localhost + connection: local + + tasks: + # This role is defined in the Submitty Repo under .setup/ansible/roles + - name: Create gradeable + ansible.builtin.include_role: + name: submitty_homework_creation + + vars_prompt: + - name: submitty_homework_creation_api_url + prompt: Enter the full API url (http://{domain.com}/api/{semester}/{course}/upload) + private: no + - name: submitty_homework_creation_passed_api_key + prompt: Enter your API key + private: yes diff --git a/.setup/ansible/roles/submitty_homework_creation/files/config_files/file_homework.json b/.setup/ansible/roles/submitty_homework_creation/files/config_files/file_homework.json new file mode 100644 index 00000000000..9f7ec77f51b --- /dev/null +++ b/.setup/ansible/roles/submitty_homework_creation/files/config_files/file_homework.json @@ -0,0 +1,162 @@ +{ + "title": "Homework from file", + "type": "Electronic File", + "id": "file_homework", + "instructions_url": "", + "syllabus_bucket": "homework", + "autograding_config_path": "\/usr\/local\/submitty\/more_autograding_examples\/python_simple_homework\/config", + "bulk_upload": false, + "ta_grading": "true", + "grade_inquiries": "true", + "dates": { + "ta_view_start_date": "1970-01-01 23:59:59", + "grade_start_date": "9997-12-31 23:59:59", + "grade_due_date": "9998-12-31 23:59:59", + "grade_released_date": "9998-12-31 23:59:59", + "team_lock_date": "1971-01-01 23:59:59", + "submission_open_date": "1971-01-01 23:59:59", + "submission_due_date": "9996-12-31 23:59:59", + "grade_inquiry_start_date": "9999-01-01 23:59:59", + "grade_inquiry_due_date": "9999-01-06 23:59:59", + "has_due_date": true, + "has_release_date": true, + "late_submission_allowed": true, + "late_days": 0 + }, + "rubric": [ + { + "title": "Read Me", + "ta_comment": "Reward student for including docstrings.", + "student_comment": "Code should be organized into logical and intuitive functions.", + "lower_clamp": 0, + "default": 2, + "max_value": 2, + "upper_clamp": 2, + "text": false, + "peer_component": false, + "page": 0, + "is_itempool_linked": false, + "itempool": "", + "marks": [ + { + "points": 0, + "title": "Full Credit", + "publish": false + }, + { + "points": -1, + "title": "Minor errors in Read Me", + "publish": false + }, + { + "points": -2, + "title": "Major errors in Read Me or Read Me missing", + "publish": false + } + ] + }, + { + "title": "Coding Style", + "ta_comment": "Deduct points if the student uses global variables.", + "student_comment": "The use of builtin functions is prohibited for this exercise.", + "lower_clamp": 0, + "default": 5, + "max_value": 5, + "upper_clamp": 5, + "text": false, + "peer_component": false, + "page": 0, + "is_itempool_linked": false, + "itempool": "", + "marks": [ + { + "points": 0, + "title": "Full Credit", + "publish": false + }, + { + "points": -5, + "title": "Code is unreadable", + "publish": false + }, + { + "points": -3, + "title": "Code is very difficult to understand", + "publish": false + }, + { + "points": -1, + "title": "Code is difficult to understand", + "publish": false + } + ] + }, + { + "title": "Documentation", + "ta_comment": "Reward student for properly using divide and conquer in code.", + "student_comment": "Code should be broken down into functions that each solve a part of the problem.", + "lower_clamp": 0, + "default": 5, + "max_value": 5, + "upper_clamp": 5, + "text": false, + "peer_component": false, + "page": 0, + "is_itempool_linked": false, + "itempool": "", + "marks": [ + { + "points": 0, + "title": "Full Credit", + "publish": false + }, + { + "points": -5, + "title": "No documentation", + "publish": false + }, + { + "points": -3, + "title": "Very little documentation or documentation makes no sense", + "publish": false + }, + { + "points": -1, + "title": "Way too much documentation and\/or documentation makes no sense", + "publish": false + } + ] + }, + { + "title": "Extra Credit", + "ta_comment": "Deduct points if the student uses global variables.", + "student_comment": "A switch case should be used and not the if-else structure.", + "lower_clamp": 0, + "default": 0, + "max_value": 0, + "upper_clamp": 5, + "text": false, + "peer_component": false, + "page": 0, + "is_itempool_linked": false, + "itempool": "", + "marks": [ + { + "points": 0, + "title": "No Credit", + "publish": false + }, + { + "points": 2, + "title": "Extra credit done poorly", + "publish": false + }, + { + "points": 5, + "title": "Extra credit is acceptable", + "publish": false + } + ] + } + ] +} \ No newline at end of file diff --git a/.setup/ansible/roles/submitty_homework_creation/files/json_list.txt b/.setup/ansible/roles/submitty_homework_creation/files/json_list.txt new file mode 100644 index 00000000000..c2da9456261 --- /dev/null +++ b/.setup/ansible/roles/submitty_homework_creation/files/json_list.txt @@ -0,0 +1 @@ +file_homework.json \ No newline at end of file diff --git a/.setup/ansible/roles/submitty_homework_creation/tasks/create_gradeable.yml b/.setup/ansible/roles/submitty_homework_creation/tasks/create_gradeable.yml new file mode 100644 index 00000000000..4375810b7a1 --- /dev/null +++ b/.setup/ansible/roles/submitty_homework_creation/tasks/create_gradeable.yml @@ -0,0 +1,16 @@ +- name: Create gradeables with API + ansible.builtin.uri: + url: "{{ submitty_homework_creation_api_url }}" + method: POST + body_format: json + body: "{{ lookup('file', var_json_file) }}" + return_content: yes + headers: + Authorization: "{{ submitty_homework_creation_api_key }}" + register: api_response + +- name: Fail when status is error + ansible.builtin.fail: + msg: "{{ (api_response.content | from_json).message }}" + when: + - (api_response.content | from_json).status != 'success' diff --git a/.setup/ansible/roles/submitty_homework_creation/tasks/main.yml b/.setup/ansible/roles/submitty_homework_creation/tasks/main.yml new file mode 100644 index 00000000000..3c1ce9adfa7 --- /dev/null +++ b/.setup/ansible/roles/submitty_homework_creation/tasks/main.yml @@ -0,0 +1,13 @@ +- name: Read JSON content from a file + ansible.builtin.set_fact: + var_json_list: "config_files/{{ lookup('file', 'json_list.txt') | split('\n') }}" + +- name: Use task list to loop through gradeables + ansible.builtin.include_tasks: + file: create_gradeable.yml + loop: "{{ var_json_list }}" + loop_control: + loop_var: submitty_homework_api_json_file + vars: + var_json_file: "{{ submitty_homework_api_json_file }}" + api_key: "{{ passed_api_key }}" diff --git a/site/cypress/e2e/Cypress-Ansible/ansible-course.spec.js b/site/cypress/e2e/Cypress-Ansible/ansible-course.spec.js index 9b40263e7f7..93403fcfc02 100644 --- a/site/cypress/e2e/Cypress-Ansible/ansible-course.spec.js +++ b/site/cypress/e2e/Cypress-Ansible/ansible-course.spec.js @@ -1,6 +1,6 @@ describe('Testing website when created by ansible scripts', () => { it('Should be able to login and see the course', () => { cy.login('instructor'); - cy.visit('term', 'course'); + cy.visit('term/course'); }); }); diff --git a/site/cypress/support/utils.js b/site/cypress/support/utils.js index 1e1298cee9c..a82aa2a315a 100644 --- a/site/cypress/support/utils.js +++ b/site/cypress/support/utils.js @@ -43,6 +43,7 @@ export function getApiKey(user_id, password) { }).then((response) => { return response.body.data.token; }); + } /**