From d9ef4559b259014ce4a45041cfd293b0c3d4e248 Mon Sep 17 00:00:00 2001 From: Corey Oordt Date: Mon, 29 Jul 2024 14:33:52 -0500 Subject: [PATCH] Added boilerplate content. --- .cookiecutter.json | 8 - .editorconfig | 23 ++ .github/dependabot.yml | 13 ++ .github/workflows/docs-final.yml | 33 +++ .github/workflows/docs-preview.yml | 38 ++++ .gitignore | 170 +++++++++++++++ .pre-commit-config.yaml | 46 ++++ CODE_OF_CONDUCT.md | 132 ++++++++++++ CONTRIBUTING.md | 147 +++++++++++++ README.md | 13 +- docs/assets/css/cards.css | 200 ++++++++++++++++++ docs/assets/css/extra.css | 54 +++++ docs/assets/css/field-list.css | 34 +++ docs/assets/css/mkdocstrings.css | 39 ++++ docs/assets/favicon.png | Bin 0 -> 3499 bytes docs/assets/images/.gitkeep | 0 docs/assets/logo.svg | 1 + docs/glossary.md | 12 ++ docs/index.md | 16 ++ docs/introduction.md | 21 ++ hiring_software_engineers/__init__.py | 3 - .../hiring_software_engineers.py | 1 - mkdocs.yml | 80 +++++++ .../python/material/docstring/attributes.html | 90 ++++++++ .../python/material/docstring/parameters.html | 98 +++++++++ .../python/material/docstring/raises.html | 72 +++++++ .../python/material/docstring/returns.html | 94 ++++++++ overrides/partials/comments.html | 37 ++++ requirements.txt | 15 ++ tests/__init__.py | 1 - tests/test_hiring_software_engineers.py | 4 - tools/create-release.sh | 28 +++ tools/drawioexport.py | 132 ++++++++++++ tools/gen-codeowners.sh | 21 ++ tools/update_frontmatter.py | 77 +++++++ 35 files changed, 1724 insertions(+), 29 deletions(-) delete mode 100644 .cookiecutter.json create mode 100644 .editorconfig create mode 100644 .github/dependabot.yml create mode 100644 .github/workflows/docs-final.yml create mode 100644 .github/workflows/docs-preview.yml create mode 100644 .gitignore create mode 100644 .pre-commit-config.yaml create mode 100644 CODE_OF_CONDUCT.md create mode 100644 CONTRIBUTING.md create mode 100644 docs/assets/css/cards.css create mode 100644 docs/assets/css/extra.css create mode 100644 docs/assets/css/field-list.css create mode 100644 docs/assets/css/mkdocstrings.css create mode 100644 docs/assets/favicon.png create mode 100644 docs/assets/images/.gitkeep create mode 100644 docs/assets/logo.svg create mode 100644 docs/glossary.md create mode 100644 docs/index.md create mode 100644 docs/introduction.md delete mode 100644 hiring_software_engineers/__init__.py delete mode 100644 hiring_software_engineers/hiring_software_engineers.py create mode 100644 mkdocs.yml create mode 100644 overrides/mkdocstrings/python/material/docstring/attributes.html create mode 100644 overrides/mkdocstrings/python/material/docstring/parameters.html create mode 100644 overrides/mkdocstrings/python/material/docstring/raises.html create mode 100644 overrides/mkdocstrings/python/material/docstring/returns.html create mode 100644 overrides/partials/comments.html create mode 100644 requirements.txt delete mode 100644 tests/__init__.py delete mode 100644 tests/test_hiring_software_engineers.py create mode 100755 tools/create-release.sh create mode 100644 tools/drawioexport.py create mode 100755 tools/gen-codeowners.sh create mode 100755 tools/update_frontmatter.py diff --git a/.cookiecutter.json b/.cookiecutter.json deleted file mode 100644 index 6560994..0000000 --- a/.cookiecutter.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "friendly_name": "Hiring Software Engineers", - "github_user": "callowayproject", - "project_name": "hiring-software-engineers", - "project_short_description": "A community guide to hiring software engineers", - "project_slug": "hiring_software_engineers", - "version": "0.1.0" -} diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..585e2ab --- /dev/null +++ b/.editorconfig @@ -0,0 +1,23 @@ +# http://editorconfig.org + +root = true + +[*] +charset = utf-8 +end_of_line = lf +insert_final_newline = true +trim_trailing_whitespace = true + +[*.{py,rst,ini}] +indent_style = space +indent_size = 4 + +[*.{html,css,scss,json,yml}] +indent_style = space +indent_size = 2 + +[*.md] +trim_trailing_whitespace = false + +[Makefile] +indent_style = tab diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..be006de --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,13 @@ +# Keep GitHub Actions up to date with GitHub's Dependabot... +# https://docs.github.com/en/code-security/dependabot/working-with-dependabot/keeping-your-actions-up-to-date-with-dependabot +# https://docs.github.com/en/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file#package-ecosystem +version: 2 +updates: + - package-ecosystem: github-actions + directory: / + groups: + github-actions: + patterns: + - "*" # Group all Actions updates into a single larger pull request + schedule: + interval: weekly diff --git a/.github/workflows/docs-final.yml b/.github/workflows/docs-final.yml new file mode 100644 index 0000000..97aa67f --- /dev/null +++ b/.github/workflows/docs-final.yml @@ -0,0 +1,33 @@ +name: Deploy final documentation + +on: + push: + branches: [ "master" ] + +concurrency: master + +jobs: + build: + + runs-on: ubuntu-latest + + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + fetch-depth: 0 + token: ${{ secrets.PAT }} + + - name: Set up Python 3.10 + uses: actions/setup-python@v5 + with: + python-version: "3.10" + + - name: Install dependencies + run: | + git pull --all + python -m pip install ".[docs]" + + - name: Build and deploy documentation + run: | + mkdocs gh-deploy --strict -v diff --git a/.github/workflows/docs-preview.yml b/.github/workflows/docs-preview.yml new file mode 100644 index 0000000..db4fbd1 --- /dev/null +++ b/.github/workflows/docs-preview.yml @@ -0,0 +1,38 @@ +name: Deploy PR previews + +on: + pull_request: + types: + - opened + - reopened + - synchronize + - closed + +concurrency: preview-${{ github.ref }} + +jobs: + deploy-preview: + runs-on: ubuntu-20.04 + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Set up Python 3.10 + uses: actions/setup-python@v5 + with: + python-version: "3.10" + + - name: Install dependencies + run: | + python -m pip install ".[docs]" + + - name: Build documentation + run: | + mkdocs build --strict -v + + - name: Deploy preview + uses: rossjrw/pr-preview-action@v1 + with: + source-dir: ./site/ diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..82f46d4 --- /dev/null +++ b/.gitignore @@ -0,0 +1,170 @@ +### macOS ### +# General +.DS_Store +.AppleDouble +.LSOverride + +### Python ### +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +share/python-wheels/ +*.egg-info/ +.installed.cfg +*.egg +MANIFEST + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.nox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*.cover +*.py,cover +.hypothesis/ +.pytest_cache/ +cover/ + +# Translations +*.mo +*.pot + +# Django stuff: +*.log +local_settings.py +db.sqlite3 +db.sqlite3-journal + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +#docs +#docsrc/_build/ +#docsrc/_autosummary + +# PyBuilder +.pybuilder/ +target/ + +# Jupyter Notebook +.ipynb_checkpoints +*/.ipynb_checkpoints/* + +# IPython +profile_default/ +ipython_config.py + +# pyenv +# For a library or package, you might want to ignore these files since the code is +# intended to run in multiple environments; otherwise, check them in: +# .python-version + +# pipenv +# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. +# However, in case of collaboration, if having platform-specific dependencies or dependencies +# having no cross-platform support, pipenv may install dependencies that don't work, or not +# install all needed dependencies. +#Pipfile.lock + +# PEP 582; used by e.g. github.com/David-OConnor/pyflow +__pypackages__/ + +# celery stuff +celerybeat-schedule +celerybeat.pid + +# SageMath parsed files +*.sage.py + +# Environments +.env +.venv +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ + +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject + +# mkdocs documentation +/site + +# mypy +.mypy_cache/ +.dmypy.json +dmypy.json + +# Pyre type checker +.pyre/ + +# pytype static type analyzer +.pytype/ + +# Cython debug symbols +cython_debug/ + +# Mr Developer +.mr.developer.cfg +.project +.pydevproject + +# Pycharm/Intellij +.idea + +# Complexity +output/*.html +output/*/index.html + +# Testing artifacts +junit-*.xml +flake8-errors.txt + +RELEASE.txt +site-packages +reports +*.env +todo.txt diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 0000000..62b6f30 --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,46 @@ +repos: + - repo: https://github.com/pre-commit/pre-commit-hooks + rev: v4.6.0 + hooks: + - id: check-added-large-files + - id: check-case-conflict + - id: check-executables-have-shebangs + - id: check-json + exclude: test.* + - id: check-merge-conflict + - id: check-shebang-scripts-are-executable + - id: check-symlinks + - id: check-toml + - id: check-yaml + exclude: | + (?x)^( + test.*| + mkdocs.yml + )$ + args: [--allow-multiple-documents] + - id: debug-statements + - id: end-of-file-fixer + exclude: "^tests/resources/" + - id: fix-byte-order-marker + - id: requirements-txt-fixer + - repo: https://github.com/Yelp/detect-secrets + rev: v1.5.0 + hooks: + - id: detect-secrets + additional_dependencies: ["gibberish-detector"] + - repo: https://github.com/executablebooks/mdformat + rev: 0.7.17 + hooks: + - id: mdformat + additional_dependencies: + - mdformat-gfm + - mdformat-black + - mdformat-admon + - mdformat-deflist + - mdformat-frontmatter + - mdformat-mkdocs + - mdformat-tables + - mdformat-toc + +ci: + autofix_prs: false diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md new file mode 100644 index 0000000..35b5167 --- /dev/null +++ b/CODE_OF_CONDUCT.md @@ -0,0 +1,132 @@ +# Contributor Covenant Code of Conduct + +## Our Pledge + +We as members, contributors, and leaders pledge to make participation in our +community a harassment-free experience for everyone, regardless of age, body +size, visible or invisible disability, ethnicity, sex characteristics, gender +identity and expression, level of experience, education, socio-economic status, +nationality, personal appearance, race, caste, color, religion, or sexual +identity and orientation. + +We pledge to act and interact in ways that contribute to an open, welcoming, +diverse, inclusive, and healthy community. + +## Our Standards + +Examples of behavior that contributes to a positive environment for our +community include: + +* Demonstrating empathy and kindness toward other people +* Being respectful of differing opinions, viewpoints, and experiences +* Giving and gracefully accepting constructive feedback +* Accepting responsibility and apologizing to those affected by our mistakes, + and learning from the experience +* Focusing on what is best not just for us as individuals, but for the overall + community + +Examples of unacceptable behavior include: + +* The use of sexualized language or imagery, and sexual attention or advances of + any kind +* Trolling, insulting or derogatory comments, and personal or political attacks +* Public or private harassment +* Publishing others' private information, such as a physical or email address, + without their explicit permission +* Other conduct which could reasonably be considered inappropriate in a + professional setting + +## Enforcement Responsibilities + +Community leaders are responsible for clarifying and enforcing our standards of +acceptable behavior and will take appropriate and fair corrective action in +response to any behavior that they deem inappropriate, threatening, offensive, +or harmful. + +Community leaders have the right and responsibility to remove, edit, or reject +comments, commits, code, wiki edits, issues, and other contributions that are +not aligned to this Code of Conduct, and will communicate reasons for moderation +decisions when appropriate. + +## Scope + +This Code of Conduct applies within all community spaces, and also applies when +an individual is officially representing the community in public spaces. +Examples of representing our community include using an official e-mail address, +posting via an official social media account, or acting as an appointed +representative at an online or offline event. + +## Enforcement + +Instances of abusive, harassing, or otherwise unacceptable behavior may be +reported to the community leaders responsible for enforcement at +[INSERT CONTACT METHOD]. +All complaints will be reviewed and investigated promptly and fairly. + +All community leaders are obligated to respect the privacy and security of the +reporter of any incident. + +## Enforcement Guidelines + +Community leaders will follow these Community Impact Guidelines in determining +the consequences for any action they deem in violation of this Code of Conduct: + +### 1. Correction + +**Community Impact**: Use of inappropriate language or other behavior deemed +unprofessional or unwelcome in the community. + +**Consequence**: A private, written warning from community leaders, providing +clarity around the nature of the violation and an explanation of why the +behavior was inappropriate. A public apology may be requested. + +### 2. Warning + +**Community Impact**: A violation through a single incident or series of +actions. + +**Consequence**: A warning with consequences for continued behavior. No +interaction with the people involved, including unsolicited interaction with +those enforcing the Code of Conduct, for a specified period of time. This +includes avoiding interactions in community spaces as well as external channels +like social media. Violating these terms may lead to a temporary or permanent +ban. + +### 3. Temporary Ban + +**Community Impact**: A serious violation of community standards, including +sustained inappropriate behavior. + +**Consequence**: A temporary ban from any sort of interaction or public +communication with the community for a specified period of time. No public or +private interaction with the people involved, including unsolicited interaction +with those enforcing the Code of Conduct, is allowed during this period. +Violating these terms may lead to a permanent ban. + +### 4. Permanent Ban + +**Community Impact**: Demonstrating a pattern of violation of community +standards, including sustained inappropriate behavior, harassment of an +individual, or aggression toward or disparagement of classes of individuals. + +**Consequence**: A permanent ban from any sort of public interaction within the +community. + +## Attribution + +This Code of Conduct is adapted from the [Contributor Covenant][homepage], +version 2.1, available at +[https://www.contributor-covenant.org/version/2/1/code_of_conduct.html][v2.1]. + +Community Impact Guidelines were inspired by +[Mozilla's code of conduct enforcement ladder][Mozilla CoC]. + +For answers to common questions about this code of conduct, see the FAQ at +[https://www.contributor-covenant.org/faq][FAQ]. Translations are available at +[https://www.contributor-covenant.org/translations][translations]. + +[homepage]: https://www.contributor-covenant.org +[v2.1]: https://www.contributor-covenant.org/version/2/1/code_of_conduct.html +[Mozilla CoC]: https://github.com/mozilla/diversity +[FAQ]: https://www.contributor-covenant.org/faq +[translations]: https://www.contributor-covenant.org/translations diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..0675d93 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,147 @@ +# Contributing to Hiring Software Engineers + +First off, thanks for taking the time to contribute! ❤️ + +All types of contributions are encouraged and valued. See the [Table of Contents](#table-of-contents) for different ways to help and details about how this project handles them. Please make sure to read the relevant section before making your contribution. It will make it much easier for us maintainers and smooth out the experience for all involved. The community looks forward to your contributions. 🎉 + +> If you like the project but don't have time to contribute, that's fine. There are other easy ways to support the project and show your appreciation, which we would also be very happy about: +> - Star the project +> - Tweet about it +> - Refer to this project in your project's readme +> - Mention the project at local meetups and tell your friends/colleagues + +## Table of Contents + +- [Code of Conduct](#code-of-conduct) +- [I Have a Question](#i-have-a-question) +- [Reporting Bugs](#reporting-bugs) +- [Suggesting Enhancements](#suggesting-enhancements) +- [Your First Code Contribution](#your-first-code-contribution) +- [Improving The Documentation](#improving-the-documentation) +- [Styleguides](#styleguides) +- [Join The Project Team](#join-the-project-team) + + +## Code of Conduct + +This project and everyone participating in it are governed by the +[Code of Conduct](https://github.com/callowayproject/hiring-software-engineers/blob/master/CODE_OF_CONDUCT.md). By participating, you are expected to uphold this code. Please report unacceptable behavior +to . + + +## I Have a Question + +> If you want to ask a question, we assume that you have read the available [Documentation](https://callowayproject.github.io/hiring-software-engineers/). + +Before you ask a question, it is best to search for existing [Issues](https://github.com/callowayproject/hiring-software-engineers/issues) that might help you. In case you have found a suitable issue and still need clarification, you can write your question in this issue. It is also advisable to search the internet for answers first. + +If you then still feel the need to ask a question and need clarification, we recommend the following: + +- Open an [Issue](https://github.com/callowayproject/hiring-software-engineers/issues/new). +- Provide as much context as you can about what you're running into. +- Provide project and platform versions (nodejs, npm, etc), depending on what seems relevant. + +We will then take care of the issue as soon as possible. + +## Reporting Bugs + +### Before Submitting a Bug Report + +A good bug report shouldn't leave others needing to chase you up for more information. Therefore, we ask you to investigate carefully, collect information, and describe the issue in detail in your report. Please complete the following steps in advance to help us fix any potential bug as fast as possible. + +- Make sure that you are using the latest version. +- Determine if your bug is really a bug and not an error on your side e.g. using incompatible environment components/versions (Make sure that you have read the [documentation](https://callowayproject.github.io/hiring-software-engineers/). If you are looking for support, you might want to check [this section](#i-have-a-question)). +- To see if other users have experienced (and potentially already solved) the same issue you are having, check if there is not already a bug report existing for your bug or error in the [bug tracker](https://github.com/callowayproject/hiring-software-engineers/issues). +- Also, make sure to search the internet (including Stack Overflow) to see if users outside of the GitHub community have discussed the issue. +- Collect information about the bug: + - Stack trace (Traceback) + - OS, Platform, and Version (Windows, Linux, macOS, x86, ARM) + - The version of Python + - Possibly your input and the output + - Can you reliably reproduce the issue? And can you also reproduce it with older versions? + + +### How Do I Submit a Good Bug Report? + +> You must never report security-related issues, vulnerabilities, or bugs that include sensitive information to the issue tracker or elsewhere in public. Instead, sensitive bugs must be sent by email to . + +We use GitHub issues to track bugs and errors. If you run into an issue with the project: + +- Open an [Issue](https://github.com/callowayproject/hiring-software-engineers/issues/new). (Since we can't be sure at this point whether it is a bug or not, we ask you not to talk about a bug yet and not to label the issue.) +- Explain the behavior you would expect and the actual behavior. +- Please provide as much context as possible and describe the *reproduction steps* that someone else can follow to recreate the issue on their own. This usually includes your code. For good bug reports, you should isolate the problem and create a reduced test case. +- Provide the information you collected in the previous section. + +Once it's filed: + +- The project team will label the issue accordingly. +- A team member will try to reproduce the issue with your provided steps. If there are no reproduction steps or no obvious way to reproduce the issue, the team will ask you for those steps and will not address them until they are included. +- If the team is able to reproduce the issue, the issue will be left to be [implemented by someone](#your-first-code-contribution). + + +## Suggesting Enhancements + +This section guides you through submitting an enhancement suggestion for Hiring Software Engineers, **including completely new features and minor improvements to existing functionality**. Following these guidelines will help maintainers and the community to understand your suggestion and find related suggestions. + +### Before Submitting an Enhancement + +- Make sure that you are using the latest version. +- Read the [documentation](https://callowayproject.github.io/hiring-software-engineers/) carefully and find out if the functionality is already covered, maybe by an individual configuration. +- Perform a [search](https://github.com/callowayproject/hiring-software-engineers/issues) to see if the enhancement has already been suggested. If it has, add a comment to the existing issue instead of opening a new one. +- Find out whether your idea fits with the scope and aims of the project. It's up to you to make a strong case to convince the project's developers of the merits of this feature. Keep in mind that we want features that will be useful to the majority of our users and not just a small subset. If you're just targeting a minority of users, consider writing an add-on/plugin library. + +### How Do I Submit a Good Enhancement Suggestion? + +Enhancement suggestions are tracked as [GitHub issues](https://github.com/callowayproject/hiring-software-engineers/issues). + +- Use a **clear and descriptive title** for the issue to identify the suggestion. +- **Describe the problem or use case** this enhancement solves **or the new benefit** it provides. +- **Explain why this enhancement would be useful** to most Hiring Software Engineers users. You may also want to point out the other projects that solved it better and which could serve as inspiration. +- Provide a **step-by-step description of the suggested enhancement** in as many details as possible. +- You may also tell how current alternatives do not work for you, if appropriate + + + +## Your First Code Contribution + + +> ### Legal Notice +> +> When contributing to this project, you must agree that you have authored 100% of the content, that you have the necessary rights to the content and that the content you contribute may be provided under the project license. + +### Setup + +There are several ways to create your isolated environment. This is the default method. + +Run the following in a terminal: + +``` +# Clone the repository +git clone https://github.com/callowayproject/hiring-software-engineers.git + +# Enter the repository +cd hiring-software-engineers + +# Create then activate a virtual environment +python -m venv venv +source venv/bin/activate + +# Install the development requirements +python -m pip install ".[dev,test,docs]" +``` + +### Run tests + +Once setup, you should be able to run tests: +``` +pytest +``` + +## Install Pre-commit Hooks + + +Pre-commit hooks are scripts that run every time you make a commit. If any of the scripts fail, it stops the commit. You can see a listing of the checks in the ``.pre-commit-config.yaml`` file. + +``` +pre-commit install +``` diff --git a/README.md b/README.md index e025210..55859d0 100644 --- a/README.md +++ b/README.md @@ -1,16 +1,5 @@ # Hiring Software Engineers -[![image](https://img.shields.io/pypi/v/hiring-software-engineers.svg)](https://pypi.org/project/hiring-software-engineers/) -[![image](https://img.shields.io/pypi/l/hiring-software-engineers.svg)](https://pypi.org/project/hiring-software-engineers/) -[![image](https://img.shields.io/pypi/pyversions/hiring-software-engineers.svg)](https://pypi.org/project/hiring-software-engineers/) -[![GitHub Actions](https://github.com/callowayproject/hiring-software-engineers/workflows/CI/badge.svg)](https://github.com/callowayproject/hiring-software-engineers/actions) - A community guide to hiring software engineers -*Put a meaningful, short, plain-language description of:* - -- *what this project is trying to accomplish.* -- *why it matters.* -- *the problem(s) this project solves.* -- *how this software can improve the lives of its audience.* -- *what sets this apart from related-projects. Linking to another doc or page is OK if this can't be expressed in a sentence or two.* +## Outline diff --git a/docs/assets/css/cards.css b/docs/assets/css/cards.css new file mode 100644 index 0000000..95d2e5c --- /dev/null +++ b/docs/assets/css/cards.css @@ -0,0 +1,200 @@ +/************* + Grid Modification +*/ + +.md-typeset .grid.wide-gap { + gap: 1rem; +} + +/************* + Cards +*/ +.card-container { + background-color: white; + color: rgba(0, 0, 0, 0.87); + border-radius: 4px; + box-shadow: rgba(0, 0, 0, 0.2) 0 2px 1px -1px, rgba(0, 0, 0, 0.14) 0 1px 1px 0, rgba(0, 0, 0, 0.12) 0 1px 3px 0; + overflow: hidden; +} + +.card-container.depth-0 { + box-shadow: none; +} + +/************* + Cards - Header +*/ + +.card-header { + padding: 16px 16px 24px; + background: var(--md-primary-fg-color); + color: var(--md-primary-bg-color); +} + +.card-header.backstage-green { + background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='1368' height='400' fill='none'%3e%3cmask id='a' width='1368' height='401' x='0' y='0' maskUnits='userSpaceOnUse'%3e%3cpath fill='url(%23paint0_linear)' d='M437 116C223 116 112 0 112 0h1256v400c-82 0-225-21-282-109-112-175-436-175-649-175z'/%3e%3cpath fill='url(%23paint1_linear)' d='M1368 400V282C891-29 788 40 711 161 608 324 121 372 0 361v39h1368z'/%3e%3cpath fill='url(%23paint2_linear)' d='M1368 244v156H0V94c92-24 198-46 375 0l135 41c176 51 195 109 858 109z'/%3e%3cpath fill='url(%23paint3_linear)' d='M1252 400h116c-14-7-35-14-116-16-663-14-837-128-1013-258l-85-61C98 28 46 8 0 0v400h1252z'/%3e%3c/mask%3e%3cg mask='url(%23a)'%3e%3cpath fill='white' d='M-172-98h1671v601H-172z'/%3e%3c/g%3e%3cdefs%3e%3clinearGradient id='paint0_linear' x1='602' x2='1093.5' y1='-960.5' y2='272' gradientUnits='userSpaceOnUse'%3e%3cstop stop-color='white'/%3e%3cstop offset='1' stop-color='white' stop-opacity='0'/%3e%3c/linearGradient%3e%3clinearGradient id='paint1_linear' x1='482' x2='480' y1='1058.5' y2='70.5' gradientUnits='userSpaceOnUse'%3e%3cstop stop-color='white'/%3e%3cstop offset='1' stop-color='white' stop-opacity='0'/%3e%3c/linearGradient%3e%3clinearGradient id='paint2_linear' x1='424' x2='446.1' y1='-587.5' y2='274.6' gradientUnits='userSpaceOnUse'%3e%3cstop stop-color='white'/%3e%3cstop offset='1' stop-color='white' stop-opacity='0'/%3e%3c/linearGradient%3e%3clinearGradient id='paint3_linear' x1='587' x2='349' y1='-1120.5' y2='341' gradientUnits='userSpaceOnUse'%3e%3cstop stop-color='white'/%3e%3cstop offset='1' stop-color='white' stop-opacity='0'/%3e%3c/linearGradient%3e%3c/defs%3e%3c/svg%3e"), linear-gradient(90deg, rgb(0, 91, 75), rgb(0, 91, 75)); + color: rgb(255, 255, 255); +} + +.card-header.backstage-blue { + background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='1368' height='400' fill='none'%3e%3cmask id='a' width='1368' height='401' x='0' y='0' maskUnits='userSpaceOnUse'%3e%3cpath fill='url(%23paint0_linear)' d='M437 116C223 116 112 0 112 0h1256v400c-82 0-225-21-282-109-112-175-436-175-649-175z'/%3e%3cpath fill='url(%23paint1_linear)' d='M1368 400V282C891-29 788 40 711 161 608 324 121 372 0 361v39h1368z'/%3e%3cpath fill='url(%23paint2_linear)' d='M1368 244v156H0V94c92-24 198-46 375 0l135 41c176 51 195 109 858 109z'/%3e%3cpath fill='url(%23paint3_linear)' d='M1252 400h116c-14-7-35-14-116-16-663-14-837-128-1013-258l-85-61C98 28 46 8 0 0v400h1252z'/%3e%3c/mask%3e%3cg mask='url(%23a)'%3e%3cpath fill='white' d='M-172-98h1671v601H-172z'/%3e%3c/g%3e%3cdefs%3e%3clinearGradient id='paint0_linear' x1='602' x2='1093.5' y1='-960.5' y2='272' gradientUnits='userSpaceOnUse'%3e%3cstop stop-color='white'/%3e%3cstop offset='1' stop-color='white' stop-opacity='0'/%3e%3c/linearGradient%3e%3clinearGradient id='paint1_linear' x1='482' x2='480' y1='1058.5' y2='70.5' gradientUnits='userSpaceOnUse'%3e%3cstop stop-color='white'/%3e%3cstop offset='1' stop-color='white' stop-opacity='0'/%3e%3c/linearGradient%3e%3clinearGradient id='paint2_linear' x1='424' x2='446.1' y1='-587.5' y2='274.6' gradientUnits='userSpaceOnUse'%3e%3cstop stop-color='white'/%3e%3cstop offset='1' stop-color='white' stop-opacity='0'/%3e%3c/linearGradient%3e%3clinearGradient id='paint3_linear' x1='587' x2='349' y1='-1120.5' y2='341' gradientUnits='userSpaceOnUse'%3e%3cstop stop-color='white'/%3e%3cstop offset='1' stop-color='white' stop-opacity='0'/%3e%3c/linearGradient%3e%3c/defs%3e%3c/svg%3e"), linear-gradient(90deg, rgb(0, 109, 143), rgb(0, 73, 161)); + color: rgb(255, 255, 255); +} + +.card-header p.subtitle { + margin: 0; + font-size: 0.8em; + font-family: "Helvetica Neue", Helvetica, Roboto, Arial, sans-serif; + font-weight: 500; + line-height: 1.57; +} + +.card-header p.title { + margin: 0; + font-size: 1.14em; + font-family: "Helvetica Neue", Helvetica, Roboto, Arial, sans-serif; + font-weight: 700; + line-height: 1.6; + margin-bottom: 2px; +} + +/************* + Cards - Media +*/ + +.card-media { + display: block; + background-size: cover; + background-repeat: no-repeat; + background-position: center; + width: 100%; + object-fit: cover; +} + +.card-media p { + margin: 0; +} + +/************* + Cards - Content +*/ + +.card-content { + padding: 16px; +} + +.card-content p { + margin: 0; +} + +.card-content p + p { + margin-top: 1em; +} + +.card-content-title { + margin-top: 0; + font-weight: 400; + font-size: 1.5rem; + line-height: 1.334; + letter-spacing: 0; + margin-bottom: 0.35em; +} + +.card-content-title p { + margin: 0; +} + +/************* + Cards - Actions +*/ + +.card-actions { + padding: 16px; +} + +.card-actions ul:not([hidden]) { + display: flex; + margin: 0; +} + +.card-actions ul { + list-style: none; + padding: 0; + margin: 0; + display: flex; + flex-wrap: wrap; + gap: 16px; +} +.card-actions.right ul { + justify-content: flex-end; +} + +.card-actions p { + margin: 0; +} + +[dir=ltr] .card-actions ul li { + margin: 0; +} + +.card-actions a { + background-color: transparent; + margin-top: 0; + vertical-align: middle; + font-weight: 500; + font-size: 0.8125rem; + line-height: 1.75; + letter-spacing: 0.02857em; + text-transform: uppercase; +} + +/************* + Cards - Tags +*/ + +.card-tags { + display: flex; + flex-wrap: wrap; + box-sizing: border-box; + padding: 16px; +} + +.card-tags ul:not([hidden]) { + display: flex; + margin: 0; +} + +.card-tags ul { + list-style: none; + padding: 0; + margin: 0; + display: flex; + flex-wrap: wrap; + gap: 16px; +} + +[dir=ltr] .card-tags ul li { + padding: 2px 8px; + margin: 0; + box-sizing: border-box; + font-size: 12px; + font-weight: 500; + color: #000; + background-color: rgba(0, 0, 0, 0.12); + border-radius: 16px; + height: 24px; + line-height: 20px; +} + +/************* + Cards - Divider +*/ + +.card-divider { + margin: 0; + padding: 0 16px; +} + +.card-divider hr { + margin: 0; +} diff --git a/docs/assets/css/extra.css b/docs/assets/css/extra.css new file mode 100644 index 0000000..51a8e5b --- /dev/null +++ b/docs/assets/css/extra.css @@ -0,0 +1,54 @@ +/* Indentation. */ +div.doc-contents:not(.first) { + padding-left: 25px; + border-left: .05rem solid var(--md-typeset-table-color); +} + +/* Normal size fonts on parameter tables */ +.md-typeset div.doc-contents table { + font-size: 1em; + width: 100%; + display: table; +} + +/* Mark external links as such. */ +a.autorefs-external::after { + /* https://primer.style/octicons/arrow-up-right-24 */ + background-image: url('data:image/svg+xml,'); + content: ' '; + + display: inline-block; + vertical-align: middle; + position: relative; + bottom: 0.1em; + margin-left: 0.2em; + margin-right: 0.1em; + + height: 0.7em; + width: 0.7em; + border-radius: 100%; + background-color: var(--md-typeset-a-color); +} +a.autorefs-external:hover::after { + background-color: var(--md-accent-fg-color); +} +span.doc-param-annotation:first-child{ + border-top: 1px solid var(--md-typeset-table-color); + padding-top: 5px; + margin-top: 5px; + margin-bottom: -5px; +} +span.doc-param-annotation { + font-size: 0.8em; + display: block; +} +span.doc-param-default { + font-size: 0.8em; + float: unset; +} +.doc-label { border-radius: 15px; padding: 0 5px; } +.doc-label code { background-color: transparent; color: white;} +.doc-label-special { background-color: blue; color: white; } +.doc-label-private { background-color: red; color: white; } +.doc-label-property { background-color: green; color: white; } +.doc-label-read-only { background-color: yellow; color: black; } diff --git a/docs/assets/css/field-list.css b/docs/assets/css/field-list.css new file mode 100644 index 0000000..ace471b --- /dev/null +++ b/docs/assets/css/field-list.css @@ -0,0 +1,34 @@ +dl.field-list .doc-param-default, dl.doc-field-list .doc-param-default { + float: none; +} + +.field-list > dl, dl.field-list, dl.doc-field-list { + display: flex; + flex-flow: row wrap; + padding-left: 10px; +} + +.field-list > dl > dt, dl.field-list > dt, dl.doc-field-list > dt { + flex-basis: 20%; + font-weight: bold; + word-break: break-word; + padding: 10px 0; + border-bottom: 1px solid #e5e5e5; +} + +.field-list > dl > dt:after, dl.field-list > dt:after { + content: ":"; +} + +[dir=ltr] .field-list > dl > dd, dl.field-list > dd.doc-field-def, dl.doc-field-list > dd.doc-field-def { + flex-basis: 70%; + flex-grow: 1; + margin: 0; + padding: 10px 0 10px 10px; + border-bottom: 1px solid #e5e5e5; +} + +dd.doc-field-def > p:last-child { + padding-bottom: 0; + margin-bottom: 0; +} diff --git a/docs/assets/css/mkdocstrings.css b/docs/assets/css/mkdocstrings.css new file mode 100644 index 0000000..6288f53 --- /dev/null +++ b/docs/assets/css/mkdocstrings.css @@ -0,0 +1,39 @@ +/* Indentation. */ +div.doc-contents:not(.first) { + padding-left: 25px; + border-left: .05rem solid var(--md-typeset-table-color); +} + +/* Mark external links as such. */ +a.external::after, +a.autorefs-external::after { + /* https://primer.style/octicons/arrow-up-right-24 */ + mask-image: url('data:image/svg+xml,'); + -webkit-mask-image: url('data:image/svg+xml,'); + content: ' '; + + display: inline-block; + vertical-align: middle; + position: relative; + + height: 1em; + width: 1em; + background-color: var(--md-typeset-a-color); +} + +a.external:hover::after, +a.autorefs-external:hover::after { + background-color: var(--md-accent-fg-color); +} + +.doc-param-key, .doc-field-term, .doc-section-head { + font-weight: bold; +} + +.doc.doc-heading { + text-transform: none; +} + +h5.doc-heading, h6.doc-heading { + font-size: 1em; +} diff --git a/docs/assets/favicon.png b/docs/assets/favicon.png new file mode 100644 index 0000000000000000000000000000000000000000..c7391588b8cfa6fd3bd0087321e2d32b043fb7e8 GIT binary patch literal 3499 zcmai1d0diN7k&lTKrL<8ilNj}5d<|PaW^&B&|I>aBn8Cb)lrr~mOU=E$S8HmTX1?!_7r6I1=eg%R=brQaNOX3zmS47h82|wC zwl7{NMZU&aB74lkGq;s9V|!ef$s0x2BC z0g4}uPDGAWR3i~IUn0_7-vQ&mw4nIYY{FR-mvBc{pYT8*Ltmtc@iHSG0VD{faL5Q= za1fnM;1Q8ayae#~;x-zISTf-R5|JJb&Ik(zi-OSC(bvHsjh7*eSiV#O$#UmsXK+PC z`g1r;0va6}8mbeD(_ygu(7J|(hG+~Hjm4rs3luwy&LQ(qboS;&iccJt6t)kG#^lf# zbi^Vj`2d5?%={-~2Z#S{9vu8l8f=bL2q?s7QNM}l&jZ-5VN42|L}4?y zEFX$h2!+nsyrjgUE(B*9j}qizNeiaX*`T^aq#pinpy$7U7K|VU%LTkt6e3c0$!AeH zf^9I_kK#`A<@kT$`nqpVq5J(ESd1))yI9&ibQ+io_A8giSB!|Xg&M*YnIy65zg@wQ(usV8RUw*?G>Q4a~|2;qS=jhOjUH4~rM(FPnFj_MBOPhjz zpZ37^2j>X-%OC+4Uq%sy4$dDIIB1@!Ee`|$i5MDKn(s;i09#YJsgJcRcdx87p(fl< zI6x+kH5Z#7OE`{AKazb`x8d5O9KWdZVO^6Q_Sr!vhE}Q>M4_f(&ol!I6EZGeNt6#4 zjX$;Nc_||1&s9$44incHja@GCYOO5jeMi++B2jyLPW-NMXL=N8>fEaB!wJybWff6T z*pS%%%JE7=?}xJ4!n1{Dd-6sTsF`7}55DdT=wR~f%B>!rx2x5t{jq4D^Yr~DWgQd4 z+>n{OWZXtr+&Nnh+mCPVq1&)UI@)NB0zcUAk0Wz`nNGi*MN1rd6YOy>VYxXuR<{=3 zTvyx}$5B3O?dDoPvLMR$wPNXK$tPuMr>k51sH#0lKkfG!WI_57ls_u z#*+;IFy+NZ0?5u?3ji`JY%R@P{rN*#(ZzfAtg17aGQO84VXoVB<2d3vP7i9XJia=U z+@koiLq%+@svn$ZGx9#(;N*uU-;>FuMJD#I?#c0_M;U^U<5z9sLHo)(LrH z)k+cY9#X;oQFv3_s1nQyN+^;qHg=Tm8Q}Hcztwa9IDBxzIp1*GU$5m$Xwv1+|L(8ofUkp(6RD8+tyx3SI6P2fgl36X|r*I2vO7z$i4^{KNo|Fu2m-35hy?j*@`m`m3 zA9|s0SloyL-_x>#T~4W$5=_Z*EWY&Ax(zcKC9j2dUF)YLIxnmn%{ckItxie2JJMKc z`u61YGiGz?0w*FGqTV+S6Sg;Ryg!?HF8tNayD8P3btYz{@a?Ob ztOfnx3jPzN7HL_Ls^o8^(<5G+I@8Odu~561>$7(Z@Z)uy&4XQq!eipb!6CtrVog>Z zziy(}My%yIr!IZg>A5oQ6b}04jYy0Bp<;{N`DP`mXP5;e%a=Jqg{ZKE^egz+e|mI9ZeBE;!EBRO-Fs;~YQ6+%++#z3@&* zxzKrOGD=H{05m?Clk5mH$_cO9Y8P*mmayen(UcR(bG&83_%0DNQ(zDnt_TA1p z#_mqmqS^9QVK3@Zw?}V$gPnq?e7UOO zKUFs{DQ9C5Zu#T75%eCQhiZg%Sx(bVbX! zJvXNnqB1)2^cp=kxkJV$rq0FU0$mJiE(xEC8yyF`@NbK=VtJReVsY0fh)7M$rs>rs z`v%A=X>WtPn{QWS5r?!1gq;9d!mF>Jcu~4h`f8JL`w`Z`#o$+Z6xC8{vglw5u#t8- zsrUtlN$2f|Uk^w!aib5z!>*$;M3zb?|09eT6m%%?-rctLcKk&su=xqz6QG! z<8@%7pc{vqxAP-8+^ahkZYm;E2TIEtTwiOeeOPx9S7{*}iCHCV;c%0!YJ1PVxo-ZV z(VCUEIl=DZzRH6EspY%#v0?@BMX++-utIcmO9jLOHUSEellBPeBj9zngy-!)6G0qZ zF1EN`{&?1(FC$2=JfwZRDZpNXM9n&OsKuS~gW_zFUQmalnntE_ZW!soPwfXqJXsJ60uXhQl*2g$>3O8z)=td!_1IJ-^Yj%UU2`35;ngs^|Qq73y?>3=GEM zaHVP2u%@e`R`QM{O_gil+2g>yI>gQttA^wXK{xAEgNEjV&VUa&6N9EyqX+SdKxsB= zzD+CWkwuX~jfJrG@?q2hm5IQQhr}72;adwHDVD6fCMPmVKf#Oru9#tUpqsXbBRd_$?CE!#(AOLefliUO4OdCcuk~~*Q~O1N9BHKZT(})#dtDqX z9xvM?pkkcE76N=Pws5nF^(A|yg4X({du=-R1O4gl4OJs%1E-?>`BQSfGeX^sW1ai2 zwtU$0R=CTUIS-So(~wxxr(aU^*w~k9cO|1gu&Gg_sJ~vL$P<;!mF<%lhKt~P51%=a z@^iYN{-DmN?#01NWz%S-^F*l$_z~svRu%c4b diff --git a/docs/glossary.md b/docs/glossary.md new file mode 100644 index 0000000..90a8703 --- /dev/null +++ b/docs/glossary.md @@ -0,0 +1,12 @@ +--- +title: Glossary +description: A glossary of terminology used in the Hiring Software Engineers package and documentation. +date: 2024-07-26 +comments: true +--- + +A glossary of terminology and nomenclature used in the hiring-software-engineers package and documentation. + +!!! warning + + Glossary not implemented yet! Recommend each item has its own anchor link. diff --git a/docs/index.md b/docs/index.md new file mode 100644 index 0000000..d26d8cf --- /dev/null +++ b/docs/index.md @@ -0,0 +1,16 @@ +--- +title: hiring-software-engineers +description: A community guide to hiring software engineers +date: 2024-07-26 +comments: true +--- + +# Hiring Software Engineers + +{% + include-markdown + "../README.md" + start="" + end="" + rewrite-relative-urls=false +%} diff --git a/docs/introduction.md b/docs/introduction.md new file mode 100644 index 0000000..078d285 --- /dev/null +++ b/docs/introduction.md @@ -0,0 +1,21 @@ +--- +title: Explanations +description: Why Hiring Software Engineers is the way it is! +date: 2024-07-26 +comments: true +--- + +This page explains why Hiring Software Engineers is the way it is. + +!!! warning + + Explanation has not been implemented yet! + +Explanation is **discussion** that clarifies and illuminates a particular topic. Explanation is **understanding-oriented.** + +- Give context and background on your library +- Explain why you created it +- Provide multiple examples and approaches of how to work with it +- Help the reader make connections +- Avoid writing instructions or technical descriptions here +- [More Information](https://diataxis.fr/explanation/) diff --git a/hiring_software_engineers/__init__.py b/hiring_software_engineers/__init__.py deleted file mode 100644 index c503390..0000000 --- a/hiring_software_engineers/__init__.py +++ /dev/null @@ -1,3 +0,0 @@ -"""Top-level package for hiring-software-engineers.""" - -__version__: str = "0.1.0" diff --git a/hiring_software_engineers/hiring_software_engineers.py b/hiring_software_engineers/hiring_software_engineers.py deleted file mode 100644 index dd0b80e..0000000 --- a/hiring_software_engineers/hiring_software_engineers.py +++ /dev/null @@ -1 +0,0 @@ -"""Main module.""" diff --git a/mkdocs.yml b/mkdocs.yml new file mode 100644 index 0000000..cdf7ffe --- /dev/null +++ b/mkdocs.yml @@ -0,0 +1,80 @@ +site_name: Hiring Software Engineers +repo_url: https://github.com/callowayproject/hiring-software-engineers +edit_uri: edit/main/docs/ +theme: + name: material + custom_dir: overrides + logo: assets/logo.svg + favicon: assets/favicon.png + features: + - navigation.tabs + - navigation.sections + - navigation.path + - navigation.indexes + - toc.integrate + - content.action.edit + - content.action.view + - content.code.annotate + - content.tabs.link + palette: + - media: "(prefers-color-scheme: light)" + scheme: default + toggle: + icon: material/toggle-switch-off-outline + name: Switch to dark mode + - media: "(prefers-color-scheme: dark)" + scheme: slate + toggle: + icon: material/toggle-switch + name: Switch to light mode +use_directory_urls: true +markdown_extensions: + - abbr + - admonition + - attr_list + - customblocks + - def_list + - footnotes + - md_in_html + - mdx_truly_sane_lists + - pymdownx.details + - pymdownx.emoji: + emoji_index: !!python/name:material.extensions.emoji.twemoji + emoji_generator: !!python/name:material.extensions.emoji.to_svg + - pymdownx.highlight + - pymdownx.snippets + - pymdownx.superfences: + custom_fences: + - name: mermaid + class: mermaid + format: !!python/name:pymdownx.superfences.fence_code_format + - pymdownx.tabbed + - smarty + - toc: + permalink: true + - tables + +plugins: + - search + - social + - git-revision-date-localized + - git-authors: + show_email_address: false + - include-markdown + - gen-files: + scripts: + - docs/gen_doc_stubs.py + - literate-nav: + nav_file: SUMMARY.md + - minify + +extra_css: + - assets/css/extra.css + - assets/css/mkdocstrings.css + - assets/css/cards.css + - assets/css/field-list.css + +nav: + - Home: index.md + - Introduction: introduction.md + - Glossary: glossary.md diff --git a/overrides/mkdocstrings/python/material/docstring/attributes.html b/overrides/mkdocstrings/python/material/docstring/attributes.html new file mode 100644 index 0000000..ce50d65 --- /dev/null +++ b/overrides/mkdocstrings/python/material/docstring/attributes.html @@ -0,0 +1,90 @@ +{{ log.debug("Rendering attributes section") }} + +{% import "language.html" as lang with context %} + +{% if config.docstring_section_style == "table" %} + {% block table_style scoped %} +

{{ section.title or lang.t("Attributes:") }}

+ + + + + + + + + + {% for attribute in section.value %} + + + + + + {% endfor %} + +
{{ lang.t("Name") }}{{ lang.t("Type") }}{{ lang.t("Description") }}
{{ attribute.name }} + {% if attribute.annotation %} + {% with expression = attribute.annotation %} + {% include "expression.html" with context %} + {% endwith %} + {% endif %} + +
+ {{ attribute.description|convert_markdown(heading_level, html_id) }} +
+
+ {% endblock table_style %} +{% elif config.docstring_section_style == "list" %} + {% block list_style scoped %} +

{{ section.title or lang.t("Attributes:") }}

+
    + {% for attribute in section.value %} +
  • + {{ attribute.name }} + {% if attribute.annotation %} + {% with expression = attribute.annotation %} + ({% include "expression.html" with context %}) + {% endwith %} + {% endif %} + – +
    + {{ attribute.description|convert_markdown(heading_level, html_id) }} +
    +
  • + {% endfor %} +
+ {% endblock list_style %} +{% elif config.docstring_section_style == "spacy" %} + {% block spacy_style scoped %} + + + + + + + + + {% for attribute in section.value %} + + + + + {% endfor %} + +
{{ (section.title or lang.t("ATTRIBUTE")).rstrip(":").upper() }}{{ lang.t("DESCRIPTION") }}
{{ attribute.name }} +
+ {{ attribute.description|convert_markdown(heading_level, html_id) }} +
+

+ {% if attribute.annotation %} + + TYPE: + {% with expression = attribute.annotation %} + {% include "expression.html" with context %} + {% endwith %} + + {% endif %} +

+
+ {% endblock spacy_style %} +{% endif %} diff --git a/overrides/mkdocstrings/python/material/docstring/parameters.html b/overrides/mkdocstrings/python/material/docstring/parameters.html new file mode 100644 index 0000000..ab4889e --- /dev/null +++ b/overrides/mkdocstrings/python/material/docstring/parameters.html @@ -0,0 +1,98 @@ +{{ log.debug("Rendering parameters section") }} + +{% import "language.html" as lang with context %} + +{% if config.docstring_section_style == "table" %} + {% block table_style scoped %} +

{{ section.title or lang.t("Parameters:") }}

+ + + + + + + + + + + {% for parameter in section.value %} + + + + + + + {% endfor %} + +
{{ lang.t("Name") }}{{ lang.t("Type") }}{{ lang.t("Description") }}{{ lang.t("Default") }}
{{ parameter.name }} + {% if parameter.annotation %} + {% with expression = parameter.annotation %} + {% include "expression.html" with context %} + {% endwith %} + {% endif %} + +
+ {{ parameter.description|convert_markdown(heading_level, html_id) }} +
+
+ {% if parameter.default %} + {% with expression = parameter.default %} + {% include "expression.html" with context %} + {% endwith %} + {% else %} + {{ lang.t("required") }} + {% endif %} +
+ {% endblock table_style %} +{% elif config.docstring_section_style == "list" %} + {% block list_style scoped %} +

{{ section.title or lang.t("Parameters:") }}

+
    + {% for parameter in section.value %} +
  • + {{ parameter.name }} + {% if parameter.annotation %} + {% with expression = parameter.annotation %} + ({% include "expression.html" with context %} + {%- if parameter.default %}, {{ lang.t("default:") }} + {% with expression = parameter.default %} + {% include "expression.html" with context %} + {% endwith %} + {% endif %}) + {% endwith %} + {% endif %} + – +
    + {{ parameter.description|convert_markdown(heading_level, html_id) }} +
    +
  • + {% endfor %} +
+ {% endblock list_style %} +{% elif config.docstring_section_style == "spacy" %} + {% block spacy_style scoped %} +

{{ section.title or lang.t("Parameters:") }}

+
+ {% for parameter in section.value %} +
{{ parameter.name }}
+
+
+ {{ parameter.description|convert_markdown(heading_level, html_id) }} +
+ {% if parameter.annotation %}

+ {{ lang.t("TYPE:") }} + {% with expression = parameter.annotation %} + {% include "expression.html" with context %} + {% endwith %} +

{% endif %} + {% if parameter.default %}

+ {{ lang.t("DEFAULT:") }} + {% with expression = parameter.default %} + {% include "expression.html" with context %} + {% endwith %} +

{% endif %} +
+ {% endfor %} +
+ {% endblock spacy_style %} +{% endif %} diff --git a/overrides/mkdocstrings/python/material/docstring/raises.html b/overrides/mkdocstrings/python/material/docstring/raises.html new file mode 100644 index 0000000..628e41b --- /dev/null +++ b/overrides/mkdocstrings/python/material/docstring/raises.html @@ -0,0 +1,72 @@ +{{ log.debug("Rendering raises section") }} + +{% import "language.html" as lang with context %} + +{% if config.docstring_section_style == "table" %} + {% block table_style scoped %} +

{{ section.title or lang.t("Raises:") }}

+ + + + + + + + + {% for raises in section.value %} + + + + + {% endfor %} + +
{{ lang.t("Type") }}{{ lang.t("Description") }}
+ {% if raises.annotation %} + {% with expression = raises.annotation %} + {% include "expression.html" with context %} + {% endwith %} + {% endif %} + +
+ {{ raises.description|convert_markdown(heading_level, html_id) }} +
+
+ {% endblock table_style %} +{% elif config.docstring_section_style == "list" %} + {% block list_style scoped %} +

{{ lang.t(section.title) or lang.t("Raises:") }}

+
    + {% for raises in section.value %} +
  • + {% if raises.annotation %} + {% with expression = raises.annotation %} + {% include "expression.html" with context %} + {% endwith %} + – + {% endif %} +
    + {{ raises.description|convert_markdown(heading_level, html_id) }} +
    +
  • + {% endfor %} +
+ {% endblock list_style %} +{% elif config.docstring_section_style == "spacy" %} + {% block spacy_style scoped %} +

{{ (section.title or lang.t("Raises:")) }}

+
+ {% for raises in section.value %} +
+ {% with expression = raises.annotation %} + {% include "expression.html" with context %} + {% endwith %} +
+
+
+ {{ raises.description|convert_markdown(heading_level, html_id) }} +
+
+ {% endfor %} +
+ {% endblock spacy_style %} +{% endif %} diff --git a/overrides/mkdocstrings/python/material/docstring/returns.html b/overrides/mkdocstrings/python/material/docstring/returns.html new file mode 100644 index 0000000..bd60840 --- /dev/null +++ b/overrides/mkdocstrings/python/material/docstring/returns.html @@ -0,0 +1,94 @@ +{{ log.debug("Rendering returns section") }} + +{% import "language.html" as lang with context %} + +{% if config.docstring_section_style == "table" %} + {% block table_style scoped %} + {% set name_column = section.value|selectattr("name")|any %} +

{{ section.title or lang.t("Returns:") }}

+ + + + {% if name_column %}{% endif %} + + + + + + {% for returns in section.value %} + + {% if name_column %}{% endif %} + + + + {% endfor %} + +
{{ lang.t("Name") }}{{ lang.t("Type") }}{{ lang.t("Description") }}
{% if returns.name %}{{ returns.name }}{% endif %} + {% if returns.annotation %} + {% with expression = returns.annotation %} + {% include "expression.html" with context %} + {% endwith %} + {% endif %} + +
+ {{ returns.description|convert_markdown(heading_level, html_id) }} +
+
+ {% endblock table_style %} +{% elif config.docstring_section_style == "list" %} + {% block list_style scoped %} +

{{ section.title or lang.t("Returns:") }}

+
    + {% for returns in section.value %} +
  • + {% if returns.name %}{{ returns.name }}{% endif %} + {% if returns.annotation %} + {% with expression = returns.annotation %} + {% if returns.name %} ({% endif %} + {% include "expression.html" with context %} + {% if returns.name %}){% endif %} + {% endwith %} + {% endif %} + – +
    + {{ returns.description|convert_markdown(heading_level, html_id) }} +
    +
  • + {% endfor %} +
+ {% endblock list_style %} +{% elif config.docstring_section_style == "spacy" %} + {% block spacy_style scoped %} +

{{ (section.title or lang.t("Returns:")) }}

+
+ {% for returns in section.value %} +
+ {% if returns.name %} + {{ returns.name }} + {% elif returns.annotation %} + + {% with expression = returns.annotation %} + {% include "expression.html" with context %} + {% endwith %} + + {% endif %} +
+
+
+ {{ returns.description|convert_markdown(heading_level, html_id) }} +
+ {% if returns.name and returns.annotation %} +

+ + {{ lang.t("TYPE:") }} + {% with expression = returns.annotation %} + {% include "expression.html" with context %} + {% endwith %} + +

+ {% endif %} +
+ {% endfor %} +
+ {% endblock spacy_style %} +{% endif %} diff --git a/overrides/partials/comments.html b/overrides/partials/comments.html new file mode 100644 index 0000000..d7ae25a --- /dev/null +++ b/overrides/partials/comments.html @@ -0,0 +1,37 @@ +{% if page.meta.comments %} +

{{ lang.t("meta.comments") }}

+ + + + +{% endif %} diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..247936e --- /dev/null +++ b/requirements.txt @@ -0,0 +1,15 @@ +black +markdown-customblocks +mdx-truly-sane-lists +mkdocs +mkdocs-gen-files +mkdocs-git-authors-plugin +mkdocs-git-committers-plugin +mkdocs-git-revision-date-localized-plugin +mkdocs-include-markdown-plugin +mkdocs-literate-nav +mkdocs-material +mkdocs-minify-plugin +mkdocs-section-index +pre-commit +python-frontmatter diff --git a/tests/__init__.py b/tests/__init__.py deleted file mode 100644 index 62805f3..0000000 --- a/tests/__init__.py +++ /dev/null @@ -1 +0,0 @@ -"""Unit test package for hiring_software_engineers.""" diff --git a/tests/test_hiring_software_engineers.py b/tests/test_hiring_software_engineers.py deleted file mode 100644 index 1209c7d..0000000 --- a/tests/test_hiring_software_engineers.py +++ /dev/null @@ -1,4 +0,0 @@ -"""Tests for `hiring_software_engineers` package.""" - -import pytest -from hiring_software_engineers import hiring_software_engineers diff --git a/tools/create-release.sh b/tools/create-release.sh new file mode 100755 index 0000000..c3ce499 --- /dev/null +++ b/tools/create-release.sh @@ -0,0 +1,28 @@ +#!/usr/bin/env bash + + +function extract_version_content() { + changelog=$1 + target_version=$2 + + awk -v target="$target_version" ' + /^## / { + if (found) exit; + version=$2; + if (version == target) found=1; + next; + } + found { print; } + ' <<< "$changelog" +} + +changelog=$(cat "CHANGELOG.md") +TARGET_VERSION=$(bump-my-version show current_version) +NOTES=$(extract_version_content "$changelog" "$TARGET_VERSION") +echo "Creating a GitHub release for version ${TARGET_VERSION} with notes." +gh release create \ + "${TARGET_VERSION}" \ + ./dist/* \ + --title "${TARGET_VERSION}" \ + --notes "${NOTES}" \ + --draft diff --git a/tools/drawioexport.py b/tools/drawioexport.py new file mode 100644 index 0000000..fc75e53 --- /dev/null +++ b/tools/drawioexport.py @@ -0,0 +1,132 @@ +"""Draw.io export script.""" + +import os.path +import shutil +import subprocess +import sys +from pathlib import Path +from typing import List, Optional + + +def get_executable_paths() -> list[str]: + """Get the Draw.io executable paths for the platform. + + Declared as a function to allow us to use API/environment information + available only when running under the specified platform. + + Returns: + All known paths. + """ + if sys.platform.startswith("darwin"): + applications = [os.path.expanduser("~/Applications"), "/Applications"] + drawio_path = os.path.join("draw.io.app", "Contents", "MacOS", "draw.io") + return [os.path.join(d, drawio_path) for d in applications] + elif sys.platform.startswith("linux"): + return ["/opt/draw.io/drawio"] + elif sys.platform.startswith("win32"): + program_files = [os.environ["ProgramFiles"]] + if "ProgramFiles(x86)" in os.environ: + program_files.append(os.environ["ProgramFiles(x86)"]) + return [os.path.join(d, "draw.io", "draw.io.exe") for d in program_files] + else: + return [] + + +def get_drawio_executable(executable_names: Optional[List[str]] = None) -> Optional[str]: + """Ensure the Draw.io executable path is configured, or guess it. + + Args: + executable_names: List of executable names to check. + + Returns: + Final Draw.io executable. + """ + executable_names = executable_names or ["draw.io", "drawio"] + + for executable_name in executable_names: + executable = shutil.which(executable_name) + if executable: + return executable + + executable_paths = get_executable_paths() + + return next( + (executable_path for executable_path in executable_paths if os.path.isfile(executable_path)), + None, + ) + + +def use_cached_file(source: Path, cache_filename: Path) -> bool: + """Is the cached copy up to date? + + Args: + source: Source path. + cache_filename: Export cache filename. + + Returns: + True if cache is up to date else False. + """ + return cache_filename.exists() and cache_filename.stat().st_mtime >= source.stat().st_mtime + + +def export_file( + source: Path, + page_index: int, + dest: Path, + export_format: str, +) -> int: + """Export an individual file. + + Args: + source: Source path, absolute. + page_index: Page index, numbered from zero. + dest: Destination path, within cache. + export_format: Export format. + + Returns: + The Draw.io exit status. + """ + drawio_executable = get_drawio_executable() + cmd = [ + str(drawio_executable), + "--export", + str(source), + "--page-index", + str(page_index), + "--output", + str(dest), + "--format", + export_format, + "--embed-svg-images", + "--scale", + "2", + ] + result = subprocess.run(cmd) # noqa: S603 + return result.returncode + + +def export_file_if_needed(source: Path, page_index: int, dest_path: Path) -> None: + """Export an individual file if needed. + + Args: + source: Source path, absolute. + page_index: Page index, numbered from zero. + dest_path: Destination path. + """ + if not use_cached_file(source, dest_path): + export_file(source, page_index, dest_path, "svg") + else: + print(f"Using cached file {dest_path}") # noqa: T201 + + +if __name__ == "__main__": + drawio_path = "docs/images/example.drawio" + destination = "docs/images/" + output_files = [ + # SVG name for each page in the Draw.io file. + ] + source_path = Path(__file__).parent.parent.joinpath(drawio_path) + dest_path = Path(__file__).parent.parent.joinpath(destination) + for index, filename in enumerate(output_files): + filepath = dest_path.joinpath(filename) + export_file_if_needed(source_path, index, filepath) diff --git a/tools/gen-codeowners.sh b/tools/gen-codeowners.sh new file mode 100755 index 0000000..af8e556 --- /dev/null +++ b/tools/gen-codeowners.sh @@ -0,0 +1,21 @@ +#!/usr/bin/env bash + +# Generate the CODEOWNERS file for all unempty files +# +# Requires git-fame: pip install git-fame +# +# Usage: gen-codeowners.sh path1 [path2 ...] + +owners(){ + for f in $(git ls-files "$*"); do + LINECOUNT=$(wc -l "$f" | awk '{print $1}') + if [[ $LINECOUNT -gt 0 ]]; then + echo -n "$f " + # author emails if loc distribution >= 30% + git fame -esnwMC --incl "$f" | tr '/' '|' \ + | awk -v filename="$f" -F '|' '(NR>6 && $6>=30) {print $2}' \ + | xargs echo + fi + done +} +owners "$*" | tee CODEOWNERS diff --git a/tools/update_frontmatter.py b/tools/update_frontmatter.py new file mode 100755 index 0000000..fb34762 --- /dev/null +++ b/tools/update_frontmatter.py @@ -0,0 +1,77 @@ +#!/usr/bin/env python +"""Update frontmatter of markdown files.""" + +import argparse +from pathlib import Path +from typing import Any, Dict, Optional + +import frontmatter + + +def extract_main_heading(markdown_content: str) -> Optional[str]: + """ + Extracts the first level 1 heading from the provided Markdown content. + + Args: + markdown_content: A string containing Markdown text. + + Returns: + The text of the first level 1 heading, or None if no such heading is found. + """ + lines = markdown_content.split("\n") + + return next((line[2:] for line in lines if line.startswith("# ")), None) + + +def calc_title(post: frontmatter.Post) -> str: + """Calculate the title of the post.""" + return extract_main_heading(post.content) or post.get("title", "") + + +def calc_comment(post: frontmatter.Post) -> bool: + """Calculate if the post has comments.""" + return bool(post.get("comments", True)) + + +def calculate_update(post: frontmatter.Post) -> dict: + """Calculate if the frontmatter needs to be updated.""" + expected_title = calc_title(post) + expected_comment = calc_comment(post) + update: Dict[str, Any] = {} + if expected_title and expected_title != post.get("title"): + update["title"] = expected_title + if expected_comment != post.get("comments"): + update["comments"] = expected_comment + return update + + +def process_file(markdown_path: Path) -> None: + """Process a single file.""" + if not (markdown_path.is_file() and markdown_path.suffix == ".md"): + return + raw_text = markdown_path.read_text() + post = frontmatter.loads(raw_text) + + update = calculate_update(post) + if update: + for key, value in update.items(): + post[key] = value + new_text = frontmatter.dumps(post) + print(f"Updating {markdown_path}") # noqa: T201 + markdown_path.write_text(new_text) + + +def parse_args() -> argparse.Namespace: + """Parse command line arguments.""" + parser = argparse.ArgumentParser(description="Update frontmatter of markdown files") + parser.add_argument("markdown_path", type=str, nargs="+", help="Path or glob to markdown files") + return parser.parse_args() + + +if __name__ == "__main__": + # call `python tools/update_frontmatter.py "docs/**/*.md"` + args = parse_args() + documents = args.markdown_path + for document in documents: + for path in Path().glob(document): + process_file(path)