Skip to content
This repository has been archived by the owner on Jul 29, 2024. It is now read-only.

Commit

Permalink
Multiple small changes (#45)
Browse files Browse the repository at this point in the history
  • Loading branch information
davidbrownell authored Jun 10, 2024
2 parents 69f86e0 + aae9705 commit dbb9400
Show file tree
Hide file tree
Showing 7 changed files with 83 additions and 8 deletions.
33 changes: 30 additions & 3 deletions src/PythonProjectBootstrapper/ProjectGenerationUtils.py
Original file line number Diff line number Diff line change
Expand Up @@ -190,8 +190,13 @@ def CopyToOutputDir(

prompt_file = src_dir / prompt_filename
if prompt_file.is_file():
dest_filename = dest_dir / prompt_filename

if dest_filename.is_file():
dest_filename.unlink()

shutil.move(prompt_file, dest_dir)
PathEx.EnsureFile(dest_dir / prompt_filename)
PathEx.EnsureFile(dest_filename)

# existing_manifest will be populated/updated as necessary and saved
generated_manifest: dict[str, str] = CreateManifest(src_dir)
Expand All @@ -209,7 +214,7 @@ def CopyToOutputDir(
with open(potential_manifest, "r") as existing_manifest_file:
existing_manifest = yaml.load(existing_manifest_file, Loader=yaml.Loader)

# Removing <prompt_filename> from the manifest for backward compatability.
# Removing <prompt_filename> from the manifest for backward compatibility.
# Previous iterations of PythonProjectBootstrapper saved "<prompt_filename>"" in the manifest file when it should not have been there
# (the manifest was created using the contents of the temporary directory and "<prompt_filename>"" was there but was removed from the output directory)
# This results in "<prompt_filename>" being listed as a removed file since it exists in the manifest but not in the output directory
Expand Down Expand Up @@ -262,9 +267,31 @@ def CopyToOutputDir(
and current_file_hash == existing_manifest[rel_filepath]
):
modified_template_files.append(output_dir_filepath.as_posix())
elif potential_manifest.is_file():
# If here, the file no longer exists. We still want the file to exist in the manifest
# (so that future generations are still aware of it), but do not want it to be created
# again.
merged_manifest[rel_filepath] = generated_hash

while True:
sys.stdout.write(
f"\nWould you like to recreate {str(output_dir_filepath)}? [yes/no]: "
)
recreate = input().strip().lower()

if recreate in ["yes", "y"]:
added_files.append(output_dir_filepath.as_posix())
break

if recreate in ["no", "n"]:
generated_filename = PathEx.EnsureFile(src_dir / rel_filepath)
generated_filename.unlink()

break
else:
added_files.append(output_dir_filepath.as_posix())
# If here, we are looking at a first time generation and don't need to prompt
merged_manifest[rel_filepath] = generated_hash
added_files.append(output_dir_filepath.as_posix())

# create and save manifest
yaml_comments = textwrap.dedent(
Expand Down
19 changes: 18 additions & 1 deletion src/PythonProjectBootstrapper/package/hooks/post_gen_project.py
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ def SavePrompts() -> None:
""",
)

{% if cookiecutter.minisign_public_key != 'none' %}
{% if cookiecutter.minisign_public_key.strip().lower() != 'none' %}
prompts["Save the Minisign Private Key"] = textwrap.dedent(
f"""\
In this step, we will save the Minisign private key as a GitHub Action Secret.
Expand Down Expand Up @@ -186,6 +186,23 @@ def SavePrompts() -> None:
""",
)

{% if cookiecutter.minisign_public_key.strip().lower() != 'none' %}
prompts["Validate Minisign Signature"] = textwrap.dedent(
"""\
In this step, we validate that a binary was correctly signed.
1. Download a binary and its corresponding signature file from {{ cookiecutter.github_url }}/{{ cookiecutter.github_username }}/{{ cookiecutter.github_project_name }}/releases/latest.
2. In the download directory, run;
docker run -i --rm -v ".:/host" jedisct1/minisign -V -P {{ cookiecutter.minisign_public_key }} -m /host/<binary_name>
replacing '<binary_name>' with the name of the file downloaded in the previous step.
3. Verify that 'Signature and comment signature verified' is displayed in the output.
""",
)

{% endif %}

{% if cookiecutter.openssf_best_practices_badge_id != "none" %}
prompts["Update the OpenSSF Best Practices Badge [Basics]"] = textwrap.dedent(
"""\
Expand Down
2 changes: 1 addition & 1 deletion src/PythonProjectBootstrapper/package/hooks/startup.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ def Execute(
step-by-step instructions on how to set up your project so that it works with 3rd party
solutions (GitHub, PyPi, etc.).
The entire process should take about 20 minutes to complete.
The entire process should take about 25 minutes to complete.
""",
)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -232,6 +232,6 @@ jobs:
release_sources_configuration_filename: .github/release_sources.yaml
secrets:
PYPI_TOKEN: {% raw %}${{ secrets.PYPI_TOKEN }}{% endraw %}
{% if cookiecutter.minisign_public_key != 'none' %}
{% if cookiecutter.minisign_public_key.strip().lower() != 'none' %}
MINISIGN_PRIVATE_KEY: {% raw %}${{ secrets.MINISIGN_PRIVATE_KEY }}{% endraw %}
{% endif %}
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,6 @@ Deactivate*.sh
build/**
dist/**
src/{{ cookiecutter.pypi_project_name }}.egg-info/**

key.pri
key.pub
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
[![PyPI - Python Version](https://img.shields.io/pypi/pyversions/{{ cookiecutter.pypi_project_name }}?color=dark-green)](https://pypi.org/project/{{ cookiecutter.pypi_project_name | pypi_string }}/)
[![PyPI - Version](https://img.shields.io/pypi/v/{{ cookiecutter.pypi_project_name }}?color=dark-green)](https://pypi.org/project/{{ cookiecutter.pypi_project_name | pypi_string }}/)
[![PyPI - Downloads](https://img.shields.io/pypi/dm/{{ cookiecutter.pypi_project_name }})](https://pypistats.org/packages/{{ cookiecutter.pypi_project_name | pypi_string }})
{% if cookiecutter.openssf_best_practices_badge_id != 'none' -%}
{% if cookiecutter.openssf_best_practices_badge_id.strip().lower() != 'none' -%}
[![OpenSSF Best Practices](https://www.bestpractices.dev/projects/{{ cookiecutter.openssf_best_practices_badge_id }}/badge)](https://www.bestpractices.dev/projects/{{ cookiecutter.openssf_best_practices_badge_id }})
{% endif %}
<!-- END: Exclude Package -->
Expand Down Expand Up @@ -48,7 +48,7 @@ Download an executable for Linux, MacOS, or Windows to use the functionality pro
1. Download the archive for the latest release [here]({{ cookiecutter.github_url }}/{{ cookiecutter.github_username }}/{{ cookiecutter.github_project_name }}/releases/latest); the files will begin with `exe.` and contain the name of your operating system.
2. Decompress the archive

{% if cookiecutter.minisign_public_key != 'none' %}
{% if cookiecutter.minisign_public_key.strip().lower() != 'none' %}
#### Verifying Signed Executables

Executables are signed and validated using [Minisign](https://jedisct1.github.io/minisign/).
Expand Down
28 changes: 28 additions & 0 deletions tests/ProjectGenerationUtils_UnitTest.py
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,34 @@ def test_CopyToOutputDir_overwritePrompt(fs, overwrite):
assert status.st_mode & S_IRUSR == S_IRUSR


# ----------------------------------------------------------------------
@pytest.mark.parametrize("recreate", ["y", "n"])
def test_CopyToOutputDir_recreatePrompt(fs, recreate):
src = Path("src")
src2 = Path("src2")
dest = Path("dest")

files1 = [("testFile", "abc"), ("testFile2", "def"), ("testFile3", "hello")]
files2 = [("testFile", "abc"), ("testFile2", "def"), ("testFile3", "hi")]

for filepath, content in files1:
fs.create_file(src / filepath, contents=content)
fs.create_file(src2 / filepath, contents=content)

fs.create_dir(dest)

CopyToOutputDir(src_dir=src, dest_dir=dest)

dest_filename = dest / "testFile"

dest_filename.unlink()

with patch("builtins.input", lambda *args: recreate):
CopyToOutputDir(src_dir=src2, dest_dir=dest)

assert dest_filename.is_file() == (recreate == "y")


# ----------------------------------------------------------------------
def test_CopyToOutputDir_no_prompt(fs):
# Test for the following:
Expand Down

0 comments on commit dbb9400

Please sign in to comment.