{"id":37040601,"url":"https://github.com/savonia-cs/savonia-assignment-tool","last_synced_at":"2026-01-14T04:48:25.349Z","repository":{"id":154359901,"uuid":"591265131","full_name":"savonia-cs/savonia-assignment-tool","owner":"savonia-cs","description":"Savonia Assignment Helper Tool","archived":false,"fork":false,"pushed_at":"2025-04-28T08:58:14.000Z","size":161,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2025-10-29T03:32:50.270Z","etag":null,"topics":["cli","tool"],"latest_commit_sha":null,"homepage":"https://www.nuget.org/packages/Savonia.Assignment.Tool","language":"C#","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/savonia-cs.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2023-01-20T10:31:43.000Z","updated_at":"2025-04-28T08:58:20.000Z","dependencies_parsed_at":"2024-09-10T13:31:24.529Z","dependency_job_id":null,"html_url":"https://github.com/savonia-cs/savonia-assignment-tool","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/savonia-cs/savonia-assignment-tool","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/savonia-cs%2Fsavonia-assignment-tool","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/savonia-cs%2Fsavonia-assignment-tool/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/savonia-cs%2Fsavonia-assignment-tool/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/savonia-cs%2Fsavonia-assignment-tool/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/savonia-cs","download_url":"https://codeload.github.com/savonia-cs/savonia-assignment-tool/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/savonia-cs%2Fsavonia-assignment-tool/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28409858,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-14T01:52:23.358Z","status":"online","status_checked_at":"2026-01-14T02:00:06.678Z","response_time":107,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["cli","tool"],"created_at":"2026-01-14T04:48:24.801Z","updated_at":"2026-01-14T04:48:25.341Z","avatar_url":"https://github.com/savonia-cs.png","language":"C#","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Savonia.Assignment.Tool\n\nThis package contains a CLI tool (savoniatool) to help with programming assignments.\n\n\u003e Version 2.* targets .NET 8\n\n\u003e Version 1.3.*+ have major changes to some commands and their parameters that will prevent possible existing response files from working.\n\u003e\n\u003e Each command can be run with `-h` switch to see the command's help.\n\nThe tool can be installed with command:\n```dotnetcli\ndotnet tool install --global Savonia.Assignment.Tool\n```\n\nThe tool can be uninstalled with command:\n```dotnetcli\ndotnet tool uninstall --global Savonia.Assignment.Tool\n```\n\nContains commands\n\n- `solution pack`: to create a zip package of your solution.\n- `submissions unpack`: to unpack (unzip) all answers. Typically each person's answer is in a zip file.\n- `submissions list`: to list all answer folders. The list has numbers to the folders and the numbers can be used to select individual or a range of folders to test.\n- `submissions test`: to perform various operations on the submissions.\n- `submissions pack`: to pack (zip) all answers. Packs each persons's answer folder individually to zip file.\n- `submissions open`: to open submissions one-by-one with an editor (by default with [VS Code](https://code.visualstudio.com/)) for manual evaluation\n- `hash create`: to create hash from selected file(s) in answers. Used to find duplicates.\n- `hash compare`: to find duplicates among the created hashes.\n- `hash open`: to open duplicates in an editor (by default VS Code) for manual checking.\n- `csv parse`: to parse a CSV file with selected fields and possible Regex filters and output to another CSV file.\n\nCommands for submissions have been designed with C# related .NET projects (console apps, MAUI apps etc.) as primary target.\n\n## Usage\n\nWhen installed the tool can be used as follows\n\n### To pack files\n\n- To pack all \\*.cs files in all directories except *obj* and *tests* directories under current working directory to *sourcefiles.zip*\n\n```dotnetcli\nsavoniatool solution pack --output sourcefiles.zip --verbose --includes \"**/*.cs\" --excludes \"**/obj\" \"**/tests\"\n```\n\n`--includes` and `--excludes` options support multiple values without defining the option name multiple times. Use double quotes (\") to define arbitrary filters e.g. `\"**/*\"` for all files in all folders. Leaving the quotes out in MacOS or Linux will result in filter execution before providing the filter value to the option. Check different pattern formats from document [File globbing in .NET](https://learn.microsoft.com/en-us/dotnet/core/extensions/file-globbing#pattern-formats).\n\nThe tool also supports Response files to provide the parameters.\n\n```dotnetcli\nsavoniatool @respfile.rsp\n```\n\nContents of *respfile.rsp*:\n```\nsolution\npack\n--output\nsourcefile.zip\n--verbose\n--includes\n\"**/*.cs\"\n--excludes\n\"**/obj\"\n\"**/tests\"\n```\n\n### To unpack submissions\n\n- To unpack all submission zip files in a directory\n\n```dotnetcli\nsavoniatool submissions unpack\n```\n\nThis will read all .zip files in current directory and unzip them. Each .zip is unzipped in a folder named the same as the .zip file without the .zip extension (e.g. *myanswer.zip* is unpacked to folder *myanswer*).\n\n### To test submissions\n\n- To test all submissions\n\n```dotnetcli\nsavoniatool submissions test run\n```\n\nThis is used to run the tests and create a test run summary to each submission folder.\n\n### To pack submissions\n\n- To pack all submission folders in a directory\n\n```dotnetcli\nsavoniatool submissions pack\n```\n\nThis will create a zip file for each subdirectory. The subdirectory itself is not included in the zip file, only files and folders inside the subdirectory. The default values for `--includes` and `--excludes` are good for common usage scenario where all subdirectories in target directory (default is current directory) are to be packed to individual zip files.\n\nThe individual zip files can be packed to a single zip file with command\n\n```dotnetcli\nsavoniatool submissions pack -o submissions.zip\n```\n\nDefining value for option `--output` or `-o` will change the packing behavior to pack resulting files to a single zip file. The default values for `--includes` and `--excludes` are good for common usage scenario where all zip files in target directory (default is current directory) are to be packed to a single zip file.\n\n### To create hash\n\n- To create hash from selected file(s) in answers\n\n```dotnetcli\nsavoniatool hash create \u003cpath\u003e hashes.csv --includes \"**/*.cs\"\n```\n\nThis will find all **.cs* files in all directories and creates a hash from the files. Code comments (line and block), white spaces, new lines and carriage returns are removed by default before creating the hash. Hashes are saved in the output file defined with option `-o` (or `--output`).\n\n`--filter-source-code` option uses flags arguments. Define multiple values with comma (,). E.g. `--filter-source-code whitespaces,newlines` to filter out white spaces and new lines. Set option `--filter-source-code none` to create hash from the file as is (without any filtering).\n\n### To open duplicates in editor\n\n- To open duplicate source files in editor for manual checking\n\n```dotnetcli\nsavoniatool hash open duplicates.csv \u003csourcePath\u003e\n```\n\nThis will read hash groups (files that create the same hash value) from source file `duplicates.csv` and open the files with an editor. Uses VS Code as default editor to open the files and assumes that the editor is in PATH environment variable to allow opening from terminal. Reads filename from the first column and hash value from the last column. Define zero-based index values for options `--file-index` and `--hash-index` if first and last column assumptions are not valid for source file.\n\n\u003e NOTE! This will try to open as many instances of the editor as there are hash groups in the source file. Each instance will open all code files within the hash group. **This may result in excess amounts of editor instances**.\n\n### To parse a CSV file\n\n- To parse required fields from a CSV. The file could be for example downloaded from Moodle LMS's Task activity.\n\n```dotnetcli\nsavoniatool csv parse moodle-csv-file.csv --fields 1 2 3 -o parsed.csv --field-filters 1 \\d+\n```\n\nThis reads fields (or columns) 1, 2 and 3 from source CSV file (`moodle-csv-file.csv`). Uses regex filter (\\d+) to get only numbers from the field 1 and outputs the result to parsed.csv file. The `--field-filters` option is used to define how the selected fields are parsed with regex pattern(s). The regex pattern can be defined in the --field-filters option directly or to a JSON file that is read with option `--regexes`. The JSON file must contain the regexes as a key-value pair (or dictionary with string keys and string values) like:\n\n```json\n{\n    \"num\": \"\\\\d+\",\n    \"word\": \"^([\\\\w\\\\-]+)\"\n}\n```\n\n`--field-filters` option references the regex from JSON file with the key value like `--field-filters 3 word` to select the first word from field 3.\n\nThe fields in the CSV file can be referenced by number or by name when the CSV file contains a header row. The numbers start from one (1) (i.e. the first field's number is one). Options `--fields` and `--field-filters` both uses the field references.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsavonia-cs%2Fsavonia-assignment-tool","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsavonia-cs%2Fsavonia-assignment-tool","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsavonia-cs%2Fsavonia-assignment-tool/lists"}