Skip to content

Commit 7f0b6b5

Browse files
committed
Add release workflow
1 parent 562abdc commit 7f0b6b5

File tree

5 files changed

+211
-26
lines changed

5 files changed

+211
-26
lines changed

.github/workflows/release.yml

Lines changed: 162 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,162 @@
1+
name: Release
2+
3+
on:
4+
pull_request:
5+
branches:
6+
- "master"
7+
- "ci"
8+
- "[0-9]+.[0-9x]+*"
9+
paths:
10+
- "parsing/_version.py"
11+
12+
jobs:
13+
validate-release-request:
14+
runs-on: ubuntu-latest
15+
steps:
16+
- name: Validate release PR
17+
uses: edgedb/action-release/validate-pr@master
18+
id: checkver
19+
with:
20+
require_team: Release Managers
21+
require_approval: no
22+
github_token: ${{ secrets.RELEASE_BOT_GITHUB_TOKEN }}
23+
version_file: parsing/_version.py
24+
version_line_pattern: |
25+
__version__\s*=\s*(?:['"])([[:PEP440:]])(?:['"])
26+
27+
- name: Stop if not approved
28+
if: steps.checkver.outputs.approved != 'true'
29+
run: |
30+
echo ::error::PR is not approved yet.
31+
exit 1
32+
33+
- name: Store release version for later use
34+
env:
35+
VERSION: ${{ steps.checkver.outputs.version }}
36+
run: |
37+
mkdir -p dist/
38+
echo "${VERSION}" > dist/VERSION
39+
40+
- uses: actions/upload-artifact@v2
41+
with:
42+
name: dist
43+
path: dist/
44+
45+
build-sdist:
46+
needs: validate-release-request
47+
runs-on: ubuntu-latest
48+
49+
env:
50+
PIP_DISABLE_PIP_VERSION_CHECK: 1
51+
52+
steps:
53+
- uses: actions/checkout@v2
54+
with:
55+
fetch-depth: 50
56+
submodules: true
57+
58+
- name: Set up Python
59+
uses: actions/setup-python@v2
60+
61+
- name: Build source distribution
62+
run: |
63+
pip install -U setuptools wheel pip
64+
python setup.py sdist
65+
66+
- uses: actions/upload-artifact@v2
67+
with:
68+
name: dist
69+
path: dist/*.tar.*
70+
71+
build-wheels:
72+
needs: validate-release-request
73+
runs-on: ${{ matrix.os }}
74+
strategy:
75+
matrix:
76+
os: [ubuntu-latest, macos-latest, windows-latest]
77+
cibw_python: ["cp37-*", "cp38-*", "cp39-*", "cp310-*"]
78+
cibw_arch: ["auto64"]
79+
80+
defaults:
81+
run:
82+
shell: bash
83+
84+
env:
85+
PIP_DISABLE_PIP_VERSION_CHECK: 1
86+
87+
steps:
88+
- uses: actions/checkout@v2
89+
with:
90+
fetch-depth: 50
91+
submodules: true
92+
93+
- uses: pypa/[email protected]
94+
env:
95+
CIBW_BUILD_VERBOSITY: 1
96+
CIBW_BUILD: ${{ matrix.cibw_python }}
97+
CIBW_ARCHS: ${{ matrix.cibw_arch }}
98+
CIBW_ENVIRONMENT: "PARSING_USE_MYPYC=1"
99+
CIBW_BEFORE_ALL_LINUX: >
100+
yum -y install libffi-devel
101+
CIBW_TEST_EXTRAS: "test"
102+
CIBW_TEST_COMMAND: >
103+
python {project}/tests/__init__.py
104+
CIBW_TEST_COMMAND_WINDOWS: >
105+
python {project}\tests\__init__.py
106+
107+
- uses: actions/upload-artifact@v2
108+
with:
109+
name: dist
110+
path: wheelhouse/*.whl
111+
112+
publish:
113+
needs: [build-sdist, build-wheels]
114+
runs-on: ubuntu-latest
115+
116+
steps:
117+
- uses: actions/checkout@v2
118+
with:
119+
fetch-depth: 5
120+
submodules: false
121+
122+
- uses: actions/download-artifact@v2
123+
with:
124+
name: dist
125+
path: dist/
126+
127+
- name: Extract Release Version
128+
id: relver
129+
run: |
130+
set -e
131+
echo ::set-output name=version::$(cat dist/VERSION)
132+
rm dist/VERSION
133+
134+
- name: Merge and tag the PR
135+
uses: edgedb/action-release/merge@master
136+
with:
137+
github_token: ${{ secrets.RELEASE_BOT_GITHUB_TOKEN }}
138+
ssh_key: ${{ secrets.RELEASE_BOT_SSH_KEY }}
139+
gpg_key: ${{ secrets.RELEASE_BOT_GPG_KEY }}
140+
gpg_key_id: "5C468778062D87BF!"
141+
tag_name: v${{ steps.relver.outputs.version }}
142+
143+
- name: Publish Github Release
144+
uses: elprans/gh-action-create-release@master
145+
env:
146+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
147+
with:
148+
tag_name: v${{ steps.relver.outputs.version }}
149+
release_name: v${{ steps.relver.outputs.version }}
150+
target: ${{ github.event.pull_request.base.ref }}
151+
body: ${{ github.event.pull_request.body }}
152+
153+
- run: |
154+
ls -al dist/
155+
156+
- name: Upload to PyPI
157+
uses: pypa/gh-action-pypi-publish@master
158+
with:
159+
user: __token__
160+
password: ${{ secrets.PYPI_TOKEN }}
161+
# password: ${{ secrets.TEST_PYPI_TOKEN }}
162+
# repository_url: https://test.pypi.org/legacy/

README.rst

Lines changed: 14 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,7 @@
1-
.. image:: https://travis-ci.org/sprymix/parsing.svg?branch=master
2-
:target: https://travis-ci.org/sprymix/parsing
3-
4-
51
Parsing
62
=======
73

8-
The Parsing module implements an LR(1) parser generator, as well as the
4+
The ``parsing`` module implements an LR(1) parser generator, as well as the
95
runtime support for using a generated parser, via the Lr and Glr parser
106
drivers. There is no special parser generator input file format, but the
117
parser generator still needs to know what classes/methods correspond to
@@ -27,18 +23,19 @@ exist in a true LR(1) parser. For more information on the algorithm, see::
2723
Acta Informatica 7, 249-268 (1977)
2824

2925
Parsing table generation requires non-trivial amounts of time for large
30-
grammars. Internal pickling support makes it possible to cache the most
31-
recent version of the parsing table on disk, and use the table if the
32-
current parser specification is still compatible with the one that was used
33-
to generate the pickled parsing table. Since the compatibility checking is
34-
quite fast, even for large grammars, this removes the need to use the
35-
standard code generation method that is used by most parser generators.
36-
37-
Parser specifications are encapsulated by the Spec class. Parser instances
38-
use Spec instances, but are themselves based on separate classes. This
39-
allows multiple parser instances to exist simultaneously, without requiring
40-
multiple copies of the parsing tables. There are two separate parser driver
41-
classes:
26+
grammars, however it is still quite fast. Internal pickling support makes
27+
it possible to cache the most recent version of the parsing table on disk,
28+
and use the table if the current parser specification is still compatible
29+
with the one that was used to generate the pickled parsing table. Since
30+
the compatibility checking is quite fast, even for large grammars, this
31+
removes the need to use the standard code generation method that is used
32+
by most parser generators.
33+
34+
Parser specifications are encapsulated by the ``Spec`` class. Parser
35+
instances use ``Spec`` instances, but are themselves based on separate
36+
classes. This allows multiple parser instances to exist simultaneously,
37+
without requiring multiple copies of the parsing tables. There are two
38+
separate parser driver classes:
4239

4340
Lr:
4441
Standard Characteristic Finite State Machine (CFSM) driver, based on

parsing/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,8 +135,10 @@
135135
"SpecSource",
136136
"UnexpectedToken",
137137
"Token",
138+
"__version__",
138139
)
139140

141+
from parsing._version import __version__
140142
from parsing.automaton import Spec
141143
from parsing.ast import Nonterm, Token, Precedence
142144
from parsing.errors import SpecError, UnexpectedToken

parsing/_version.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
# This file MUST NOT contain anything but the __version__ assignment.
2+
#
3+
# When making a release, change the value of __version__
4+
# to an appropriate value, and open a pull request against
5+
# the correct branch (master if making a new feature release).
6+
# The commit message MUST contain a properly formatted release
7+
# log, and the commit must be signed.
8+
#
9+
# The release automation will: build and test the packages for the
10+
# supported platforms, publish the packages on PyPI, merge the PR
11+
# to the target branch, create a Git tag pointing to the commit.
12+
13+
__version__ = "2.0.0.dev0"

setup.py

Lines changed: 20 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,29 @@
11
import os
2+
import pathlib
23
import sys
34

45
from setuptools import extension as setuptools_ext
56
from setuptools import setup
67
from setuptools.command import build_ext as setuptools_build_ext
78

89

9-
extra = {}
10+
_ROOT = pathlib.Path(__file__).parent
1011

11-
f = open("README.rst", "r")
12-
try:
13-
extra["long_description"] = f.read()
14-
extra["long_description_content_type"] = "text/x-rst"
15-
finally:
16-
f.close()
12+
13+
with open(str(_ROOT / "README.rst")) as f:
14+
readme = f.read()
15+
16+
17+
with open(str(_ROOT / "parsing" / "_version.py")) as f:
18+
for line in f:
19+
if line.startswith("__version__ ="):
20+
_, _, version = line.partition("=")
21+
VERSION = version.strip(" \n'\"")
22+
break
23+
else:
24+
raise RuntimeError(
25+
"unable to read the version from parsing/_version.py"
26+
)
1727

1828

1929
USE_MYPYC = False
@@ -79,14 +89,16 @@ def finalize_options(self) -> None:
7989

8090
setup(
8191
name="parsing",
82-
version="2.0.0.dev0",
92+
version=VERSION,
8393
python_requires=">=3.7.0",
8494
url="http://www.canonware.com/Parsing/",
8595
license="MIT",
8696
author="Jason Evans",
8797
author_email="[email protected]",
8898
description="A pure-Python module that implements an LR(1) "
8999
"parser generator, as well as CFSM and GLR parser drivers.",
100+
long_description=readme,
101+
long_description_content_type="text/x-rst",
90102
classifiers=[
91103
"Development Status :: 5 - Production/Stable",
92104
"Intended Audience :: Developers",
@@ -107,5 +119,4 @@ def finalize_options(self) -> None:
107119
]
108120
},
109121
cmdclass={"build_ext": build_ext},
110-
**extra,
111122
)

0 commit comments

Comments
 (0)