Rename folders
This commit is contained in:
@@ -0,0 +1,12 @@
|
||||
import {ActionReference, ActionOutputs} from "@github/actions-languageservice/action";
|
||||
import {Octokit} from "@octokit/rest";
|
||||
import {fetchActionMetadata} from "../utils/action-metadata";
|
||||
import {TTLCache} from "../utils/cache";
|
||||
|
||||
export async function getActionOutputs(
|
||||
octokit: Octokit,
|
||||
cache: TTLCache,
|
||||
action: ActionReference
|
||||
): Promise<ActionOutputs | undefined> {
|
||||
return (await fetchActionMetadata(octokit, cache, action))?.outputs;
|
||||
}
|
||||
@@ -0,0 +1,162 @@
|
||||
import {data, DescriptionDictionary} from "@github/actions-expressions";
|
||||
import {StringData} from "@github/actions-expressions/data/string";
|
||||
import {WorkflowContext} from "@github/actions-languageservice/context/workflow-context";
|
||||
import {isMapping, isString} from "@github/actions-workflow-parser";
|
||||
import {Octokit} from "@octokit/rest";
|
||||
import {RepositoryContext} from "../initializationOptions";
|
||||
import {TTLCache} from "../utils/cache";
|
||||
|
||||
export async function getSecrets(
|
||||
workflowContext: WorkflowContext,
|
||||
octokit: Octokit,
|
||||
cache: TTLCache,
|
||||
repo: RepositoryContext,
|
||||
defaultContext: DescriptionDictionary | undefined
|
||||
): Promise<DescriptionDictionary> {
|
||||
let environmentName: string | undefined;
|
||||
if (workflowContext?.job?.environment) {
|
||||
if (isString(workflowContext.job.environment)) {
|
||||
environmentName = workflowContext.job.environment.value;
|
||||
} else if (isMapping(workflowContext.job.environment)) {
|
||||
for (const x of workflowContext.job.environment) {
|
||||
if (isString(x.key) && x.key.value === "name") {
|
||||
if (isString(x.value)) {
|
||||
environmentName = x.value.value;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const secretsContext = defaultContext || new DescriptionDictionary();
|
||||
try {
|
||||
const secrets = await getRemoteSecrets(octokit, cache, repo, environmentName);
|
||||
|
||||
// Build combined map of secrets
|
||||
const secretsMap = new Map<
|
||||
string,
|
||||
{
|
||||
key: string;
|
||||
value: data.StringData;
|
||||
description?: string;
|
||||
}
|
||||
>();
|
||||
|
||||
secrets.orgSecrets.forEach(secret =>
|
||||
secretsMap.set(secret.value.toLowerCase(), {
|
||||
key: secret.value,
|
||||
value: new data.StringData("***"),
|
||||
description: "Organization secret"
|
||||
})
|
||||
);
|
||||
|
||||
// Override org secrets with repo secrets
|
||||
secrets.repoSecrets.forEach(secret =>
|
||||
secretsMap.set(secret.value.toLowerCase(), {
|
||||
key: secret.value,
|
||||
value: new data.StringData("***"),
|
||||
description: "Repository secret"
|
||||
})
|
||||
);
|
||||
|
||||
// Override repo secrets with environment secrets (if defined)
|
||||
secrets.environmentSecrets.forEach(secret =>
|
||||
secretsMap.set(secret.value.toLowerCase(), {
|
||||
key: secret.value,
|
||||
value: new data.StringData("***"),
|
||||
description: `Secret for environment \`${environmentName}\``
|
||||
})
|
||||
);
|
||||
|
||||
// Sort secrets by key and add to context
|
||||
Array.from(secretsMap.values())
|
||||
.sort((a, b) => a.key.localeCompare(b.key))
|
||||
.forEach(secret => secretsContext?.add(secret.key, secret.value, secret.description));
|
||||
} catch (e: any) {
|
||||
if (e.status === 403 || e.status === 404) {
|
||||
secretsContext.complete = false;
|
||||
}
|
||||
}
|
||||
return secretsContext;
|
||||
}
|
||||
|
||||
async function getRemoteSecrets(
|
||||
octokit: Octokit,
|
||||
cache: TTLCache,
|
||||
repo: RepositoryContext,
|
||||
environmentName?: string
|
||||
): Promise<{
|
||||
repoSecrets: StringData[];
|
||||
environmentSecrets: StringData[];
|
||||
orgSecrets: StringData[];
|
||||
}> {
|
||||
return {
|
||||
repoSecrets: await cache.get(`${repo.owner}/${repo.name}/secrets`, undefined, () =>
|
||||
fetchSecrets(octokit, repo.owner, repo.name)
|
||||
),
|
||||
environmentSecrets:
|
||||
(environmentName &&
|
||||
(await cache.get(`${repo.owner}/${repo.name}/secrets/environment/${environmentName}`, undefined, () =>
|
||||
fetchEnvironmentSecrets(octokit, repo.id, environmentName)
|
||||
))) ||
|
||||
[],
|
||||
orgSecrets: await cache.get(`${repo.owner}/secrets`, undefined, () => fetchOrganizationSecrets(octokit, repo))
|
||||
};
|
||||
}
|
||||
|
||||
async function fetchSecrets(octokit: Octokit, owner: string, name: string): Promise<StringData[]> {
|
||||
try {
|
||||
return await octokit.paginate(
|
||||
octokit.actions.listRepoSecrets,
|
||||
{
|
||||
owner,
|
||||
repo: name,
|
||||
per_page: 100
|
||||
},
|
||||
response => response.data.map(secret => new StringData(secret.name))
|
||||
);
|
||||
} catch (e) {
|
||||
console.log("Failure to retrieve secrets: ", e);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
async function fetchEnvironmentSecrets(
|
||||
octokit: Octokit,
|
||||
repositoryId: number,
|
||||
environmentName: string
|
||||
): Promise<StringData[]> {
|
||||
try {
|
||||
return await octokit.paginate(
|
||||
octokit.actions.listEnvironmentSecrets,
|
||||
{
|
||||
repository_id: repositoryId,
|
||||
environment_name: environmentName,
|
||||
per_page: 100
|
||||
},
|
||||
response => response.data.map(secret => new StringData(secret.name))
|
||||
);
|
||||
} catch (e) {
|
||||
console.log("Failure to retrieve environment secrets: ", e);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
async function fetchOrganizationSecrets(octokit: Octokit, repo: RepositoryContext): Promise<StringData[]> {
|
||||
if (!repo.organizationOwned) {
|
||||
return [];
|
||||
}
|
||||
|
||||
try {
|
||||
const secrets: {name: string}[] = await octokit.paginate("GET /repos/{owner}/{repo}/actions/organization-secrets", {
|
||||
owner: repo.owner,
|
||||
repo: repo.name,
|
||||
per_page: 100
|
||||
});
|
||||
return secrets.map(secret => new StringData(secret.name));
|
||||
} catch (e) {
|
||||
console.log("Failure to retrieve organization secrets: ", e);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,113 @@
|
||||
import {data, DescriptionDictionary} from "@github/actions-expressions";
|
||||
import {getStepsContext as getDefaultStepsContext} from "@github/actions-languageservice/context-providers/steps";
|
||||
import {Octokit} from "@octokit/rest";
|
||||
import fetchMock from "fetch-mock";
|
||||
|
||||
import {createWorkflowContext} from "../test-utils/workflow-context";
|
||||
import {TTLCache} from "../utils/cache";
|
||||
import {getStepsContext} from "./steps";
|
||||
|
||||
const workflow = `
|
||||
name: Caching Primes
|
||||
|
||||
on: push
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- name: Cache Primes
|
||||
id: cache-primes
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: prime-numbers
|
||||
key: \${{ runner.os }}-primes
|
||||
|
||||
- name: Generate Prime Numbers
|
||||
if: steps.cache-primes.outputs.cache-hit != 'true'
|
||||
run: /generate-primes.sh -d prime-numbers
|
||||
|
||||
- name: Use Prime Numbers
|
||||
run: /primes.sh -d prime-numbers
|
||||
`;
|
||||
|
||||
// https://api.github.com/repos/actions/cache/contents/action.yml?ref=v3
|
||||
const actionMetadata = {
|
||||
name: "action.yml",
|
||||
path: "action.yml",
|
||||
sha: "3e158e3ee33f7e597ccf45c369a6e830dc8d43e3",
|
||||
size: 946,
|
||||
url: "https://api.github.com/repos/actions/cache/contents/action.yml?ref=v3",
|
||||
html_url: "https://github.com/actions/cache/blob/v3/action.yml",
|
||||
git_url: "https://api.github.com/repos/actions/cache/git/blobs/3e158e3ee33f7e597ccf45c369a6e830dc8d43e3",
|
||||
download_url: "https://raw.githubusercontent.com/actions/cache/v3/action.yml",
|
||||
type: "file",
|
||||
content:
|
||||
"bmFtZTogJ0NhY2hlJwpkZXNjcmlwdGlvbjogJ0NhY2hlIGFydGlmYWN0cyBs\naWtlIGRlcGVuZGVuY2llcyBhbmQgYnVpbGQgb3V0cHV0cyB0byBpbXByb3Zl\nIHdvcmtmbG93IGV4ZWN1dGlvbiB0aW1lJwphdXRob3I6ICdHaXRIdWInCmlu\ncHV0czoKICBwYXRoOgogICAgZGVzY3JpcHRpb246ICdBIGxpc3Qgb2YgZmls\nZXMsIGRpcmVjdG9yaWVzLCBhbmQgd2lsZGNhcmQgcGF0dGVybnMgdG8gY2Fj\naGUgYW5kIHJlc3RvcmUnCiAgICByZXF1aXJlZDogdHJ1ZQogIGtleToKICAg\nIGRlc2NyaXB0aW9uOiAnQW4gZXhwbGljaXQga2V5IGZvciByZXN0b3Jpbmcg\nYW5kIHNhdmluZyB0aGUgY2FjaGUnCiAgICByZXF1aXJlZDogdHJ1ZQogIHJl\nc3RvcmUta2V5czoKICAgIGRlc2NyaXB0aW9uOiAnQW4gb3JkZXJlZCBsaXN0\nIG9mIGtleXMgdG8gdXNlIGZvciByZXN0b3Jpbmcgc3RhbGUgY2FjaGUgaWYg\nbm8gY2FjaGUgaGl0IG9jY3VycmVkIGZvciBrZXkuIE5vdGUgYGNhY2hlLWhp\ndGAgcmV0dXJucyBmYWxzZSBpbiB0aGlzIGNhc2UuJwogICAgcmVxdWlyZWQ6\nIGZhbHNlCiAgdXBsb2FkLWNodW5rLXNpemU6CiAgICBkZXNjcmlwdGlvbjog\nJ1RoZSBjaHVuayBzaXplIHVzZWQgdG8gc3BsaXQgdXAgbGFyZ2UgZmlsZXMg\nZHVyaW5nIHVwbG9hZCwgaW4gYnl0ZXMnCiAgICByZXF1aXJlZDogZmFsc2UK\nb3V0cHV0czoKICBjYWNoZS1oaXQ6CiAgICBkZXNjcmlwdGlvbjogJ0EgYm9v\nbGVhbiB2YWx1ZSB0byBpbmRpY2F0ZSBhbiBleGFjdCBtYXRjaCB3YXMgZm91\nbmQgZm9yIHRoZSBwcmltYXJ5IGtleScKcnVuczoKICB1c2luZzogJ25vZGUx\nNicKICBtYWluOiAnZGlzdC9yZXN0b3JlL2luZGV4LmpzJwogIHBvc3Q6ICdk\naXN0L3NhdmUvaW5kZXguanMnCiAgcG9zdC1pZjogJ3N1Y2Nlc3MoKScKYnJh\nbmRpbmc6CiAgaWNvbjogJ2FyY2hpdmUnCiAgY29sb3I6ICdncmF5LWRhcmsn\nCg==\n",
|
||||
encoding: "base64",
|
||||
_links: {
|
||||
self: "https://api.github.com/repos/actions/cache/contents/action.yml?ref=v3",
|
||||
git: "https://api.github.com/repos/actions/cache/git/blobs/3e158e3ee33f7e597ccf45c369a6e830dc8d43e3",
|
||||
html: "https://github.com/actions/cache/blob/v3/action.yml"
|
||||
}
|
||||
};
|
||||
|
||||
it("returns default context when job is undefined", async () => {
|
||||
const workflowContext = await createWorkflowContext(workflow, undefined);
|
||||
const defaultContext = getDefaultStepsContext(workflowContext);
|
||||
|
||||
const stepsContext = await getStepsContext(new Octokit(), new TTLCache(), defaultContext, workflowContext);
|
||||
expect(stepsContext).toEqual(defaultContext);
|
||||
});
|
||||
|
||||
it("adds action outputs", async () => {
|
||||
const mock = fetchMock
|
||||
.sandbox()
|
||||
.getOnce("https://api.github.com/repos/actions/cache/contents/action.yml?ref=v3", actionMetadata);
|
||||
|
||||
const workflowContext = await createWorkflowContext(workflow, "build");
|
||||
const defaultContext = getDefaultStepsContext(workflowContext);
|
||||
|
||||
const stepsContext = await getStepsContext(
|
||||
new Octokit({
|
||||
request: {
|
||||
fetch: mock
|
||||
}
|
||||
}),
|
||||
new TTLCache(),
|
||||
defaultContext,
|
||||
workflowContext
|
||||
);
|
||||
expect(stepsContext).toBeDefined();
|
||||
|
||||
expect(stepsContext).toEqual(
|
||||
new DescriptionDictionary({
|
||||
key: "cache-primes",
|
||||
value: new DescriptionDictionary(
|
||||
{
|
||||
key: "outputs",
|
||||
value: new DescriptionDictionary({
|
||||
key: "cache-hit",
|
||||
value: new data.StringData("A boolean value to indicate an exact match was found for the primary key"),
|
||||
description: "A boolean value to indicate an exact match was found for the primary key"
|
||||
})
|
||||
},
|
||||
{
|
||||
key: "conclusion",
|
||||
value: new data.Null(),
|
||||
description:
|
||||
"The result of a completed step after `continue-on-error` is applied. Possible values are `success`, `failure`, `cancelled`, or `skipped`. When a `continue-on-error` step fails, the `outcome` is `failure`, but the final conclusion is `success`."
|
||||
},
|
||||
{
|
||||
key: "outcome",
|
||||
value: new data.Null(),
|
||||
description:
|
||||
"The result of a completed step before `continue-on-error` is applied. Possible values are `success`, `failure`, `cancelled`, or `skipped`. When a `continue-on-error` step fails, the `outcome` is `failure`, but the final conclusion is `success`."
|
||||
}
|
||||
)
|
||||
})
|
||||
);
|
||||
});
|
||||
@@ -0,0 +1,74 @@
|
||||
import {data, DescriptionDictionary, isDescriptionDictionary} from "@github/actions-expressions";
|
||||
import {parseActionReference} from "@github/actions-languageservice/action";
|
||||
import {WorkflowContext} from "@github/actions-languageservice/context/workflow-context";
|
||||
import {isActionStep} from "@github/actions-workflow-parser/model/type-guards";
|
||||
import {Octokit} from "@octokit/rest";
|
||||
import {TTLCache} from "../utils/cache";
|
||||
import {getActionOutputs} from "./action-outputs";
|
||||
|
||||
export async function getStepsContext(
|
||||
octokit: Octokit,
|
||||
cache: TTLCache,
|
||||
defaultContext: DescriptionDictionary | undefined,
|
||||
workflowContext: WorkflowContext
|
||||
): Promise<DescriptionDictionary | undefined> {
|
||||
if (!defaultContext || !workflowContext.job) {
|
||||
return defaultContext;
|
||||
}
|
||||
|
||||
// The default context includes the set of valid
|
||||
// step ids that can be used in expressions
|
||||
const contextSteps = new Set<string>();
|
||||
for (const {key} of defaultContext.pairs()) {
|
||||
contextSteps.add(key);
|
||||
}
|
||||
|
||||
// Copy the default context for each step
|
||||
// If the step is an action, add the action outputs to the context
|
||||
const stepsContext = new DescriptionDictionary();
|
||||
for (const step of workflowContext.job.steps) {
|
||||
if (!contextSteps.has(step.id)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const defaultStepContext = defaultContext.get(step.id);
|
||||
if (!defaultStepContext) {
|
||||
stepsContext.add(step.id, new data.Null());
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!isActionStep(step) || !isDescriptionDictionary(defaultStepContext)) {
|
||||
stepsContext.add(step.id, defaultStepContext);
|
||||
continue;
|
||||
}
|
||||
|
||||
const action = parseActionReference(step.uses.value);
|
||||
if (!action) {
|
||||
stepsContext.add(step.id, defaultStepContext);
|
||||
continue;
|
||||
}
|
||||
|
||||
const stepContext = new DescriptionDictionary();
|
||||
for (const {key, value, description} of defaultStepContext.pairs()) {
|
||||
switch (key) {
|
||||
case "outputs":
|
||||
const outputs = await getActionOutputs(octokit, cache, action);
|
||||
if (!outputs) {
|
||||
stepContext.add(key, value, description);
|
||||
continue;
|
||||
}
|
||||
const outputsDict = new DescriptionDictionary();
|
||||
for (const [key, value] of Object.entries(outputs)) {
|
||||
outputsDict.add(key, new data.StringData(value.description), value.description);
|
||||
}
|
||||
stepContext.add("outputs", outputsDict);
|
||||
break;
|
||||
default:
|
||||
stepContext.add(key, value, description);
|
||||
}
|
||||
}
|
||||
stepsContext.add(step.id, stepContext);
|
||||
}
|
||||
|
||||
return stepsContext;
|
||||
}
|
||||
@@ -0,0 +1,177 @@
|
||||
import {data, DescriptionDictionary} from "@github/actions-expressions";
|
||||
import {WorkflowContext} from "@github/actions-languageservice/context/workflow-context";
|
||||
import {isMapping, isString} from "@github/actions-workflow-parser";
|
||||
import {Octokit} from "@octokit/rest";
|
||||
import {Pair} from "@github/actions-expressions/data/expressiondata";
|
||||
import {RepositoryContext} from "../initializationOptions";
|
||||
import {StringData} from "@github/actions-expressions/data/index";
|
||||
import {TTLCache} from "../utils/cache";
|
||||
|
||||
export async function getVariables(
|
||||
workflowContext: WorkflowContext,
|
||||
octokit: Octokit,
|
||||
cache: TTLCache,
|
||||
repo: RepositoryContext,
|
||||
defaultContext: DescriptionDictionary | undefined
|
||||
): Promise<DescriptionDictionary | undefined> {
|
||||
let environmentName: string | undefined;
|
||||
if (workflowContext?.job?.environment) {
|
||||
if (isString(workflowContext.job.environment)) {
|
||||
environmentName = workflowContext.job.environment.value;
|
||||
} else if (isMapping(workflowContext.job.environment)) {
|
||||
for (const x of workflowContext.job.environment) {
|
||||
if (isString(x.key) && x.key.value === "name") {
|
||||
if (isString(x.value)) {
|
||||
environmentName = x.value.value;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const variablesContext = defaultContext || new DescriptionDictionary();
|
||||
try {
|
||||
const variables = await getRemoteVariables(octokit, cache, repo, environmentName);
|
||||
|
||||
// Build combined map of variables
|
||||
const variablesMap = new Map<
|
||||
string,
|
||||
{
|
||||
key: string;
|
||||
value: data.StringData;
|
||||
description?: string;
|
||||
}
|
||||
>();
|
||||
|
||||
variables.organizationVariables.forEach(variable =>
|
||||
variablesMap.set(variable.key.toLowerCase(), {
|
||||
key: variable.key,
|
||||
value: new data.StringData(variable.value.coerceString()),
|
||||
description: `${variable.value.coerceString()} - Organization variable`
|
||||
})
|
||||
);
|
||||
|
||||
// Override org variables with repo variables
|
||||
variables.repoVariables.forEach(variable =>
|
||||
variablesMap.set(variable.key.toLowerCase(), {
|
||||
key: variable.key,
|
||||
value: new data.StringData(variable.value.coerceString()),
|
||||
description: `${variable.value.coerceString()} - Repository variable`
|
||||
})
|
||||
);
|
||||
|
||||
// Override repo variables with environment veriables (if defined)
|
||||
variables.environmentVariables.forEach(variable =>
|
||||
variablesMap.set(variable.key.toLowerCase(), {
|
||||
key: variable.key,
|
||||
value: new data.StringData(variable.value.coerceString()),
|
||||
description: `${variable.value.coerceString()} - Variable for environment \`${environmentName}\``
|
||||
})
|
||||
);
|
||||
|
||||
// Sort variables by key and add to context
|
||||
Array.from(variablesMap.values())
|
||||
.sort((a, b) => a.key.localeCompare(b.key))
|
||||
.forEach(variable => variablesContext?.add(variable.key, variable.value, variable.description));
|
||||
} catch (e: any) {
|
||||
if (e.status === 403 || e.status === 404) {
|
||||
variablesContext.complete = false;
|
||||
}
|
||||
}
|
||||
return variablesContext;
|
||||
}
|
||||
|
||||
export async function getRemoteVariables(
|
||||
octokit: Octokit,
|
||||
cache: TTLCache,
|
||||
repo: RepositoryContext,
|
||||
environmentName?: string
|
||||
): Promise<{
|
||||
repoVariables: Pair[];
|
||||
environmentVariables: Pair[];
|
||||
organizationVariables: Pair[];
|
||||
}> {
|
||||
// Repo variables
|
||||
return {
|
||||
repoVariables: await cache.get(`${repo.owner}/${repo.name}/vars`, undefined, () =>
|
||||
fetchVariables(octokit, repo.owner, repo.name)
|
||||
),
|
||||
environmentVariables:
|
||||
(environmentName &&
|
||||
(await cache.get(`${repo.owner}/${repo.name}/vars/environment/${environmentName}`, undefined, () =>
|
||||
fetchEnvironmentVariables(octokit, repo.id, environmentName)
|
||||
))) ||
|
||||
[],
|
||||
organizationVariables: await cache.get(`${repo.owner}/vars`, undefined, () =>
|
||||
fetchOrganizationVariables(octokit, repo)
|
||||
)
|
||||
};
|
||||
}
|
||||
|
||||
async function fetchVariables(octokit: Octokit, owner: string, name: string): Promise<Pair[]> {
|
||||
try {
|
||||
return await octokit.paginate(
|
||||
octokit.actions.listRepoVariables,
|
||||
{
|
||||
owner: owner,
|
||||
repo: name,
|
||||
per_page: 100
|
||||
},
|
||||
response =>
|
||||
response.data.map(variable => {
|
||||
return {key: variable.name, value: new StringData(variable.value)};
|
||||
})
|
||||
);
|
||||
} catch (e) {
|
||||
console.log("Failure to retrieve variables: ", e);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
async function fetchEnvironmentVariables(
|
||||
octokit: Octokit,
|
||||
repositoryId: number,
|
||||
environmentName: string
|
||||
): Promise<Pair[]> {
|
||||
try {
|
||||
return await octokit.paginate(
|
||||
octokit.actions.listEnvironmentVariables,
|
||||
{
|
||||
repository_id: repositoryId,
|
||||
environment_name: environmentName,
|
||||
per_page: 100
|
||||
},
|
||||
response =>
|
||||
response.data.map(variable => {
|
||||
return {key: variable.name, value: new StringData(variable.value)};
|
||||
})
|
||||
);
|
||||
} catch (e) {
|
||||
console.log("Failure to retrieve environment variables: ", e);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
async function fetchOrganizationVariables(octokit: Octokit, repo: RepositoryContext): Promise<Pair[]> {
|
||||
if (!repo.organizationOwned) {
|
||||
return [];
|
||||
}
|
||||
|
||||
try {
|
||||
const variables: {name: string; value: string}[] = await octokit.paginate(
|
||||
"GET /repos/{owner}/{repo}/actions/organization-variables",
|
||||
{
|
||||
owner: repo.owner,
|
||||
repo: repo.name,
|
||||
per_page: 100
|
||||
}
|
||||
);
|
||||
return variables.map(variable => {
|
||||
return {key: variable.name, value: new StringData(variable.value)};
|
||||
});
|
||||
} catch (e) {
|
||||
console.log("Failure to retrieve organization variables: ", e);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user