-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit 75c67bb
Showing
28 changed files
with
1,676 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
on: | ||
release: | ||
types: [created] | ||
|
||
jobs: | ||
releases-matrix: | ||
name: Release Go Binary | ||
runs-on: ubuntu-latest | ||
strategy: | ||
matrix: | ||
# build and publish in parallel: linux/386, linux/amd64, linux/arm64, darwin/amd64, darwin/arm64 | ||
goos: [linux, darwin] | ||
goarch: ["386", amd64, arm64] | ||
exclude: | ||
- goarch: "386" | ||
goos: darwin | ||
steps: | ||
- uses: actions/checkout@v3 | ||
- uses: wangyoucao577/[email protected] | ||
with: | ||
github_token: ${{ secrets.GITHUB_TOKEN }} | ||
goos: ${{ matrix.goos }} | ||
goarch: ${{ matrix.goarch }} | ||
extra_files: LICENSE Readme.md |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
# Binaries for programs and plugins | ||
*.exe | ||
*.exe~ | ||
*.dll | ||
*.so | ||
*.dylib | ||
|
||
# Test binary, built with `go test -c` | ||
*.test | ||
|
||
# Output of the go coverage tool, specifically when used with LiteIDE | ||
*.out | ||
|
||
# Dependency directories (remove the comment below to include it) | ||
# vendor/ | ||
|
||
# Go workspace file | ||
go.work | ||
|
||
### Go Patch ### | ||
/vendor/ | ||
/Godeps/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
MIT License | ||
|
||
Copyright (c) 2022 Emerson Mello | ||
|
||
Permission is hereby granted, free of charge, to any person obtaining a copy | ||
of this software and associated documentation files (the "Software"), to deal | ||
in the Software without restriction, including without limitation the rights | ||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
copies of the Software, and to permit persons to whom the Software is | ||
furnished to do so, subject to the following conditions: | ||
|
||
The above copyright notice and this permission notice shall be included in all | ||
copies or substantial portions of the Software. | ||
|
||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
SOFTWARE. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,159 @@ | ||
<picture> | ||
<source media="(prefers-color-scheme: dark)" srcset="images/logo-dark.png"> | ||
<img alt="Different logo for light and dark themes" src="images/logo.png"> | ||
</picture> | ||
|
||
**claro** is a [GitHub Classroom](https://classroom.github.com) CLI for teachers | ||
|
||
[![GitHub license](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE) | ||
|
||
# Overview | ||
|
||
**claro** (**cla**ss**ro**om) is a cli tool that offers a simple interface that allows the teacher to clone all student repositories at once for grading and then send grades at once to all these repositories. | ||
|
||
**claro** was inspired by the [Git-Gud-tool](https://github.com/NikolaiMagnussen/Git-Gud-tool) and it was created to make my life simpler as a teacher who relies on Github Classroom. It is suitable for scenarios where the teacher needs to manually grade each assignment and the Github Classroom autograding is not an option. | ||
|
||
**claro** relies on [Github's REST API](https://docs.github.com/en/rest) because currently Github Classroom does not offer an API and it has features that are not present in [Github Classroom Assistant](https://classroom.github.com/assistant). The best one: it is a [CLI](https://clig.dev) :heart:! | ||
|
||
|
||
**claro** provides: | ||
- mass clone of Github repositories | ||
- a template in Markdown for grading (it creates one file per repository) | ||
- customization (commit message, grade sheet title, grading file, etc.) | ||
- access to [Github Personal Access Token](https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/creating-a-personal-access-token) from operating system keyring (i.e. macOS Keychain, Gnome Keyring), environment var or claro's config file | ||
|
||
## Requirements | ||
- [git](https://git-scm.com/docs/git) command line application configured properly | ||
```bash | ||
git config --global user.email "[email protected]" | ||
git config --global user.name "Your Name" | ||
``` | ||
- [Git credential store](https://git-scm.com/book/en/v2/Git-Tools-Credential-Storage) configured properly | ||
- See [section below](#authenticating-with-git-command-line-to-access-repositories-on-github) | ||
|
||
## Download | ||
|
||
- [Download Binaries for different platforms](https://github.com/emersonmello/claro/releases/latest) | ||
- macOS | ||
- darwin-amd64 | ||
- darwin-arm64 | ||
- Linux | ||
- linux-386 | ||
- linux-amd64 | ||
- linux-arm64 | ||
|
||
|
||
## Usage | ||
|
||
### Straight workflow | ||
|
||
1. Create a Github Classroom assignment with a distinguish repository prefix | ||
- Example: `2022-01-assignment-01` | ||
2. Clone all repositories from a Github Classroom organization with a specific assignment prefix | ||
|
||
![cloning](images/clone.gif) | ||
|
||
3. Grade each student's work and write down the feedback in the respective Markdown file | ||
![grading](images/grading.gif) | ||
4. Push the grading | ||
![pushing](images/push.gif) | ||
## Other commands | ||
![claro help message](images/claro.png) | ||
### Pull students repositories | ||
**claro** offers a `pull` command suitable for workflows where students make incremental deliveries to the same GitHub Classroom repository. | ||
- Example: | ||
```bash | ||
claro pull 2022-01-assignment-01 | ||
``` | ||
### List all repositories which start with a specific prefix | ||
Before cloning multiple repositories, you might want to check which repositories will be cloned with a specific prefix. **claro** offers the `list` command for that. | ||
- Example: | ||
```bash | ||
claro list 2022-01-assignment-01 | ||
``` | ||
### Customize commit message, grading filename, grading string | ||
The **claro** default strings are: | ||
- **Grading filename:** `GRADING.md` | ||
- It will be created and pushed to student repository | ||
- **Grade string:** `Grade: ` | ||
- It will be inside grading file | ||
- **Commit message:** `Graded project, the file containing the grade is in the root directory` | ||
- It is the commit message | ||
- **Grade sheet title** `Feedback` | ||
- It will be inside grading file as title 1 (# Feedback) | ||
You can change the values using **claro** `config` command. The new values will be stored in the **claro**'s config file (default `$HOME/.claro.env`). | ||
- Examples: | ||
- `claro config filename "Correcao.md"` | ||
- `claro config grade "Nota: "` | ||
- `claro config message "Correção finalizada, veja arquivo na raiz do repositório"` | ||
- `claro config title "Comentários"` | ||
|
||
## Storing claro's GitHub Personal Access Token in the OS keyring | ||
|
||
**claro** only supports HTTPS remote URL (git over SSH is so [annoying](https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/about-authentication-to-github#authenticating-with-the-command-line)). | ||
|
||
**claro** consumes [Github's REST API](https://docs.github.com/en/rest) to fetch the list of repositories (assignments) from a GitHub Classroom organization. So, **claro** uses a [GitHub Personal Access Token](https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/creating-a-personal-access-token). | ||
- **claro** will try to get GitHub Personal Access Token from: (1) operating system keyring; (2) environment var (`GH_TOKEN`); (3) **claro**'s config file (default `$HOME/.claro.env`) | ||
|
||
You can inform the token whenever you clone repositories, or you can save the token in the operating system keyring (recommended) or in the **claro**'s config file. Please, have a look at [Authenticating with git command line to access repositories on GitHub](#authenticating-with-git-command-line-to-access-repositories-on-github). | ||
- To save the token (**claro** will try to save to the OS keyring first and then to the config file.) | ||
- `claro config token add` | ||
- To delete the token from OS keyring | ||
- `claro config token del` | ||
## Authenticating with git command line to access repositories on GitHub | ||
> Using an HTTPS remote URL has some advantages compared with using SSH. It's easier to set up than SSH, and usually works through strict firewalls and proxies. However, it also prompts you to enter your GitHub credentials every time you pull or push a repository. ([GitHub Docs](https://docs.github.com/en/get-started/getting-started-with-git/why-is-git-always-asking-for-my-password)). | ||
|
||
To access repositories on GitHub from the command line application over HTTPS you must authenticate with a [GitHub personal access token](https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/about-authentication-to-github#authenticating-with-the-command-line). | ||
|
||
You can avoid being prompted for your password (personal access token) by configuring Git to cache your credentials for you on [git credential storage](https://git-scm.com/book/en/v2/Git-Tools-Credential-Storage). Git works with several credential helper: | ||
|
||
- **Unsafe and simple way** (not recommended!) | ||
- This method stores your password in plaintext on disk, protected only by filesystem permissions (default `$HOME/.git-credentials`) | ||
- on Linux, macOS or Windows | ||
```bash | ||
git config --global credential.helper store | ||
``` | ||
- The first time git will ask the username and password. Subsequent request will use the credentials from the store (default `$HOME/.git-credentials`). | ||
- Example: | ||
`https://username:[email protected]` | ||
- **Safe with a little complexity** | ||
- This method stores your password encrypted on disk in the operating system keyring service. | ||
- You can use native operating system keyring | ||
- Linux [Secret Service](https://specifications.freedesktop.org/secret-service/latest/) dbus interface, which is provided by [GNOME Keyring](https://wiki.gnome.org/Projects/GnomeKeyring) | ||
- Use [Seahorse app](https://wiki.gnome.org/Apps/Seahorse) to create a default collection with `login` name | ||
- Open `seahorse`; go to `file->new->password keyring`; when asked for a name, use: `login` | ||
|
||
```bash | ||
# ------------------------------------------------# | ||
# on Ubuntu Linux 22.04 LTS | ||
# ------------------------------------------------# | ||
sudo apt-get install libsecret-1-0 libsecret-1-dev g++ make | ||
cd /usr/share/doc/git/contrib/credential/libsecret && sudo make | ||
git config --global credential.helper /usr/share/doc/git/contrib/credential/libsecret/git-credential-libsecret | ||
# ------------------------------------------------# | ||
``` | ||
- macOS Keychain (`/usr/bin/security`) | ||
- `git config --global credential.helper osxkeychain` | ||
- Multi-plataform (Linux, macOS or Windows) | ||
- You can also use a credential helper like [Git Credential Manager](https://github.com/GitCredentialManager/git-credential-manager) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,78 @@ | ||
package cmd | ||
|
||
import ( | ||
"fmt" | ||
"os" | ||
|
||
"github.com/emersonmello/claro/utils" | ||
"github.com/pterm/pterm" | ||
"github.com/spf13/cobra" | ||
"github.com/spf13/viper" | ||
) | ||
|
||
var OutputDir string | ||
|
||
var cloneCmd = &cobra.Command{ | ||
Use: "clone <organization> <assignment repositories prefix>", | ||
Short: "Clone all students assignment repositories in an organization", | ||
Example: "claro clone ifsc-classroom 2022-01-assignment-01", | ||
SilenceErrors: true, | ||
Args: cobra.ExactArgs(2), | ||
|
||
Run: func(cmd *cobra.Command, args []string) { | ||
|
||
if OutputDir == "repository prefix" { | ||
OutputDir = args[1] | ||
} | ||
|
||
if _, err := os.Stat(OutputDir); !os.IsNotExist(err) { | ||
pterm.Error.Printf("The output directory '%s' already exists on the current directory!\n", OutputDir) | ||
os.Exit(1) | ||
} | ||
|
||
repositories := utils.GetRepositoryList(args[0], args[1]) | ||
|
||
if len(repositories) <= 0 { | ||
pterm.Warning.Printfln("Organization %s does not contains repositories with prefix %s\n", args[0], args[1]) | ||
os.Exit(0) | ||
} else { | ||
fmt.Printf("%d repositories were found\n", len(repositories)) | ||
} | ||
|
||
if !utils.PromptUser("Would you like to proceed (Y/n)? ", "yes") { | ||
os.Exit(0) | ||
} | ||
|
||
s, _ := pterm.DefaultSpinner.Start("Creating " + OutputDir + " directory") | ||
if e := os.Mkdir(OutputDir, os.ModePerm); e != nil { | ||
OutputDir = "" | ||
s.Fail(e.Error()) | ||
os.Exit(1) | ||
} | ||
s.Success() | ||
|
||
utils.CloneRepositories(OutputDir, repositories) | ||
|
||
e := os.Chdir(OutputDir) | ||
checkError(e) | ||
|
||
s, _ = pterm.DefaultSpinner.Start("Creating Markdown files") | ||
for _, r := range repositories { | ||
f, e := os.Create("grade-" + r.Name + ".md") | ||
if e != nil { | ||
s.Fail(e.Error()) | ||
} | ||
_, e = f.WriteString("# " + viper.GetString("grade_title") + "\n\n- ...\n- " + viper.GetString("grade_string") + " \n\n") | ||
defer f.Close() | ||
if e != nil { | ||
s.Fail(e.Error()) | ||
} | ||
} | ||
s.Success() | ||
}, | ||
} | ||
|
||
func init() { | ||
rootCmd.AddCommand(cloneCmd) | ||
cloneCmd.Flags().StringVarP(&OutputDir, "output-directory", "o", "repository prefix", "Directory where the cloned repositories should be stored") | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
/* | ||
Copyright © 2022 Emerson Mello | ||
*/ | ||
package cmd | ||
|
||
import ( | ||
"github.com/spf13/cobra" | ||
) | ||
|
||
// configCmd represents the config command | ||
var configCmd = &cobra.Command{ | ||
Use: "config", | ||
Short: "Configure claro's properties (github token, commit message, etc.)", | ||
} | ||
|
||
func init() { | ||
rootCmd.AddCommand(configCmd) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
/* | ||
Copyright © 2022 Emerson Mello | ||
*/ | ||
package cmd | ||
|
||
import ( | ||
"github.com/emersonmello/claro/utils" | ||
"github.com/spf13/cobra" | ||
) | ||
|
||
// filenameCmd represents the filename command | ||
var filenameCmd = &cobra.Command{ | ||
Use: "filename <filename.md>", | ||
Example: "claro config filename \"GRADING.md\" ", | ||
Short: "define the name of the file that will be created in the student repository containing the feedback", | ||
Args: cobra.ExactArgs(1), | ||
Run: func(cmd *cobra.Command, args []string) { | ||
utils.WriteConfigFile("grade_filename", args[0], "Grade sheet filename has been set successfully!") | ||
}, | ||
} | ||
|
||
func init() { | ||
configCmd.AddCommand(filenameCmd) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
/* | ||
Copyright © 2022 Emerson Mello | ||
*/ | ||
package cmd | ||
|
||
import ( | ||
"github.com/emersonmello/claro/utils" | ||
"github.com/spf13/cobra" | ||
) | ||
|
||
// gradeCmd represents the grade command | ||
var gradeCmd = &cobra.Command{ | ||
Use: "grade <\"string\">", | ||
Example: "claro config grade \"Grade: \"", | ||
Short: "define the grade string inserted in the file representing the grade sheet", | ||
Args: cobra.ExactArgs(1), | ||
Run: func(cmd *cobra.Command, args []string) { | ||
utils.WriteConfigFile("grade_string", args[0], "Grade string has been set successfully!") | ||
}, | ||
} | ||
|
||
func init() { | ||
configCmd.AddCommand(gradeCmd) | ||
} |
Oops, something went wrong.