Skip to content

Commit 345f8ac

Browse files
committed
feat: Extract git remote into its own option.
This makes the usage of git remotes more explicit and easier to understand. It also allows to combine gitRemote and manifestPath if the manifest file is not in the root of the git repository.
1 parent 88c9d87 commit 345f8ac

File tree

8 files changed

+202
-367
lines changed

8 files changed

+202
-367
lines changed

API.md

Lines changed: 85 additions & 299 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

README.md

Lines changed: 22 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -54,23 +54,6 @@ lambda-project
5454
└── main.rs
5555
```
5656

57-
Note that `manifestPath` can be a remote git repository which will be cloned for you, i.e:
58-
59-
```ts
60-
import { RustFunction } from 'cargo-lambda-cdk';
61-
62-
new RustFunction(stack, 'Rust function', {
63-
// Specify the branch to clone, defaults to HEAD.
64-
branch: 'branch',
65-
manifestPath: 'https://github.com/your_user/your_repo',
66-
// Other flavors of git urls should work ☝️ too:
67-
//
68-
// https://github.com/user/repo.git
69-
// ssh://user@host:22/user/repo.git
70-
// [email protected]:user/repo.git
71-
});
72-
```
73-
7457
### Runtime
7558

7659
The `RustFunction` uses the `provided.al2023` runtime. If you want to change it, you can use the property `runtime`. The only other valid option is `provided.al2`:
@@ -102,6 +85,28 @@ new RustFunction(this, 'Rust function', {
10285
],
10386
});
10487
```
88+
89+
## Remote Git sources
90+
91+
Both `RustFunction` and `RustExtension` support cloning a git repository to get the source code for the function or extension.
92+
To download the source code from a remote git repository, specify the `gitRemote`. This option can be a valid git remote url, such as `https://github.com/your_user/your_repo`, or a valid ssh url, such as `[email protected]:your_user/your_repo.git`.
93+
94+
By default, the latest commit from the `HEAD` branch will be downloaded. To download a different git reference, specify the `gitReference` option. This can be a branch name, tag, or commit hash.
95+
96+
If you want to always clone the repository even if it has already been cloned to the temporary directory, set the `gitForceClone` option to `true`.
97+
98+
If you specify a `manifestPath`, it will be relative to the root of the git repository once it has been cloned.
99+
100+
```ts
101+
import { RustFunction } from 'cargo-lambda-cdk';
102+
103+
new RustFunction(stack, 'Rust function', {
104+
gitRemote: 'https://github.com/your_user/your_repo',
105+
gitReference: 'branch',
106+
gitForceClone: true,
107+
});
108+
```
109+
105110
## Bundling
106111

107112
Bundling is the process by which `cargo lambda` gets called to build, package, and deliver the Rust

package.json

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

src/cargo.ts

Lines changed: 36 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,24 @@ import { mkdirSync, existsSync, readFileSync, rmSync } from 'node:fs';
22
import { join, parse } from 'node:path';
33
import { tmpdir } from 'os';
44
import { load } from 'js-toml';
5+
import { BundlingOptions } from './types';
56
import { exec } from './util';
67

8+
/**
9+
* Base properties for a Cargo project.
10+
*
11+
* RustFunctionProps and RustExtensionProps cannot inherit from this interface
12+
* because jsii only supports direct inheritance from a single interface.
13+
*/
14+
interface CargoProject {
15+
readonly bundling?: BundlingOptions;
16+
readonly binaryName?: string;
17+
readonly manifestPath?: string;
18+
readonly gitRemote?: string;
19+
readonly gitReference?: string;
20+
readonly gitForceClone?: boolean;
21+
}
22+
723
export interface Workspace {
824
members: string[];
925
}
@@ -18,30 +34,40 @@ export interface Manifest {
1834
workspace?: Workspace;
1935
}
2036

21-
export function getManifestPath(manifestPath: string, branch?: string, alwaysClone?: boolean): string {
37+
export function getManifestPath(project: CargoProject): string {
38+
const defaultManifestPath = project.manifestPath || 'Cargo.toml';
39+
let manifestPath = defaultManifestPath;
40+
2241
// Determine what type of URL this is and download (git repo) locally
23-
if (isValidGitUrl(manifestPath)) {
42+
if (project.gitRemote && isValidGitUrl(project.gitRemote)) {
43+
const gitReference = project.gitReference || 'HEAD';
44+
2445
// i.e: 3ed81b4751e8f09bfa39fe743ee143df60304db5 HEAD
25-
let latestCommit = exec('git', ['ls-remote', manifestPath, branch ?? 'HEAD']).stdout.toString().split(/(\s+)/)[0];
46+
let latestCommit = exec('git', ['ls-remote', project.gitRemote, gitReference]).stdout.toString().split(/(\s+)/)[0];
2647
const localPath = join(tmpdir(), latestCommit);
2748

28-
if (alwaysClone) {
49+
if (project.gitForceClone) {
2950
rmSync(localPath, { recursive: true, force: true });
3051
}
3152

3253
if (!existsSync(localPath)) {
3354
mkdirSync(localPath, { recursive: true });
3455

35-
const args = ['clone', '--depth', '1', manifestPath, localPath];
36-
if (branch !== undefined) {
37-
args.push('--branch', branch);
56+
const args = ['clone'];
57+
if (gitReference === 'HEAD') {
58+
args.push('--depth', '1');
3859
}
3960

61+
args.push(project.gitRemote, localPath);
4062
exec('git', args);
41-
}
4263

43-
// Append Cargo.toml to the path
44-
manifestPath = join(localPath, 'Cargo.toml');
64+
if (gitReference !== 'HEAD') {
65+
exec('git', ['checkout', gitReference], { cwd: localPath });
66+
}
67+
68+
// Append Cargo.toml to the path
69+
manifestPath = join(localPath, defaultManifestPath);
70+
}
4571
}
4672

4773
let manifestPathResult;

src/extension.ts

Lines changed: 26 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,20 @@ import { LayerVersion, LayerVersionOptions } from 'aws-cdk-lib/aws-lambda';
22
import { Construct } from 'constructs';
33
import { Bundling } from './bundling';
44
import { getManifestPath } from './cargo';
5+
// import { CargoProject } from './cargo';
56
import { BundlingOptions } from './types';
67

7-
8+
/**
9+
* Properties for a RustExtension
10+
*/
811
export interface RustExtensionProps extends LayerVersionOptions {
12+
/**
13+
* Bundling options
14+
*
15+
* @default - use default bundling options
16+
*/
17+
readonly bundling?: BundlingOptions;
18+
919
/**
1020
* The name of the binary to build, in case that's different than the package's name.
1121
*/
@@ -14,47 +24,48 @@ export interface RustExtensionProps extends LayerVersionOptions {
1424
/**
1525
* Path to a directory containing your Cargo.toml file, or to your Cargo.toml directly.
1626
*
17-
* This will accept a directory path containing a `Cargo.toml` file, a filepath to your
18-
* `Cargo.toml` file (i.e. `path/to/Cargo.toml`), or a git repository URL
19-
* (e.g. `https://github.com/your_user/your_repo`).
20-
*
21-
* When using a git repository URL, the repository will be cloned to a temporary directory.
27+
* This will accept a directory path containing a `Cargo.toml` file (i.e. `path/to/package`), or a filepath to your
28+
* `Cargo.toml` file (i.e. `path/to/Cargo.toml`). When the `gitRemote` option is provided,
29+
* the `manifestPath` is relative to the root of the git repository.
2230
*
2331
* @default - check the current directory for a `Cargo.toml` file, and throws
2432
* an error if the file doesn't exist.
2533
*/
2634
readonly manifestPath?: string;
2735

2836
/**
29-
* Bundling options
37+
* The git remote URL to clone (e.g `https://github.com/your_user/your_repo`).
3038
*
31-
* @default - use default bundling options
39+
* This repository will be cloned to a temporary directory using `git`.
40+
* The `git` command must be available in the PATH.
3241
*/
33-
readonly bundling?: BundlingOptions;
42+
readonly gitRemote?: string;
3443

3544
/**
36-
* The branch to clone if the `manifestPath` is a git repository.
45+
* The git reference to checkout. This can be a branch, tag, or commit hash.
46+
*
47+
* If this option is not provided, `git clone` will run with the flag `--depth 1`.
3748
*
3849
* @default - the default branch, i.e. HEAD.
3950
*/
40-
readonly branch?: string;
51+
readonly gitReference?: string;
4152

4253
/**
43-
* Always clone the repository if using a git `manifestPath`, even if it has already been
54+
* Always clone the repository if using the `gitRemote` option, even if it has already been
4455
* cloned to the temporary directory.
4556
*
46-
* @default - clones only if the repository and branch does not already exist in the
57+
* @default - clones only if the repository and reference don't already exist in the
4758
* temporary directory.
4859
*/
49-
readonly alwaysClone?: boolean;
60+
readonly gitForceClone?: boolean;
5061
}
5162

5263
/**
5364
* A Lambda extension written in Rust
5465
*/
5566
export class RustExtension extends LayerVersion {
5667
constructor(scope: Construct, resourceName: string, props?: RustExtensionProps) {
57-
const manifestPath = getManifestPath(props?.manifestPath ?? 'Cargo.toml', props?.branch, props?.alwaysClone);
68+
const manifestPath = getManifestPath(props || {});
5869
const bundling = props?.bundling ?? {};
5970

6071
super(scope, resourceName, {

src/function.ts

Lines changed: 27 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -11,61 +11,69 @@ export { cargoLambdaVersion } from './bundling';
1111
* Properties for a RustFunction
1212
*/
1313
export interface RustFunctionProps extends FunctionOptions {
14-
/**
15-
* The name of the binary to build, in case that's different than the package's name.
16-
*/
17-
readonly binaryName?: string;
18-
1914
/**
2015
* The Lambda runtime to deploy this function.
2116
* `provided.al2023` is the default runtime when this option is not provided.
2217
*/
2318
readonly runtime?: 'provided.al2023' | 'provided.al2';
2419

20+
/**
21+
* Bundling options
22+
*
23+
* @default - use default bundling options
24+
*/
25+
readonly bundling?: BundlingOptions;
26+
27+
/**
28+
* The name of the binary to build, in case that's different than the package's name.
29+
*/
30+
readonly binaryName?: string;
31+
2532
/**
2633
* Path to a directory containing your Cargo.toml file, or to your Cargo.toml directly.
2734
*
28-
* This will accept a directory path containing a `Cargo.toml` file, a filepath to your
29-
* `Cargo.toml` file (i.e. `path/to/Cargo.toml`), or a git repository url
30-
* (e.g. `https://github.com/your_user/your_repo`).
31-
*
32-
* When using a git repository URL, the repository will be cloned to a temporary directory.
35+
* This will accept a directory path containing a `Cargo.toml` file (i.e. `path/to/package`), or a filepath to your
36+
* `Cargo.toml` file (i.e. `path/to/Cargo.toml`). When the `gitRemote` option is provided,
37+
* the `manifestPath` is relative to the root of the git repository.
3338
*
3439
* @default - check the current directory for a `Cargo.toml` file, and throws
3540
* an error if the file doesn't exist.
3641
*/
3742
readonly manifestPath?: string;
3843

3944
/**
40-
* Bundling options
45+
* The git remote URL to clone (e.g `https://github.com/your_user/your_repo`).
4146
*
42-
* @default - use default bundling options
47+
* This repository will be cloned to a temporary directory using `git`.
48+
* The `git` command must be available in the PATH.
4349
*/
44-
readonly bundling?: BundlingOptions;
50+
readonly gitRemote?: string;
4551

4652
/**
47-
* The branch to clone if the `manifestPath` is a git repository.
53+
* The git reference to checkout. This can be a branch, tag, or commit hash.
54+
*
55+
* If this option is not provided, `git clone` will run with the flag `--depth 1`.
4856
*
4957
* @default - the default branch, i.e. HEAD.
5058
*/
51-
readonly branch?: string;
59+
readonly gitReference?: string;
5260

5361
/**
54-
* Always clone the repository if using a git `manifestPath`, even if it has already been
62+
* Always clone the repository if using the `gitRemote` option, even if it has already been
5563
* cloned to the temporary directory.
5664
*
57-
* @default - clones only if the repository and branch does not already exist in the
65+
* @default - clones only if the repository and reference don't already exist in the
5866
* temporary directory.
5967
*/
60-
readonly alwaysClone?: boolean;
68+
readonly gitForceClone?: boolean;
6169
}
6270

6371
/**
6472
* A Rust Lambda function
6573
*/
6674
export class RustFunction extends Function {
6775
constructor(scope: Construct, resourceName: string, props?: RustFunctionProps) {
68-
const manifestPath = getManifestPath(props?.manifestPath ?? 'Cargo.toml', props?.branch, props?.alwaysClone);
76+
const manifestPath = getManifestPath(props || {});
6977

7078
const runtime = new Runtime(props?.runtime || 'provided.al2023');
7179
const bundling = bundlingOptionsFromRustFunctionProps(props);

test/bundlingOptions.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ describe('bundlingOptionsFromRustFunctionProps', () => {
5454
const forcedDockerBundling = !!env.FORCE_DOCKER_RUN || !cargoLambdaVersion();
5555

5656
const getTestManifestPath = () => {
57-
return getManifestPath(path.join(__dirname, 'fixtures/single-package/Cargo.toml'));
57+
return getManifestPath({ manifestPath: path.join(__dirname, 'fixtures/single-package/Cargo.toml') });
5858
};
5959

6060
const templateWithProps = (props?: RustFunctionProps) => {

test/cargo.test.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,22 +4,22 @@ import { getManifest, getManifestPath } from '../src/cargo';
44
describe('getManifestPath', () => {
55
it('works with a path to an existent Cargo.toml file', () => {
66
const fixture = join(__dirname, 'fixtures/single-package/Cargo.toml');
7-
expect(getManifestPath(fixture)).toEqual(fixture);
7+
expect(getManifestPath({ manifestPath: fixture })).toEqual(fixture);
88
});
99

1010
it('works with a base directory', () => {
1111
const fixture = join(__dirname, 'fixtures/single-package');
12-
expect(getManifestPath(fixture)).toEqual(join(fixture, 'Cargo.toml'));
12+
expect(getManifestPath({ manifestPath: fixture })).toEqual(join(fixture, 'Cargo.toml'));
1313
});
1414

1515
it('fails with a different file', () => {
1616
const fixture = join(__dirname, 'fixtures/single-package/src/main.rs');
17-
expect(() => getManifestPath(fixture)).toThrow('manifestPath is specifying a file that is not Cargo.toml');
17+
expect(() => getManifestPath({ manifestPath: fixture })).toThrow('manifestPath is specifying a file that is not Cargo.toml');
1818
});
1919

2020
it('fails with a directory that doesn\'t include a Cargo.toml file', () => {
2121
const fixture = join(__dirname, 'fixtures/single-package/src');
22-
expect(() => getManifestPath(fixture)).toThrow(`'${fixture}/Cargo.toml' is not a path to a Cargo.toml file, use the option \`manifestPath\` to specify the location of the Cargo.toml file`);
22+
expect(() => getManifestPath({ manifestPath: fixture })).toThrow(`'${fixture}/Cargo.toml' is not a path to a Cargo.toml file, use the option \`manifestPath\` to specify the location of the Cargo.toml file`);
2323
});
2424
});
2525

0 commit comments

Comments
 (0)