Skip to content

Commit

Permalink
feat(gh-85): take git tokens from environment (#88)
Browse files Browse the repository at this point in the history
  • Loading branch information
lampajr committed Dec 10, 2023
1 parent aac73bf commit 70da575
Show file tree
Hide file tree
Showing 17 changed files with 456 additions and 24 deletions.
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

0 comments on commit 70da575

Please sign in to comment.