Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 10 additions & 3 deletions DOCUMENTATION.md
Original file line number Diff line number Diff line change
Expand Up @@ -214,9 +214,16 @@ A Git profile contains:

- **name** – unique identifier for the profile
- **repository** – the GitHub repository in the format `owner/repo`
- **authenticationType** – either `SSH` or `PAT` (Personal Access Token)
- **username** – optional username (only for token authentication)
- **token** – Personal Access Token (if `PAT` is selected)
- **authenticationType** – either `SSH` or `HTTPS`
- **username** – optional username (used for commit authoring)

#### Authentication
The authentication is delegated your local Git configuration, based on the selected method (SSH or HTTPS).

Besides profile authentication, the git related commands can also be set up in pipelines via the following environment variables:
- GIT_REPOSITORY – the GitHub repository in the format `owner/repo`
- GIT_TOKEN – a GitHub personal access token with `repo` scope (for HTTPS authentication)
- GIT_USERNAME – username (used for commit authoring)

#### When to create a Git profile
A Git profile should be created to represent of Github repository and Github user credentials you want to use for interacting with content.
Expand Down
9 changes: 5 additions & 4 deletions docs/internal-architecture.md
Original file line number Diff line number Diff line change
Expand Up @@ -73,14 +73,15 @@ A git profile includes:
- **Name** – the profile identifier
- **Repository** – the Github repository in the format `owner/repository`
- **Authentication** – either:
- **Personal Access Token (PAT)** for HTTPS-based authentication
- **SSH key** for SSH-based authentication
- **Username** (optional, used with PATs)
- **HTTPS** uses HTTPS-based authentication
- **SSH** uses SSH-based authentication
- **Username** (optional, used for commit authoring)

### Implementation

- Credentials are fetched from the active Git profile stored in a local directory
and translated into an authenticated Github repository URL.
and then based on the authentication method a Git URL is constructed, which delegates authentication
to the local Git configuration (SSH keys or credential helpers).
- Git operations are executed via [`simple-git`](https://github.com/steveukx/git-js).
- Temporary working directories are created when pulling/pushing, ensuring isolation and cleanup.

Expand Down
5 changes: 2 additions & 3 deletions src/commands/git-profile/git-profile-command.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,10 @@ export class GitProfileCommandService {
profile.name = await questions.ask("Name of the Git profile to create: ");
profile.username = await questions.ask("Your Git username: ");
profile.repository = await questions.ask("Your repository (format: repoOwner/repoName): ");
const type = await questions.ask("Authentication type: PAT (1), SSH token (2): " );
const type = await questions.ask("Authentication type: HTTPS (1), SSH token (2): " );
switch (type) {
case "1":
profile.authenticationType = AuthenticationType.PAT;
profile.token = await questions.ask("Your Personal Access Token (PAT): " );
profile.authenticationType = AuthenticationType.HTTPS;
break;
case "2":
profile.authenticationType = AuthenticationType.SSH;
Expand Down
1 change: 1 addition & 0 deletions src/content-cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ program.configureHelp({
program.version(VersionUtils.getCurrentCliVersion());
program.option("-q, --quietmode", "Reduce output to a minimum", false);
program.option("-p, --profile [profile]");
program.option("--gitProfile [gitProfile]", "Git profile to use");
program.option("--debug", "Print debug messages", false);
program.option("--dev", "Development Mode", false);
program.parseOptions(process.argv);
Expand Down
6 changes: 3 additions & 3 deletions src/core/git-profile/git-profile.interface.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
export interface GitProfile {
name: string;
username?: string;
repository: string; // in the format "owner/repository"
token?: string;
repository: string; // in the format "owner/repository"
authenticationType: AuthenticationType;
}

export type AuthenticationType = "SSH" | "Personal Access Token";
export type AuthenticationType = "SSH" | "HTTPS";

// tslint:disable-next-line:variable-name
export const AuthenticationType: { [key: string]: AuthenticationType } = {
SSH: "SSH",
PAT: "Personal Access Token",
HTTPS: "HTTPS",
};
15 changes: 8 additions & 7 deletions src/core/git-profile/git-profile.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ export class GitProfileService {

public async findProfile(profileName: string): Promise<GitProfile> {
return new Promise<GitProfile>((resolve, reject) => {
if (process.env.USERNAME && process.env.GIT_TOKEN && process.env.REPOSITORY) {
if (process.env.GIT_USERNAME && process.env.GIT_TOKEN && process.env.GIT_REPOSITORY) {
resolve(this.buildProfileFromEnvVariables());
} else {
if (!profileName) {
Expand All @@ -42,7 +42,7 @@ export class GitProfileService {
resolve(profile);
})
.catch(err => {
logger.error(new FatalError("Git Profile does not exit."));
logger.error(new FatalError("Git Profile does not exist."));
reject(err);
});
});
Expand All @@ -68,10 +68,11 @@ export class GitProfileService {
private async buildProfileFromEnvVariables(): Promise<GitProfile> {
const profileVariables = this.getProfileEnvVariables();
const profile: GitProfile = {
name: profileVariables.repository,
name: "env-profile",
username: profileVariables.username,
repository: profileVariables.repository,
token: profileVariables.apiToken,
authenticationType: AuthenticationType.SSH,
token: profileVariables.token,
authenticationType: AuthenticationType.HTTPS,
};
profile.authenticationType = await GitProfileValidator.validateProfile(profile);
return profile;
Expand Down Expand Up @@ -112,9 +113,9 @@ export class GitProfileService {

private getProfileEnvVariables(): any {
return {
username: process.env.USERNAME,
username: process.env.GIT_USERNAME,
token: process.env.GIT_TOKEN,
repository: process.env.REPOSITORY,
repository: process.env.GIT_REPOSITORY,
};
}
}
3 changes: 0 additions & 3 deletions src/core/git-profile/git-profile.validator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,5 @@ export class GitProfileValidator {
if (gitProfile.authenticationType == null) {
logger.error(new FatalError("The authentication type can not be empty"));
}
if (gitProfile.authenticationType === AuthenticationType.PAT && gitProfile.token == null) {
logger.error(new FatalError("The token can not be empty for authentication with PAT"));
}
}
}
9 changes: 6 additions & 3 deletions src/core/git-profile/git/git.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -97,9 +97,12 @@ export class GitService {
return `git@github.com:${repository}.git`;
}

const safeUsername = encodeURIComponent(username ?? "git");
const safeToken = encodeURIComponent(token);
return `https://${safeUsername}:${safeToken}@github.com/${repository}.git`;
if (token) {
const safeUsername = encodeURIComponent(username ?? "git");
const safeToken = encodeURIComponent(token);
return `https://${safeUsername}:${safeToken}@github.com/${repository}.git`;
}
return `https://github.com/${repository}.git`;
}

private cleanupGitDirectory(repoDirectory: string): void {
Expand Down
Loading