背景
作为研发,如果你想提高开发效率、解放生产力、CI/CD,一定离不开脚本。随着功能不断完善,脚本体量越来越大,统一一门脚本语言,解耦复用模块,组件化开发脚本变得更加重要。
所以,统一持续使用一门合适的脚本语言是非常有必要的。
作为移动端研发,我推荐使用Python
,相比Shell,Ruby,Gradle,JS,Swift等等,优势如下:
入门简单,社区庞大,生态完善,很多坑别人都踩过,很多功能都有人实现过(这点很重要,不然你可能会因为一些大坑带来的挫败感停滞不前);
各端都有各自常用的脚本语言,而Python貌似更加的平台不相关,开发多端复用的工具也许Python更合适;
应用广泛,也许你后期可以拓展学习人工智能,大数据等;
下面详细介绍下组件化
开发一套Python命令行工具需要用到的工具链及相关配置。(本文以MacOS
为例)
安装Python3.x
Mac系统自带Python,可能会被系统工具依赖,如果玩坏了影响范围较大。一般版本较旧,且不方便管理,这里我建议自己再安装一套,推荐用Homebrew安装。(或者官网下载)
# 安装3.x版本
brew install python3
# 系统自带的Python在 /usr/bin/python3
# 使用Homebrew安装的Python一般在 /usr/local/bin/python3
# 查看安装位置,安装后会打印brew安装的路径
which python3
# python包管理工具,下面介绍
which pip3
# 如果路径不对,一般是PATH没有记录新路径,添加一下即可
echo $PATH
# 卸载
brew uninstall python3
关于pip3
类似iOS的Cocoapods,Java的Maven,前端的npm,pip3是官方自带的包管理工具,从PyPI或私有源上你可以轻松找到可供你使用的轮子(以下都称package
)。
# 下载package
python3 -m pip install <package>
# 或者
pip3 install <package>
# 查看已安装package
pip3 show <package>
# 查看下载到本地的所有package
pip3 list [-v]
# 卸载
pip3 uninstall <package>
关于pip3导入包的作用域
全局作用域
一般来说,pip3 install默认导入到全局作用域,即模块导入到/usr/local/lib/python3.x/site-packages路径下,可执行文件导入到/usr/local/bin/。
在系统目录下,可被所有用户共享。
用户作用域
添加--user选项,导入到用户作用域,即模块导入到/Users/lyon/Library/Python/3.x/ lib/python/site-packages,可执行文件导入到/Users/lyon/Library/Python/3.11/bin/。
在当前用户目录下,不可被其他用户共享。
注:
/Users/lyon/Library/
此路径一般不在环境变量PATH中,也就是说,如果pip3 install导入到用户作用域下可能因命令不可见导致调用失败。
安装pipx
pip3安装package以用户为最小隔离单位,即同一个用户安装的package在同一目录下。而且不支持同一个package的多版本共存,如果用户开发或使用的多个工程(以下称application
orapp
)依赖的同一个package版本冲突时将无法解决。
pipx是python package,封装并优化了pip的安装逻辑,对多个app依赖的packages隔离管理,解决了上述问题。
# 安装
brew install pipx
# 添加pipx的工作目录到PATH变量中
pipx ensurepath
安装poetry
pip3/pipx准确说是针对工具使用者
的包管理工具,比如要下载名为AppUploader的工具,使用者通过pip install安装时会自动下载该工具依赖的packages。
对于工具开发者,至少需要添加及管理依赖、隔离开发和生产环境、配置命令行入口的功能,可选工具有Pipenv、venv、setuptools、Poetry等,这些工具也都可以看作是对pip功能的封装。
推荐poetry,提供了从开发、依赖、编译、发布一整套的工程化解决方案,相比setuptools使用体验更好。
# 安装
pipx install poetry
# 创建新工程
poetry new YOUR_PROJ_NAME
# 初始化已有工程
poetry init
# 添加依赖
poetry add requests
# 导入/对齐依赖
poetry install
# 更新依赖
poetry update requests
# 激活虚环境(追加PATH,覆盖生产环境目录)
poetry shell
poetry初始化之后,主要配置pyproject.toml文件,样例如下:
[tool.poetry]
name = "metis-ios-workflow"
version = "1.0.2"
description = "CLI tools for Metis."
authors = ["xxx"]
readme = "README.md"
packages = [
{include = "metis_ios_workflow", from = "src"},
]
license = "MIT"
homepage = "xxx"
[tool.poetry.scripts]
metis = "metis_ios_workflow.cli.entry:metis"
[tool.poetry.dependencies]
python = "^3.11"
requests = "^2.31.0"
jira = {version = "^3.5.2", extras = ["cli"]}
appstoreconnect = {git = "https://github.com/xxx/xxx.git", branch = "xxx"}
[tool.poetry.group.dev.dependencies]
flake8 = "^6.0.0"
flake8-quotes = "*"
[build-system]
requires = ["poetry-core"]
build-backend = "poetry.core.masonry.api"
代码风格检查
主流的代码风格检查工具有flake8,black,isort,其中black和isort提供格式化代码的入口。
关于代码风格建议详见《PEP 8 – Style Guide for Python Code》,根据规范制定的错误码详见pycodestyle。
# 安装(仅开发环境)
poetry add flake8 isort black --group=dev
安装及配置pre-commit
pre-commit可以集中管理git hooks各个阶段的脚本,并且提供丰富的插件及自定义插件的能力,flake8和isort均提供了相关插件,代码检查时机可通过配置pre-commit完成,在git pre-commit时自动检查,检查不通过则commit失败。
# step1:安装
pipx install pre-commit
# step2:通过`.pre-commit-config.yaml`配置pre-commit(git仓库根目录)
# step3:导入git hook插件(git仓库根目录执行)
pre-commit install
其中.pre-commit-config.yaml文件配置如下:
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.2.0
hooks:
- id: end-of-file-fixer
- id: trailing-whitespace
- repo: https://github.com/pycqa/flake8
rev: 4.0.1
hooks:
- id: flake8
additional_dependencies: [flake8_commas, flake8_quotes]
- repo: https://github.com/pycqa/isort
rev: 5.12.0
hooks:
- id: isort
安装及配置PyCharm CE
相比VSCode,PyCharm默认集成了代码提示,风格检查,查看API,Debug工具,自动导入poetry依赖,自动激活虚环境等一系列强大功能,而且与IDEA交互风格非常相似,熟悉以上IDE的研发可以无缝切换,推荐使用PyCharm。
JetBrains推出了很多优秀的开发工具,其中IDEA、WebStorm等是目前业内最受欢迎的IDE,PyCharm是旗下专业的Python IDE,可以下载社区免费版。
自动格式化代码
“cmd+,”进入偏好设置,找到External Tools
,点击+号,这里分别添加black和isort外部工具。
black配置如下,其中:
$PyInterpreterDirectory$
是python3解释器路径,在poetry虚环境下即是其可执行文件目录,确保black cli在此目录下即可。
$FilePath$
是当前选中的文件/目录,作为black cli入参,指定需要格式化的文件/目录。
isort配置如下:
选中文件/目录后,可在菜单栏中点击调用对应的命令完成代码格式化。
也可以如下配置快捷键。(或者监听文件变化自动执行,参考:Automate linting & formatting in PyCharm with your favourite tools)
[图片上传失败...(image-a0e2a1-1694170216976)]
定制命令入口
[图片上传失败...(image-e820ba-1694165964506)]
对于一套功能较复杂的CLI,如git命令,以git [options] <command> [<args>]
的形式组合了clone/commit/push等功能,方便统一查看帮助信息,也可以结构化复用相关参数,需要定制层级分明、可组合式的命令行入口。
推荐使用click三方库辅助设计,通过poetry add click安装。
定制一套形如metis <command> <subcommand> [<args>]
的CLI,可如下设计:
metis
作为命令入口,添加各子功能模块。
import click
from metis_ios_workflow.cli.cmds.app import app
from metis_ios_workflow.cli.cmds.gitlab import gitlab
from metis_ios_workflow.cli.cmds.jira import jira
from metis_ios_workflow.cli.cmds.notify import notify
from metis_ios_workflow.cli.cmds.pod import pod
from metis_ios_workflow.cli.cmds.release import release
from metis_ios_workflow.cli.cmds.scrum import scrum
from metis_ios_workflow.cli.cmds.sentry import sentry
from metis_ios_workflow.cli.cmds.xcrc import xcrc
CONTEXT_SETTINGS = {"help_option_names": ["-h", "--help"]}
@click.group(context_settings=CONTEXT_SETTINGS)
@click.version_option(None, "-v", "-V", "--version")
def metis():
pass
metis.add_command(app)
metis.add_command(notify)
metis.add_command(release)
metis.add_command(jira)
metis.add_command(gitlab)
metis.add_command(scrum)
metis.add_command(pod)
metis.add_command(sentry)
metis.add_command(xcrc)
以metis release pre-release
命令为例,将pre-release
命令添加到release
组下。
import click
from metis_ios_workflow.app_release_assist.app_review_monitor import app_review_monitor
from metis_ios_workflow.app_release_assist.post_build import post_build_cli
from metis_ios_workflow.app_release_assist.post_release import post_release_cli
from metis_ios_workflow.app_release_assist.pre_release import pre_release_cli
from metis_ios_workflow.utils.macro import BuildConfiguration
@click.group(help="发版助手")
def release():
pass
@release.command(help="「预发版」任务处理")
@click.option("--target_list", type=click.STRING, required=True, help="App Target列表,以,间隔")
@click.option("-v", "--version", type=click.STRING, required=True, help="App三位版本号")
@click.option(
"--ref",
type=click.STRING,
required=False,
help="设置从特定的ref(branch/tag/commitSHA)开分支,不传时默认从master分支的最新提交开分支",
)
@click.option(
"--pbxproj_path",
type=click.STRING,
required=True,
help="project.pbxproj文件路径,用于自动更新对应App的版本号",
)
def pre_release(target_list, version, ref, pbxproj_path):
pre_release_cli(target_list, version, ref, pbxproj_path)
使用者角度可以明确metis
工具集的功能范围及使用介绍。
metis --help
Usage: metis [OPTIONS] COMMAND [ARGS]...
Options:
-v, -V, --version Show the version and exit.
-h, --help Show this message and exit.
Commands:
app app相关工具
gitlab gitlab工具
jira jira工具
notify 企微通知工具
pod Cocoapods工具
release 发版助手
scrum scrum助手
sentry sentry工具
xcrc XCRemoteCache相关
命令入参详细介绍。
metis release pre-release --help
Usage: metis release pre-release [OPTIONS]
「预发版」任务处理
Options:
--target_list TEXT App Target列表,以,间隔 [required]
-v, --version TEXT App三位版本号 [required]
--ref TEXT 设置从特定的ref(branch/tag/commitSHA)开分支,不传时默认从master分支的最新提交开
分支
--pbxproj_path TEXT project.pbxproj文件路径,用于自动更新对应App的版本号 [required]
-h, --help Show this message and exit.
发布
发布渠道有三种:PyPI、私有源、git仓库,对应使用方三种安装方式。
# PyPI
# 发布
poetry publish
# 安装
pip3 install <PACKAGE_NAME>
# 私有源
# 首次需配置私有源
poetry config repo.REPO_NAME REPO_INDEX_URL
# 发布
poetry publish --repository=<REPO_NAME>
# 安装
pip3 install <PACKAGE_NAME> --extra-index-url <REPO_INDEX_URL> --trusted-host <DOMAIN_OF_REPO_INDEX_URL>
# Git仓库
# 发布:提交到远端分支即视为发布
# 安装
pip3 install git+ssh://git@github.com/xxx/xxx.git@BRANCH_NAME
总结
- 安装Python3开发包;
- pipx:隔离依赖packages,避免版本冲突;
- poetry:适用开发者的工程配置、依赖管理工具集;
- 代码风格检查:flake8/black/isort + pre-commit,自动执行代码检查;
- PyCharm:自带完善功能的IDE,配置自动格式化代码;
- click:三方开发库,定制可组合式的命令行工具集;
- 三种发布及安装方式;
以上是组件化开发一套命令行工具,需要使用的工具链及配置。
工欲善其事必先利其器,也许你实现过以调用py文件的方式执行脚本,不过随着功能逐渐完善,脚本文件逐渐增多,建立一套相对规范的组件化工程将助力你更高效开发高可用的工具集。
参考
PEP 8 – Style Guide for Python Code
click[图片上传失败...(image-3523d4-1694417794422)]
[图片上传失败...(image-eccf1b-1694417794422)]
[图片上传失败...(image-f3a304-1694417794422)]
[图片上传失败...(image-bc7ec2-1694417794422)]
[图片上传失败...(image-bd810b-1694417794422)]