diff --git a/.flake8 b/.flake8 new file mode 100644 index 0000000..113ca5f --- /dev/null +++ b/.flake8 @@ -0,0 +1,2 @@ +[flake8] +max-line-length = 125 diff --git a/.github/maintainers_guide.md b/.github/maintainers_guide.md new file mode 100644 index 0000000..14b1f3d --- /dev/null +++ b/.github/maintainers_guide.md @@ -0,0 +1,215 @@ +# Maintainers Guide + +This document describes tools, tasks and workflow that one needs to be familiar with in order to effectively maintain +this project. If you use this package within your own software as is but don't plan on modifying it, this guide is +**not** for you. + +## Tools + +### Python (and friends) + +We recommend using [pyenv](https://github.com/pyenv/pyenv) for Python runtime management. If you use macOS, follow the following steps: + +```zsh +brew update +brew install pyenv +``` + +Install necessary Python runtimes for development/testing. You can rely on GitHub Actions for testing with various major versions. + +```zsh +pyenv install -l | grep -v "-e[conda|stackless|pypy]" + +pyenv install 3.8.5 # select the latest patch version +pyenv local 3.8.5 + +pyenv versions + system + 3.6.10 + 3.7.7 +* 3.8.5 (set by /path-to-python-slack-hooks/.python-version) + +pyenv rehash +``` + +Then, you can create a new Virtual Environment this way: + +```zsh +python -m venv env_3.8.5 +source env_3.8.5/bin/activate +``` + +## Tasks + +### Testing + +#### Run All the Unit Tests + +If you make some changes to this project, please write corresponding unit tests as much as possible. You can easily run all the tests by running the following scripts. + +If this is your first time to run tests, although it may take a bit longer, running the following script is the easiest. + +```zsh +./scripts/install_and_run_tests.sh +``` + +To simply install all the development dependencies for this project. + +```zsh +./scripts/install.sh +``` + +Once you installed all the required dependencies, you can use the following. + +```zsh +./scripts/run_tests.sh +./scripts/run_tests.sh tests/scenario_test/test_get_hooks.py +``` + +To format this project + +```zsh +./scripts/format.sh +``` + +To lint this project + +```zsh +./scripts/lint.sh +``` + +This project uses [pytype](https://google.github.io/pytype/) to check and infers types for your Python code. + +```zsh +./scripts/run_pytype.sh +``` + +#### Develop Locally + +If you want to test the package locally you can. + +1. Build the package locally + - Run + + ```zsh + scripts/build_pypi_package.sh + ``` + + - This will create a `.whl` file in the `./dist` folder +2. Use the built package + - Example `/dist/slack_cli_hooks-1.2.3-py2.py3-none-any.whl` was created + - From anywhere on your machine you can install this package to a project with + + ```zsh + pip install /dist/slack_cli_hooks-1.2.3-py2.py3-none-any.whl + ``` + +### Releasing + +#### test.pypi.org deployment + +It is possible to deploy this project on in order to try out packaging and deploy related changes + +```zsh +./scripts/deploy_to_test_pypi.sh +``` + +#### Development Deployment + +1. Create a branch in which the development release will live: + - Bump the version number in adherence to [Semantic Versioning](http://semver.org/) and [Developmental Release](https://peps.python.org/pep-0440/#developmental-releases) in `slack_cli_hooks/version.py` + - Example the current version is `1.2.3` a proper development bump would be `1.3.0.dev0` + - `.dev` will indicate to pip that this is a [Development Release](https://peps.python.org/pep-0440/#developmental-releases) + - Note that the `dev` version can be bumped in development releases: `1.3.0.dev0` -> `1.3.0.dev1` + - Commit with a message including the new version number. For example `1.3.0.dev0` & Push the commit to a branch where the development release will live (create it if it does not exist) + - `git checkout -b future-release` + - `git commit -m 'version 1.3.0.dev0'` + - `git push future-release` + - Create a git tag for the release. For example `git tag v1.3.0.dev0`. + - Push the tag up to github with `git push origin --tags` + +2. Distribute the release + - Use the latest stable Python runtime + - `python -m venv .venv` + - `./scripts/deploy_to_prod_pypi.sh` + - You do not need to create a GitHub release + +3. (Slack Internal) Communicate the release internally + +#### Production Deployment + +1. Create the commit for the release: + - Bump the version number in adherence to [Semantic Versioning](http://semver.org/) in `slack_cli_hooks/version.py` + - Commit with a message including the new version number. For example `1.2.3` & Push the commit to a branch and create a PR to sanity check. + - `git checkout -b v1.2.3-release` + - `git commit -m 'version 1.2.3'` + - `git push {your-fork} v1.2.3-release` + - Merge in release PR after getting an approval from at least one maintainer. + - Create a git tag for the release. For example `git tag v1.2.3`. + - Push the tag up to github with `git push origin --tags` + +2. Distribute the release + - Use the latest stable Python runtime + - `python -m venv .venv` + - `./scripts/deploy_to_pypi_org.sh` + - Create a GitHub release - + + ```markdown + ## New Features + + ### Awesome Feature 1 + + Description here. + + ### Awesome Feature 2 + + Description here. + + ## Changes + + * #123 Make it better - thanks @SlackHQ + * #123 Fix something wrong - thanks @seratch + ``` + +3. (Slack Internal) Communicate the release internally + - Include a link to the GitHub release + +4. (Slack Internal) Tweet by @SlackAPI + - Not necessary for patch updates, might be needed for minor updates, definitely needed for major updates. Include a link to the GitHub release + +## Workflow + +### Versioning and Tags + +This project uses semantic versioning, expressed through the numbering scheme of +[PEP-0440](https://www.python.org/dev/peps/pep-0440/). + +### Branches + +`main` is where active development occurs. Long running named feature branches are occasionally created for +collaboration on a feature that has a large scope (because everyone cannot push commits to another person's open Pull +Request). At some point in the future after a major version increment, there may be maintenance branches for older major +versions. + +### Issue Management + +Labels are used to run issues through an organized workflow. Here are the basic definitions: + +- `bug`: A confirmed bug report. A bug is considered confirmed when reproduction steps have been + documented and the issue has been reproduced. +- `enhancement`: A feature request for something this package might not already do. +- `docs`: An issue that is purely about documentation work. +- `tests`: An issue that is purely about testing work. +- `discussion`: An issue that is purely meant to hold a discussion. Typically the maintainers are looking for feedback in this issues. +- `question`: An issue that is like a support request because the user's usage was not correct. + +**Triage** is the process of taking new issues that aren't yet "seen" and marking them with a basic level of information +with labels. An issue should have **one** of the following labels applied: `bug`, `enhancement`, `question`, +`needs feedback`, `docs`, `tests`, or `discussion`. + +Issues are closed when a resolution has been reached. If for any reason a closed issue seems relevant once again, +reopening is great and better than creating a duplicate issue. + +## Everything else + +When in doubt, find the other maintainers and ask. diff --git a/.github/workflows/codecov.yml b/.github/workflows/codecov.yml new file mode 100644 index 0000000..0b3edc4 --- /dev/null +++ b/.github/workflows/codecov.yml @@ -0,0 +1,34 @@ +name: Run codecov + +on: + push: + branches: [main] + pull_request: + +jobs: + build: + runs-on: ubuntu-latest + timeout-minutes: 10 + strategy: + matrix: + python-version: ["3.12"] + steps: + - uses: actions/checkout@v4 + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v4 + with: + python-version: ${{ matrix.python-version }} + - name: Install dependencies + run: | + pip install -U pip + pip install . + pip install -r requirements/testing.txt + - name: Run all tests for codecov + run: | + pytest --cov=./slack_cli_hooks/ --cov-report=xml + # TODO uncomment when repo public + # - name: Upload coverage to Codecov + # uses: codecov/codecov-action@v3 + # with: + # fail_ci_if_error: true + # verbose: true diff --git a/.github/workflows/flake8.yml b/.github/workflows/flake8.yml new file mode 100644 index 0000000..839c411 --- /dev/null +++ b/.github/workflows/flake8.yml @@ -0,0 +1,23 @@ +name: Run flake8 validation + +on: + push: + branches: [main] + pull_request: + +jobs: + build: + runs-on: ubuntu-latest + timeout-minutes: 2 + strategy: + matrix: + python-version: ["3.12"] + steps: + - uses: actions/checkout@v4 + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v4 + with: + python-version: ${{ matrix.python-version }} + - name: Run flake8 verification + run: | + ./scripts/lint.sh diff --git a/.github/workflows/pytype.yml b/.github/workflows/pytype.yml new file mode 100644 index 0000000..8995c92 --- /dev/null +++ b/.github/workflows/pytype.yml @@ -0,0 +1,23 @@ +name: Run pytype validation + +on: + push: + branches: [main] + pull_request: + +jobs: + build: + runs-on: ubuntu-latest + timeout-minutes: 2 + strategy: + matrix: + python-version: ["3.11"] + steps: + - uses: actions/checkout@v4 + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v4 + with: + python-version: ${{ matrix.python-version }} + - name: Run pytype verification + run: | + ./scripts/run_pytype.sh diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml new file mode 100644 index 0000000..caa693e --- /dev/null +++ b/.github/workflows/tests.yml @@ -0,0 +1,29 @@ +name: Run all the unit tests + +on: + push: + branches: [main] + pull_request: + +jobs: + build: + # Avoiding -latest due to https://github.com/actions/setup-python/issues/162 + runs-on: ubuntu-20.04 + timeout-minutes: 5 + strategy: + matrix: + python-version: ["3.6", "3.7", "3.8", "3.9", "3.10", "3.11", "3.12"] + steps: + - uses: actions/checkout@v4 + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v4 + with: + python-version: ${{ matrix.python-version }} + - name: Install dependencies + run: | + pip install -U pip + pip install . + pip install -r requirements/testing.txt + - name: Run tests + run: | + pytest diff --git a/.github/workflows/triage-issues.yml b/.github/workflows/triage-issues.yml new file mode 100644 index 0000000..1a12b80 --- /dev/null +++ b/.github/workflows/triage-issues.yml @@ -0,0 +1,33 @@ +# This workflow uses the following github action to automate +# management of stale issues and prs in this repo: +# https://github.com/marketplace/actions/close-stale-issues + +name: Close stale issues and PRs + +on: + workflow_dispatch: + schedule: + - cron: "0 0 * * 1" + +permissions: + issues: write + pull-requests: write + +jobs: + stale: + runs-on: ubuntu-latest + steps: + - uses: actions/stale@v8 + with: + days-before-issue-stale: 30 + days-before-issue-close: 10 + days-before-pr-stale: -1 + days-before-pr-close: -1 + stale-issue-label: auto-triage-stale + stale-issue-message: 👋 It looks like this issue has been open for 30 days with no activity. We'll mark this as stale for now, and wait 10 days for an update or for further comment before closing this issue out. If you think this issue needs to be prioritized, please comment to get the thread going again! Maintainers also review issues marked as stale on a regular basis and comment or adjust status if the issue needs to be reprioritized. + close-issue-message: As this issue has been inactive for more than one month, we will be closing it. Thank you to all the participants! If you would like to raise a related issue, please create a new issue which includes your specific details and references this issue number. + exempt-issue-labels: auto-triage-skip + exempt-all-milestones: true + remove-stale-when-updated: true + enable-statistics: true + operations-per-run: 60 diff --git a/.gitignore b/.gitignore index 68bc17f..eabc2dd 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,13 @@ +# general things to ignore +tmp.txt +.DS_Store +logs/ +*.db +*.so +*~ +docs/_sources/ +docs/.doctrees + # Byte-compiled / optimized / DLL files __pycache__/ *.py[cod] @@ -65,9 +75,6 @@ db.sqlite3-journal instance/ .webassets-cache -# Scrapy stuff: -.scrapy - # Sphinx documentation docs/_build/ @@ -85,67 +92,23 @@ 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 - -# poetry -# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control. -# This is especially recommended for binary packages to ensure reproducibility, and is more -# commonly ignored for libraries. -# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control -#poetry.lock - -# pdm -# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control. -#pdm.lock -# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it -# in version control. -# https://pdm.fming.dev/#use-with-ide -.pdm.toml +.python-version # PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm __pypackages__/ -# Celery stuff -celerybeat-schedule -celerybeat.pid - -# SageMath parsed files -*.sage.py - # Environments .env .venv -env/ -venv/ +env*/ +venv*/ +.venv*/ +.env*/ +.env* 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/ @@ -157,4 +120,4 @@ cython_debug/ # be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore # and can be added to the global gitignore or merged into this file. For a more nuclear # option (not recommended) you can uncomment the following to ignore the entire idea folder. -#.idea/ +.idea/ diff --git a/LICENSE b/LICENSE index 67f5552..85a0798 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2023 SlackAPI +Copyright (c) 2023- Slack Technologies, LLC Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/MANIFEST.in b/MANIFEST.in new file mode 100644 index 0000000..5d75442 --- /dev/null +++ b/MANIFEST.in @@ -0,0 +1 @@ +include README.md LICENSE slack_cli_hooks/py.typed diff --git a/codecov.yml b/codecov.yml new file mode 100644 index 0000000..5568e5e --- /dev/null +++ b/codecov.yml @@ -0,0 +1,8 @@ +coverage: + status: + project: + default: + threshold: 2.0% + patch: + default: + target: 50% diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..4067b3d --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,53 @@ +[build-system] +requires = ["setuptools", "pytest-runner"] +build-backend = "setuptools.build_meta" + +[project] +name = "slack_cli_hooks" +dynamic = ["version", "readme", "dependencies"] +description = "The Slack CLI contract implementation for Bolt Python" +license = { text = "MIT" } +authors = [{ name = "Slack Technologies, LLC", email = "opensource@slack.com" }] +requires-python = ">=3.6" +classifiers = [ + "Development Status :: 2 - Pre-Alpha", + "Environment :: Console", + "Intended Audience :: Developers", + "Topic :: Office/Business", + "Topic :: Software Development", + "License :: OSI Approved :: MIT License", + "Programming Language :: Python", + "Programming Language :: Python :: 3 :: Only", + "Programming Language :: Python :: 3.6", + "Programming Language :: Python :: 3.7", + "Programming Language :: Python :: 3.8", + "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", + "Programming Language :: Python :: Implementation :: CPython", + "Programming Language :: Python :: Implementation :: PyPy", +] + + +[project.urls] +"Source Code" = "https://github.com/slackapi/python-slack-hooks" + + +[tool.setuptools.packages.find] +include = ["slack_cli_hooks*"] + +[tool.setuptools.dynamic] +version = { attr = "slack_cli_hooks.version.__version__" } +readme = { file = ["README.md"], content-type = "text/markdown" } +dependencies = { file = ["requirements.txt"] } + +[tool.black] +line-length = 125 + +[tool.pytest.ini_options] +testpaths = ["tests"] +log_file = "logs/pytest.log" +log_file_level = "DEBUG" +log_format = "%(asctime)s %(levelname)s %(message)s" +log_date_format = "%Y-%m-%d %H:%M:%S" diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..e3ccbaa --- /dev/null +++ b/requirements.txt @@ -0,0 +1 @@ +slack_bolt>=1.18.0,<2 diff --git a/requirements/build.txt b/requirements/build.txt new file mode 100644 index 0000000..4377557 --- /dev/null +++ b/requirements/build.txt @@ -0,0 +1,3 @@ +# pip install -r requirements/build.txt +twine +build diff --git a/requirements/format.txt b/requirements/format.txt new file mode 100644 index 0000000..6e78bf4 --- /dev/null +++ b/requirements/format.txt @@ -0,0 +1,6 @@ +black==22.8.0; python_version=="3.6" +black; python_version>"3.6" # Until we drop Python 3.6 support, we have to stay with this version +flake8>=5.0.4; python_version=="3.6" +flake8==6.0.0; python_version>"3.6" +pytype; (python_version<"3.11" or python_version>"3.11") +pytype==2023.11.29; python_version=="3.11" diff --git a/requirements/testing.txt b/requirements/testing.txt new file mode 100644 index 0000000..d48df50 --- /dev/null +++ b/requirements/testing.txt @@ -0,0 +1,3 @@ +# pip install -r requirements/testing.txt +pytest>=6.2.5,<7 +pytest-cov>=3,<4 diff --git a/scripts/_utils.sh b/scripts/_utils.sh new file mode 100644 index 0000000..f41d7aa --- /dev/null +++ b/scripts/_utils.sh @@ -0,0 +1,35 @@ +#!/bin/bash + +set_prj_as_cwd() { + script_dir=`dirname $0` + cd ${script_dir}/.. +} + +clean_project() { + rm -rf dist/ build/ slack_cli_hooks.egg-info/ +} + +install_development_requirements() { + python_version=`python --version | awk '{print $2}'` + + if [ ${python_version:0:3} == "3.6" ] + then + pip install -r requirements.txt + else + pip install -e . + fi + + pip install -U pip + pip install -r requirements/testing.txt + pip install -r requirements/format.txt +} + +build() { + pip install -r requirements/build.txt && \ + python -m build && \ + twine check dist/* +} + +format() { + black slack_cli_hooks/ tests/ +} diff --git a/scripts/build_pypi_package.sh b/scripts/build_pypi_package.sh new file mode 100755 index 0000000..1f6e893 --- /dev/null +++ b/scripts/build_pypi_package.sh @@ -0,0 +1,8 @@ +#!/bin/bash +source ./scripts/_utils.sh + +set_prj_as_cwd + +clean_project + +build diff --git a/scripts/deploy_to_prod_pypi.sh b/scripts/deploy_to_prod_pypi.sh new file mode 100755 index 0000000..f8b7a50 --- /dev/null +++ b/scripts/deploy_to_prod_pypi.sh @@ -0,0 +1,10 @@ +#!/bin/bash +source ./scripts/_utils.sh + +set_prj_as_cwd + +clean_project + +build + +twine upload dist/* diff --git a/scripts/deploy_to_test_pypi.sh b/scripts/deploy_to_test_pypi.sh new file mode 100755 index 0000000..57d2f22 --- /dev/null +++ b/scripts/deploy_to_test_pypi.sh @@ -0,0 +1,10 @@ +#!/bin/bash +source ./scripts/_utils.sh + +set_prj_as_cwd + +clean_project + +build + +twine upload --repository testpypi dist/* diff --git a/scripts/format.sh b/scripts/format.sh new file mode 100755 index 0000000..d0b21ce --- /dev/null +++ b/scripts/format.sh @@ -0,0 +1,9 @@ +#!/bin/bash +source ./scripts/_utils.sh + +set_prj_as_cwd + +pip install -U pip +pip install -r requirements/format.txt + +format diff --git a/scripts/install.sh b/scripts/install.sh new file mode 100755 index 0000000..bf45bc9 --- /dev/null +++ b/scripts/install.sh @@ -0,0 +1,6 @@ +#!/bin/bash +source ./scripts/_utils.sh + +set_prj_as_cwd + +install_development_requirements diff --git a/scripts/install_and_run_tests.sh b/scripts/install_and_run_tests.sh new file mode 100755 index 0000000..c31e6da --- /dev/null +++ b/scripts/install_and_run_tests.sh @@ -0,0 +1,20 @@ +#!/bin/bash +# all: ./scripts/install_and_run_tests.sh +# single: ./scripts/install_and_run_tests.sh tests/scenario_tests/test_app.py + +test_target="$1" +source ./scripts/_utils.sh + +set_prj_as_cwd + +install_development_requirements + +format + +if [[ $test_target != "" ]] +then + pytest -vv $1 +else + pytest && \ + pytype slack_cli_hooks/ +fi diff --git a/scripts/lint.sh b/scripts/lint.sh new file mode 100755 index 0000000..0f86131 --- /dev/null +++ b/scripts/lint.sh @@ -0,0 +1,10 @@ +#!/bin/bash + +source ./scripts/_utils.sh + +set_prj_as_cwd + +pip install -U pip +pip install -r requirements/format.txt + +flake8 slack_cli_hooks/ && flake8 tests/ diff --git a/scripts/run_pytype.sh b/scripts/run_pytype.sh new file mode 100755 index 0000000..b02e173 --- /dev/null +++ b/scripts/run_pytype.sh @@ -0,0 +1,9 @@ +#!/bin/bash + +source ./scripts/_utils.sh + +set_prj_as_cwd + +install_development_requirements + +pytype slack_cli_hooks/ diff --git a/scripts/run_tests.sh b/scripts/run_tests.sh new file mode 100755 index 0000000..fd91348 --- /dev/null +++ b/scripts/run_tests.sh @@ -0,0 +1,17 @@ +#!/bin/bash +# all: ./scripts/run_tests.sh +# single: ./scripts/run_tests.sh tests/scenario_tests/test_app.py + +test_target="$1" +source ./scripts/_utils.sh + +set_prj_as_cwd + +format + +if [[ $test_target != "" ]] +then + pytest -vv $1 +else + pytest +fi diff --git a/scripts/uninstall_all.sh b/scripts/uninstall_all.sh new file mode 100755 index 0000000..15f5527 --- /dev/null +++ b/scripts/uninstall_all.sh @@ -0,0 +1,4 @@ +#!/bin/bash + +pip uninstall -y slack-cli-hooks && \ + pip freeze | grep -v "^-e" | xargs pip uninstall -y diff --git a/slack_cli_hooks/__init__.py b/slack_cli_hooks/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/slack_cli_hooks/version.py b/slack_cli_hooks/version.py new file mode 100644 index 0000000..e10a723 --- /dev/null +++ b/slack_cli_hooks/version.py @@ -0,0 +1,2 @@ +"""Check the latest version at https://pypi.org/project/slack-cli-hooks/""" +__version__ = "0.0.0.dev0" diff --git a/tests/__init__.py b/tests/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tests/test_dummy.py b/tests/test_dummy.py new file mode 100644 index 0000000..22ed597 --- /dev/null +++ b/tests/test_dummy.py @@ -0,0 +1,9 @@ +class TestDummy: + def setup_method(self): + pass + + def teardown_method(self): + pass + + def test_dummy(self): + assert True