gitlab-api-async-iterator
Advanced tools
Comparing version 1.0.0 to 1.1.0
@@ -17,2 +17,3 @@ const axios = require("axios"); | ||
const waitBeforeRetry = async (error, retries) => { | ||
// Be forgiving if we hit server errors or rate limits and retry after some time | ||
if ( | ||
@@ -23,18 +24,37 @@ error && | ||
) { | ||
if (error.response.headers && error.response.headers["ratelimit-reset"]) { | ||
const wait = | ||
parseInt(error.response.headers["ratelimit-reset"], 10) * 1000 - | ||
new Date().getTime(); | ||
let wait; | ||
console.warn( | ||
`Got a status code of ${error.response.status} and Retry-After. Waiting until ${error.response.headers["ratelimit-resettime"]} (${wait} ms)` | ||
); | ||
await timeout(wait); | ||
} else { | ||
const wait = 2 ** retries * 100; | ||
console.warn( | ||
`Got a status code of ${error.response.status}. Retry #${retries}. Waiting ${wait} ms` | ||
); | ||
await timeout(wait); | ||
const log = [`Got a status code of ${error.response.status}.`]; | ||
if (error.response.headers) { | ||
try { | ||
const { | ||
"ratelimit-reset": rateLimitReset, | ||
"ratelimit-resettime": rateLimitResetTime, | ||
"retry-after": retryAfter, | ||
} = error.response.headers; | ||
if (rateLimitReset) { | ||
wait = parseInt(rateLimitReset, 10) * 1000 - new Date().getTime(); | ||
log.push( | ||
`Found a ratelimit-reset header, waiting until ${rateLimitResetTime}.` | ||
); | ||
} | ||
if (retryAfter) { | ||
wait = parseInt(retryAfter, 10) * 1000; | ||
log.push(`Found a retry-after header (${retryAfter}).`); | ||
} | ||
} catch (e) {} | ||
} | ||
if (!wait) { | ||
wait = 2 ** retries * 100; | ||
} | ||
log.push(`Waiting ${wait} ms`); | ||
console.warn(log.join(" ")); | ||
await timeout(wait); | ||
return retries + 1; | ||
@@ -46,2 +66,7 @@ } else { | ||
const getTokenFromProcess = () => | ||
process && | ||
process.env && | ||
(process.env.GITLAB_TOKEN || process.env.DANGER_GITLAB_API_TOKEN); | ||
const GitLabAPIFactory = (options = {}) => { | ||
@@ -55,6 +80,3 @@ const { | ||
if ( | ||
!privateToken && | ||
!(process.env.GITLAB_TOKEN || process.env.DANGER_GITLAB_API_TOKEN) | ||
) { | ||
if (!privateToken && !getTokenFromProcess()) { | ||
throw new Error( | ||
@@ -72,6 +94,3 @@ "Please provide a GitLab token as an ENV variable via GITLAB_TOKEN or DANGER_GITLAB_API_TOKEN" | ||
...headers, | ||
"PRIVATE-TOKEN": | ||
privateToken || | ||
process.env.GITLAB_TOKEN || | ||
process.env.DANGER_GITLAB_API_TOKEN, | ||
"PRIVATE-TOKEN": privateToken || getTokenFromProcess(), | ||
}, | ||
@@ -78,0 +97,0 @@ }); |
{ | ||
"name": "gitlab-api-async-iterator", | ||
"version": "1.0.0", | ||
"description": "Async iterator for GitLab API", | ||
"version": "1.1.0", | ||
"description": "Async iterator for GitLab API based on axios", | ||
"keywords": [ | ||
"gitlab" | ||
"gitlab", | ||
"api", | ||
"async", | ||
"iterator" | ||
], | ||
@@ -19,3 +22,3 @@ "author": "Lukas Eipert <git@leipert.io>", | ||
"url": "https://gitlab.com/leipert-projects/npm-packages.git", | ||
"directory": "scoped/gitlab-spec-failures" | ||
"directory": "packages/gitlab-api-async-iterator" | ||
}, | ||
@@ -31,3 +34,3 @@ "scripts": { | ||
}, | ||
"gitHead": "e1df79b5d47c0841628a74c6c883bf34d3b1bcca" | ||
"gitHead": "3bc01ef8097e96e0a72521d49e3b4426fd0a45de" | ||
} |
109
README.md
# `gitlab-api-async-iterator` | ||
> TODO: description | ||
> Async iterator for GitLab API based on axios | ||
## Usage | ||
This module exposes a factory for creating async iterators for GitLab APIs. | ||
This allows to use APIs pretty efficiently (code-wise). | ||
It has a built-in retry feature in case you hit one of the following API errors: [429, 500, 502, 503, 504] | ||
### Instantiation | ||
```js | ||
// es6 / webpack | ||
import factory from "gitlab-api-async-iterator"; | ||
// node | ||
const factory = require("gitlab-api-async-iterator"); | ||
const { GitlabAPI, GitLabAPIIterator } = factory({ | ||
//default values | ||
baseURL: "https://gitlab.com/api/v4/", | ||
// If no token is defined, it tries to read process.env.GITLAB_TOKEN || process.env.DANGER_GITLAB_API_TOKEN | ||
privateToken: null, | ||
// How often certain failing requests are retried | ||
maxRetries: 5, | ||
// You can supply other options which would be provided to axios.create: | ||
// https://github.com/axios/axios#request-config | ||
}); | ||
``` | ||
// TODO: DEMONSTRATE API | ||
### Usage of the API | ||
```js | ||
let response; | ||
// The GitLabAPI object is a normal instance of axios.create, so you could do: | ||
response = await GitlabAPI.get("/user"); // Retrieve current user | ||
response = await GitlabAPI.get("/version"); // Retrieve current GitLab version | ||
response = await GitlabAPI.post("/projects", { name: "foobar" }); // Create a project | ||
``` | ||
### Usage of the API Iterator | ||
```js | ||
// The real powerhouse is the GitLabAPIIterator: | ||
const groupIterator = new GitLabAPIIterator("/groups"); | ||
// This will paginate through _all_ groups, and you have normal loop controls | ||
for await (const group of groupIterator) { | ||
//Skip groups starting with 'A' | ||
if (group.name.startsWith("A")) { | ||
continue; | ||
} | ||
// Stop looping as soon as we hit a group starting with C | ||
if (group.name.startsWith("C")) { | ||
break; | ||
} | ||
console.log("Group Details:", group); | ||
} | ||
// You can provide options to the group iterator: | ||
const aliceIterator = new GitLabAPIIterator("/users", { | ||
// General parameters: | ||
page: 2, // Start with page two | ||
maxPages: Number.MAX_SAFE_INTEGER, // how many pages to receive at a maximum | ||
per_page: 20, //Pagination size (GitLab default is 20) | ||
// Parameters specific to the endpoint | ||
search: "Alice", | ||
}); | ||
for await (const alice of aliceIterator) { | ||
console.log("Found a Alice", alice); | ||
} | ||
``` | ||
### Subclassing the API Iterator: | ||
```js | ||
class PipelineIterator extends GitLabAPIIterator { | ||
constructor(projectId, options) { | ||
super(`/projects/${projectId}/pipelines`, options); | ||
} | ||
} | ||
class PipelineJobIterator extends GitLabAPIIterator { | ||
constructor(projectId, pipelineId, options) { | ||
super(`/projects/${projectId}/pipelines/${pipelineId}/jobs`, options); | ||
} | ||
} | ||
const projectId = "foobar"; | ||
const pipelines = new PipelineIterator(projectId); | ||
for await (const pipeline of pipelines) { | ||
console.log(pipeline); | ||
const jobs = new PipelineIterator(projectId, pipeline.id); | ||
let found = false; | ||
for await (const job of jobs) { | ||
if (job.name.includes("jest")) { | ||
found = true; | ||
break; | ||
} | ||
} | ||
if (found) { | ||
console.log(`${pipeline.web_url} is the first Pipeline with a jest job`); | ||
break; | ||
} | ||
} | ||
``` |
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 1 instance in 1 package
8500
6
134
115
3