Skip to content

Commit 28b7024

Browse files
Add option for conda and pip internal uploads (#62)
1 parent 8853637 commit 28b7024

File tree

6 files changed

+145
-23
lines changed

6 files changed

+145
-23
lines changed

.github/workflows/conda-build.yml

+9
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,10 @@ on:
2121
description: "GitHub environment in which secrets are stored"
2222
type: string
2323
default: "release"
24+
destination:
25+
description: "Upload packaging index destination. Must be one of [anaconda, internal]."
26+
type: string
27+
default: anaconda
2428
secrets:
2529
ANACONDA_TOKEN:
2630
required: true
@@ -49,6 +53,7 @@ jobs:
4953
token-exists:
5054
runs-on: ubuntu-latest
5155
environment: ${{ inputs.environment }}
56+
if: inputs.destination == 'anaconda'
5257
steps:
5358
- name: check if ANACONDA_TOKEN exists
5459
env:
@@ -83,6 +88,10 @@ jobs:
8388
- name: Add conda channel
8489
run: conda config --add channels city-modelling-lab
8590

91+
- name: Add internal conda channel
92+
if: inputs.destination == 'internal'
93+
run: conda config --add channels https://packages.arup.com/conda
94+
8695
- name: Build conda package
8796
run: conda mambabuild ${{ inputs.recipe_dir }}
8897

.github/workflows/conda-upload.yml

+51-3
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,10 @@ on:
1919
description: "GitHub environment in which secrets are stored"
2020
type: string
2121
default: "release"
22+
destination:
23+
description: "Upload packaging index destination. Must be one of [anaconda, internal]."
24+
type: string
25+
default: anaconda
2226
secrets:
2327
ANACONDA_TOKEN:
2428
required: true
@@ -28,11 +32,12 @@ defaults:
2832
shell: bash -l {0}
2933

3034
jobs:
31-
conda-publish:
35+
conda-anaconda-publish:
36+
if: inputs.destination == 'anaconda'
3237
runs-on: ubuntu-latest
3338
environment: ${{ inputs.environment }}
3439
env:
35-
PACKAGENAME: "conda-build[a-zA-Z0-9-.]*-${{ inputs.package_name }}-${{ inputs.version }}"
40+
ARTIFACTNAME: "conda-build[a-zA-Z0-9-.]*-${{ inputs.package_name }}-${{ inputs.version }}"
3641
steps:
3742
- uses: actions/checkout@v4
3843
- uses: mamba-org/setup-micromamba@v2
@@ -49,7 +54,7 @@ jobs:
4954
if: inputs.build_workflow != ''
5055
uses: dawidd6/action-download-artifact@v7
5156
with:
52-
name: ${{ env.PACKAGENAME }}
57+
name: ${{ env.ARTIFACTNAME }}
5358
name_is_regexp: true
5459
workflow: ${{ inputs.build_workflow }}
5560
path: ${{ runner.temp }}/conda_builds
@@ -58,6 +63,7 @@ jobs:
5863
if: inputs.build_workflow == ''
5964
uses: actions/download-artifact@v4
6065
with:
66+
pattern: ${{ env.ARTIFACTNAME }}
6167
path: ${{ runner.temp }}/conda_builds
6268

6369
- name: Get version without the v
@@ -69,3 +75,45 @@ jobs:
6975
env:
7076
ANACONDA_API_TOKEN: ${{ secrets.ANACONDA_TOKEN }}
7177
run: find ${{ runner.temp }}/conda_builds -path "**/${{ inputs.package_name }}-${{ env.VERSION }}-*.tar.bz2" -exec anaconda upload {} +
78+
79+
conda-internal-publish:
80+
if: inputs.destination == 'internal'
81+
runs-on: [self-hosted, linux, packages]
82+
env:
83+
ARTIFACTNAME: "conda-build[a-zA-Z0-9-.]*-${{ inputs.package_name }}-${{ inputs.version }}"
84+
PACKAGENAME: "conda-build-*-${{ inputs.package_name }}-${{ inputs.version }}"
85+
steps:
86+
- uses: mamba-org/setup-micromamba@v2
87+
with:
88+
micromamba-version: '1.5.10-0'
89+
environment-name: condaindex
90+
create-args: conda-index
91+
post-cleanup: all
92+
cache-environment: true
93+
micromamba-binary-path: ${{ runner.temp }}/bin/micromamba
94+
95+
- name: Download built conda package from another workflow
96+
uses: dawidd6/action-download-artifact@v7
97+
with:
98+
name: ${{ env.ARTIFACTNAME }}
99+
name_is_regexp: true
100+
workflow: ${{ inputs.build_workflow }}
101+
path: ${{ runner.temp }}/conda_builds
102+
103+
- name: Get version without the v
104+
run: |
105+
TAG=${{ inputs.version }}
106+
echo "VERSION=${TAG#v}" >> $GITHUB_ENV
107+
108+
# Move to a location that can be accessed at packages.arup.com
109+
- name: Move package to download location
110+
shell: bash
111+
run: |
112+
touch ${{ runner.temp }}/.condarc
113+
rsync -a -v --prune-empty-dirs --include '*/' --include '${{ inputs.package_name }}-${{ env.VERSION }}-*.tar.bz2' --exclude '*' ${{ runner.temp }}/conda_builds/${{ env.PACKAGENAME }}/ ~/packages/conda/
114+
115+
- name: Re-index conda
116+
env:
117+
CONDARC: ${{ runner.temp }}/.condarc
118+
shell: bash -l {0}
119+
run: python -m conda_index ~/packages/conda

.github/workflows/pip-build.yml

+6-2
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,10 @@ on:
2121
required: false
2222
type: string
2323
default: "--no-deps"
24+
destination:
25+
description: "Upload packaging index destination. Must be one of [pypi, internal]."
26+
type: string
27+
default: pypi
2428

2529
secrets:
2630
TEST_PYPI_API_TOKEN:
@@ -42,7 +46,7 @@ jobs:
4246
# cannot use secrets directly in conditionals
4347
# see https://docs.github.com/en/actions/security-guides/using-secrets-in-github-actions#using-secrets-in-a-workflow
4448
test_pypi_token: ${{ secrets.TEST_PYPI_API_TOKEN }}
45-
if: env.test_pypi_token == ''
49+
if: inputs.destination == 'pypi' && env.test_pypi_token == ''
4650
run: |
4751
echo "the secret \"TEST_PYPI_API_TOKEN\" is not available, so the pypi package cannot be uploaded to the test index site."
4852
echo "Please go to \"settings \> secrets \> actions\" to create it before trying to build the pip package."
@@ -98,7 +102,7 @@ jobs:
98102
pip-test-upload: # upload to test-pypi and then check install from there succeeds
99103
needs: [pip-build, pip-test-build]
100104
environment: ${{ inputs.environment }}
101-
if: needs.pip-build.result == 'success' && needs.pip-test-build.result == 'success'
105+
if: needs.pip-build.result == 'success' && needs.pip-test-build.result == 'success' && inputs.destination == 'pypi'
102106
runs-on: ubuntu-latest
103107
steps:
104108
- uses: mamba-org/setup-micromamba@v2

.github/workflows/pip-upload.yml

+39-5
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,10 @@ on:
1919
description: "GitHub environment in which secrets are stored"
2020
type: string
2121
default: "pre-release"
22+
destination:
23+
description: "Upload packaging index destination. Must be one of [pypi, internal]."
24+
type: string
25+
default: pypi
2226
secrets:
2327
PYPI_API_TOKEN:
2428
required: true
@@ -28,11 +32,12 @@ defaults:
2832
shell: bash -l {0}
2933

3034
jobs:
31-
pip-publish:
35+
pip-pypi-publish:
3236
runs-on: ubuntu-latest
37+
if: inputs.destination == 'pypi'
3338
environment: ${{ inputs.environment }}
3439
env:
35-
PACKAGENAME: "pip-build-${{ inputs.package_name }}-${{ inputs.version }}"
40+
ARTIFACTNAME: "pip-build-${{ inputs.package_name }}-${{ inputs.version }}"
3641

3742
steps:
3843
- name: check if PYPI_API_TOKEN exists
@@ -50,18 +55,47 @@ jobs:
5055
if: inputs.build_workflow != ''
5156
uses: dawidd6/action-download-artifact@v7
5257
with:
53-
name: ${{ env.PACKAGENAME }}
58+
name: ${{ env.ARTIFACTNAME }}
5459
workflow: ${{ inputs.build_workflow }}
5560
path: dist/
5661

5762
- name: Download built package from same workflow
5863
if: inputs.build_workflow == ''
5964
uses: actions/download-artifact@v4
6065
with:
61-
name: ${{ env.PACKAGENAME }}
66+
name: ${{ env.ARTIFACTNAME }}
6267
path: dist/
6368

6469
- name: Publish distribution 📦 to PyPI
6570
uses: pypa/gh-action-pypi-publish@release/v1
6671
with:
67-
password: ${{ secrets.PYPI_API_TOKEN }}
72+
password: ${{ secrets.PYPI_API_TOKEN }}
73+
74+
75+
pip-internal-publish:
76+
if: inputs.destination == 'internal'
77+
runs-on: [self-hosted, linux, packages]
78+
environment: ${{ inputs.environment }}
79+
env:
80+
ARTIFACTNAME: "pip-build-${{ inputs.package_name }}-${{ inputs.version }}"
81+
82+
steps:
83+
- name: Download built package from another workflow
84+
if: inputs.build_workflow != ''
85+
uses: dawidd6/action-download-artifact@v7
86+
with:
87+
name: ${{ env.ARTIFACTNAME }}
88+
workflow: ${{ inputs.build_workflow }}
89+
path: ${{ runner.temp }}/${{ env.ARTIFACTNAME }}/
90+
91+
- name: Download built package from same workflow
92+
if: inputs.build_workflow == ''
93+
uses: actions/download-artifact@v4
94+
with:
95+
name: ${{ env.ARTIFACTNAME }}
96+
path: ${{ runner.temp }}/${{ env.ARTIFACTNAME }}/
97+
98+
- name: Publish distribution 📦 to internal repository
99+
run: |
100+
cp ${{ runner.temp }}/${{ env.ARTIFACTNAME }}/${{ inputs.package_name }}-*.tar.gz ~/packages/
101+
cp ${{ runner.temp }}/${{ env.ARTIFACTNAME }}/${{ inputs.package_name }}-*.tar.gz ~/packages/${{ inputs.package_name }}.tar.gz

CHANGELOG.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -33,10 +33,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
3333

3434
### Added
3535

36+
- Ability to upload pip / conda packages to <https://packages.arup.com> for internal Arup projects.
3637
- Composite action for building a project-specific conda environment, used across reusable workflows but also available for direct use as a step in other projects (#26).
3738
- Environment cache directory within the runner working directory (`.cache/envs`) (#29).
3839

39-
4040
## [v1.0.0] - 2024-07-12
4141

4242
### Fixed

README.md

+39-12
Original file line numberDiff line numberDiff line change
@@ -108,15 +108,14 @@ jobs:
108108
message: "AWS upload action"
109109
```
110110
111-
!!! note
112-
113-
You can _only_ use `secrets: inherit` if you are hosting your repository in the `arup-group` organisation.
114-
If you have the repo under your own username, you will need to explicitly pass the necessary secrets, e.g.:
115-
116-
``` yaml
117-
secrets:
118-
SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK }}
119-
```
111+
> [!NOTE]
112+
> You can _only_ use `secrets: inherit` if you are hosting your repository in the `arup-group` organisation.
113+
> If you have the repo under your own username, you will need to explicitly pass the necessary secrets, e.g.:
114+
>
115+
> ``` yaml
116+
> secrets:
117+
> SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK }}
118+
> ```
120119

121120
## Available workflows
122121

@@ -146,8 +145,15 @@ _Inputs_:
146145
- environment (optional, default="pre-release"): GitHub environment in which secrets are stored.
147146
Environments help to ensure that only certain operations are available to different user types.
148147
E.g., releasing packages can be given an extra layer of security whereby a maintainer has to approve an action before it can run.
148+
- destination (optional, default="anaconda"): One of "anaconda" or "internal", to specify what the ultimate destination of the package will be.
149+
If `internal`, the package will be uploaded to <https://packages.arup.com/conda>.
150+
If `anaconda`, the package will be uploaded to <https://anaconda.org/[CHANNEL-NAME]/> where `[CHANNEL-NAME]` is linked to the `ANACONDA_TOKEN` secret.
149151

150152
_Required secrets_: `ANACONDA_TOKEN` (required to verify that later upload will not fail) stored in a GitHub actions environment of the same name as `environment`.
153+
If `destination=internal`, this secret must still be defined, but can be a placeholder string (e.g. "NA").
154+
155+
> [!NOTE]
156+
> To use this action with `destination=internal`, you must request access to the `packages` self-hosted runner for your repository via an Arup service-now request.
151157

152158
### Upload a conda package
153159

@@ -164,10 +170,17 @@ _Inputs_:
164170
- environment (optional, default="pre-release"): GitHub environment in which secrets are stored.
165171
Environments help to ensure that only certain operations are available to different user types.
166172
E.g., releasing packages can be given an extra layer of security whereby a maintainer has to approve an action before it can run.
173+
- destination (optional, default="anaconda"): One of "anaconda" or "internal", to specify what the ultimate destination of the package will be.
174+
If `internal`, the package will be uploaded to <https://packages.arup.com/conda>.
175+
If `anaconda`, the package will be uploaded to <https://anaconda.org/[CHANNEL-NAME]/> where `[CHANNEL-NAME]` is linked to the `ANACONDA_TOKEN` secret.
167176

168177
_Required secrets_: `ANACONDA_TOKEN` stored in a GitHub actions environment of the same name as `environment`.
178+
If `destination=internal`, this secret must still be defined, but can be a placeholder string (e.g. "NA").
169179

170-
### Build a pip package for upload to PyPI
180+
> [!NOTE]
181+
> To use this action with `destination=internal`, you must request access to the `packages` self-hosted runner for your repository via an Arup service-now request.
182+
183+
### Build a pip package for upload to PyPI or to <https://packages.arup.com>
171184

172185
_URL_: `arup-group/actions-city-modelling-lab/.github/workflows/pip-build.yml`
173186

@@ -187,10 +200,17 @@ E.g., releasing packages can be given an extra layer of security whereby a maint
187200
- pip_args (optional, default="--no-deps"). Any arguments to pass to pip when running test installations.
188201
Many of our packages have non-python dependencies, so it is useful to use `--no-deps` in the installation.
189202
However, if you know that your library has purely python dependencies then the pip build process is made more robust by removing this argument (i.e. `pip_args: ""`)
203+
- destination (optional, default="pypi"): One of "pypi" or "internal", to specify what the ultimate destination of the package will be.
204+
If `internal`, the package will be uploaded to <https://packages.arup.com>.
205+
If `pypi`, the package will be uploaded to <https://test.pypi.org/> for testing and <https://pypi.org/> for final upload.
190206

191207
_Required secrets_: `TEST_PYPI_API_TOKEN` stored in a GitHub actions environment of the same name as `environment`.
208+
If `destination=internal`, this secret must still be defined, but can be a placeholder string (e.g. "NA").
209+
210+
> [!NOTE]
211+
> To use this action with `destination=internal`, you must request access to the `packages` self-hosted runner for your repository via an Arup service-now request.
192212

193-
### Upload a pip package to PyPI
213+
### Upload a pip package to PyPI or to <https://packages.arup.com>
194214

195215
_URL_: `arup-group/actions-city-modelling-lab/.github/workflows/pip-upload.yml`
196216

@@ -205,8 +225,15 @@ _Inputs_:
205225
- environment (optional, default="pre-release"): GitHub environment in which secrets are stored.
206226
Environments help to ensure that only certain operations are available to different user types.
207227
E.g., releasing packages can be given an extra layer of security whereby a maintainer has to approve an action before it can run.
228+
- destination (optional, default="pypi"): One of "pypi" or "internal", to specify what the ultimate destination of the package will be.
229+
If `internal`, the package will be uploaded to <https://packages.arup.com>.
230+
If `pypi`, the package will be uploaded to <https://test.pypi.org/> for testing and <https://pypi.org/> for final upload.
208231

209232
_Required secrets_: `PYPI_API_TOKEN` stored in a GitHub actions environment of the same name as `environment`.
233+
If `destination=internal`, this secret must still be defined, but can be a placeholder string (e.g. "NA").
234+
235+
> [!NOTE]
236+
> To use this action with `destination=internal`, you must request access to the `packages` self-hosted runner for your repository via an Arup service-now request.
210237

211238
### Deploy documentation
212239

@@ -296,4 +323,4 @@ _Required secrets_: `SLACK_WEBHOOK`
296323

297324
_URL_: `arup-group/actions-city-modelling-lab/.github/workflows/template-check.yml`
298325

299-
_description_: If your project was generated using a [cookiecutter](https://github.com/cookiecutter/cookiecutter) template, check whether there are changes to the template that could be pulled into the project.
326+
_description_: If your project was generated using a [cookiecutter](https://github.com/cookiecutter/cookiecutter) template, check whether there are changes to the template that could be pulled into the project.

0 commit comments

Comments
 (0)