Skip to content

Commit 1f0ca46

Browse files
[cli] Add git metadata to vc deploy (vercel#7910)
Currently, git metadata is not included on the Vercel dashboard when a project is deployed via the CLI. This PR populates the git metadata. ### πŸ“‹ Checklist <!-- Please keep your PR as a Draft until the checklist is complete --> #### Tests - [x] The code changed/added as part of this PR has been covered with tests - [x] All tests pass locally with `yarn test-unit` #### Code Review - [ ] This PR has a concise title and thorough description useful to a reviewer - [ ] Issue from task tracker has a link to this PR
1 parent 17cb5f1 commit 1f0ca46

File tree

154 files changed

+5146
-2
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

154 files changed

+5146
-2
lines changed

β€Ž.gitattributes

+4
Original file line numberDiff line numberDiff line change
@@ -8,3 +8,7 @@ packages/*/test/* linguist-vendored
88
# Go build fails with Windows line endings.
99
*.go text eol=lf
1010
go.mod text eol=lf
11+
12+
# Mark certain files as "binary" -- hide diffs
13+
**/test/fixtures/**/git/**/* binary
14+
**/test/fixtures/**/git/**/* linguist-generated

β€Žpackages/cli/package.json

+3
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@
7171
"@types/fs-extra": "9.0.13",
7272
"@types/glob": "7.1.1",
7373
"@types/http-proxy": "1.16.2",
74+
"@types/ini": "1.3.31",
7475
"@types/inquirer": "7.3.1",
7576
"@types/jest": "27.4.1",
7677
"@types/jest-expect-message": "1.0.3",
@@ -130,8 +131,10 @@
130131
"fast-deep-equal": "3.1.3",
131132
"fs-extra": "10.0.0",
132133
"get-port": "5.1.1",
134+
"git-last-commit": "1.0.1",
133135
"glob": "7.1.2",
134136
"http-proxy": "1.18.1",
137+
"ini": "3.0.0",
135138
"inquirer": "7.0.4",
136139
"is-docker": "2.2.1",
137140
"is-port-reachable": "3.0.0",

β€Žpackages/cli/src/commands/deploy/index.ts

+4
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ import { help } from './args';
6565
import { getDeploymentChecks } from '../../util/deploy/get-deployment-checks';
6666
import parseTarget from '../../util/deploy/parse-target';
6767
import getPrebuiltJson from '../../util/deploy/get-prebuilt-json';
68+
import { createGitMeta } from '../../util/deploy/create-git-meta';
6869

6970
export default async (client: Client) => {
7071
const { output } = client;
@@ -417,6 +418,8 @@ export default async (client: Client) => {
417418
parseMeta(argv['--meta'])
418419
);
419420

421+
const gitMetadata = await createGitMeta(path, output);
422+
420423
// Merge dotenv config, `env` from vercel.json, and `--env` / `-e` arguments
421424
const deploymentEnv = Object.assign(
422425
{},
@@ -479,6 +482,7 @@ export default async (client: Client) => {
479482
nowConfig: localConfig,
480483
regions,
481484
meta,
485+
gitMetadata,
482486
deployStamp,
483487
target,
484488
skipAutoDetectionConfirmation: autoConfirm,

β€Žpackages/cli/src/types.ts

+9
Original file line numberDiff line numberDiff line change
@@ -296,6 +296,15 @@ export interface Token {
296296
teamId?: string;
297297
}
298298

299+
export interface GitMetadata {
300+
commitAuthorName?: string | undefined;
301+
commitMessage?: string | undefined;
302+
commitRef?: string | undefined;
303+
commitSha?: string | undefined;
304+
dirty?: boolean | undefined;
305+
remoteUrl: string;
306+
}
307+
299308
/**
300309
* An object representing a Build on Vercel
301310
*/
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
import fs from 'fs-extra';
2+
import { join } from 'path';
3+
import ini from 'ini';
4+
import git from 'git-last-commit';
5+
import { exec } from 'child_process';
6+
import { GitMetadata } from '../../types';
7+
import { Output } from '../output';
8+
9+
export function isDirty(directory: string): Promise<boolean> {
10+
return new Promise((resolve, reject) => {
11+
exec('git status -s', { cwd: directory }, function (err, stdout, stderr) {
12+
if (err) return reject(err);
13+
if (stderr)
14+
return reject(
15+
new Error(
16+
`Failed to determine if git repo has been modified: ${stderr.trim()}`
17+
)
18+
);
19+
resolve(stdout.trim().length > 0);
20+
});
21+
});
22+
}
23+
24+
function getLastCommit(directory: string): Promise<git.Commit> {
25+
return new Promise((resolve, reject) => {
26+
git.getLastCommit(
27+
(err, commit) => {
28+
if (err) return reject(err);
29+
resolve(commit);
30+
},
31+
{ dst: directory }
32+
);
33+
});
34+
}
35+
36+
export async function getRemoteUrl(
37+
configPath: string,
38+
output: Output
39+
): Promise<string | null> {
40+
let gitConfig;
41+
try {
42+
gitConfig = ini.parse(await fs.readFile(configPath, 'utf-8'));
43+
} catch (error) {
44+
output.debug(`Error while parsing repo data: ${error.message}`);
45+
}
46+
if (!gitConfig) {
47+
return null;
48+
}
49+
50+
const originUrl: string = gitConfig['remote "origin"']?.url;
51+
if (originUrl) {
52+
return originUrl;
53+
}
54+
return null;
55+
}
56+
57+
export async function createGitMeta(
58+
directory: string,
59+
output: Output
60+
): Promise<GitMetadata | undefined> {
61+
const remoteUrl = await getRemoteUrl(join(directory, '.git/config'), output);
62+
// If we can't get the repo URL, then don't return any metadata
63+
if (!remoteUrl) {
64+
return;
65+
}
66+
const [commit, dirty] = await Promise.all([
67+
getLastCommit(directory),
68+
isDirty(directory),
69+
]);
70+
71+
return {
72+
remoteUrl,
73+
commitAuthorName: commit.author.name,
74+
commitMessage: commit.subject,
75+
commitRef: commit.branch,
76+
commitSha: commit.hash,
77+
dirty,
78+
};
79+
}

β€Žpackages/cli/src/util/index.ts

+4-1
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ import { responseError } from './error';
1414
import stamp from './output/stamp';
1515
import { APIError, BuildError } from './errors-ts';
1616
import printIndications from './print-indications';
17-
import { Org } from '../types';
17+
import { GitMetadata, Org } from '../types';
1818
import { VercelConfig } from './dev/types';
1919
import Client, { FetchOptions, isJSONObject } from './client';
2020
import { Dictionary } from '@vercel/client';
@@ -38,6 +38,7 @@ export interface CreateOptions {
3838
prebuilt?: boolean;
3939
rootDirectory?: string;
4040
meta: Dictionary<string>;
41+
gitMetadata?: GitMetadata;
4142
regions?: string[];
4243
quiet?: boolean;
4344
env: Dictionary<string>;
@@ -116,6 +117,7 @@ export default class Now extends EventEmitter {
116117
rootDirectory,
117118
wantsPublic,
118119
meta,
120+
gitMetadata,
119121
regions,
120122
quiet = false,
121123
env,
@@ -142,6 +144,7 @@ export default class Now extends EventEmitter {
142144
name,
143145
project,
144146
meta,
147+
gitMetadata,
145148
regions,
146149
target: target || undefined,
147150
projectSettings,

β€Žpackages/cli/src/util/output/create-output.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ export interface LogOptions extends PrintOptions {
1616
}
1717

1818
export class Output {
19-
private debugEnabled: boolean;
19+
debugEnabled: boolean;
2020
private spinnerMessage: string;
2121
private _spinner: StopSpinner | null;
2222
isTTY: boolean;

β€Žpackages/cli/test/fixtures/unit/create-git-meta/dirty/git/HEAD

+1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

β€Žpackages/cli/test/fixtures/unit/create-git-meta/dirty/git/config

+7
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

β€Žpackages/cli/test/fixtures/unit/create-git-meta/dirty/git/description

+1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

β€Žpackages/cli/test/fixtures/unit/create-git-meta/dirty/git/hooks/applypatch-msg.sample

+15
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

β€Žpackages/cli/test/fixtures/unit/create-git-meta/dirty/git/hooks/commit-msg.sample

+24
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
Β (0)