Skip to content

Commit

Permalink
Add init command
Browse files Browse the repository at this point in the history
  • Loading branch information
nheeb committed Jul 25, 2024
1 parent c54bf7b commit 398fc8f
Show file tree
Hide file tree
Showing 4 changed files with 207 additions and 1 deletion.
1 change: 1 addition & 0 deletions src/hermes/commands/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@

from hermes.commands.base import HermesHelpCommand
from hermes.commands.clean.base import HermesCleanCommand
from hermes.commands.init.base import HermesInitCommand
from hermes.commands.curate.base import HermesCurateCommand
from hermes.commands.harvest.base import HermesHarvestCommand
from hermes.commands.process.base import HermesProcessCommand
Expand Down
3 changes: 2 additions & 1 deletion src/hermes/commands/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
import argparse

from hermes.commands import HermesHelpCommand, HermesCleanCommand, HermesHarvestCommand, HermesProcessCommand, \
HermesCurateCommand, HermesDepositCommand, HermesPostprocessCommand
HermesCurateCommand, HermesDepositCommand, HermesPostprocessCommand, HermesInitCommand
from hermes.commands.base import HermesCommand


Expand All @@ -34,6 +34,7 @@ def main() -> None:

for command in (
HermesHelpCommand(parser),
HermesInitCommand(parser),
HermesCleanCommand(parser),
HermesHarvestCommand(parser),
HermesProcessCommand(parser),
Expand Down
3 changes: 3 additions & 0 deletions src/hermes/commands/init/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# SPDX-FileCopyrightText: 2022 German Aerospace Center (DLR)
#
# SPDX-License-Identifier: Apache-2.0
201 changes: 201 additions & 0 deletions src/hermes/commands/init/base.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,201 @@
# SPDX-FileCopyrightText: 2022 German Aerospace Center (DLR)
#
# SPDX-License-Identifier: Apache-2.0

# SPDX-FileContributor: Michael Meinel

import argparse
import shutil
import os
import subprocess
import requests
import click
from pydantic import BaseModel

from hermes.commands.base import HermesCommand


class HermesInitFolderInfo:
def __init__(self):
self.absolute_path: str = ""
self.has_git: bool = False
self.git_remote_url: str = ""
self.uses_github: bool = False
self.uses_gitlab: bool = False
self.has_hermes_toml: bool = False
self.has_gitignore: bool = False
self.has_citation_cff = False
self.current_branch: str = ""


def scout_current_folder() -> HermesInitFolderInfo:
info = HermesInitFolderInfo()
current_dir = os.getcwd()
info.absolute_path = str(current_dir)
info.has_git = os.path.isdir(os.path.join(current_dir, ".git"))
if info.has_git:
remote_info = subprocess.run(['git', 'remote', '-v'], capture_output=True, text=True, check=True).stdout
for line in remote_info.splitlines():
if line.startswith("origin"):
whitespace_split = line.split()
if len(whitespace_split) > 1:
info.git_remote_url = whitespace_split[1]
break
branch_info = subprocess.run(['git', 'branch'], capture_output=True, text=True, check=True).stdout
for line in remote_info.splitlines():
if line.startswith("*"):
info.current_branch = line.split()[1].strip()
break
info.uses_github = "github" in info.git_remote_url
info.uses_gitlab = "gitlab" in info.git_remote_url
info.has_hermes_toml = os.path.isfile(os.path.join(current_dir, "hermes.toml"))
info.has_gitignore = os.path.isfile(os.path.join(current_dir, ".gitignore"))
info.has_citation_cff = os.path.isfile(os.path.join(current_dir, "CITATION.cff"))
return info


def wait_until_the_user_is_done():
if not click.confirm("Are you done?", default=False):
while not click.confirm("Are you done now?", default=True):
pass


def create_console_hyperlink(url: str, word: str) -> str:
return f"\033]8;;{url}\033\\{word}\033]8;;\033\\"


def download_file_from_url(url, filepath):
with requests.get(url, stream=True) as r:
r.raise_for_status()
with open(filepath, 'wb') as f:
for chunk in r.iter_content(chunk_size=8192):
f.write(chunk)


class HermesInitSettings(BaseModel):
"""Configuration of the ``init`` command."""
pass


class HermesInitCommand(HermesCommand):
""" Install HERMES onto a project. """

command_name = "init"
settings_class = HermesInitSettings

def __init__(self, parser: argparse.ArgumentParser):
super().__init__(parser)
self.folder_info: HermesInitFolderInfo = HermesInitFolderInfo()

def load_settings(self, args: argparse.Namespace):
pass

def refresh_folder_info(self):
self.folder_info = scout_current_folder()

def __call__(self, args: argparse.Namespace) -> None:
self.refresh_folder_info()
click.echo(f"Starting to initialize HERMES in {self.folder_info.absolute_path}")

# Abort if there is already a hermes.toml
if self.folder_info.has_hermes_toml:
click.echo("The current directory already has a `hermes.toml`. "
"It seems like HERMES was already initialized for this project.")
return

# Abort if there is no git
if not self.folder_info.has_git:
click.echo("The current directory already has no `.git` subdirectory. "
"Please execute `hermes init` in the root directory of your git project.")
return

# Abort if neither GitHub nor gitlab is used
if not (self.folder_info.uses_github or self.folder_info.uses_gitlab):
click.echo("Your git project ({}) is not connected to github or gitlab. It is mandatory for HERMES to "
"use one of those hosting services.".format(self.folder_info.git_remote_url))
return

# Creating the citation File
if not self.folder_info.has_citation_cff:
citation_cff_url = "https://citation-file-format.github.io/cff-initializer-javascript/#/"
click.echo("Your project does not contain a `CITATION.cff` file (yet). It would be very helpful for "
"saving important metadata which is necessary for publishing.")
create_cff_now = click.confirm("Do you want to create a `CITATION.cff` file now?", default=True)
if create_cff_now:
click.echo("{} to create the file. Then move it into the project folder before you continue.".format(
create_console_hyperlink(citation_cff_url, "Click here")))
done_creating_cff = click.confirm("Are you done?", default=False)
while not done_creating_cff:
done_creating_cff = click.confirm("Are you done now?", default=True)
self.refresh_folder_info()
if self.folder_info.has_citation_cff:
click.echo("Good job!")
else:
click.echo("Hey you lied to me :( Don't forget to add the `CITATION.cff` file later!")
else:
click.echo("You better do it later or HERMES won't work properly.")
click.echo("You can {} to create the file. Then move it into the project folder.".format(
create_console_hyperlink(citation_cff_url, "click here")))
else:
click.echo("Your project already contains a `CITATION.cff` file. Nice!")

# Creating the hermes.toml file
hermes_toml_raw_url = "https://raw.githubusercontent.com/nheeb/zenodo-test/main/hermes.toml"
download_file_from_url(hermes_toml_raw_url, os.path.join(os.getcwd(), "hermes.toml"))
click.echo("hermes.toml was created.")

# Adding .hermes to the .gitignore
if not self.folder_info.has_gitignore:
with open(".gitignore", 'w') as file:
pass
click.echo("A new `.gitignore` file was created.")
self.refresh_folder_info()
if self.folder_info.has_gitignore:
with open(".gitignore", "r") as file:
gitignore_lines = file.readlines()
if any([line.startswith(".hermes") for line in gitignore_lines]):
click.echo("The `.gitignore` file already contains `.hermes/`")
else:
with open(".gitignore", "a") as file:
file.write("# Ignoring all HERMES cache files")
file.write(".hermes/")
click.echo("Added `.hermes/` to the `.gitignore` file.")

# Creating the ci file
if self.folder_info.uses_github:
github_ci_template_raw_url = ("https://raw.githubusercontent.com/softwarepub/ci-templates/main"
"/TEMPLATE_hermes_github_to_zenodo.yml")
github_folder_path = os.path.join(os.getcwd(), ".github")
if not os.path.isdir(github_folder_path):
os.mkdir(github_folder_path)
workflows_folder_path = os.path.join(github_folder_path, "workflows")
if not os.path.isdir(workflows_folder_path):
os.mkdir(workflows_folder_path)
ci_file_path = os.path.join(workflows_folder_path, "hermes_github_to_zenodo.yml")
download_file_from_url(github_ci_template_raw_url, ci_file_path)
click.echo(f"GitHub CI yml file was created at {ci_file_path}")

# Zenodo access token -> Github Secrets
zenodo_token_url = "https://sandbox.zenodo.org/account/settings/applications/tokens/new/"
click.echo("If you haven't already, {}. You might have to create an account first.".format(
create_console_hyperlink(zenodo_token_url, "create a access token for zenodo")
))
wait_until_the_user_is_done()
if self.folder_info.uses_github:
click.echo("Now add this token to your {} under the name ZENODO_SANDBOX.".format(
create_console_hyperlink(self.folder_info.git_remote_url.replace(".git", "/settings/secrets/actions"),
"project's GitHub secrets")
))
wait_until_the_user_is_done()
click.echo("Next go to your {} and check the checkbox which reads:".format(
create_console_hyperlink(self.folder_info.git_remote_url.replace(".git", "/settings/actions"),
"project settings")
))
click.echo(click.style("Allow GitHub Actions to create and approve pull requests", bold=True))
wait_until_the_user_is_done()
click.echo("Good job!")
elif self.folder_info.uses_gitlab:
print("GITLAB INIT NOT IMPLEMENTED YET")

click.echo("HERMES was initialized.")

0 comments on commit 398fc8f

Please sign in to comment.