Skip to content

Commit

Permalink
feat: Support Scaleway provider (#812)
Browse files Browse the repository at this point in the history
Co-authored-by: Andy Méry <[email protected]>
  • Loading branch information
pgrzesik and cyclimse authored Jan 14, 2024
1 parent 16c0e68 commit 1b0faae
Show file tree
Hide file tree
Showing 9 changed files with 126 additions and 3 deletions.
25 changes: 25 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -580,6 +580,31 @@ package:
- '**'
```

## Custom Provider Support

### Scaleway

This plugin is compatible with the [Scaleway Serverless Framework Plugin](https://github.com/scaleway/serverless-scaleway-functions) to package dependencies for Python functions deployed on [Scaleway](https://www.scaleway.com/en/serverless-functions/). To use it, add the following to your `serverless.yml`:

```yaml
provider:
name: scaleway
runtime: python311
plugins:
- serverless-python-requirements
- serverless-scaleway-functions
```

To handle native dependencies, it's recommended to use the Docker builder with the image provided by Scaleway:

```yaml
custom:
pythonRequirements:
# Can use any Python version supported by Scaleway
dockerImage: rg.fr-par.scw.cloud/scwfunctionsruntimes-public/python-dep:3.11
```

## Contributors

- [@dschep](https://github.com/dschep) - Original developer
Expand Down
5 changes: 4 additions & 1 deletion index.js
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,10 @@ class ServerlessPythonRequirements {
) {
options.pythonBin = 'python';
}

if (/python3[0-9]+/.test(options.pythonBin)) {
// "google" and "scaleway" providers' runtimes uses python3XX
options.pythonBin = options.pythonBin.replace(/3([0-9]+)/, '3.$1');
}
if (options.dockerizePip === 'non-linux') {
options.dockerizePip = process.platform !== 'linux';
}
Expand Down
23 changes: 21 additions & 2 deletions lib/inject.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,16 @@ BbPromise.promisifyAll(fse);
* Inject requirements into packaged application.
* @param {string} requirementsPath requirements folder path
* @param {string} packagePath target package path
* @param {string} injectionRelativePath installation directory in target package
* @param {Object} options our options object
* @return {Promise} the JSZip object constructed.
*/
function injectRequirements(requirementsPath, packagePath, options) {
function injectRequirements(
requirementsPath,
packagePath,
injectionRelativePath,
options
) {
const noDeploy = new Set(options.noDeploy || []);

return fse
Expand All @@ -29,7 +35,13 @@ function injectRequirements(requirementsPath, packagePath, options) {
dot: true,
})
)
.map((file) => [file, path.relative(requirementsPath, file)])
.map((file) => [
file,
path.join(
injectionRelativePath,
path.relative(requirementsPath, file)
),
])
.filter(
([file, relativeFile]) =>
!file.endsWith('/') &&
Expand Down Expand Up @@ -101,6 +113,11 @@ async function injectAllRequirements(funcArtifact) {
this.serverless.cli.log('Injecting required Python packages to package...');
}

let injectionRelativePath = '.';
if (this.serverless.service.provider.name == 'scaleway') {
injectionRelativePath = 'package';
}

try {
if (this.serverless.service.package.individually) {
await BbPromise.resolve(this.targetFuncs)
Expand Down Expand Up @@ -138,13 +155,15 @@ async function injectAllRequirements(funcArtifact) {
: injectRequirements(
path.join('.serverless', func.module, 'requirements'),
func.package.artifact,
injectionRelativePath,
this.options
);
});
} else if (!this.options.zip) {
await injectRequirements(
path.join('.serverless', 'requirements'),
this.serverless.service.package.artifact || funcArtifact,
injectionRelativePath,
this.options
);
}
Expand Down
17 changes: 17 additions & 0 deletions test.js
Original file line number Diff line number Diff line change
Expand Up @@ -1729,3 +1729,20 @@ test('poetry py3.9 only installs optional packages specified in onlyGroups', asy
t.true(zipfiles.includes(`boto3${sep}__init__.py`), 'boto3 is packaged');
t.end();
});

test('py3.7 injects dependencies into `package` folder when using scaleway provider', async (t) => {
process.chdir('tests/scaleway_provider');
const path = npm(['pack', '../..']);
npm(['i', path]);
sls(['package'], { env: {} });
const zipfiles = await listZipFiles('.serverless/sls-py-req-test.zip');
t.true(
zipfiles.includes(`package${sep}flask${sep}__init__.py`),
'flask is packaged'
);
t.true(
zipfiles.includes(`package${sep}boto3${sep}__init__.py`),
'boto3 is packaged'
);
t.end();
});
2 changes: 2 additions & 0 deletions tests/scaleway_provider/_slimPatterns.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
slimPatterns:
- '**/__main__.py'
5 changes: 5 additions & 0 deletions tests/scaleway_provider/handler.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import requests


def hello(event, context):
return requests.get('https://httpbin.org/get').json()
15 changes: 15 additions & 0 deletions tests/scaleway_provider/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
"name": "example",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC",
"dependencies": {
"serverless-python-requirements": "file:serverless-python-requirements-6.0.0.tgz",
"serverless-scaleway-functions": "^0.4.8"
}
}
3 changes: 3 additions & 0 deletions tests/scaleway_provider/requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
flask==0.12.5
bottle
boto3
34 changes: 34 additions & 0 deletions tests/scaleway_provider/serverless.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
service: sls-py-req-test

configValidationMode: off

provider:
name: scaleway
runtime: python39

plugins:
- serverless-python-requirements
- serverless-scaleway-functions

custom:
pythonRequirements:
zip: ${env:zip, self:custom.defaults.zip}
slim: ${env:slim, self:custom.defaults.slim}
slimPatterns: ${file(./slimPatterns.yml):slimPatterns, self:custom.defaults.slimPatterns}
slimPatternsAppendDefaults: ${env:slimPatternsAppendDefaults, self:custom.defaults.slimPatternsAppendDefaults}
dockerizePip: ${env:dockerizePip, self:custom.defaults.dockerizePip}
defaults:
zip: false
slimPatterns: false
slimPatternsAppendDefaults: true
slim: false
dockerizePip: false

package:
patterns:
- '!**/*'
- 'handler.py'

functions:
hello:
handler: handler.hello

0 comments on commit 1b0faae

Please sign in to comment.