def reset(): subprocess.run(["git", "checkout", "master"], stdout=PIPE, stderr=PIPE) # Reset back to inital commit. cli.info("Rewinding history.") res = subprocess.run(["git", "rev-list", "--max-parents=0", "HEAD"], stdout=PIPE, stderr=PIPE) root_commit = res.stdout.decode("utf-8").strip() subprocess.run(["git", "reset", "--hard", root_commit], stdout=PIPE, stderr=PIPE) # Force push master cli.info("Resetting remote master.") subprocess.run(["git", "push", "--force"], stdout=PIPE, stderr=PIPE) # Delete branch cli.info(f"Removing branch `{BRANCH_NAME}`.") subprocess.run(["git", "branch", "-D", BRANCH_NAME], stdout=PIPE, stderr=PIPE) # Delete remote branch cli.info(f"Removing remote branch `{BRANCH_NAME}`.") subprocess.run(["git", "push", "-d", "origin", BRANCH_NAME], stdout=PIPE, stderr=PIPE) # Setup again cli.info("Setting up again.") setup()
def setup(): # Copy repo so we can practice pulling. repo_name = os.getcwd() pull_repo_name = repo_name + PULL_SUFFIX if os.path.exists(pull_repo_name): delete = typer.confirm( f"The directory {pull_repo_name} already exists. Do you want to delete it?" ) if not delete: cli.info("Not deleting.") raise typer.Abort() cli.info(f"Deleting {pull_repo_name}.") utils.rmtree_readonly(pull_repo_name) shutil.copytree(repo_name, pull_repo_name) # Setup original repo so we can practice pushing. with open(".gsc_id", "w") as f: f.write("push_and_pull") res = subprocess.run(["git", "add", ".gsc_id"], stdout=PIPE, stderr=PIPE) if res.returncode != 0: raise setup_exercise.SetupError("Failed to add gsc_id. Contact us for help.") res = subprocess.run(["git", "commit", "-m", COMMIT_MSG], stdout=PIPE, stderr=PIPE) if res.returncode != 0: raise setup_exercise.SetupError( "Failed to setup Git Scientist. Contact us for help." )
def reset(): while not os.path.exists(".git"): os.chdir("..") if os.getcwd() == "/": raise ResetError("This is not a git repo.") if not os.path.exists(".gsc_id"): raise ResetError("This is not a Git Scientist exercise.") gsc_id = pathlib.Path(".gsc_id").read_text().strip() cli.info(f"Resetting {gsc_id}") if gsc_id == "sync_error": sync_error.reset() elif gsc_id == "merge_conflict": merge_conflict.reset() elif gsc_id == "multiple_remotes": multiple_remotes.reset() elif gsc_id == "use_the_force": use_the_force.reset() elif gsc_id == "revert": revert.reset() elif gsc_id == "reset_file": reset_file.reset() elif gsc_id == "amend": amend.reset() else: raise ResetError("Unknown Git Scientist exercise. Try upgrading gsc.")
def reset(): subprocess.run(["git", "checkout", "master"], stdout=PIPE, stderr=PIPE) subprocess.run(["git", "reset", "--hard", "origin/master"], stdout=PIPE, stderr=PIPE) cli.info("Setting up again.") setup()
def setup(): # Make sure we're on the master branch subprocess.run(["git", "checkout", "master"], stdout=PIPE, stderr=PIPE) # Commit a change which needs to be amended codefile = pathlib.Path(FILE_NAME) code = codefile.read_text() changed = code.replace( """ def subtract(x, y): return x + y """, """ def subtract(x, y): # TODO: delete this comment return x - y """, ) codefile.write_text(changed) res = subprocess.run(["git", "add", FILE_NAME], stdout=PIPE, stderr=PIPE) if res.returncode != 0: raise setup_exercise.SetupError("Failed to add code change to master.") res = subprocess.run(["git", "commit", "-m", MASTER_COMMIT_MSG], stdout=PIPE, stderr=PIPE) if res.returncode != 0: raise setup_exercise.SetupError("Failed to commit to master.") cli.info( "\nUse `git status` and `git log` to take a look at what's changed in your local repo.\n" "When you're ready to start, amend the most recent commit.\n")
def check_commit_message(msg: str) -> None: cli.info(f"Checking commit message: {msg}") if msg.endswith("."): cli.warn( "You shouldn't put a full stop at the end of your Git commit messages.\n" "Messages should be concise and not gramatically correct sentences." ) if len(msg) >= 50: cli.warn( "Git commit messages should be fewer than 50 characters long.\n" f"You've used {len(msg)}.\n" "Try to make your commit messages more concise." )
def login(email: str): res = requests.post(API_URL + "/login", data={"email": email}) if res.status_code != 200: raise AuthenticationError("User not found.") cli.info("We sent you an email. Click the link inside to login.") # Start a localhost HTTP server to wait for the email verification token. server = http.server.HTTPServer(("", LOCAL_PORT), TokenHandler) server.handle_request() # Check for new token to see if we logged in successfully try: get_token() except AuthenticationError: raise AuthenticationError("Login Failed.")
async def handle_login(email: str): url = BASE_URL + "/socket/websocket" async with websockets.connect(url) as websocket: login_msg = { "topic": "login", "event": "phx_join", "payload": { "email": email }, "ref": "", } await websocket.send(json.dumps(login_msg)) while True: raw = await websocket.recv() resp = json.loads(raw) event = resp["event"] if event == "phx_reply": if resp["payload"]["status"] == "ok": cli.info( "We sent you an email. Click the link inside to log in." ) else: raise LoginError( "Login failed unexpectedly.\n" f'Response: {json.dumps(resp["payload"]["response"])}\n' "Contact us if this error persists.") break elif event == "login_success": session_unique_id = resp["payload"]["session_unique_id"] if not os.path.exists(GSC_DIR): os.makedirs(GSC_DIR) with open(GSC_TOKEN, "w") as f: f.write(session_unique_id) break elif event == "error": raise LoginError( f'Login failed.\nReason: {resp["payload"]["reason"]}\n') break
def setup(gsc_id: str): while not os.path.exists(".git"): os.chdir("..") if os.getcwd() == "/": raise SetupError("This is not a git repo.") if not gsc_id: if not os.path.exists(".gsc_id"): raise SetupError( "Could not find a Git Scientist exercise ID.\n" "Did you mean to give an ID as an argument to gsc?") gsc_id = pathlib.Path(".gsc_id").read_text().strip() # Just in case someone decides to use dashes. gsc_id = gsc_id.replace("-", "_") cli.info(f"Setting up {gsc_id}") if gsc_id == "push_and_pull": push_and_pull.setup() elif gsc_id == "sync_error": sync_error.setup() elif gsc_id == "merge_conflict": merge_conflict.setup() elif gsc_id == "multiple_remotes": multiple_remotes.setup() elif gsc_id == "use_the_force": use_the_force.setup() elif gsc_id == "revert": revert.setup() elif gsc_id == "reset_file": reset_file.setup() elif gsc_id == "amend": amend.setup() else: raise SetupError("Unknown Git Scientist exercise. Try upgrading gsc.")
def reset(): # Reset back to inital commit. cli.info("Rewinding history.") res = subprocess.run( ["git", "rev-list", "--max-parents=0", "HEAD"], stdout=PIPE, stderr=PIPE ) root_commit = res.stdout.decode("utf-8").strip() subprocess.run(["git", "reset", "--hard", root_commit], stdout=PIPE, stderr=PIPE) # Force push cli.info("Cleaning remote repo.") subprocess.run(["git", "push", "--force"], stdout=PIPE, stderr=PIPE) # Setup again cli.info("Setting up again.") setup()
def setup(): state = {} # Make sure we're on the master branch subprocess.run(["git", "checkout", "master"], stdout=PIPE, stderr=PIPE) # Create branch res = subprocess.run(["git", "branch", BRANCH_NAME], stdout=PIPE, stderr=PIPE) if res.returncode != 0: raise setup_exercise.SetupError( f"Failed to create branch `{BRANCH_NAME}`. Run `gsc reset`." ) codefile = pathlib.Path(FILE_NAME) # Create commit on master cli.info("Implementing the divide function incorrectly on master.") code = codefile.read_text() implemented_divide = code.replace( """ def divide(x, y): return "Hello World" """, """ def divide(x, y): # This is probably correct - don't have time to test return x % y """, ) codefile.write_text(implemented_divide) res = subprocess.run(["git", "add", FILE_NAME], stdout=PIPE, stderr=PIPE) if res.returncode != 0: raise setup_exercise.SetupError("Failed to add code change to master.") res = subprocess.run( ["git", "commit", "-m", MASTER_COMMIT_MSG], stdout=PIPE, stderr=PIPE ) if res.returncode != 0: raise setup_exercise.SetupError("Failed to commit to master.") res = subprocess.run(["git", "rev-parse", "HEAD"], stdout=PIPE, stderr=PIPE) if res.returncode != 0: raise setup_exercise.SetupError("Failed to get hash of commit on master.") state["master_hash"] = res.stdout.decode("utf-8").strip() # Push master branch cli.info("Pushing master.") res = subprocess.run(["git", "push"], stdout=PIPE, stderr=PIPE) if res.returncode != 0: raise setup_exercise.SetupError("Failed to push commit.") # Switch branch cli.info("Switching branch.") subprocess.run(["git", "checkout", BRANCH_NAME], stdout=PIPE, stderr=PIPE) # Create local commit cli.info(f"Implementing the divide function correctly on branch `{BRANCH_NAME}`.") implemented_divide = code.replace( """ def divide(x, y): return "Hello World" """, """ def divide(x, y): return x / y """, ) codefile.write_text(implemented_divide) res = subprocess.run(["git", "add", FILE_NAME], stdout=PIPE, stderr=PIPE) if res.returncode != 0: raise setup_exercise.SetupError("Failed to add code change to branch.") res = subprocess.run( ["git", "commit", "-m", BRANCH_COMMIT_MSG], stdout=PIPE, stderr=PIPE ) if res.returncode != 0: raise setup_exercise.SetupError("Failed to commit to branch.") # Push local branch cli.info(f"Pushing {BRANCH_NAME}.") res = subprocess.run( ["git", "push", "--set-upstream", "origin", BRANCH_NAME], stdout=PIPE, stderr=PIPE, ) if res.returncode != 0: raise setup_exercise.SetupError("Failed to push commit.") # Back to master cli.info("Switching back to master.") subprocess.run(["git", "checkout", "master"], stdout=PIPE, stderr=PIPE) # Stash master commit hash for verification later pathlib.Path(".gsc_state").write_text(json.dumps(state)) cli.info( "\nUse `git status`, `git log`, and `git branch` to take a look at what's changed in your local repo.\n" f"When you're ready to start, rebase the `{BRANCH_NAME}` branch onto master and push it.\n" )
def setup(): cli.info("There's no setup for this exercise.")
def setup(): state = {} # Make sure we're on the master branch subprocess.run(["git", "checkout", "master"], stdout=PIPE, stderr=PIPE) # Create branch res = subprocess.run(["git", "branch", BRANCH_NAME], stdout=PIPE, stderr=PIPE) if res.returncode != 0: raise setup_exercise.SetupError( f"Failed to create branch `{BRANCH_NAME}`. Run `gsc reset`.") codefile = pathlib.Path(FILE_NAME) # Create commit on master cli.info("Implementing the subtract function incorrectly on master.") code = codefile.read_text() implemented_subtract = code.replace( """ def subtract(x, y): return x + y """, """ def subtract(x, y): if x > 0: return x - y return x + y """, ) codefile.write_text(implemented_subtract) res = subprocess.run(["git", "add", FILE_NAME], stdout=PIPE, stderr=PIPE) if res.returncode != 0: raise setup_exercise.SetupError("Failed to add code change to master.") res = subprocess.run(["git", "commit", "-m", MASTER_COMMIT_MSG], stdout=PIPE, stderr=PIPE) if res.returncode != 0: raise setup_exercise.SetupError("Failed to commit to master.") res = subprocess.run(["git", "rev-parse", "HEAD"], stdout=PIPE, stderr=PIPE) if res.returncode != 0: raise setup_exercise.SetupError( "Failed to get hash of commit on master.") state["master_hash"] = res.stdout.decode("utf-8").strip() # Switch branch cli.info("Switching branch.") subprocess.run(["git", "checkout", BRANCH_NAME], stdout=PIPE, stderr=PIPE) # Create local commit cli.info( f"Implementing the subtract function correctly on branch `{BRANCH_NAME}`." ) implemented_subtract = code.replace( """ def subtract(x, y): return x + y """, """ def subtract(x, y): return x - y """, ) codefile.write_text(implemented_subtract) res = subprocess.run(["git", "add", FILE_NAME], stdout=PIPE, stderr=PIPE) if res.returncode != 0: raise setup_exercise.SetupError("Failed to add code change to branch.") res = subprocess.run(["git", "commit", "-m", BRANCH_COMMIT_MSG], stdout=PIPE, stderr=PIPE) if res.returncode != 0: raise setup_exercise.SetupError("Failed to commit to branch.") cli.info("Switching back to master.") subprocess.run(["git", "checkout", "master"], stdout=PIPE, stderr=PIPE) # Stash master commit hash for verification later pathlib.Path(".gsc_state").write_text(json.dumps(state)) cli.info( "\nUse `git status`, `git log`, and `git branch` to take a look at what's changed in your local repo.\n" "When you're ready to start the exercise, switch to the `fix-subtract` branch and try to rebase onto master.\n" )
def reset(): cli.info("There's no reset for this exercise.")
def setup(): state = {} # Backup .git shutil.copytree(".git", ".git.bak") codefile = pathlib.Path(FILE_NAME) # Create remote commit & push cli.info("Implementing the subtract function.") code = codefile.read_text() implemented_subtract = code.replace( """ def subtract(x, y): pass """, """ def subtract(x, y): return x - y """, ) codefile.write_text(implemented_subtract) res = subprocess.run(["git", "add", FILE_NAME], stdout=PIPE, stderr=PIPE) if res.returncode != 0: raise setup_exercise.SetupError("Failed to add first code change.") res = subprocess.run( ["git", "commit", "-m", REMOTE_COMMIT_MSG], stdout=PIPE, stderr=PIPE ) if res.returncode != 0: raise setup_exercise.SetupError("Failed to commit first code change.") res = subprocess.run(["git", "rev-parse", "HEAD"], stdout=PIPE, stderr=PIPE) if res.returncode != 0: raise setup_exercise.SetupError("Failed to get hash of first commit.") state["remote_hash"] = res.stdout.decode("utf-8").strip() cli.info("Pushing the commit.") res = subprocess.run(["git", "push"], stdout=PIPE, stderr=PIPE) if res.returncode != 0: raise setup_exercise.SetupError("Failed to push commit.") # Restore .git cli.info("Forgetting about remote commit.") utils.rmtree_readonly(".git") shutil.copytree(".git.bak", ".git") utils.rmtree_readonly(".git.bak") # Create local commit cli.info("Implementing the divide function.") implemented_divide = code.replace( """ def divide(x, y): pass """, """ def divide(x, y): return x / y """, ) codefile.write_text(implemented_divide) res = subprocess.run(["git", "add", FILE_NAME], stdout=PIPE, stderr=PIPE) if res.returncode != 0: raise setup_exercise.SetupError("Failed to add second code change.") res = subprocess.run( ["git", "commit", "-m", LOCAL_COMMIT_MSG], stdout=PIPE, stderr=PIPE ) if res.returncode != 0: raise setup_exercise.SetupError("Failed to commit second code change.") # Stash remote commit hash for verification later pathlib.Path(".gsc_state").write_text(json.dumps(state)) cli.info( "\nUse `git status` and `git log` to take a look at what's changed in your local repo.\n" "When you're ready to start the exercise, try `git push`.\n" )