mirror of
https://github.com/bellingcat/vk-url-scraper.git
synced 2026-06-08 03:18:37 +03:00
Initial commit
This commit is contained in:
175
scripts/personalize.py
Normal file
175
scripts/personalize.py
Normal file
@@ -0,0 +1,175 @@
|
||||
"""
|
||||
Run this script once after first creating your project from this template repo to personalize
|
||||
it for own project.
|
||||
|
||||
This script is interactive and will prompt you for various inputs.
|
||||
"""
|
||||
|
||||
from pathlib import Path
|
||||
from typing import Generator, List, Tuple
|
||||
|
||||
import click
|
||||
from click_help_colors import HelpColorsCommand
|
||||
from rich import print
|
||||
from rich.markdown import Markdown
|
||||
from rich.prompt import Confirm
|
||||
from rich.syntax import Syntax
|
||||
from rich.traceback import install
|
||||
|
||||
install(show_locals=True, suppress=[click])
|
||||
|
||||
REPO_BASE = (Path(__file__).parent / "..").resolve()
|
||||
|
||||
FILES_TO_REMOVE = {
|
||||
REPO_BASE / ".github" / "workflows" / "setup.yml",
|
||||
REPO_BASE / "setup-requirements.txt",
|
||||
REPO_BASE / "scripts" / "personalize.py",
|
||||
}
|
||||
|
||||
PATHS_TO_IGNORE = {
|
||||
REPO_BASE / "README.md",
|
||||
REPO_BASE / ".git",
|
||||
REPO_BASE / "docs" / "source" / "_static" / "favicon.ico",
|
||||
}
|
||||
|
||||
GITIGNORE_LIST = [
|
||||
line.strip()
|
||||
for line in (REPO_BASE / ".gitignore").open().readlines()
|
||||
if line.strip() and not line.startswith("#")
|
||||
]
|
||||
|
||||
REPO_NAME_TO_REPLACE = "python-package-template"
|
||||
BASE_URL_TO_REPLACE = "https://github.com/allenai/python-package-template"
|
||||
|
||||
|
||||
@click.command(
|
||||
cls=HelpColorsCommand,
|
||||
help_options_color="green",
|
||||
help_headers_color="yellow",
|
||||
context_settings={"max_content_width": 115},
|
||||
)
|
||||
@click.option(
|
||||
"--github-org",
|
||||
prompt="GitHub organization or user (e.g. 'allenai')",
|
||||
help="The name of your GitHub organization or user.",
|
||||
)
|
||||
@click.option(
|
||||
"--github-repo",
|
||||
prompt="GitHub repository (e.g. 'python-package-template')",
|
||||
help="The name of your GitHub repository.",
|
||||
)
|
||||
@click.option(
|
||||
"--package-name",
|
||||
prompt="Python package name (e.g. 'my-package')",
|
||||
help="The name of your Python package.",
|
||||
)
|
||||
@click.option(
|
||||
"-y",
|
||||
"--yes",
|
||||
is_flag=True,
|
||||
help="Run the script without prompting for a confirmation.",
|
||||
default=False,
|
||||
)
|
||||
@click.option(
|
||||
"--dry-run",
|
||||
is_flag=True,
|
||||
hidden=True,
|
||||
default=False,
|
||||
)
|
||||
def main(
|
||||
github_org: str, github_repo: str, package_name: str, yes: bool = False, dry_run: bool = False
|
||||
):
|
||||
repo_url = f"https://github.com/{github_org}/{github_repo}"
|
||||
package_actual_name = package_name.replace("_", "-")
|
||||
package_dir_name = package_name.replace("-", "_")
|
||||
|
||||
# Confirm before continuing.
|
||||
print(f"Repository URL set to: [link={repo_url}]{repo_url}[/]")
|
||||
print(f"Package name set to: [cyan]{package_actual_name}[/]")
|
||||
if not yes:
|
||||
yes = Confirm.ask("Is this correct?")
|
||||
if not yes:
|
||||
raise click.ClickException("Aborted, please run script again")
|
||||
|
||||
# Delete files that we don't need.
|
||||
for path in FILES_TO_REMOVE:
|
||||
assert path.is_file(), path
|
||||
if not dry_run:
|
||||
path.unlink()
|
||||
else:
|
||||
print(f"Removing {path}")
|
||||
|
||||
# Personalize remaining files.
|
||||
replacements = [
|
||||
(BASE_URL_TO_REPLACE, repo_url),
|
||||
(REPO_NAME_TO_REPLACE, github_repo),
|
||||
("my-package", package_actual_name),
|
||||
("my_package", package_dir_name),
|
||||
]
|
||||
if dry_run:
|
||||
for old, new in replacements:
|
||||
print(f"Replacing '{old}' with '{new}'")
|
||||
for path in iterfiles(REPO_BASE):
|
||||
personalize_file(path, dry_run, replacements)
|
||||
|
||||
# Rename 'my_package' directory to `package_dir_name`.
|
||||
if not dry_run:
|
||||
(REPO_BASE / "my_package").replace(REPO_BASE / package_dir_name)
|
||||
else:
|
||||
print(f"Renaming 'my_package' directory to '{package_dir_name}'")
|
||||
|
||||
# Start with a fresh README.
|
||||
readme_contents = f"""# {package_actual_name}\n"""
|
||||
if not dry_run:
|
||||
with open(REPO_BASE / "README.md", "w+t") as readme_file:
|
||||
readme_file.write(readme_contents)
|
||||
else:
|
||||
print("Replacing README.md contents with:\n", Markdown(readme_contents))
|
||||
|
||||
install_example = Syntax("pip install -e '.[dev]'", "bash")
|
||||
print(
|
||||
"[green]\N{check mark} Success![/] You can now install your package locally in development mode with:\n",
|
||||
install_example,
|
||||
)
|
||||
|
||||
|
||||
def iterfiles(dir: Path) -> Generator[Path, None, None]:
|
||||
assert dir.is_dir()
|
||||
for path in dir.iterdir():
|
||||
if path in PATHS_TO_IGNORE:
|
||||
continue
|
||||
|
||||
is_ignored_file = False
|
||||
for gitignore_entry in GITIGNORE_LIST:
|
||||
if path.relative_to(REPO_BASE).match(gitignore_entry):
|
||||
is_ignored_file = True
|
||||
break
|
||||
if is_ignored_file:
|
||||
continue
|
||||
|
||||
if path.is_dir():
|
||||
yield from iterfiles(path)
|
||||
else:
|
||||
yield path
|
||||
|
||||
|
||||
def personalize_file(path: Path, dry_run: bool, replacements: List[Tuple[str, str]]):
|
||||
with path.open("r+t") as file:
|
||||
filedata = file.read()
|
||||
|
||||
should_update: bool = False
|
||||
for old, new in replacements:
|
||||
if filedata.count(old):
|
||||
should_update = True
|
||||
filedata = filedata.replace(old, new)
|
||||
|
||||
if should_update:
|
||||
if not dry_run:
|
||||
with path.open("w+t") as file:
|
||||
file.write(filedata)
|
||||
else:
|
||||
print(f"Updating {path}")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
39
scripts/prepare_changelog.py
Normal file
39
scripts/prepare_changelog.py
Normal file
@@ -0,0 +1,39 @@
|
||||
from datetime import datetime
|
||||
from pathlib import Path
|
||||
|
||||
from my_package.version import VERSION
|
||||
|
||||
|
||||
def main():
|
||||
changelog = Path("CHANGELOG.md")
|
||||
|
||||
with changelog.open() as f:
|
||||
lines = f.readlines()
|
||||
|
||||
insert_index: int = -1
|
||||
for i in range(len(lines)):
|
||||
line = lines[i]
|
||||
if line.startswith("## Unreleased"):
|
||||
insert_index = i + 1
|
||||
elif line.startswith(f"## [v{VERSION}]"):
|
||||
print("CHANGELOG already up-to-date")
|
||||
return
|
||||
elif line.startswith("## [v"):
|
||||
break
|
||||
|
||||
if insert_index < 0:
|
||||
raise RuntimeError("Couldn't find 'Unreleased' section")
|
||||
|
||||
lines.insert(insert_index, "\n")
|
||||
lines.insert(
|
||||
insert_index + 1,
|
||||
f"## [v{VERSION}](https://github.com/allenai/python-package-template/releases/tag/v{VERSION}) - "
|
||||
f"{datetime.now().strftime('%Y-%m-%d')}\n",
|
||||
)
|
||||
|
||||
with changelog.open("w") as f:
|
||||
f.writelines(lines)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
19
scripts/release.sh
Executable file
19
scripts/release.sh
Executable file
@@ -0,0 +1,19 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -e
|
||||
|
||||
TAG=$(python -c 'from my_package.version import VERSION; print("v" + VERSION)')
|
||||
|
||||
read -p "Creating new release for $TAG. Do you want to continue? [Y/n] " prompt
|
||||
|
||||
if [[ $prompt == "y" || $prompt == "Y" || $prompt == "yes" || $prompt == "Yes" ]]; then
|
||||
python scripts/prepare_changelog.py
|
||||
git add -A
|
||||
git commit -m "Bump version to $TAG for release" || true && git push
|
||||
echo "Creating new git tag $TAG"
|
||||
git tag "$TAG" -m "$TAG"
|
||||
git push --tags
|
||||
else
|
||||
echo "Cancelled"
|
||||
exit 1
|
||||
fi
|
||||
78
scripts/release_notes.py
Executable file
78
scripts/release_notes.py
Executable file
@@ -0,0 +1,78 @@
|
||||
# encoding: utf-8
|
||||
|
||||
"""
|
||||
Prepares markdown release notes for GitHub releases.
|
||||
"""
|
||||
|
||||
import os
|
||||
from typing import List, Optional
|
||||
|
||||
import packaging.version
|
||||
|
||||
TAG = os.environ["TAG"]
|
||||
|
||||
ADDED_HEADER = "### Added 🎉"
|
||||
CHANGED_HEADER = "### Changed ⚠️"
|
||||
FIXED_HEADER = "### Fixed ✅"
|
||||
REMOVED_HEADER = "### Removed 👋"
|
||||
|
||||
|
||||
def get_change_log_notes() -> str:
|
||||
in_current_section = False
|
||||
current_section_notes: List[str] = []
|
||||
with open("CHANGELOG.md") as changelog:
|
||||
for line in changelog:
|
||||
if line.startswith("## "):
|
||||
if line.startswith("## Unreleased"):
|
||||
continue
|
||||
if line.startswith(f"## [{TAG}]"):
|
||||
in_current_section = True
|
||||
continue
|
||||
break
|
||||
if in_current_section:
|
||||
if line.startswith("### Added"):
|
||||
line = ADDED_HEADER + "\n"
|
||||
elif line.startswith("### Changed"):
|
||||
line = CHANGED_HEADER + "\n"
|
||||
elif line.startswith("### Fixed"):
|
||||
line = FIXED_HEADER + "\n"
|
||||
elif line.startswith("### Removed"):
|
||||
line = REMOVED_HEADER + "\n"
|
||||
current_section_notes.append(line)
|
||||
assert current_section_notes
|
||||
return "## What's new\n\n" + "".join(current_section_notes).strip() + "\n"
|
||||
|
||||
|
||||
def get_commit_history() -> str:
|
||||
new_version = packaging.version.parse(TAG)
|
||||
|
||||
# Get all tags sorted by version, latest first.
|
||||
all_tags = os.popen("git tag -l --sort=-version:refname 'v*'").read().split("\n")
|
||||
|
||||
# Out of `all_tags`, find the latest previous version so that we can collect all
|
||||
# commits between that version and the new version we're about to publish.
|
||||
# Note that we ignore pre-releases unless the new version is also a pre-release.
|
||||
last_tag: Optional[str] = None
|
||||
for tag in all_tags:
|
||||
if not tag.strip(): # could be blank line
|
||||
continue
|
||||
version = packaging.version.parse(tag)
|
||||
if new_version.pre is None and version.pre is not None:
|
||||
continue
|
||||
if version < new_version:
|
||||
last_tag = tag
|
||||
break
|
||||
if last_tag is not None:
|
||||
commits = os.popen(f"git log {last_tag}..{TAG}^ --oneline --first-parent").read()
|
||||
else:
|
||||
commits = os.popen("git log --oneline --first-parent").read()
|
||||
return "## Commits\n\n" + commits
|
||||
|
||||
|
||||
def main():
|
||||
print(get_change_log_notes())
|
||||
print(get_commit_history())
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user