prepare-assignment 0.2.1__tar.gz → 0.4.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (99) hide show
  1. prepare_assignment-0.4.0/.github/ISSUE_TEMPLATE/bug_report.md +18 -0
  2. prepare_assignment-0.4.0/.github/ISSUE_TEMPLATE/feature_request.md +20 -0
  3. prepare_assignment-0.4.0/.github/dependabot.yml +25 -0
  4. prepare_assignment-0.4.0/.github/workflows/pr-title.yml +39 -0
  5. prepare_assignment-0.4.0/.github/workflows/pypi-publish.yml +45 -0
  6. prepare_assignment-0.4.0/.github/workflows/release.yml +33 -0
  7. prepare_assignment-0.4.0/.github/workflows/semantic-release.yml +57 -0
  8. prepare_assignment-0.4.0/.github/workflows/test.yml +63 -0
  9. prepare_assignment-0.4.0/.gitignore +165 -0
  10. prepare_assignment-0.4.0/.releaserc.json +9 -0
  11. prepare_assignment-0.4.0/PKG-INFO +208 -0
  12. prepare_assignment-0.4.0/README.md +187 -0
  13. prepare_assignment-0.4.0/prepare_assignment/cli/main.py +129 -0
  14. {prepare_assignment-0.2.1 → prepare_assignment-0.4.0}/prepare_assignment/cli/task.py +3 -3
  15. prepare_assignment-0.4.0/prepare_assignment/core/check.py +142 -0
  16. {prepare_assignment-0.2.1 → prepare_assignment-0.4.0}/prepare_assignment/core/command.py +52 -9
  17. prepare_assignment-0.4.0/prepare_assignment/core/expression.py +175 -0
  18. {prepare_assignment-0.2.1 → prepare_assignment-0.4.0}/prepare_assignment/core/main.py +15 -9
  19. prepare_assignment-0.4.0/prepare_assignment/core/preparer.py +297 -0
  20. prepare_assignment-0.4.0/prepare_assignment/core/runner.py +237 -0
  21. prepare_assignment-0.4.0/prepare_assignment/core/shell.py +126 -0
  22. prepare_assignment-0.4.0/prepare_assignment/core/subsituter.py +74 -0
  23. {prepare_assignment-0.2.1 → prepare_assignment-0.4.0}/prepare_assignment/core/task_handler.py +31 -13
  24. {prepare_assignment-0.2.1 → prepare_assignment-0.4.0}/prepare_assignment/core/validator.py +9 -24
  25. prepare_assignment-0.4.0/prepare_assignment/core/versions.py +124 -0
  26. {prepare_assignment-0.2.1 → prepare_assignment-0.4.0}/prepare_assignment/data/config.py +1 -0
  27. prepare_assignment-0.4.0/prepare_assignment/data/constants.py +12 -0
  28. {prepare_assignment-0.2.1 → prepare_assignment-0.4.0}/prepare_assignment/data/errors.py +14 -0
  29. prepare_assignment-0.4.0/prepare_assignment/data/job_environment.py +26 -0
  30. {prepare_assignment-0.2.1 → prepare_assignment-0.4.0}/prepare_assignment/data/prepare.py +20 -5
  31. {prepare_assignment-0.2.1 → prepare_assignment-0.4.0}/prepare_assignment/data/task_definition.py +11 -10
  32. {prepare_assignment-0.2.1 → prepare_assignment-0.4.0}/prepare_assignment/data/task_properties.py +2 -2
  33. prepare_assignment-0.4.0/prepare_assignment/data/types.py +26 -0
  34. {prepare_assignment-0.2.1 → prepare_assignment-0.4.0}/prepare_assignment/schemas/config.schema.json +14 -1
  35. prepare_assignment-0.4.0/prepare_assignment/schemas/prepare.schema.json +116 -0
  36. {prepare_assignment-0.2.1 → prepare_assignment-0.4.0}/prepare_assignment/schemas/task.schema.json +37 -1
  37. {prepare_assignment-0.2.1 → prepare_assignment-0.4.0}/prepare_assignment/utils/config.py +2 -4
  38. prepare_assignment-0.4.0/prepare_assignment/utils/files.py +40 -0
  39. {prepare_assignment-0.2.1 → prepare_assignment-0.4.0}/prepare_assignment/utils/logger.py +13 -0
  40. prepare_assignment-0.4.0/prepare_assignment/utils/resources.py +14 -0
  41. {prepare_assignment-0.2.1 → prepare_assignment-0.4.0}/prepare_assignment/utils/tasks.py +1 -1
  42. prepare_assignment-0.4.0/pyproject.toml +48 -0
  43. prepare_assignment-0.4.0/tests/__init__.py +0 -0
  44. prepare_assignment-0.4.0/tests/core/__init__.py +0 -0
  45. prepare_assignment-0.4.0/tests/core/test_check.py +205 -0
  46. prepare_assignment-0.4.0/tests/core/test_command.py +180 -0
  47. prepare_assignment-0.4.0/tests/core/test_expression.py +288 -0
  48. prepare_assignment-0.4.0/tests/core/test_preparer.py +285 -0
  49. prepare_assignment-0.4.0/tests/core/test_resolve_version.py +197 -0
  50. prepare_assignment-0.4.0/tests/core/test_runner.py +573 -0
  51. prepare_assignment-0.4.0/tests/core/test_runner_process.py +290 -0
  52. prepare_assignment-0.4.0/tests/core/test_shell.py +145 -0
  53. prepare_assignment-0.4.0/tests/core/test_substituter.py +132 -0
  54. prepare_assignment-0.4.0/tests/core/test_task_handler.py +95 -0
  55. prepare_assignment-0.4.0/tests/core/test_validator.py +181 -0
  56. prepare_assignment-0.4.0/tests/data/__init__.py +0 -0
  57. prepare_assignment-0.4.0/tests/data/test_prepare.py +66 -0
  58. prepare_assignment-0.4.0/tests/data/test_types.py +27 -0
  59. prepare_assignment-0.4.0/tests/test_main.py +88 -0
  60. prepare_assignment-0.4.0/tests/testproject/prepare.yml +22 -0
  61. prepare_assignment-0.4.0/tests/testproject/solution/pom.xml +19 -0
  62. prepare_assignment-0.4.0/tests/testproject/solution/src/main/java/gradelist/AssessmentResult.java +36 -0
  63. prepare_assignment-0.4.0/tests/testproject/solution/src/main/java/gradelist/GradeList.java +40 -0
  64. prepare_assignment-0.4.0/tests/testproject/solution/src/main/java/gradelist/Test.java +3 -0
  65. prepare_assignment-0.4.0/tests/testproject/solution/src/test/java/gradelist/AssessmentResultTest.java +65 -0
  66. prepare_assignment-0.4.0/tests/testproject/solution/src/test/java/gradelist/GradeListTest.java +67 -0
  67. prepare_assignment-0.4.0/tests/utils/__init__.py +0 -0
  68. prepare_assignment-0.4.0/tests/utils/test_config.py +30 -0
  69. prepare_assignment-0.4.0/tests/utils/test_default_validator.py +39 -0
  70. prepare_assignment-0.4.0/tests/utils/test_files.py +46 -0
  71. prepare_assignment-0.4.0/tests/utils/test_logger.py +115 -0
  72. prepare_assignment-0.4.0/tests/utils/test_paths.py +98 -0
  73. prepare_assignment-0.4.0/tests/utils/test_resources.py +14 -0
  74. prepare_assignment-0.4.0/uv.lock +972 -0
  75. prepare_assignment-0.2.1/PKG-INFO +0 -129
  76. prepare_assignment-0.2.1/README.md +0 -99
  77. prepare_assignment-0.2.1/prepare_assignment/cli/main.py +0 -61
  78. prepare_assignment-0.2.1/prepare_assignment/core/preparer.py +0 -244
  79. prepare_assignment-0.2.1/prepare_assignment/core/runner.py +0 -130
  80. prepare_assignment-0.2.1/prepare_assignment/core/subsituter.py +0 -102
  81. prepare_assignment-0.2.1/prepare_assignment/data/constants.py +0 -32
  82. prepare_assignment-0.2.1/prepare_assignment/data/job_environment.py +0 -14
  83. prepare_assignment-0.2.1/prepare_assignment/schemas/prepare.schema.json +0 -51
  84. prepare_assignment-0.2.1/prepare_assignment/schemas/task.schema.json_template +0 -22
  85. prepare_assignment-0.2.1/prepare_assignment/utils/executables.py +0 -24
  86. prepare_assignment-0.2.1/pyproject.toml +0 -42
  87. {prepare_assignment-0.2.1 → prepare_assignment-0.4.0}/LICENSE +0 -0
  88. {prepare_assignment-0.2.1 → prepare_assignment-0.4.0}/prepare_assignment/__init__.py +0 -0
  89. {prepare_assignment-0.2.1 → prepare_assignment-0.4.0}/prepare_assignment/__main__.py +0 -0
  90. {prepare_assignment-0.2.1 → prepare_assignment-0.4.0}/prepare_assignment/cli/__init__.py +0 -0
  91. {prepare_assignment-0.2.1 → prepare_assignment-0.4.0}/prepare_assignment/cli/tasks.py +0 -0
  92. {prepare_assignment-0.2.1 → prepare_assignment-0.4.0}/prepare_assignment/core/__init__.py +0 -0
  93. {prepare_assignment-0.2.1 → prepare_assignment-0.4.0}/prepare_assignment/data/__init__.py +0 -0
  94. {prepare_assignment-0.2.1 → prepare_assignment-0.4.0}/prepare_assignment/utils/__init__.py +0 -0
  95. {prepare_assignment-0.2.1 → prepare_assignment-0.4.0}/prepare_assignment/utils/default_validator.py +0 -0
  96. {prepare_assignment-0.2.1 → prepare_assignment-0.4.0}/prepare_assignment/utils/dependency.py +0 -0
  97. {prepare_assignment-0.2.1 → prepare_assignment-0.4.0}/prepare_assignment/utils/paths.py +0 -0
  98. {prepare_assignment-0.2.1 → prepare_assignment-0.4.0}/prepare_assignment/utils/virtual_env.py +0 -0
  99. {prepare_assignment-0.2.1 → prepare_assignment-0.4.0}/prepare_assignment/utils/yml_loader.py +0 -0
@@ -0,0 +1,18 @@
1
+ ---
2
+ name: Bug report
3
+ about: Create a report to help us improve
4
+ title: '[Bug] '
5
+ labels: ["bug"]
6
+ assignees: ''
7
+ ---
8
+
9
+ ## Describe the bug
10
+ A clear and concise description of what the bug is.
11
+
12
+ ## Expected behavior
13
+ A clear and concise description of what you expected to happen.
14
+
15
+ ## To Reproduce
16
+ Steps to reproduce the behavior:
17
+
18
+ 1.
@@ -0,0 +1,20 @@
1
+ ---
2
+ name: Feature request
3
+ about: Suggest an idea for this project
4
+ title: ''
5
+ labels: ''
6
+ assignees: ''
7
+
8
+ ---
9
+
10
+ **Is your feature request related to a problem? Please describe.**
11
+ A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
12
+
13
+ **Describe the solution you'd like**
14
+ A clear and concise description of what you want to happen.
15
+
16
+ **Describe alternatives you've considered**
17
+ A clear and concise description of any alternative solutions or features you've considered.
18
+
19
+ **Additional context**
20
+ Add any other context or screenshots about the feature request here.
@@ -0,0 +1,25 @@
1
+ version: 2
2
+ updates:
3
+ - package-ecosystem: "uv"
4
+ directory: "/"
5
+ schedule:
6
+ interval: "weekly"
7
+ # PR titles must follow Conventional Commits (checked by pr-title.yml)
8
+ commit-message:
9
+ prefix: "build"
10
+ include: "scope"
11
+ groups:
12
+ python-dependencies:
13
+ patterns:
14
+ - "*"
15
+ - package-ecosystem: "github-actions"
16
+ directory: "/"
17
+ schedule:
18
+ interval: "weekly"
19
+ commit-message:
20
+ prefix: "ci"
21
+ include: "scope"
22
+ groups:
23
+ github-actions:
24
+ patterns:
25
+ - "*"
@@ -0,0 +1,39 @@
1
+ name: PR title
2
+
3
+ # With squash merging the PR title becomes the commit subject on main, which is
4
+ # what semantic-release parses to pick the next version. An unparseable title
5
+ # is therefore a release that silently does not happen.
6
+ on:
7
+ pull_request:
8
+ branches: [main]
9
+ types: [opened, edited, synchronize, reopened]
10
+
11
+ concurrency:
12
+ group: pr-title-${{ github.event.pull_request.number }}
13
+ cancel-in-progress: true
14
+
15
+ permissions:
16
+ pull-requests: read
17
+
18
+ jobs:
19
+ lint:
20
+ name: conventional title
21
+ runs-on: ubuntu-latest
22
+ steps:
23
+ - uses: amannn/action-semantic-pull-request@v6
24
+ env:
25
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
26
+ with:
27
+ # The types already in use on main, plus revert.
28
+ types: |
29
+ feat
30
+ fix
31
+ docs
32
+ refactor
33
+ test
34
+ ci
35
+ style
36
+ chore
37
+ perf
38
+ build
39
+ revert
@@ -0,0 +1,45 @@
1
+ name: PyPI publish
2
+
3
+ # Reusable build and publish. Two callers pass a version in:
4
+ # - release.yml on a human-pushed v* tag
5
+ # - semantic-release.yml after semantic-release cuts a new version
6
+ #
7
+ # It lives here rather than in either caller because a tag pushed with
8
+ # GITHUB_TOKEN does not trigger workflows, so semantic-release cannot rely on
9
+ # release.yml's tag trigger to publish the version it just cut.
10
+ on:
11
+ workflow_call:
12
+ inputs:
13
+ version:
14
+ description: Version to build and publish, without the leading v (e.g. 1.2.3).
15
+ required: true
16
+ type: string
17
+
18
+ permissions:
19
+ contents: read
20
+
21
+ jobs:
22
+ publish:
23
+ name: build & publish
24
+ runs-on: ubuntu-latest
25
+
26
+ steps:
27
+ - uses: actions/checkout@v7
28
+
29
+ - name: Install uv
30
+ uses: astral-sh/setup-uv@v10.1.0
31
+ with:
32
+ python-version: "3.12"
33
+
34
+ # The version is not committed back to main, so the version in
35
+ # pyproject.toml is stale. Set the released version just for this build.
36
+ - name: Set version
37
+ run: uv version "${{ inputs.version }}" --frozen
38
+
39
+ - name: Build
40
+ run: uv build
41
+
42
+ - name: Publish
43
+ run: uv publish
44
+ env:
45
+ UV_PUBLISH_TOKEN: ${{ secrets.PYPI_TOKEN }}
@@ -0,0 +1,33 @@
1
+ name: Release
2
+
3
+ # Fires only on tags pushed by a human: a manual tag cut as an escape hatch.
4
+ # Routine releases come from semantic-release.yml, whose GITHUB_TOKEN-pushed
5
+ # tags deliberately do not trigger this workflow — that is what keeps a
6
+ # release from being published twice.
7
+ on:
8
+ push:
9
+ tags: ["v*"]
10
+
11
+ concurrency:
12
+ group: release-${{ github.ref }}
13
+ cancel-in-progress: true
14
+
15
+ permissions:
16
+ contents: read
17
+
18
+ jobs:
19
+ version:
20
+ name: version from tag
21
+ runs-on: ubuntu-latest
22
+ outputs:
23
+ version: ${{ steps.version.outputs.version }}
24
+ steps:
25
+ - id: version
26
+ run: echo "version=${GITHUB_REF_NAME#v}" >> "$GITHUB_OUTPUT"
27
+
28
+ publish:
29
+ needs: version
30
+ uses: ./.github/workflows/pypi-publish.yml
31
+ with:
32
+ version: ${{ needs.version.outputs.version }}
33
+ secrets: inherit
@@ -0,0 +1,57 @@
1
+ name: Semantic release
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+
7
+ # Never cancel a release mid-flight: a half-run that has tagged but not yet
8
+ # published would need cleaning up by hand.
9
+ concurrency:
10
+ group: semantic-release-${{ github.ref }}
11
+ cancel-in-progress: false
12
+
13
+ permissions:
14
+ contents: read
15
+
16
+ jobs:
17
+ release:
18
+ name: version
19
+ runs-on: ubuntu-latest
20
+ permissions:
21
+ contents: write # create the tag and the GitHub release
22
+ issues: write # comment "released in vX.Y.Z" on issues
23
+ pull-requests: write # and on the PRs that fed the release
24
+ outputs:
25
+ published: ${{ steps.semantic.outputs.new_release_published }}
26
+ version: ${{ steps.semantic.outputs.new_release_version }}
27
+
28
+ steps:
29
+ - uses: actions/checkout@v7
30
+ with:
31
+ # semantic-release walks back to the previous tag to decide the bump,
32
+ # so a shallow clone makes it compute the wrong version.
33
+ fetch-depth: 0
34
+ persist-credentials: false
35
+
36
+ - uses: actions/setup-node@v7
37
+ with:
38
+ node-version: 22
39
+
40
+ # Pinned to an exact version: this action publishes no floating major
41
+ # tags, so @v6 would not resolve. All three plugins in .releaserc.json
42
+ # ship with the semantic-release core it bundles.
43
+ - name: Semantic release
44
+ id: semantic
45
+ uses: cycjimmy/semantic-release-action@v6.0.0
46
+ env:
47
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
48
+
49
+ # The tag above was pushed with GITHUB_TOKEN, so it will not trigger
50
+ # release.yml. Publish to PyPI here instead.
51
+ publish:
52
+ needs: release
53
+ if: needs.release.outputs.published == 'true'
54
+ uses: ./.github/workflows/pypi-publish.yml
55
+ with:
56
+ version: ${{ needs.release.outputs.version }}
57
+ secrets: inherit
@@ -0,0 +1,63 @@
1
+ name: Test
2
+
3
+ defaults:
4
+ run:
5
+ shell: bash
6
+
7
+ # Only on pull requests: main only changes through squash-merged PRs, which
8
+ # have already passed these checks.
9
+ on:
10
+ pull_request:
11
+ branches: [ "main" ]
12
+
13
+ jobs:
14
+ test:
15
+ strategy:
16
+ fail-fast: false
17
+ matrix:
18
+ python-version: ["3.11", "3.12", "3.13", "3.14"]
19
+ os: ["ubuntu-latest", "windows-latest", "macos-latest"]
20
+ runs-on: ${{ matrix.os }}
21
+ permissions:
22
+ contents: read
23
+ checks: write
24
+ steps:
25
+ - uses: actions/checkout@v7
26
+ - name: Install uv and Python ${{ matrix.python-version }}
27
+ uses: astral-sh/setup-uv@v10.1.0
28
+ with:
29
+ python-version: ${{ matrix.python-version }}
30
+ enable-cache: true
31
+ cache-dependency-glob: "uv.lock"
32
+ cache-suffix: py${{ matrix.python-version }}
33
+ - name: Install dependencies
34
+ run: uv sync --locked --group test
35
+ - name: Run tests
36
+ env:
37
+ PREPARE_TEST_GIT_MODE: https
38
+ run: uv run pytest --cov --cov-report=xml --junitxml=tests.xml
39
+ - name: Test Report
40
+ uses: mikepenz/action-junit-report@v6
41
+ if: success() || failure()
42
+ with:
43
+ check_name: Test Results (Python ${{ matrix.python-version }}, ${{ matrix.os }})
44
+ report_paths: tests.xml
45
+
46
+ typecheck:
47
+ strategy:
48
+ matrix:
49
+ python-version: [ "3.12" ]
50
+ runs-on: "ubuntu-latest"
51
+ steps:
52
+ - uses: actions/checkout@v7
53
+ - name: Install uv and Python ${{ matrix.python-version }}
54
+ uses: astral-sh/setup-uv@v10.1.0
55
+ with:
56
+ python-version: ${{ matrix.python-version }}
57
+ enable-cache: true
58
+ cache-dependency-glob: "uv.lock"
59
+ cache-suffix: typecheck
60
+ - name: Install dependencies
61
+ run: uv sync --locked --group test
62
+ - name: Type checker
63
+ run: uv run mypy prepare_assignment
@@ -0,0 +1,165 @@
1
+ # Byte-compiled / optimized / DLL files
2
+ __pycache__/
3
+ *.py[cod]
4
+ *$py.class
5
+
6
+ # C extensions
7
+ *.so
8
+
9
+ # Distribution / packaging
10
+ .Python
11
+ build/
12
+ develop-eggs/
13
+ dist/
14
+ downloads/
15
+ eggs/
16
+ .eggs/
17
+ lib/
18
+ lib64/
19
+ parts/
20
+ sdist/
21
+ var/
22
+ wheels/
23
+ share/python-wheels/
24
+ *.egg-info/
25
+ .installed.cfg
26
+ *.egg
27
+ MANIFEST
28
+
29
+ # PyInstaller
30
+ # Usually these files are written by a python script from a template
31
+ # before PyInstaller builds the exe, so as to inject date/other infos into it.
32
+ *.manifest
33
+ *.spec
34
+
35
+ # Installer logs
36
+ pip-log.txt
37
+ pip-delete-this-directory.txt
38
+
39
+ # Unit test / coverage reports
40
+ htmlcov/
41
+ .tox/
42
+ .nox/
43
+ .coverage
44
+ .coverage.*
45
+ .cache
46
+ nosetests.xml
47
+ coverage.xml
48
+ *.cover
49
+ *.py,cover
50
+ .hypothesis/
51
+ .pytest_cache/
52
+ cover/
53
+
54
+ # Translations
55
+ *.mo
56
+ *.pot
57
+
58
+ # Django stuff:
59
+ *.log
60
+ local_settings.py
61
+ db.sqlite3
62
+ db.sqlite3-journal
63
+
64
+ # Flask stuff:
65
+ instance/
66
+ .webassets-cache
67
+
68
+ # Scrapy stuff:
69
+ .scrapy
70
+
71
+ # Sphinx documentation
72
+ docs/_build/
73
+
74
+ # PyBuilder
75
+ .pybuilder/
76
+ target/
77
+
78
+ # Jupyter Notebook
79
+ .ipynb_checkpoints
80
+
81
+ # IPython
82
+ profile_default/
83
+ ipython_config.py
84
+
85
+ # pyenv
86
+ # For a library or package, you might want to ignore these files since the code is
87
+ # intended to run in multiple environments; otherwise, check them in:
88
+ # .python-version
89
+
90
+ # pipenv
91
+ # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
92
+ # However, in case of collaboration, if having platform-specific dependencies or dependencies
93
+ # having no cross-platform support, pipenv may install dependencies that don't work, or not
94
+ # install all needed dependencies.
95
+ #Pipfile.lock
96
+
97
+ # poetry
98
+ # Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
99
+ # This is especially recommended for binary packages to ensure reproducibility, and is more
100
+ # commonly ignored for libraries.
101
+ # https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
102
+ #poetry.lock
103
+
104
+ # pdm
105
+ # Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
106
+ #pdm.lock
107
+ # pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
108
+ # in version control.
109
+ # https://pdm.fming.dev/#use-with-ide
110
+ .pdm.toml
111
+
112
+ # PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
113
+ __pypackages__/
114
+
115
+ # Celery stuff
116
+ celerybeat-schedule
117
+ celerybeat.pid
118
+
119
+ # SageMath parsed files
120
+ *.sage.py
121
+
122
+ # Environments
123
+ .env
124
+ .venv
125
+ env/
126
+ venv/
127
+ ENV/
128
+ env.bak/
129
+ venv.bak/
130
+
131
+ # Spyder project settings
132
+ .spyderproject
133
+ .spyproject
134
+
135
+ # Rope project settings
136
+ .ropeproject
137
+
138
+ # mkdocs documentation
139
+ /site
140
+
141
+ # mypy
142
+ .mypy_cache/
143
+ .dmypy.json
144
+ dmypy.json
145
+
146
+ # Pyre type checker
147
+ .pyre/
148
+
149
+ # pytype static type analyzer
150
+ .pytype/
151
+
152
+ # Cython debug symbols
153
+ cython_debug/
154
+
155
+ # PyCharm
156
+ # JetBrains specific template is maintained in a separate JetBrains.gitignore that can
157
+ # be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
158
+ # and can be added to the global gitignore or merged into this file. For a more nuclear
159
+ # option (not recommended) you can uncomment the following to ignore the entire idea folder.
160
+ .idea/
161
+ exampleproject/
162
+ tests.xml
163
+ out.txt
164
+ out/
165
+ .vscode
@@ -0,0 +1,9 @@
1
+ {
2
+ "branches": ["main"],
3
+ "tagFormat": "v${version}",
4
+ "plugins": [
5
+ "@semantic-release/commit-analyzer",
6
+ "@semantic-release/release-notes-generator",
7
+ "@semantic-release/github"
8
+ ]
9
+ }
@@ -0,0 +1,208 @@
1
+ Metadata-Version: 2.5
2
+ Name: prepare-assignment
3
+ Version: 0.4.0
4
+ Summary: Prepare assignment
5
+ Author-email: Bonajo <m.bonajo@fontys.nl>
6
+ License: MIT
7
+ License-File: LICENSE
8
+ Requires-Python: >=3.11
9
+ Requires-Dist: dacite>=1.9.2
10
+ Requires-Dist: gitpython>=3.1.59
11
+ Requires-Dist: jsonschema>=4.21.1
12
+ Requires-Dist: multipledispatch>=1.0.0
13
+ Requires-Dist: packaging>=24.0
14
+ Requires-Dist: prepare-toolbox==0.4.0
15
+ Requires-Dist: ruamel-yaml>=0.18.5
16
+ Requires-Dist: simpleeval>=1.0.0
17
+ Requires-Dist: treelib>=1.7.0
18
+ Requires-Dist: typer==0.27.2
19
+ Requires-Dist: virtualenv>=20.25.0
20
+ Description-Content-Type: text/markdown
21
+
22
+ # Prepare assignment
23
+
24
+ Prepare assignment is a GitHub Actions inspired helper tool to prepare assignments at Fontys Venlo. The goal is to define jobs inside the `prepare.yml` that indicate how to convert a solution project into a student project.
25
+
26
+ ## Dependencies
27
+
28
+ - Git
29
+ - Python >=3.11
30
+
31
+ ## Installation
32
+
33
+ Prepare-assignment is available from [PyPI](https://pypi.org/).
34
+
35
+
36
+ ```bash
37
+ # To install:
38
+ python3 -m pip install prepare-assignment
39
+
40
+ # To upgrade
41
+ python3 -m pip install --upgrade prepare-assignment
42
+ ```
43
+
44
+ ## Executing prepare-assignment
45
+
46
+ To execute a `prepare.yml` simply run `prepare run` from the same directory.
47
+
48
+ ### Command line interface
49
+
50
+ Use `prepare --help` to which commands and flags are available.
51
+
52
+ ## Example `prepare.yml`
53
+
54
+ First we need to have tasks available that can be executed. Take for example a look at the [remove](https://github.com/prepare-assignment/remove) task.
55
+
56
+ The tests use a [testproject](https://github.com/prepare-assignment/core/tree/tests/testproject), which contains an example of a `prepare.yml`, see below for convenience.
57
+
58
+ ```yaml
59
+ name: Test project
60
+ jobs:
61
+ prepare:
62
+ - name: remove out
63
+ uses: remove
64
+ with:
65
+ input:
66
+ - "out"
67
+ - "out.txt"
68
+ force: true
69
+ recursive: true
70
+ - name: codestripper
71
+ id: codestripper
72
+ uses: codestripper
73
+ with:
74
+ include:
75
+ - "**/*.java"
76
+ - "pom.xml"
77
+ working-directory: "solution"
78
+ verbosity: 5
79
+ - name: Test a run command with substitution
80
+ run: echo '${{ tasks.codestripper.outputs.stripped-files }}' > out.txt
81
+ ```
82
+
83
+ For people familiar with GitHub Actions this should look very familiar. We have jobs that indicate what should happen to prepare an assignment. The tasks are defined in their own repositories, if the `uses` tag doesn't have a username/organization, it will default to `prepare-assignment`. So for example the `remove` task uses the following repository: [prepare-assignment/remove](https://github.com/prepare-assignment/remove)
84
+
85
+ ## Step reference
86
+
87
+ Every step has a `name` and either `uses` (a task) or `run` (a shell command).
88
+
89
+ | Property | Applies to | Description |
90
+ |---------------------|----------------|------------------------------------------------------------------------------------------------------------|
91
+ | `name` | all | Name of the step (required) |
92
+ | `id` | all | Identifier used to reference the outputs of the step: `${{ tasks.<id>.outputs.<name> }}` |
93
+ | `if` | all | Only run the step if the expression is true, see [Conditions](#conditions) |
94
+ | `uses` | task | The task to execute, e.g. `remove`, `remove@v1`, `my-org/my-task@v1.2.0` |
95
+ | `with` | task | The inputs of the task |
96
+ | `run` | run | The command (script) to execute |
97
+ | `shell` | run | `bash` (default), `sh`, `pwsh`, `powershell`, `cmd` or `python` |
98
+ | `working-directory` | all | Directory (relative to the `prepare.yml`) in which the step is executed |
99
+ | `env` | all | Environment variables for this step only, values can contain expressions |
100
+ | `continue-on-error` | all | If `true`, a failure of this step doesn't fail the job |
101
+
102
+ The default shell can be changed in the [config file](#config-file). Using `shell: python` is the most portable
103
+ option, as Python is always available.
104
+
105
+ Like GitHub Actions, the script is written to a temporary file and executed as:
106
+
107
+ | Shell | Command | Behaviour |
108
+ |--------------|-----------------------------------------------------------------|------------------------------------------------------------------|
109
+ | `bash` | `bash --noprofile --norc -eo pipefail <file>` | Stops at the first failing command (also inside a pipe) |
110
+ | `sh` | `sh -e <file>` | Stops at the first failing command |
111
+ | `pwsh` | `pwsh -NoProfile -NonInteractive -Command ". '<file>'"` | Stops at the first error, fails if the last program failed |
112
+ | `powershell` | `powershell -NoProfile -NonInteractive -Command ". '<file>'"` | Same as `pwsh` (Windows PowerShell 5.1) |
113
+ | `cmd` | `cmd /D /E:ON /V:OFF /S /C "CALL "<file>""` | Doesn't stop on errors, the exit code of the last command counts |
114
+ | `python` | `python <file>` | The Python interpreter that runs prepare |
115
+
116
+ ```yaml
117
+ - name: Create checksum
118
+ shell: python
119
+ working-directory: out/assignment
120
+ run: |
121
+ import hashlib
122
+ digest = hashlib.sha256(open("pom.xml", "rb").read()).hexdigest()
123
+ open("pom.xml.sha256", "w").write(f"{digest} pom.xml\n")
124
+ ```
125
+
126
+ ### Expressions
127
+
128
+ Values can contain expressions: `${{ <expression> }}`. The following contexts are available:
129
+
130
+ - `inputs.<name>`: the inputs of a composite task
131
+ - `env.<NAME>`: environment variables (an unset variable is empty)
132
+ - `tasks.<id>.outputs.<name>`: the outputs of a previous step
133
+
134
+ Referencing something that doesn't exist (e.g. a typo like `inputs.nmae`) fails the step, instead of silently
135
+ evaluating to an empty string. The operators `==`, `!=`, `<`, `>`, `&&`, `||` and `!` and the functions
136
+ `contains`, `startsWith` and `endsWith` are supported.
137
+
138
+ ### Conditions
139
+
140
+ Just like GitHub Actions, a step is skipped when a previous step failed, unless its `if` uses one of the status
141
+ functions `success()`, `failure()` or `always()`. So `if: inputs.clean` behaves as `success() && inputs.clean`.
142
+
143
+ ```yaml
144
+ - name: Clean up (also when something failed)
145
+ if: always()
146
+ uses: remove
147
+ with:
148
+ input: ["out"]
149
+ force: true
150
+ recursive: true
151
+ ```
152
+
153
+ ## Checking for updates
154
+
155
+ `prepare check` shows which of the tasks used in the `prepare.yml` have newer versions (use `--all` to check all
156
+ installed tasks). Tasks that use a moving version (`latest`, `main` or a prefix like `v1`) can be updated with
157
+ `prepare task update <task>`.
158
+
159
+ ## Config file
160
+
161
+ It is possible to specify global options in a config file. The location of the config file can be found by running `prepare` without any commands.
162
+
163
+ The following settings are available:
164
+
165
+ ```yml
166
+ core:
167
+ git-mode: "ssh|https"
168
+ verbose: int
169
+ debug: int
170
+ shell: "bash|sh|pwsh|powershell|cmd|python" # default shell for run steps (default: bash)
171
+ ```
172
+
173
+ ## Tasks
174
+
175
+ There are three different kind of tasks available:
176
+
177
+ - Run tasks: these execute a shell command (see `shell` below)
178
+ - Python tasks: these execute a python script
179
+ - Composite tasks: these combine multiple tasks into one
180
+
181
+ ### Custom tasks
182
+
183
+ It is possible to create custom (python/composite) tasks.
184
+
185
+ 1. Create a repository
186
+ 2. Define the properties of the task in `task.yml`, these include
187
+ - id*: unique identifier
188
+ - name*: name of the task
189
+ - description*: short description
190
+ - runs*: whether it is a python or composite task
191
+ - inputs: the inputs for the task
192
+ - outputs: the outputs that get set by the task. For composite tasks an output gets its value from an
193
+ expression: `value: ${{ tasks.<id>.outputs.<name> }}`
194
+ 3. Validate that the task definition is correct against the [json schema](https://github.com/prepare-assignment/core/blob/main/prepare_assignment/schemas/task.schema.json)
195
+ 4. If python task, create a script that implements desired functionality
196
+
197
+ ## Releases
198
+
199
+ Releases are automated with [semantic-release](https://semantic-release.gitbook.io/). Pull requests are squash merged, so the PR title becomes the commit on `main` and must follow [Conventional Commits](https://www.conventionalcommits.org/) (checked on every PR):
200
+
201
+ | PR title | Release |
202
+ |----------|---------|
203
+ | `fix: ...` | patch (1.2.3 → 1.2.4) |
204
+ | `feat: ...` | minor (1.2.3 → 1.3.0) |
205
+ | `feat!: ...` or a `BREAKING CHANGE:` footer | major (1.2.3 → 2.0.0) |
206
+ | `docs:`, `chore:`, `ci:`, `build:`, `refactor:`, `test:`, `style:`, `perf:` | no release |
207
+
208
+ On every merge to `main` the next version is determined, tagged (`vX.Y.Z`), a GitHub release is created and the package is published to PyPI. The version is set during the build and is not committed, so the version in `pyproject.toml` is not the released version.