Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(gh-85): take git tokens from env variables at first #88

Merged
merged 1 commit into from
Dec 10, 2023
Merged
Show file tree
Hide file tree
Changes from all 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
17 changes: 15 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ This tool comes with some inputs that allow users to override the default behavi
| Target Branches | -tb, --target-branch | N | Comma separated list of branches where the changes must be backported to | |
| Pull Request | -pr, --pull-request | N | Original pull request url, the one that must be backported, e.g., https://github.com/kiegroup/git-backporting/pull/1 | |
| Configuration File | -cf, --config-file | N | Configuration file, in JSON format, containing all options to be overridded, note that if provided all other CLI options will be ignored | |
| Auth | -a, --auth | N | `GITHUB_TOKEN`, `GITLAB_TOKEN` or a `repo` scoped [Personal Access Token](https://docs.github.com/en/github/authenticating-to-github/creating-a-personal-access-token) | "" |
| Auth | -a, --auth | N | Git access/authorization token, if provided all token env variables will be ignored. See [auth token](#authorization-token) section for more details | "" |
| Folder | -f, --folder | N | Local folder full name of the repository that will be checked out, e.g., /tmp/folder | {cwd}/bp |
| Git User | -gu, --git-user | N | Local git user name | "GitHub" |
| Git Email | -ge, --git-email | N | Local git user email | "noreply@github.com" |
Expand All @@ -118,6 +118,17 @@ This tool comes with some inputs that allow users to override the default behavi

> **NOTE**: `pull request` and `target branch` are *mandatory*, they must be provided as CLI options or as part of the configuration file (if used).

#### Authorization token

Since version `4.5.0` we introduced a new feature that allows user to provide the git access token through environment variables. These env variables are taken into consideration only if the `--auth/-a` is not provided as argument/input.
Here the supported list of env variables:
- `GITHUB_TOKEN`: this is checked only if backporting on Github platform.
- `GITLAB_TOKEN`: this is checked only if backporting on Gitlab platform.
- `CODEBERG_TOKEN`: this is checked only if backporting on Codeberg platform.
- `GIT_TOKEN`: this is considered if none of the previous envs are set.

> **NOTE**: if `--auth` argument is provided, all env variables will be ignored even if not empty.

#### Configuration file example

This is an example of a configuration file that can be used.
Expand Down Expand Up @@ -194,6 +205,9 @@ on:
- closed
- labeled

env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

jobs:
backporting:
name: "Backporting"
Expand All @@ -216,7 +230,6 @@ jobs:
with:
target-branch: v1
pull-request: ${{ github.event.pull_request.url }}
auth: ${{ secrets.GITHUB_TOKEN }}
```

For a complete description of all inputs see [Inputs section](#inputs).
Expand Down
2 changes: 1 addition & 1 deletion action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ inputs:
required: false
default: "false"
auth:
description: "GITHUB_TOKEN or a `repo` scoped Personal Access Token (PAT)"
description: "GITHUB_TOKEN or a `repo` scoped Personal Access Token (PAT), if not provided will look for existing env variables like GITHUB_TOKEN"
default: ${{ github.token }}
required: false
git-user:
Expand Down
85 changes: 81 additions & 4 deletions dist/cli/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,7 @@ class CLIArgsParser extends args_parser_1.default {
.option("-tb, --target-branch <branches>", "comma separated list of branches where changes must be backported to")
.option("-pr, --pull-request <pr-url>", "pull request url, e.g., https://github.com/kiegroup/git-backporting/pull/1")
.option("-d, --dry-run", "if enabled the tool does not create any pull request nor push anything remotely")
.option("-a, --auth <auth>", "git service authentication string, e.g., github token")
.option("-a, --auth <auth>", "git authentication string, if not provided fallback by looking for existing env variables like GITHUB_TOKEN")
.option("-gu, --git-user <git-user>", "local git user name, default is 'GitHub'")
.option("-ge, --git-email <git-email>", "local git user email, default is 'noreply@github.com'")
.option("-f, --folder <folder>", "local folder where the repo will be checked out, e.g., /tmp/folder")
Expand Down Expand Up @@ -251,7 +251,9 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", ({ value: true }));
const configs_types_1 = __nccwpck_require__(4753);
const logger_service_factory_1 = __importDefault(__nccwpck_require__(8936));
const git_types_1 = __nccwpck_require__(750);
/**
* Abstract configuration parser class in charge to parse
* Args and produces a common Configs object
Expand All @@ -273,10 +275,68 @@ class ConfigsParser {
}
return Promise.resolve(configs);
}
/**
* Retrieve the git token from env variable, the default is taken from GIT_TOKEN env.
* All specific git env variable have precedence and override the default one.
* @param gitType
* @returns tuple where
* - the first element is the corresponding env value
* - the second element is true if the value is not undefined nor empty
*/
getGitTokenFromEnv(gitType) {
let [token] = this.getEnv(configs_types_1.AuthTokenId.GIT_TOKEN);
let [specToken, specOk] = [undefined, false];
if (git_types_1.GitClientType.GITHUB == gitType) {
[specToken, specOk] = this.getEnv(configs_types_1.AuthTokenId.GITHUB_TOKEN);
}
else if (git_types_1.GitClientType.GITLAB == gitType) {
[specToken, specOk] = this.getEnv(configs_types_1.AuthTokenId.GITLAB_TOKEN);
}
else if (git_types_1.GitClientType.CODEBERG == gitType) {
[specToken, specOk] = this.getEnv(configs_types_1.AuthTokenId.CODEBERG_TOKEN);
}
if (specOk) {
token = specToken;
}
return token;
}
/**
* Get process env variable given the input key string
* @param key
* @returns tuple where
* - the first element is the corresponding env value
* - the second element is true if the value is not undefined nor empty
*/
getEnv(key) {
const val = process.env[key];
return [val, val !== undefined && val !== ""];
}
}
exports["default"] = ConfigsParser;


/***/ }),

/***/ 4753:
/***/ ((__unused_webpack_module, exports) => {

"use strict";

Object.defineProperty(exports, "__esModule", ({ value: true }));
exports.AuthTokenId = void 0;
var AuthTokenId;
(function (AuthTokenId) {
// github specific token
AuthTokenId["GITHUB_TOKEN"] = "GITHUB_TOKEN";
// gitlab specific token
AuthTokenId["GITLAB_TOKEN"] = "GITLAB_TOKEN";
// codeberg specific token
AuthTokenId["CODEBERG_TOKEN"] = "CODEBERG_TOKEN";
// generic git token
AuthTokenId["GIT_TOKEN"] = "GIT_TOKEN";
})(AuthTokenId = exports.AuthTokenId || (exports.AuthTokenId = {}));


/***/ }),

/***/ 6618:
Expand Down Expand Up @@ -311,9 +371,18 @@ class PullRequestConfigsParser extends configs_parser_1.default {
if (bpBranchNames.length > 1 && bpBranchNames.length != targetBranches.length) {
throw new Error(`The number of backport branch names, if provided, must match the number of target branches or just one, provided ${bpBranchNames.length} branch names instead`);
}
// setup the auth token
let token = args.auth;
if (token === undefined) {
this.logger.info("Auth argument not provided, checking available tokens from env..");
token = this.getGitTokenFromEnv(this.gitClient.getClientType());
if (!token) {
this.logger.info("Git token not set in the env");
}
}
return {
dryRun: args.dryRun,
auth: args.auth,
auth: token,
folder: `${folder.startsWith("/") ? "" : process.cwd() + "/"}${args.folder ?? this.getDefaultFolder()}`,
mergeStrategy: args.strategy,
mergeStrategyOption: args.strategyOption,
Expand Down Expand Up @@ -567,7 +636,7 @@ class GitClientFactory {
GitClientFactory.instance = new gitlab_client_1.default(authToken, apiUrl);
break;
case git_types_1.GitClientType.CODEBERG:
GitClientFactory.instance = new github_client_1.default(authToken, apiUrl);
GitClientFactory.instance = new github_client_1.default(authToken, apiUrl, true);
break;
default:
throw new Error(`Invalid git service type received: ${type}`);
Expand Down Expand Up @@ -673,12 +742,16 @@ const github_mapper_1 = __importDefault(__nccwpck_require__(5764));
const octokit_factory_1 = __importDefault(__nccwpck_require__(4257));
const logger_service_factory_1 = __importDefault(__nccwpck_require__(8936));
class GitHubClient {
constructor(token, apiUrl) {
constructor(token, apiUrl, isForCodeberg = false) {
this.apiUrl = apiUrl;
this.isForCodeberg = isForCodeberg;
this.logger = logger_service_factory_1.default.getLogger();
this.octokit = octokit_factory_1.default.getOctokit(token, this.apiUrl);
this.mapper = new github_mapper_1.default();
}
getClientType() {
return this.isForCodeberg ? git_types_1.GitClientType.CODEBERG : git_types_1.GitClientType.GITHUB;
}
// READ
getDefaultGitUser() {
return this.apiUrl.includes(git_types_1.GitClientType.CODEBERG.toString()) ? "Codeberg" : "GitHub";
Expand Down Expand Up @@ -889,6 +962,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", ({ value: true }));
const git_types_1 = __nccwpck_require__(750);
const logger_service_factory_1 = __importDefault(__nccwpck_require__(8936));
const gitlab_mapper_1 = __importDefault(__nccwpck_require__(2675));
const axios_1 = __importDefault(__nccwpck_require__(8757));
Expand All @@ -909,6 +983,9 @@ class GitLabClient {
});
this.mapper = new gitlab_mapper_1.default(this.client);
}
getClientType() {
return git_types_1.GitClientType.GITLAB;
}
getDefaultGitUser() {
return "Gitlab";
}
Expand Down
83 changes: 80 additions & 3 deletions dist/gha/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -221,7 +221,9 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", ({ value: true }));
const configs_types_1 = __nccwpck_require__(4753);
const logger_service_factory_1 = __importDefault(__nccwpck_require__(8936));
const git_types_1 = __nccwpck_require__(750);
/**
* Abstract configuration parser class in charge to parse
* Args and produces a common Configs object
Expand All @@ -243,10 +245,68 @@ class ConfigsParser {
}
return Promise.resolve(configs);
}
/**
* Retrieve the git token from env variable, the default is taken from GIT_TOKEN env.
* All specific git env variable have precedence and override the default one.
* @param gitType
* @returns tuple where
* - the first element is the corresponding env value
* - the second element is true if the value is not undefined nor empty
*/
getGitTokenFromEnv(gitType) {
let [token] = this.getEnv(configs_types_1.AuthTokenId.GIT_TOKEN);
let [specToken, specOk] = [undefined, false];
if (git_types_1.GitClientType.GITHUB == gitType) {
[specToken, specOk] = this.getEnv(configs_types_1.AuthTokenId.GITHUB_TOKEN);
}
else if (git_types_1.GitClientType.GITLAB == gitType) {
[specToken, specOk] = this.getEnv(configs_types_1.AuthTokenId.GITLAB_TOKEN);
}
else if (git_types_1.GitClientType.CODEBERG == gitType) {
[specToken, specOk] = this.getEnv(configs_types_1.AuthTokenId.CODEBERG_TOKEN);
}
if (specOk) {
token = specToken;
}
return token;
}
/**
* Get process env variable given the input key string
* @param key
* @returns tuple where
* - the first element is the corresponding env value
* - the second element is true if the value is not undefined nor empty
*/
getEnv(key) {
const val = process.env[key];
return [val, val !== undefined && val !== ""];
}
}
exports["default"] = ConfigsParser;


/***/ }),

/***/ 4753:
/***/ ((__unused_webpack_module, exports) => {

"use strict";

Object.defineProperty(exports, "__esModule", ({ value: true }));
exports.AuthTokenId = void 0;
var AuthTokenId;
(function (AuthTokenId) {
// github specific token
AuthTokenId["GITHUB_TOKEN"] = "GITHUB_TOKEN";
// gitlab specific token
AuthTokenId["GITLAB_TOKEN"] = "GITLAB_TOKEN";
// codeberg specific token
AuthTokenId["CODEBERG_TOKEN"] = "CODEBERG_TOKEN";
// generic git token
AuthTokenId["GIT_TOKEN"] = "GIT_TOKEN";
})(AuthTokenId = exports.AuthTokenId || (exports.AuthTokenId = {}));


/***/ }),

/***/ 6618:
Expand Down Expand Up @@ -281,9 +341,18 @@ class PullRequestConfigsParser extends configs_parser_1.default {
if (bpBranchNames.length > 1 && bpBranchNames.length != targetBranches.length) {
throw new Error(`The number of backport branch names, if provided, must match the number of target branches or just one, provided ${bpBranchNames.length} branch names instead`);
}
// setup the auth token
let token = args.auth;
if (token === undefined) {
this.logger.info("Auth argument not provided, checking available tokens from env..");
token = this.getGitTokenFromEnv(this.gitClient.getClientType());
if (!token) {
this.logger.info("Git token not set in the env");
}
}
return {
dryRun: args.dryRun,
auth: args.auth,
auth: token,
folder: `${folder.startsWith("/") ? "" : process.cwd() + "/"}${args.folder ?? this.getDefaultFolder()}`,
mergeStrategy: args.strategy,
mergeStrategyOption: args.strategyOption,
Expand Down Expand Up @@ -537,7 +606,7 @@ class GitClientFactory {
GitClientFactory.instance = new gitlab_client_1.default(authToken, apiUrl);
break;
case git_types_1.GitClientType.CODEBERG:
GitClientFactory.instance = new github_client_1.default(authToken, apiUrl);
GitClientFactory.instance = new github_client_1.default(authToken, apiUrl, true);
break;
default:
throw new Error(`Invalid git service type received: ${type}`);
Expand Down Expand Up @@ -643,12 +712,16 @@ const github_mapper_1 = __importDefault(__nccwpck_require__(5764));
const octokit_factory_1 = __importDefault(__nccwpck_require__(4257));
const logger_service_factory_1 = __importDefault(__nccwpck_require__(8936));
class GitHubClient {
constructor(token, apiUrl) {
constructor(token, apiUrl, isForCodeberg = false) {
this.apiUrl = apiUrl;
this.isForCodeberg = isForCodeberg;
this.logger = logger_service_factory_1.default.getLogger();
this.octokit = octokit_factory_1.default.getOctokit(token, this.apiUrl);
this.mapper = new github_mapper_1.default();
}
getClientType() {
return this.isForCodeberg ? git_types_1.GitClientType.CODEBERG : git_types_1.GitClientType.GITHUB;
}
// READ
getDefaultGitUser() {
return this.apiUrl.includes(git_types_1.GitClientType.CODEBERG.toString()) ? "Codeberg" : "GitHub";
Expand Down Expand Up @@ -859,6 +932,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", ({ value: true }));
const git_types_1 = __nccwpck_require__(750);
const logger_service_factory_1 = __importDefault(__nccwpck_require__(8936));
const gitlab_mapper_1 = __importDefault(__nccwpck_require__(2675));
const axios_1 = __importDefault(__nccwpck_require__(8757));
Expand All @@ -879,6 +953,9 @@ class GitLabClient {
});
this.mapper = new gitlab_mapper_1.default(this.client);
}
getClientType() {
return git_types_1.GitClientType.GITLAB;
}
getDefaultGitUser() {
return "Gitlab";
}
Expand Down
2 changes: 1 addition & 1 deletion src/service/args/cli/cli-args-parser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ export default class CLIArgsParser extends ArgsParser {
.option("-tb, --target-branch <branches>", "comma separated list of branches where changes must be backported to")
.option("-pr, --pull-request <pr-url>", "pull request url, e.g., https://github.com/kiegroup/git-backporting/pull/1")
.option("-d, --dry-run", "if enabled the tool does not create any pull request nor push anything remotely")
.option("-a, --auth <auth>", "git service authentication string, e.g., github token")
.option("-a, --auth <auth>", "git authentication string, if not provided fallback by looking for existing env variables like GITHUB_TOKEN")
.option("-gu, --git-user <git-user>", "local git user name, default is 'GitHub'")
.option("-ge, --git-email <git-email>", "local git user email, default is 'noreply@github.com'")
.option("-f, --folder <folder>", "local folder where the repo will be checked out, e.g., /tmp/folder")
Expand Down
Loading