Exemplo n.º 1
0
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()
Exemplo n.º 2
0
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."
        )
Exemplo n.º 3
0
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.")
Exemplo n.º 4
0
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()
Exemplo n.º 5
0
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")
Exemplo n.º 6
0
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."
        )
Exemplo n.º 7
0
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.")
Exemplo n.º 8
0
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
Exemplo n.º 9
0
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.")
Exemplo n.º 10
0
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()
Exemplo n.º 11
0
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"
    )
Exemplo n.º 12
0
def setup():
    cli.info("There's no setup for this exercise.")
Exemplo n.º 13
0
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"
    )
Exemplo n.º 14
0
def reset():
    cli.info("There's no reset for this exercise.")
Exemplo n.º 15
0
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"
    )