Skip to content

Commit 6c56602

Browse files
authored
Merge pull request #281 from patrick91/feature/poetry-caching
Add poetry caching support
2 parents 9516be8 + 7aa3e95 commit 6c56602

File tree

9 files changed

+711
-18
lines changed

9 files changed

+711
-18
lines changed

.github/workflows/e2e-cache.yml

+26-4
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ jobs:
2121
fail-fast: false
2222
matrix:
2323
os: [ubuntu-latest, windows-latest, macos-latest]
24-
python-version: ['3.8', '3.9', 'pypy-3.7-v7.x']
24+
python-version: ['3.9', 'pypy-3.7-v7.x']
2525
steps:
2626
- uses: actions/checkout@v2
2727
- name: Setup Python
@@ -39,7 +39,7 @@ jobs:
3939
fail-fast: false
4040
matrix:
4141
os: [ubuntu-latest, windows-latest, macos-latest]
42-
python-version: ['3.8', '3.9', 'pypy-3.7-v7.x']
42+
python-version: ['3.9', 'pypy-3.7-v7.x']
4343
steps:
4444
- uses: actions/checkout@v2
4545
- name: Setup Python
@@ -52,14 +52,36 @@ jobs:
5252
- name: Install dependencies
5353
run: pipenv install numpy
5454

55+
python-poetry-dependencies-caching:
56+
name: Test poetry (Python ${{ matrix.python-version}}, ${{ matrix.os }})
57+
runs-on: ${{ matrix.os }}
58+
strategy:
59+
fail-fast: false
60+
matrix:
61+
os: [ubuntu-latest, windows-latest, macos-latest]
62+
python-version: ['3.9', 'pypy-3.7-v7.x']
63+
steps:
64+
- uses: actions/checkout@v2
65+
- name: Install poetry
66+
run: pipx install poetry
67+
- name: Setup Python
68+
uses: ./
69+
with:
70+
python-version: ${{ matrix.python-version }}
71+
cache: 'poetry'
72+
- name: Init pyproject.toml
73+
run: poetry init -n
74+
- name: Install dependencies
75+
run: poetry add flake8
76+
5577
python-pip-dependencies-caching-path:
5678
name: Test pip (Python ${{ matrix.python-version}}, ${{ matrix.os }})
5779
runs-on: ${{ matrix.os }}
5880
strategy:
5981
fail-fast: false
6082
matrix:
6183
os: [ubuntu-latest, windows-latest, macos-latest]
62-
python-version: ['3.8', '3.9', 'pypy-3.7-v7.x']
84+
python-version: ['3.9', 'pypy-3.7-v7.x']
6385
steps:
6486
- uses: actions/checkout@v2
6587
- name: Setup Python
@@ -78,7 +100,7 @@ jobs:
78100
fail-fast: false
79101
matrix:
80102
os: [ubuntu-latest, windows-latest, macos-latest]
81-
python-version: ['3.8', '3.9', 'pypy-3.7-v7.x']
103+
python-version: ['3.9', 'pypy-3.7-v7.x']
82104
steps:
83105
- uses: actions/checkout@v2
84106
- name: Setup Python

README.md

+20-5
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ This action sets up a Python environment for use in actions by:
99
- optionally installing and adding to PATH a version of Python that is already installed in the tools cache.
1010
- downloading, installing and adding to PATH an available version of Python from GitHub Releases ([actions/python-versions](https://github.com/actions/python-versions/releases)) if a specific version is not available in the tools cache.
1111
- failing if a specific version of Python is not preinstalled or available for download.
12-
- optionally caching dependencies for pip and pipenv.
12+
- optionally caching dependencies for pip, pipenv and poetry.
1313
- registering problem matchers for error output.
1414

1515
# What's new
@@ -19,7 +19,7 @@ This action sets up a Python environment for use in actions by:
1919
- Automatic setup and download of Python packages if using a self-hosted runner.
2020
- Support for pre-release versions of Python.
2121
- Support for installing any version of PyPy on-flight
22-
- Support for built-in caching of pip and pipenv dependencies
22+
- Support for built-in caching of pip, pipenv and poetry dependencies
2323

2424
# Usage
2525

@@ -209,18 +209,19 @@ pypy-3.7-nightly # Python 3.7 and nightly PyPy
209209
210210
# Caching packages dependencies
211211
212-
The action has built-in functionality for caching and restoring dependencies. It uses [actions/cache](https://github.com/actions/toolkit/tree/main/packages/cache) under the hood for caching dependencies but requires less configuration settings. Supported package managers are `pip` and `pipenv`. The `cache` input is optional, and caching is turned off by default.
212+
The action has built-in functionality for caching and restoring dependencies. It uses [actions/cache](https://github.com/actions/toolkit/tree/main/packages/cache) under the hood for caching dependencies but requires less configuration settings. Supported package managers are `pip`, `pipenv` and `poetry`. The `cache` input is optional, and caching is turned off by default.
213213
214-
The action defaults to searching for a dependency file (`requirements.txt` for pip or `Pipfile.lock` for pipenv) in the repository, and uses its hash as a part of the cache key. Use `cache-dependency-path` for cases where multiple dependency files are used, they are located in different subdirectories or different files for the hash want to be used.
214+
The action defaults to searching for a dependency file (`requirements.txt` for pip, `Pipfile.lock` for pipenv or `poetry.lock` for poetry) in the repository, and uses its hash as a part of the cache key. Use `cache-dependency-path` for cases where multiple dependency files are used, they are located in different subdirectories or different files for the hash want to be used.
215215
216216
- For pip, the action will cache global cache directory
217217
- For pipenv, the action will cache virtualenv directory
218+
- For poetry, the action will cache virtualenv directory
218219
219220
**Please Note:** Restored cache will not be used if the requirements.txt file is not updated for a long time and a newer version of the dependency is available that can lead to an increase in total build time.
220221
221222
The requirements file format allows to specify dependency versions using logical operators (for example chardet>=3.0.4) or specify dependencies without any versions. In this case the pip install -r requirements.txt command will always try to install the latest available package version. To be sure that the cache will be used, please stick to a specific dependency version and update it manually if necessary.
222223
223-
**Caching pip dependencies:**
224+
**Caching pip dependencies:**
224225
225226
```yaml
226227
steps:
@@ -245,6 +246,20 @@ steps:
245246
- run: pipenv install
246247
```
247248
249+
**Caching poetry dependencies:**
250+
```yaml
251+
steps:
252+
- uses: actions/checkout@v2
253+
- name: Install poetry
254+
run: pipx install poetry
255+
- uses: actions/setup-python@v2
256+
with:
257+
python-version: '3.9'
258+
cache: 'poetry'
259+
- run: poetry install
260+
- run: poetry run pytest
261+
```
262+
248263
**Using wildcard patterns to cache dependencies**
249264
```yaml
250265
steps:

__tests__/cache-restore.test.ts

+28-6
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,16 @@ describe('restore-cache', () => {
1010
'd8110e0006d7fb5ee76365d565eef9d37df1d11598b912d3eb66d398d57a1121';
1111
const requirementsLinuxHash =
1212
'2d0ff7f46b0e120e3d3294db65768b474934242637b9899b873e6283dfd16d7c';
13+
const poetryLockHash =
14+
'571bf984f8d210e6a97f854e479fdd4a2b5af67b5fdac109ec337a0ea16e7836';
15+
const poetryConfigOutput = `
16+
cache-dir = "/Users/patrick/Library/Caches/pypoetry"
17+
experimental.new-installer = false
18+
installer.parallel = true
19+
virtualenvs.create = true
20+
virtualenvs.in-project = true
21+
virtualenvs.path = "{cache-dir}/virtualenvs" # /Users/patrick/Library/Caches/pypoetry/virtualenvs
22+
`;
1323

1424
// core spy
1525
let infoSpy: jest.SpyInstance;
@@ -47,6 +57,9 @@ describe('restore-cache', () => {
4757
if (input.includes('pip')) {
4858
return {stdout: 'pip', stderr: '', exitCode: 0};
4959
}
60+
if (input.includes('poetry')) {
61+
return {stdout: poetryConfigOutput, stderr: '', exitCode: 0};
62+
}
5063

5164
return {stdout: '', stderr: 'Error occured', exitCode: 2};
5265
});
@@ -82,7 +95,8 @@ describe('restore-cache', () => {
8295
],
8396
['pip', '3.8.12', '__tests__/data/requirements.txt', requirementsHash],
8497
['pipenv', '3.9.1', undefined, pipFileLockHash],
85-
['pipenv', '3.9.12', '__tests__/data/requirements.txt', requirementsHash]
98+
['pipenv', '3.9.12', '__tests__/data/requirements.txt', requirementsHash],
99+
['poetry', '3.9.1', undefined, poetryLockHash]
86100
])(
87101
'restored dependencies for %s by primaryKey',
88102
async (packageManager, pythonVersion, dependencyFile, fileHash) => {
@@ -138,7 +152,8 @@ describe('restore-cache', () => {
138152
],
139153
['pip', '3.8.12', '__tests__/data/requirements.txt', pipFileLockHash],
140154
['pipenv', '3.9.1', undefined, requirementsHash],
141-
['pipenv', '3.9.12', '__tests__/data/requirements.txt', requirementsHash]
155+
['pipenv', '3.9.12', '__tests__/data/requirements.txt', requirementsHash],
156+
['poetry', '3.9.1', undefined, requirementsHash]
142157
])(
143158
'restored dependencies for %s by primaryKey',
144159
async (packageManager, pythonVersion, dependencyFile, fileHash) => {
@@ -154,10 +169,17 @@ describe('restore-cache', () => {
154169
);
155170
await cacheDistributor.restoreCache();
156171
let result = '';
157-
if (packageManager !== 'pipenv') {
158-
result = `Cache restored from key: ${fileHash}`;
159-
} else {
160-
result = 'pipenv cache is not found';
172+
173+
switch (packageManager) {
174+
case 'pip':
175+
result = `Cache restored from key: ${fileHash}`;
176+
break;
177+
case 'pipenv':
178+
result = 'pipenv cache is not found';
179+
break;
180+
case 'poetry':
181+
result = 'poetry cache is not found';
182+
break;
161183
}
162184

163185
expect(infoSpy).toHaveBeenCalledWith(result);

__tests__/cache-save.test.ts

+44
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ describe('run', () => {
1111
'd8110e0006d7fb5ee76365d565eef9d37df1d11598b912d3eb66d398d57a1121';
1212
const requirementsLinuxHash =
1313
'2d0ff7f46b0e120e3d3294db65768b474934242637b9899b873e6283dfd16d7c';
14+
const poetryLockHash =
15+
'571bf984f8d210e6a97f854e479fdd4a2b5af67b5fdac109ec337a0ea16e7836';
1416

1517
// core spy
1618
let infoSpy: jest.SpyInstance;
@@ -114,6 +116,22 @@ describe('run', () => {
114116
);
115117
expect(setFailedSpy).not.toHaveBeenCalled();
116118
});
119+
120+
it('should not save cache for pipenv', async () => {
121+
inputs['cache'] = 'pipenv';
122+
123+
await run();
124+
125+
expect(getInputSpy).toHaveBeenCalled();
126+
expect(debugSpy).toHaveBeenCalledWith(
127+
`paths for caching are ${__dirname}`
128+
);
129+
expect(getStateSpy).toHaveBeenCalledTimes(3);
130+
expect(infoSpy).toHaveBeenCalledWith(
131+
`Cache hit occurred on the primary key ${requirementsHash}, not saving cache.`
132+
);
133+
expect(setFailedSpy).not.toHaveBeenCalled();
134+
});
117135
});
118136

119137
describe('action saves the cache', () => {
@@ -168,6 +186,32 @@ describe('run', () => {
168186
);
169187
expect(setFailedSpy).not.toHaveBeenCalled();
170188
});
189+
190+
it('saves cache from poetry', async () => {
191+
inputs['cache'] = 'poetry';
192+
getStateSpy.mockImplementation((name: string) => {
193+
if (name === State.CACHE_MATCHED_KEY) {
194+
return poetryLockHash;
195+
} else if (name === State.CACHE_PATHS) {
196+
return JSON.stringify([__dirname]);
197+
} else {
198+
return requirementsHash;
199+
}
200+
});
201+
202+
await run();
203+
204+
expect(getInputSpy).toHaveBeenCalled();
205+
expect(getStateSpy).toHaveBeenCalledTimes(3);
206+
expect(infoSpy).not.toHaveBeenCalledWith(
207+
`Cache hit occurred on the primary key ${poetryLockHash}, not saving cache.`
208+
);
209+
expect(saveCacheSpy).toHaveBeenCalled();
210+
expect(infoSpy).toHaveBeenLastCalledWith(
211+
`Cache saved with the key: ${requirementsHash}`
212+
);
213+
expect(setFailedSpy).not.toHaveBeenCalled();
214+
});
171215
});
172216

173217
afterEach(() => {

0 commit comments

Comments
 (0)