diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 20b6f41f1abae..3c89389f87903 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -1,13 +1,14 @@ name: Publishing Release on: - release: - # https://docs.github.com/en/free-pro-team@latest/actions/reference/events-that-trigger-workflows#release - types: [published] - # When triggered by schedule and workflow_dispatch, github.event.action is an empty string. - # We use this to distinguish which taichi to release. schedule: - cron: "0 0 * * *" workflow_dispatch: + # Manually trigger the release workflow, a version must be provided + inputs: + version: + description: "The version to release (e.g. v0.8.0)" + type: string + required: true env: PROD_PWD: ${{ secrets.PYPI_PWD_PROD }} @@ -15,26 +16,21 @@ env: METADATA_USERNAME: ${{ secrets.METADATA_USERNAME }} METADATA_PASSWORD: ${{ secrets.METADATA_PASSWORD }} METADATA_URL: ${{ secrets.METADATA_URL }} + RELEASE_VERSION: ${{ github.event.inputs.version }} jobs: add_version_to_database: name: Add version to database # Skip running release workflow on forks - if: github.repository_owner == 'taichi-dev' + if: github.repository_owner == 'taichi-dev' && github.event_name == 'workflow_dispatch' runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - - name: set tag - id: tag - run: echo ::set-output name=version::${GITHUB_REF#refs/*/} - - name: Save new version run: | python3 -m pip install requests==2.26 - [ -z "${{ github.event.action }}" ] || python3 misc/save_new_version.py - env: - RELEASE_VERSION: ${{ steps.tag.outputs.version }} + python3 misc/save_new_version.py # This job set environment matrix with respect to production release and nightly release. matrix_prep: @@ -46,20 +42,20 @@ jobs: steps: - id: set-matrix run: | - if [ -z "${{ github.event.action }}" ]; then + if [[ "$GITHUB_EVENT_NAME" == "workflow_dispatch" ]]; then + # For production release, we run on four python versions. + echo '::set-output name=matrix::{"include":[{"name":"taichi","python":"3.6","conda_python":"py36"},{"name":"taichi","python":"3.7","conda_python":"py37"},{"name":"taichi","python":"3.8","conda_python":"py38"},{"name":"taichi","python":"3.9","conda_python":"py39"}]}"' + + echo '::set-output name=matrix_osx::{"include":[{"name":"taichi","python":"3.8"},{"name":"taichi","python":"3.9"}]}"' + else # For nightly release, we only run on python 3.8 echo '::set-output name=matrix::{"include":[{"name":"taichi-nightly","python":"3.8","conda_python":"py38"},{"name":"taichi-nightly","python":"3.10","conda_python":"py310"}]}"' # M1 only supports py38 and py39(conda), so change matrix. echo '::set-output name=matrix_osx::{"include":[{"name":"taichi-nightly","python":"3.8"},{"name":"taichi-nightly","python":"3.10"}]}"' - else - # For production release, we run on four python versions. - echo '::set-output name=matrix::{"include":[{"name":"taichi","python":"3.6","conda_python":"py36"},{"name":"taichi","python":"3.7","conda_python":"py37"},{"name":"taichi","python":"3.8","conda_python":"py38"},{"name":"taichi","python":"3.9","conda_python":"py39"}]}"' - - echo '::set-output name=matrix_osx::{"include":[{"name":"taichi","python":"3.8"},{"name":"taichi","python":"3.9"}]}"' fi - build_and_upload_linux: + build_and_test_linux: name: Build and Upload (linux only) needs: matrix_prep strategy: @@ -85,11 +81,11 @@ jobs: docker create --user dev --name taichi_build --gpus all -v /tmp/.X11-unix:/tmp/.X11-unix \ -e DISPLAY -e PY -e GPU_BUILD -e TAICHI_CMAKE_ARGS -e PROJECT_NAME \ registry.taichigraphics.com/taichidev-ubuntu18.04:v0.2.1 \ - /home/dev/taichi/.github/workflows/scripts/unix_build.sh + /home/dev/${{ github.event.repository.name }}/.github/workflows/scripts/unix_build.sh tar -cf - ../${{ github.event.repository.name }} --mode u=+rwx,g=+rwx,o=+rwx --owner 1000 --group 1000 | docker cp - taichi_build:/home/dev/ docker start -a taichi_build - docker cp taichi_build:/home/dev/taichi/dist shared/dist - docker cp taichi_build:/home/dev/taichi/build shared/build + docker cp taichi_build:/home/dev/${{ github.event.repository.name }}/dist shared/dist + docker cp taichi_build:/home/dev/${{ github.event.repository.name }}/build shared/build env: PY: ${{ matrix.conda_python }} GPU_BUILD: ON @@ -98,9 +94,9 @@ jobs: DISPLAY: ":1" - name: Archive Wheel Artifacts - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v3 with: - name: ${{ matrix.name }}-py${{ matrix.python }}-linux.whl + name: dist path: shared/dist/*.whl retention-days: 20 @@ -120,20 +116,12 @@ jobs: GPU_TEST: ON DISPLAY: ":1" - - name: Upload PyPI - env: - PROJECT_NAME: ${{ matrix.name }} - run: | - cd shared - pip install twine requests==2.26 - python3 ../misc/upload_release.py - - name: clean docker container if: always() run: | docker rm taichi_build taichi_test -f - build_and_upload_mac: + build_and_test_mac: name: Build and Upload (macOS only) needs: matrix_prep strategy: @@ -174,9 +162,9 @@ jobs: CXX: clang++ - name: Archive Wheel Artifacts - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v3 with: - name: ${{ matrix.name }}-py${{ matrix.python }}-macos.whl + name: dist path: dist/*.whl retention-days: 20 @@ -185,13 +173,7 @@ jobs: env: TI_WANTED_ARCHS: "cpu" - - name: Upload PyPI - env: - # https://docs.github.com/en/free-pro-team@latest/actions/reference/encrypted-secrets#using-encrypted-secrets-in-a-workflow - PROJECT_NAME: ${{ matrix.name }} - run: python misc/upload_release.py - - build_and_upload_m1: + build_and_test_m1: name: Build and Upload (Apple M1) needs: matrix_prep strategy: @@ -230,9 +212,9 @@ jobs: CXX: clang++ - name: Archive Wheel Artifacts - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v3 with: - name: ${{ matrix.name }}-py${{ matrix.python }}-macos-m1.whl + name: dist path: dist/*.whl retention-days: 20 @@ -245,15 +227,7 @@ jobs: PYTHON: ${{ matrix.python }} GPU_TEST: ON - - name: Upload PyPI - env: - PROJECT_NAME: ${{ matrix.name }} - PYTHON: ${{ matrix.python }} - run: | - export PATH=/Users/github/miniforge3/envs/$PYTHON/bin:$PATH - python misc/upload_release.py - - build_and_upload_macos_1014: + build_and_test_macos_1014: name: Build and Upload (macos 1014) needs: matrix_prep strategy: @@ -289,9 +263,9 @@ jobs: CXX: clang++ - name: Archive Wheel Artifacts - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v3 with: - name: ${{ matrix.name }}-py${{ matrix.python }}-macos-1014.whl + name: dist path: dist/*.whl retention-days: 20 @@ -303,15 +277,7 @@ jobs: TI_WANTED_ARCHS: "cpu" PYTHON: ${{ matrix.python }} - - name: Upload PyPI - env: - PROJECT_NAME: ${{ matrix.name }} - PYTHON: ${{ matrix.python }} - run: | - export PATH=/Users/buildbot6/miniconda3/envs/$PYTHON/bin:$PATH - python misc/upload_release.py - - build_and_upload_windows: + build_and_test_windows: name: Build and Upload (Windows only) needs: matrix_prep strategy: @@ -351,7 +317,7 @@ jobs: - name: Archive Wheel Artifacts uses: actions/upload-artifact@v2 with: - name: ${{ matrix.name }}-py${{ matrix.python }}-windows.whl + name: dist path: dist/*.whl retention-days: 20 @@ -367,10 +333,90 @@ jobs: env: TI_SKIP_VERSION_CHECK: ON - - name: Upload PyPI - shell: powershell - env: - PROJECT_NAME: ${{ matrix.name }} + upload_to_pypi: + name: Upload release to PyPI + needs: + [ + build_and_test_linux, + build_and_test_mac, + build_and_test_m1, + build_and_test_macos_1014, + build_and_test_windows, + ] + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - uses: actions/setup-python@v2 + with: + python-version: 3.9 + + - name: Get dist files + uses: actions/download-artifact@v3 + with: + name: dist + path: dist + + - name: Upload to PyPI + run: | + ls -l dist/ + if [ -z "$RELEASE_VERSION" ]; then + export PROJECT_NAME="taichi-nightly" + else + export PROJECT_NAME="taichi" + fi + python -m pip install requests twine + python misc/upload_release.py + + create_release: + name: Create tag and publish release + needs: upload_to_pypi + runs-on: ubuntu-latest + if: github.event_name == 'workflow_dispatch' + steps: + - uses: actions/checkout@v2 + - uses: actions/setup-python@v2 + with: + python-version: 3.9 + + - name: Generate Changelog + id: changelog + run: | + pip3 install gitpython + content=$(python3 misc/make_changelog.py) + echo $content + # Escape multiline strings: + # https://renehernandez.io/snippets/multiline-strings-as-a-job-output-in-github-actions/ + content="${content//'%'/'%25'}" + content="${content//$'\n'/'%0A'}" + content="${content//$'\r'/'%0D'}" + echo "::set-output name=content::$content" + + - name: Create tag + run: | + git config user.email "taichigardener@gmail.com" + git config user.name "Taichi Gardener" + git tag -a ${RELEASE_VERSION} -m "Release ${RELEASE_VERSION}" + git push origin --tags + + - name: Publish release + uses: softprops/action-gh-release@v1 + with: + body: ${{ steps.changelog.outputs.content }} + tag_name: ${{ github.event.inputs.version }} + + - name: Bump version run: | - python -m pip install twine - venv\Scripts\python misc/upload_release.py + version_parts=(${RELEASE_VERSION//./ }) + version_parts[2]=$(expr ${version_parts[2]} + 1) + next_version=$(IFS=.; echo "${version_parts[*]}") + # Update version.txt + git checkout -b "bump/$next_version" + echo "$next_version" > version.txt + git add version.txt + # Commit and push changes + git commit -m "Bump version to $next_version" + git push origin "bump/$next_version" + # Create pull request + gh pr create -B master -t "[misc] Bump version to $next_version" + env: + GITHUB_TOKEN: ${{ secrets.GARDENER_PAT }} diff --git a/MANIFEST.in b/MANIFEST.in index 71547ce2ee2f9..cbc8a16b7dc89 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -1,4 +1,5 @@ include MANIFEST.in +include version.txt include python/*.txt include python/*.py include *.cfg diff --git a/misc/upload_release.py b/misc/upload_release.py index c14828891aed9..d240c7b4bc201 100644 --- a/misc/upload_release.py +++ b/misc/upload_release.py @@ -9,28 +9,33 @@ def upload_taichi_version(): username = os.getenv('METADATA_USERNAME') password = os.getenv('METADATA_PASSWORD') url = os.getenv('METADATA_URL') - filename = os.listdir('./dist')[0] - filename = filename[:len(filename) - 4] - parts = filename.split('-') - payload = {'version': parts[1], 'platform': parts[4], 'python': parts[2]} - try: - response = requests.post(f'https://{url}/add_version/detail', - json=payload, - auth=(username, password), - timeout=5) - response.raise_for_status() - except requests.exceptions.ConnectionError as err: - sys.exit('Updating latest version failed: No internet, ' + str(err)) - except requests.exceptions.HTTPError as err: - sys.exit('Updating latest version failed: Server error, ' + str(err)) - except requests.exceptions.Timeout as err: - sys.exit( - 'Updating latest version failed: Time out when connecting server, ' - + str(err)) - except requests.exceptions.RequestException as err: - sys.exit('Updating latest version failed: ' + str(err)) - response = response.json() - print(response['message']) + for filename in os.listdir('./dist'): + filename = filename[:len(filename) - 4] + parts = filename.split('-') + payload = { + 'version': parts[1], + 'platform': parts[4], + 'python': parts[2] + } + try: + response = requests.post(f'https://{url}/add_version/detail', + json=payload, + auth=(username, password), + timeout=5) + response.raise_for_status() + except requests.exceptions.ConnectionError as err: + print('Updating latest version failed: No internet,', err) + except requests.exceptions.HTTPError as err: + print('Updating latest version failed: Server error,', err) + except requests.exceptions.Timeout as err: + print( + 'Updating latest version failed: Time out when connecting server,', + err) + except requests.exceptions.RequestException as err: + print('Updating latest version failed:', err) + else: + response = response.json() + print(response['message']) def upload_artifact(is_taichi): @@ -38,7 +43,7 @@ def upload_artifact(is_taichi): twine_password = os.getenv(pwd_env) if not twine_password: sys.exit(f'Missing password env var {pwd_env}') - command = ["python3", "-m", "twine", "upload"] + command = [sys.executable, '-m', 'twine', 'upload'] if not is_taichi: command.extend(['--repository', 'testpypi']) command.extend( @@ -50,6 +55,10 @@ def upload_artifact(is_taichi): if __name__ == '__main__': + if os.getenv('GITHUB_REPOSITORY', + 'taichi-dev/taichi') != 'taichi-dev/taichi': + print('This script should be run from taichi repo') + sys.exit(0) is_taichi = os.getenv('PROJECT_NAME', 'taichi') == 'taichi' upload_artifact(is_taichi) if is_taichi: diff --git a/python/make_release.py b/python/make_release.py deleted file mode 100644 index 0f61f316e98f2..0000000000000 --- a/python/make_release.py +++ /dev/null @@ -1,39 +0,0 @@ -import os -import shutil -import zipfile - -import requests - -projects = ['nightly', 'nightly-cuda-10-0', 'nightly-cuda-10-1'] - - -def download(url): - fn = url.split('/')[-1] - with requests.get(url, stream=True) as r: - with open(fn, 'wb') as f: - shutil.copyfileobj(r.raw, f) - return fn - - -for p in projects: - pkg_name_dash = f'taichi-{p}' - pkg_name_underscore = pkg_name_dash.replace('-', '_') - package = requests.get( - f"https://pypi.python.org/pypi/{pkg_name_dash}/json").json() - version = '0.0.75' - wheels = package["releases"][version] - for wheel in wheels: - py_ver = wheel['python_version'] - print(py_ver, wheel['url']) - fn = download(wheel['url']) - folder = wheel['python_version'] + '-' + fn[:-4] - package_extracted_folder = f"release/{folder}" - with zipfile.ZipFile(fn, 'r') as zip_ref: - zip_ref.extractall(package_extracted_folder) - os.remove(fn) - - pkg_ver = f"{pkg_name_underscore}-{version}" - shutil.make_archive( - f'release/{folder}', 'zip', - f'release/{folder}/{pkg_ver}.data/purelib/taichi/lib') - shutil.rmtree(package_extracted_folder) diff --git a/setup.py b/setup.py index 557129fb1f528..355e09679ef74 100644 --- a/setup.py +++ b/setup.py @@ -35,11 +35,20 @@ 'Programming Language :: Python :: 3.10', ] + +def get_version(): + if os.getenv("RELEASE_VERSION"): + version = os.environ["RELEASE_VERSION"] + else: + version_file = os.path.join(os.path.dirname(__file__), 'version.txt') + with open(version_file, 'r') as f: + version = f.read().strip() + return version.lstrip("v") + + project_name = os.getenv('PROJECT_NAME', 'taichi') -TI_VERSION_MAJOR = 0 -TI_VERSION_MINOR = 9 -TI_VERSION_PATCH = 2 -version = f'{TI_VERSION_MAJOR}.{TI_VERSION_MINOR}.{TI_VERSION_PATCH}' +version = get_version() +TI_VERSION_MAJOR, TI_VERSION_MINOR, TI_VERSION_PATCH = version.split('.') data_files = glob.glob('python/_lib/runtime/*') print(data_files) diff --git a/version.txt b/version.txt new file mode 100644 index 0000000000000..e6e6db4c47c64 --- /dev/null +++ b/version.txt @@ -0,0 +1 @@ +v0.9.2