1+ # .github/workflows/cd.yml
12name : TreeMapper CD
23
34permissions :
4- contents : write
5+ contents : write # Нужно для создания релиза и коммита/тега/merge
56
67on :
78 workflow_dispatch :
89 inputs :
910 version :
10- description : ' Version to release'
11+ description : ' Version to release (e.g., 1.0.0) '
1112 required : true
1213 publish_to_pypi :
1314 description : ' Publish to PyPI'
@@ -19,191 +20,193 @@ on:
1920 - ' false'
2021
2122jobs :
22- create-release :
23- name : Create GitHub Release
23+ # --- 1. Подготовка: Установка версии и создание тега/релиза ---
24+ prepare-release :
25+ name : Prepare and Create GitHub Release
2426 runs-on : ubuntu-latest
27+ outputs :
28+ version : ${{ steps.set_outputs.outputs.version }}
29+ tag_name : ${{ steps.set_outputs.outputs.tag_name }}
30+ upload_url : ${{ steps.create_release.outputs.upload_url }}
31+ release_id : ${{ steps.create_release.outputs.id }}
2532 steps :
2633 - name : Checkout Code
27- uses : actions/checkout@v3
34+ uses : actions/checkout@v4 # Используем v4
2835
2936 - name : Set up Python
30- uses : actions/setup-python@v4
37+ uses : actions/setup-python@v5 # Используем v5
3138 with :
3239 python-version : ' 3.11'
3340
34- - name : Install Dependencies
41+ - name : Set version in version.py
3542 run : |
36- python -m pip install --upgrade pip
37- pip install -r requirements.txt
38- pip install -e .
39-
40- - name : Set version (Unix)
41- if : matrix.os != 'windows-latest'
43+ VERSION="${{ github.event.inputs.version }}"
44+ echo "Setting version to $VERSION"
45+ sed -i -E "s/__version__ = \".*\"/__version__ = \"$VERSION\"/" src/treemapper/version.py
46+ echo "version.py content after change:"
47+ cat src/treemapper/version.py
48+
49+ # --- Коммит, тег И PUSH ИХ ВМЕСТЕ ---
50+ - name : Commit, Tag, and Push version bump
4251 run : |
43- python -c "import re; content = open('src/treemapper/version.py', 'r').read(); open('src/treemapper/version.py', 'w').write(re.sub('__version__ = \".*\"', '__version__ = \"${{ github.event.inputs.version }}\"', content))"
44-
45- - name : Set version (Windows)
46- if : matrix.os == 'windows-latest'
47- shell : pwsh
48- run : |
49- $content = Get-Content src/treemapper/version.py -Raw
50- $newContent = $content -replace '__version__ = ".*"', '__version__ = " ${{ github.event.inputs.version }}"'
51- Set-Content src/treemapper/version.py -Value $newContent
52-
53- - name : Create Release
52+ git config user.name github-actions[bot] # Используем стандартного бота
53+ git config user.email 41898282+github-actions[bot]@users.noreply.github.com
54+ git add src/treemapper/version.py
55+ # Коммитим только если есть изменения
56+ git diff --staged --quiet || git commit -m "Release version ${{ github.event.inputs.version }}"
57+ git tag v${{ github.event.inputs.version }}
58+ # ---> ИЗМЕНЕНИЕ: Отправляем и коммит (HEAD текущей ветки) и тег вместе <---
59+ git push origin HEAD v ${{ github.event.inputs.version }}
60+
61+ # --- Создание релиза GitHub ---
62+ - name : Create GitHub Release
5463 id : create_release
5564 uses : actions/create-release@v1
5665 env :
5766 GITHUB_TOKEN : ${{ secrets.GITHUB_TOKEN }}
5867 with :
5968 tag_name : v${{ github.event.inputs.version }}
6069 release_name : Release ${{ github.event.inputs.version }}
70+ # Commitish теперь не обязателен, т.к. tag_name уже должен существовать удаленно
71+ # Но можно оставить для ясности, т.к. тег уже запушен
72+ commitish : v${{ github.event.inputs.version }}
6173 draft : false
6274 prerelease : false
6375
64- outputs :
65- upload_url : ${{ steps.create_release.outputs.upload_url }}
66- version : ${{ github.event.inputs.version }}
67- release_id : ${{ steps.create_release.outputs.id }}
76+ - name : Set outputs for subsequent jobs
77+ id : set_outputs
78+ run : |
79+ echo "version=${{ github.event.inputs.version }}" >> $GITHUB_OUTPUT
80+ echo "tag_name=v${{ github.event.inputs.version }}" >> $GITHUB_OUTPUT
6881
82+ # --- 2. Сборка и загрузка ассетов для разных ОС ---
6983 build-and-upload :
7084 name : Build and Upload Assets
71- needs : create-release
72- runs-on : ${{ matrix.os }}
85+ needs : prepare-release
7386 strategy :
87+ fail-fast : false
7488 matrix :
7589 include :
76- - os : ubuntu-20.04
90+ - os : ubuntu-latest
7791 asset_name : linux
92+ python-version : ' 3.11'
7893 - os : macos-latest
7994 asset_name : macos
95+ python-version : ' 3.11'
8096 - os : windows-latest
8197 asset_name : windows
98+ python-version : ' 3.11'
99+ runs-on : ${{ matrix.os }}
82100 steps :
83- - name : Checkout Code
84- uses : actions/checkout@v3
101+ - name : Checkout Code at release tag
102+ uses : actions/checkout@v4
103+ with :
104+ ref : ${{ needs.prepare-release.outputs.tag_name }}
85105
86106 - name : Set up Python
87- uses : actions/setup-python@v4
107+ uses : actions/setup-python@v5
88108 with :
89- python-version : ' 3.11 '
109+ python-version : ${{ matrix.python-version }}
90110
91111 - name : Cache pip Dependencies
92- uses : actions/cache@v3
112+ uses : actions/cache@v4
113+ id : cache-pip
93114 with :
94115 path : ~/.cache/pip
95- key : ${{ runner.os }}-pip-${{ hashFiles('**/setup.cfg') }}
116+ key : ${{ runner.os }}-pip-${{ matrix.python-version }}-${{ hashFiles('**/setup.cfg') }}
96117 restore-keys : |
118+ ${{ runner.os }}-pip-${{ matrix.python-version }}-
97119 ${{ runner.os }}-pip-
98120
99- - name : Install Dependencies
121+ - name : Install Dependencies (including PyInstaller)
100122 run : |
101123 python -m pip install --upgrade pip
102- pip install -r requirements.txt
103- pip install -e .
104-
105- - name : Set version (Unix)
106- if : matrix.os != 'windows-latest'
107- run : |
108- python -c "import re; content = open('src/treemapper/version.py', 'r').read(); open('src/treemapper/version.py', 'w').write(re.sub('__version__ = \".*\"', '__version__ = \"${{ github.event.inputs.version }}\"', content))"
109-
110- - name : Set version (Windows)
111- if : matrix.os == 'windows-latest'
112- shell : pwsh
113- run : |
114- $content = Get-Content src/treemapper/version.py -Raw
115- $newContent = $content -replace '__version__ = ".*"', '__version__ = "${{ github.event.inputs.version }}"'
116- Set-Content src/treemapper/version.py -Value $newContent
124+ pip install .[dev]
117125
118126 - name : Build with PyInstaller
119127 run : |
120- python -m PyInstaller --clean -y --dist ./dist/${{ matrix.asset_name }} --workpath /tmp treemapper.spec
128+ python -m PyInstaller --clean -y --dist ./dist/${{ matrix.asset_name }} treemapper.spec
121129
122130 - name : Determine architecture
123131 id : arch
124132 shell : bash
125133 run : |
126- if [ "${{ matrix.os }}" = "macos-latest" ]; then
127- echo "ARCH=$(uname -m)" >> $GITHUB_OUTPUT
128- elif [ "${{ matrix.os }}" = "ubuntu-20.04" ]; then
129- echo "ARCH=$(uname -m)" >> $GITHUB_OUTPUT
130- else
131- echo "ARCH=x86_64" >> $GITHUB_OUTPUT
134+ ARCH=$(uname -m)
135+ if [[ "${{ runner.os }}" == "Windows" ]]; then
136+ if [[ "${{ runner.arch }}" == "X64" ]]; then ARCH="x86_64"; \
137+ elif [[ "${{ runner.arch }}" == "ARM64" ]]; then ARCH="arm64"; \
138+ else ARCH="unknown"; fi
139+ elif [[ "${{ runner.os }}" == "macOS" ]] && [[ "$ARCH" == "arm64" ]]; then
140+ echo "Detected ARM on macOS"
132141 fi
142+ echo "Determined ARCH: $ARCH"
143+ echo "arch=$ARCH" >> $GITHUB_OUTPUT
144+
133145
134146 - name : Upload Release Asset
135147 uses : actions/upload-release-asset@v1
136148 env :
137149 GITHUB_TOKEN : ${{ secrets.GITHUB_TOKEN }}
138150 with :
139- upload_url : ${{ needs.create-release.outputs.upload_url }}
140- asset_path : ./dist/${{ matrix.asset_name }}/treemapper${{ matrix.os == 'windows-latest' && '.exe' || '' }}
141- asset_name : treemapper-${{ matrix.asset_name }}-${{ steps.arch.outputs.ARCH }}-v${{ needs.create-release.outputs.version }}${{ matrix.os == 'windows-latest' && '.exe' || '' }}
151+ upload_url : ${{ needs.prepare-release.outputs.upload_url }}
152+ # Путь к ассету (PyInstaller создает папку с именем скрипта внутри dist)
153+ asset_path : ./dist/${{ matrix.asset_name }}/treemapper/${{ matrix.os == 'windows-latest' && 'treemapper.exe' || 'treemapper' }}
154+ asset_name : treemapper-${{ matrix.asset_name }}-${{ steps.arch.outputs.arch }}-v${{ needs.prepare-release.outputs.version }}${{ matrix.os == 'windows-latest' && '.exe' || '' }}
142155 asset_content_type : application/octet-stream
143156
157+ # --- 3. Публикация на PyPI (опционально) ---
144158 publish-to-pypi :
145159 name : Publish to PyPI
146- needs : [ create -release, build-and-upload ]
160+ needs : [prepare -release, build-and-upload]
147161 if : github.event.inputs.publish_to_pypi == 'true'
148162 runs-on : ubuntu-latest
163+ environment :
164+ name : pypi
165+ url : https://pypi.org/p/treemapper
166+ permissions :
167+ id-token : write
149168 steps :
150- - name : Checkout Code
151- uses : actions/checkout@v3
169+ - name : Checkout Code at release tag
170+ uses : actions/checkout@v4
171+ with :
172+ ref : ${{ needs.prepare-release.outputs.tag_name }}
152173
153174 - name : Set up Python
154- uses : actions/setup-python@v4
175+ uses : actions/setup-python@v5
155176 with :
156177 python-version : ' 3.11'
157178
158- - name : Cache pip Dependencies
159- uses : actions/cache@v3
160- with :
161- path : ~/.cache/pip
162- key : ${{ runner.os }}-pip-${{ hashFiles('**/setup.cfg') }}
163- restore-keys : |
164- ${{ runner.os }}-pip-
165-
166- - name : Install Dependencies
179+ - name : Install build tools
167180 run : |
168181 python -m pip install --upgrade pip
169- pip install -r requirements.txt
170-
171- - name : Set version (Unix)
172- if : matrix.os != 'windows-latest'
173- run : |
174- python -c "import re; content = open('src/treemapper/version.py', 'r').read(); open('src/treemapper/version.py', 'w').write(re.sub('__version__ = \".*\"', '__version__ = \"${{ github.event.inputs.version }}\"', content))"
182+ pip install build
175183
176- - name : Set version (Windows)
177- if : matrix.os == 'windows-latest'
178- shell : pwsh
179- run : |
180- $content = Get-Content src/treemapper/version.py -Raw
181- $newContent = $content -replace '__version__ = ".*"', '__version__ = "${{ github.event.inputs.version }}"'
182- Set-Content src/treemapper/version.py -Value $newContent
184+ - name : Build sdist and wheel
185+ run : python -m build
183186
184- - name : Build and Publish to PyPI
185- env :
186- TWINE_USERNAME : __token__
187- TWINE_PASSWORD : ${{ secrets.PYPI_TOKEN }}
188- run : |
189- python -m build
190- python -m twine upload dist/* --verbose
187+ - name : Publish package distributions to PyPI
188+ uses : pypa/gh-action-pypi-publish@release/v1
191189
192190
191+ # --- 4. Обновление ветки main (опционально) ---
193192 update-main-branch :
194- name : Update main branch
195- needs : [ publish-to-pypi ]
193+ name : Update main branch (Merge Tag)
194+ # Запускается ПОСЛЕ успешной сборки ассетов
195+ needs : [prepare-release, build-and-upload]
196196 runs-on : ubuntu-latest
197+ # if: always() # Раскомментируйте, если нужно мержить даже при падении build-and-upload
197198 steps :
198199 - name : Checkout main branch
199- uses : actions/checkout@v3
200+ uses : actions/checkout@v4
200201 with :
201202 ref : main
202- fetch-depth : 0
203+ fetch-depth : 0 # Нужна полная история для merge
203204
204205 - name : Merge tag into main
205206 run : |
206- git config user.name github-actions
207- git config user.email github-actions@github.com
208- git merge ${{ github.ref }} --no-ff -m "Merge tag ${{ github.ref_name }} into main"
209- git push origin main
207+ git config user.name github-actions[bot]
208+ git config user.email 41898282+github-actions[bot]@users.noreply.github.com
209+ echo "Attempting to merge tag ${{ needs.prepare-release.outputs.tag_name }} into main"
210+ # Используем --no-ff для явного коммита слияния
211+ git merge ${{ needs.prepare-release.outputs.tag_name }} --no-ff -m "Merge tag ${{ needs.prepare-release.outputs.tag_name }} into main"
212+ git push origin main
0 commit comments