Skip to content

Commit 00a5248

Browse files
authored
feature: add update-environment input (actions#411)
This option allows to specify if the action shall update environment variables (default) or not. This allows to use the setup-python action in a composite action without side effect (except downloading/installing python if version is missing).
1 parent ffcd000 commit 00a5248

File tree

16 files changed

+4399
-3868
lines changed

16 files changed

+4399
-3868
lines changed

.github/workflows/test-pypy.yml

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,3 +65,29 @@ jobs:
6565
EXECUTABLE=${EXECUTABLE%%-*} # remove any -* suffixe
6666
${EXECUTABLE} --version
6767
shell: bash
68+
69+
setup-pypy-noenv:
70+
name: Setup PyPy ${{ matrix.pypy }} ${{ matrix.os }} (noenv)
71+
runs-on: ${{ matrix.os }}
72+
strategy:
73+
fail-fast: false
74+
matrix:
75+
os: [macos-latest, windows-latest, ubuntu-18.04, ubuntu-latest]
76+
pypy: ['pypy2.7', 'pypy3.7', 'pypy3.8', 'pypy3.9-nightly']
77+
78+
steps:
79+
- name: Checkout
80+
uses: actions/checkout@v3
81+
82+
- name: setup-python ${{ matrix.pypy }}
83+
id: setup-python
84+
uses: ./
85+
with:
86+
python-version: ${{ matrix.pypy }}
87+
update-environment: false
88+
89+
- name: PyPy and Python version
90+
run: ${{ steps.setup-python.outputs.python-path }} --version
91+
92+
- name: Run simple code
93+
run: ${{ steps.setup-python.outputs.python-path }} -c 'import math; print(math.factorial(5))'

.github/workflows/test-python.yml

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -147,3 +147,28 @@ jobs:
147147

148148
- name: Run simple code
149149
run: python -c 'import math; print(math.factorial(5))'
150+
151+
setup-versions-noenv:
152+
name: Setup ${{ matrix.python }} ${{ matrix.os }} (noenv)
153+
runs-on: ${{ matrix.os }}
154+
strategy:
155+
fail-fast: false
156+
matrix:
157+
os: [macos-latest, windows-latest, ubuntu-18.04, ubuntu-20.04]
158+
python: ["3.7", "3.8", "3.9", "3.10"]
159+
steps:
160+
- name: Checkout
161+
uses: actions/checkout@v3
162+
163+
- name: setup-python ${{ matrix.python }}
164+
id: setup-python
165+
uses: ./
166+
with:
167+
python-version: ${{ matrix.python }}
168+
update-environment: false
169+
170+
- name: Python version
171+
run: ${{ steps.setup-python.outputs.python-path }} --version
172+
173+
- name: Run simple code
174+
run: ${{ steps.setup-python.outputs.python-path }} -c 'import math; print(math.factorial(5))'

.licenses/npm/@actions/core.dep.yml

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

.licenses/npm/@actions/http-client-1.0.8.dep.yml

Lines changed: 0 additions & 32 deletions
This file was deleted.

README.md

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -320,6 +320,26 @@ steps:
320320
- run: pipenv install
321321
```
322322
323+
# Environment variables
324+
325+
The `update-environment` flag defaults to `true`.
326+
With this setting, the action will add/update environment variables (e.g. `PATH`, `PKG_CONFIG_PATH`, `pythonLocation`) for `python` to just work out of the box.
327+
328+
If `update-environment` is set to `false`, the action will not add/update environment variables.
329+
This can prove useful if you want the only side-effect to be to ensure python is installed and rely on the `python-path` output to run python.
330+
Such a requirement on side-effect could be because you don't want your composite action messing with your user's workflows.
331+
332+
```yaml
333+
steps:
334+
- uses: actions/checkout@v3
335+
- uses: actions/setup-python@v4
336+
id: cp310
337+
with:
338+
python-version: '3.10'
339+
update-environment: false
340+
- run: ${{ steps.cp310.outputs.python-path }} my_script.py
341+
```
342+
323343
# Using `setup-python` with a self hosted runner
324344

325345
Python distributions are only available for the same [environments](https://github.com/actions/virtual-environments#available-environments) that GitHub Actions hosted environments are available for. If you are using an unsupported version of Ubuntu such as `19.04` or another Linux distribution such as Fedora, `setup-python` will not work. If you have a supported self-hosted runner and you would like to use `setup-python`, there are a few extra things you need to make sure are set up so that new versions of Python can be downloaded and configured on your runner.

__tests__/find-pypy.test.ts

Lines changed: 47 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import {HttpClient} from '@actions/http-client';
55
import * as ifm from '@actions/http-client/interfaces';
66
import * as tc from '@actions/tool-cache';
77
import * as exec from '@actions/exec';
8+
import * as core from '@actions/core';
89

910
import * as path from 'path';
1011
import * as semver from 'semver';
@@ -148,6 +149,8 @@ describe('findPyPyVersion', () => {
148149
let spyWriteExactPyPyVersionFile: jest.SpyInstance;
149150
let spyCacheDir: jest.SpyInstance;
150151
let spyChmodSync: jest.SpyInstance;
152+
let spyCoreAddPath: jest.SpyInstance;
153+
let spyCoreExportVariable: jest.SpyInstance;
151154

152155
beforeEach(() => {
153156
tcFind = jest.spyOn(tc, 'find');
@@ -201,6 +204,10 @@ describe('findPyPyVersion', () => {
201204

202205
spyExistsSync = jest.spyOn(fs, 'existsSync');
203206
spyExistsSync.mockReturnValue(true);
207+
208+
spyCoreAddPath = jest.spyOn(core, 'addPath');
209+
210+
spyCoreExportVariable = jest.spyOn(core, 'exportVariable');
204211
});
205212

206213
afterEach(() => {
@@ -211,22 +218,31 @@ describe('findPyPyVersion', () => {
211218

212219
it('found PyPy in toolcache', async () => {
213220
await expect(
214-
finder.findPyPyVersion('pypy-3.6-v7.3.x', architecture)
221+
finder.findPyPyVersion('pypy-3.6-v7.3.x', architecture, true)
215222
).resolves.toEqual({
216223
resolvedPythonVersion: '3.6.12',
217224
resolvedPyPyVersion: '7.3.3'
218225
});
226+
expect(spyCoreAddPath).toHaveBeenCalled();
227+
expect(spyCoreExportVariable).toHaveBeenCalledWith(
228+
'pythonLocation',
229+
expect.anything()
230+
);
231+
expect(spyCoreExportVariable).toHaveBeenCalledWith(
232+
'PKG_CONFIG_PATH',
233+
expect.anything()
234+
);
219235
});
220236

221237
it('throw on invalid input format', async () => {
222238
await expect(
223-
finder.findPyPyVersion('pypy3.7-v7.3.x', architecture)
239+
finder.findPyPyVersion('pypy3.7-v7.3.x', architecture, true)
224240
).rejects.toThrow();
225241
});
226242

227243
it('throw on invalid input format pypy3.7-7.3.x', async () => {
228244
await expect(
229-
finder.findPyPyVersion('pypy3.7-v7.3.x', architecture)
245+
finder.findPyPyVersion('pypy3.7-v7.3.x', architecture, true)
230246
).rejects.toThrow();
231247
});
232248

@@ -238,16 +254,42 @@ describe('findPyPyVersion', () => {
238254
spyChmodSync = jest.spyOn(fs, 'chmodSync');
239255
spyChmodSync.mockImplementation(() => undefined);
240256
await expect(
241-
finder.findPyPyVersion('pypy-3.7-v7.3.x', architecture)
257+
finder.findPyPyVersion('pypy-3.7-v7.3.x', architecture, true)
258+
).resolves.toEqual({
259+
resolvedPythonVersion: '3.7.9',
260+
resolvedPyPyVersion: '7.3.3'
261+
});
262+
expect(spyCoreAddPath).toHaveBeenCalled();
263+
expect(spyCoreExportVariable).toHaveBeenCalledWith(
264+
'pythonLocation',
265+
expect.anything()
266+
);
267+
expect(spyCoreExportVariable).toHaveBeenCalledWith(
268+
'PKG_CONFIG_PATH',
269+
expect.anything()
270+
);
271+
});
272+
273+
it('found and install successfully without environment update', async () => {
274+
spyCacheDir = jest.spyOn(tc, 'cacheDir');
275+
spyCacheDir.mockImplementation(() =>
276+
path.join(toolDir, 'PyPy', '3.7.7', architecture)
277+
);
278+
spyChmodSync = jest.spyOn(fs, 'chmodSync');
279+
spyChmodSync.mockImplementation(() => undefined);
280+
await expect(
281+
finder.findPyPyVersion('pypy-3.7-v7.3.x', architecture, false)
242282
).resolves.toEqual({
243283
resolvedPythonVersion: '3.7.9',
244284
resolvedPyPyVersion: '7.3.3'
245285
});
286+
expect(spyCoreAddPath).not.toHaveBeenCalled();
287+
expect(spyCoreExportVariable).not.toHaveBeenCalled();
246288
});
247289

248290
it('throw if release is not found', async () => {
249291
await expect(
250-
finder.findPyPyVersion('pypy-3.7-v7.5.x', architecture)
292+
finder.findPyPyVersion('pypy-3.7-v7.5.x', architecture, true)
251293
).rejects.toThrowError(
252294
`PyPy version 3.7 (v7.5.x) with arch ${architecture} not found`
253295
);

__tests__/finder.test.ts

Lines changed: 55 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,23 +19,54 @@ process.env['RUNNER_TOOL_CACHE'] = toolDir;
1919
process.env['RUNNER_TEMP'] = tempDir;
2020

2121
import * as tc from '@actions/tool-cache';
22+
import * as core from '@actions/core';
2223
import * as finder from '../src/find-python';
2324
import * as installer from '../src/install-python';
2425

2526
const manifestData = require('./data/versions-manifest.json');
2627

2728
describe('Finder tests', () => {
29+
let spyCoreAddPath: jest.SpyInstance;
30+
let spyCoreExportVariable: jest.SpyInstance;
31+
32+
beforeEach(() => {
33+
spyCoreAddPath = jest.spyOn(core, 'addPath');
34+
35+
spyCoreExportVariable = jest.spyOn(core, 'exportVariable');
36+
});
37+
2838
afterEach(() => {
2939
jest.resetAllMocks();
3040
jest.clearAllMocks();
41+
jest.restoreAllMocks();
3142
});
3243

3344
it('Finds Python if it is installed', async () => {
3445
const pythonDir: string = path.join(toolDir, 'Python', '3.0.0', 'x64');
3546
await io.mkdirP(pythonDir);
3647
fs.writeFileSync(`${pythonDir}.complete`, 'hello');
3748
// This will throw if it doesn't find it in the cache and in the manifest (because no such version exists)
38-
await finder.useCpythonVersion('3.x', 'x64');
49+
await finder.useCpythonVersion('3.x', 'x64', true);
50+
expect(spyCoreAddPath).toHaveBeenCalled();
51+
expect(spyCoreExportVariable).toHaveBeenCalledWith(
52+
'pythonLocation',
53+
expect.anything()
54+
);
55+
expect(spyCoreExportVariable).toHaveBeenCalledWith(
56+
'PKG_CONFIG_PATH',
57+
expect.anything()
58+
);
59+
});
60+
61+
it('Finds Python if it is installed without environment update', async () => {
62+
const pythonDir: string = path.join(toolDir, 'Python', '3.0.0', 'x64');
63+
await io.mkdirP(pythonDir);
64+
fs.writeFileSync(`${pythonDir}.complete`, 'hello');
65+
// This will throw if it doesn't find it in the cache and in the manifest (because no such version exists)
66+
await finder.useCpythonVersion('3.x', 'x64', false);
67+
expect(spyCoreAddPath).not.toHaveBeenCalled();
68+
expect(spyCoreExportVariable).not.toHaveBeenCalled();
69+
expect(spyCoreExportVariable).not.toHaveBeenCalled();
3970
});
4071

4172
it('Finds stable Python version if it is not installed, but exists in the manifest', async () => {
@@ -52,7 +83,16 @@ describe('Finder tests', () => {
5283
fs.writeFileSync(`${pythonDir}.complete`, 'hello');
5384
});
5485
// This will throw if it doesn't find it in the cache and in the manifest (because no such version exists)
55-
await finder.useCpythonVersion('1.2.3', 'x64');
86+
await finder.useCpythonVersion('1.2.3', 'x64', true);
87+
expect(spyCoreAddPath).toHaveBeenCalled();
88+
expect(spyCoreExportVariable).toHaveBeenCalledWith(
89+
'pythonLocation',
90+
expect.anything()
91+
);
92+
expect(spyCoreExportVariable).toHaveBeenCalledWith(
93+
'PKG_CONFIG_PATH',
94+
expect.anything()
95+
);
5696
});
5797

5898
it('Finds pre-release Python version in the manifest', async () => {
@@ -74,17 +114,28 @@ describe('Finder tests', () => {
74114
fs.writeFileSync(`${pythonDir}.complete`, 'hello');
75115
});
76116
// This will throw if it doesn't find it in the manifest (because no such version exists)
77-
await finder.useCpythonVersion('1.2.3-beta.2', 'x64');
117+
await finder.useCpythonVersion('1.2.3-beta.2', 'x64', true);
118+
expect(spyCoreAddPath).toHaveBeenCalled();
119+
expect(spyCoreExportVariable).toHaveBeenCalledWith(
120+
'pythonLocation',
121+
expect.anything()
122+
);
123+
expect(spyCoreExportVariable).toHaveBeenCalledWith(
124+
'PKG_CONFIG_PATH',
125+
expect.anything()
126+
);
78127
});
79128

80129
it('Errors if Python is not installed', async () => {
81130
// This will throw if it doesn't find it in the cache and in the manifest (because no such version exists)
82131
let thrown = false;
83132
try {
84-
await finder.useCpythonVersion('3.300000', 'x64');
133+
await finder.useCpythonVersion('3.300000', 'x64', true);
85134
} catch {
86135
thrown = true;
87136
}
88137
expect(thrown).toBeTruthy();
138+
expect(spyCoreAddPath).not.toHaveBeenCalled();
139+
expect(spyCoreExportVariable).not.toHaveBeenCalled();
89140
});
90141
});

action.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,9 @@ inputs:
1717
default: ${{ github.token }}
1818
cache-dependency-path:
1919
description: 'Used to specify the path to dependency files. Supports wildcards or a list of file names for caching multiple dependencies.'
20+
update-environment:
21+
description: 'Set this option if you want the action to update environment variables.'
22+
default: true
2023
outputs:
2124
python-version:
2225
description: "The installed python version. Useful when given a version range as input."

0 commit comments

Comments
 (0)