diff options
author | Nathan Fritz <fritzy@github.com> | 2021-12-16 21:01:56 +0300 |
---|---|---|
committer | Nathan Fritz <fritzy@github.com> | 2021-12-16 21:05:19 +0300 |
commit | d7265045730555c03b3142c004c7438e9577028c (patch) | |
tree | 035d81b3124bdaa09c21854934bf2b2b50e52e44 /workspaces/libnpmorg | |
parent | d8aac8448e983692cacb427e03f4688cd1b62e30 (diff) |
Bring in all libnpm modules + arborist as workspaces (#4166)
Added libnpm workspaces and arborist
Diffstat (limited to 'workspaces/libnpmorg')
-rw-r--r-- | workspaces/libnpmorg/.eslintrc.js | 14 | ||||
-rw-r--r-- | workspaces/libnpmorg/.gitignore | 23 | ||||
-rw-r--r-- | workspaces/libnpmorg/.npmrc | 3 | ||||
-rw-r--r-- | workspaces/libnpmorg/CHANGELOG.md | 33 | ||||
-rw-r--r-- | workspaces/libnpmorg/LICENSE | 13 | ||||
-rw-r--r-- | workspaces/libnpmorg/README.md | 149 | ||||
-rw-r--r-- | workspaces/libnpmorg/SECURITY.md | 3 | ||||
-rw-r--r-- | workspaces/libnpmorg/lib/index.js | 64 | ||||
-rw-r--r-- | workspaces/libnpmorg/package.json | 55 | ||||
-rw-r--r-- | workspaces/libnpmorg/test/fixtures/tnock.js | 14 | ||||
-rw-r--r-- | workspaces/libnpmorg/test/index.js | 129 |
11 files changed, 500 insertions, 0 deletions
diff --git a/workspaces/libnpmorg/.eslintrc.js b/workspaces/libnpmorg/.eslintrc.js new file mode 100644 index 000000000..022767bc3 --- /dev/null +++ b/workspaces/libnpmorg/.eslintrc.js @@ -0,0 +1,14 @@ +// This file is automatically added by @npmcli/template-oss. Do not edit. + +const { readdirSync: readdir } = require('fs') + +const localConfigs = readdir(__dirname) + .filter((file) => file.startsWith('.eslintrc.local.')) + .map((file) => `./${file}`) + +module.exports = { + extends: [ + '@npmcli', + ...localConfigs, + ], +} diff --git a/workspaces/libnpmorg/.gitignore b/workspaces/libnpmorg/.gitignore new file mode 100644 index 000000000..6ed44c72b --- /dev/null +++ b/workspaces/libnpmorg/.gitignore @@ -0,0 +1,23 @@ +# This file is automatically added by @npmcli/template-oss. Do not edit. + +# ignore everything in the root +/* + +# keep these +!/.commitlintrc.js +!/.npmrc +!/.eslintrc* +!/.github +!**/.gitignore +!/package.json +!/docs +!/bin +!/lib +!/map.js +!/tap-snapshots +!/test +!/scripts +!/README* +!/LICENSE* +!/SECURITY* +!/CHANGELOG* diff --git a/workspaces/libnpmorg/.npmrc b/workspaces/libnpmorg/.npmrc new file mode 100644 index 000000000..878b7ddef --- /dev/null +++ b/workspaces/libnpmorg/.npmrc @@ -0,0 +1,3 @@ +;This file is automatically added by @npmcli/template-oss. Do not edit. + +package-lock=false diff --git a/workspaces/libnpmorg/CHANGELOG.md b/workspaces/libnpmorg/CHANGELOG.md new file mode 100644 index 000000000..4cd5cd1cd --- /dev/null +++ b/workspaces/libnpmorg/CHANGELOG.md @@ -0,0 +1,33 @@ +# Change Log + +## 2.0.0 (2020-03-02) + +### BREAKING CHANGE +- Removed `figgy-pudding` as a dependecy +- Using native promises +- Require node >= v10 + +### Feature +- Updated stream interface to `minipass` type stream + +--- + +All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. + +<a name="1.0.1"></a> +## [1.0.1](https://github.com/npm/libnpmorg/compare/v1.0.0...v1.0.1) (2019-07-16) + + +### Bug Fixes + +* **standard:** standard --fix ([5118358](https://github.com/npm/libnpmorg/commit/5118358)) + + + +<a name="1.0.0"></a> +# 1.0.0 (2018-08-23) + + +### Features + +* **API:** implement org api ([731b9c6](https://github.com/npm/libnpmorg/commit/731b9c6)) diff --git a/workspaces/libnpmorg/LICENSE b/workspaces/libnpmorg/LICENSE new file mode 100644 index 000000000..209e4477f --- /dev/null +++ b/workspaces/libnpmorg/LICENSE @@ -0,0 +1,13 @@ +Copyright npm, Inc + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. diff --git a/workspaces/libnpmorg/README.md b/workspaces/libnpmorg/README.md new file mode 100644 index 000000000..b2e1ed589 --- /dev/null +++ b/workspaces/libnpmorg/README.md @@ -0,0 +1,149 @@ +# libnpmorg + +[![npm version](https://img.shields.io/npm/v/libnpmorg.svg)](https://npm.im/libnpmorg) +[![license](https://img.shields.io/npm/l/libnpmorg.svg)](https://npm.im/libnpmorg) +[![GitHub Actions](https://github.com/npm/libnpmorg/workflows/Node%20CI/badge.svg)](https://github.com/npm/libnpmorg/workflows/Node%20CI/badge.svg) +[![Coverage Status](https://coveralls.io/repos/github/npm/libnpmorg/badge.svg?branch=latest)](https://coveralls.io/github/npm/libnpmorg?branch=latest) + +[`libnpmorg`](https://github.com/npm/libnpmorg) is a Node.js library for +programmatically accessing the [npm Org membership +API](https://github.com/npm/registry/blob/master/docs/orgs/memberships.md#membership-detail). + +## Table of Contents + +* [Example](#example) +* [Install](#install) +* [Contributing](#contributing) +* [API](#api) + * [hook opts](#opts) + * [`set()`](#set) + * [`rm()`](#rm) + * [`ls()`](#ls) + * [`ls.stream()`](#ls-stream) + +## Example + +```js +const org = require('libnpmorg') + +console.log(await org.ls('myorg', {token: 'deadbeef'})) +=> +Roster { + zkat: 'developer', + iarna: 'admin', + isaacs: 'owner' +} +``` + +## Install + +`$ npm install libnpmorg` + +### API + +#### <a name="opts"></a> `opts` for `libnpmorg` commands + +`libnpmorg` uses [`npm-registry-fetch`](https://npm.im/npm-registry-fetch). +All options are passed through directly to that library, so please refer to [its +own `opts` +documentation](https://www.npmjs.com/package/npm-registry-fetch#fetch-options) +for options that can be passed in. + +A couple of options of note for those in a hurry: + +* `opts.token` - can be passed in and will be used as the authentication token for the registry. For other ways to pass in auth details, see the n-r-f docs. +* `opts.otp` - certain operations will require an OTP token to be passed in. If a `libnpmorg` command fails with `err.code === EOTP`, please retry the request with `{otp: <2fa token>}` + +#### <a name="set"></a> `> org.set(org, user, [role], [opts]) -> Promise` + +The returned Promise resolves to a [Membership +Detail](https://github.com/npm/registry/blob/master/docs/orgs/memberships.md#membership-detail) +object. + +The `role` is optional and should be one of `admin`, `owner`, or `developer`. +`developer` is the default if no `role` is provided. + +`org` and `user` must be scope names for the org name and user name +respectively. They can optionally be prefixed with `@`. + +See also: [`PUT +/-/org/:scope/user`](https://github.com/npm/registry/blob/master/docs/orgs/memberships.md#org-membership-replace) + +##### Example + +```javascript +await org.set('@myorg', '@myuser', 'admin', {token: 'deadbeef'}) +=> +MembershipDetail { + org: { + name: 'myorg', + size: 15 + }, + user: 'myuser', + role: 'admin' +} +``` + +#### <a name="rm"></a> `> org.rm(org, user, [opts]) -> Promise` + +The Promise resolves to `null` on success. + +`org` and `user` must be scope names for the org name and user name +respectively. They can optionally be prefixed with `@`. + +See also: [`DELETE +/-/org/:scope/user`](https://github.com/npm/registry/blob/master/docs/orgs/memberships.md#org-membership-delete) + +##### Example + +```javascript +await org.rm('myorg', 'myuser', {token: 'deadbeef'}) +``` + +#### <a name="ls"></a> `> org.ls(org, [opts]) -> Promise` + +The Promise resolves to a +[Roster](https://github.com/npm/registry/blob/master/docs/orgs/memberships.md#roster) +object. + +`org` must be a scope name for an org, and can be optionally prefixed with `@`. + +See also: [`GET +/-/org/:scope/user`](https://github.com/npm/registry/blob/master/docs/orgs/memberships.md#org-roster) + +##### Example + +```javascript +await org.ls('myorg', {token: 'deadbeef'}) +=> +Roster { + zkat: 'developer', + iarna: 'admin', + isaacs: 'owner' +} +``` + +#### <a name="ls-stream"></a> `> org.ls.stream(org, [opts]) -> Stream` + +Returns a stream of entries for a +[Roster](https://github.com/npm/registry/blob/master/docs/orgs/memberships.md#roster), +with each emitted entry in `[key, value]` format. + +`org` must be a scope name for an org, and can be optionally prefixed with `@`. + +The returned stream is a valid `Symbol.asyncIterator`. + +See also: [`GET +/-/org/:scope/user`](https://github.com/npm/registry/blob/master/docs/orgs/memberships.md#org-roster) + +##### Example + +```javascript +for await (let [user, role] of org.ls.stream('myorg', {token: 'deadbeef'})) { + console.log(`user: ${user} (${role})`) +} +=> +user: zkat (developer) +user: iarna (admin) +user: isaacs (owner) +``` diff --git a/workspaces/libnpmorg/SECURITY.md b/workspaces/libnpmorg/SECURITY.md new file mode 100644 index 000000000..a93106d0c --- /dev/null +++ b/workspaces/libnpmorg/SECURITY.md @@ -0,0 +1,3 @@ +<!-- This file is automatically added by @npmcli/template-oss. Do not edit. --> + +Please send vulnerability reports through [hackerone](https://hackerone.com/github). diff --git a/workspaces/libnpmorg/lib/index.js b/workspaces/libnpmorg/lib/index.js new file mode 100644 index 000000000..4684b516d --- /dev/null +++ b/workspaces/libnpmorg/lib/index.js @@ -0,0 +1,64 @@ +'use strict' + +const eu = encodeURIComponent +const fetch = require('npm-registry-fetch') +const validate = require('aproba') + +// From https://github.com/npm/registry/blob/master/docs/orgs/memberships.md +const cmd = module.exports + +class MembershipDetail {} +cmd.set = (org, user, role, opts = {}) => { + if ( + typeof role === 'object' && + Object.keys(opts).length === 0 + ) { + opts = role + role = undefined + } + validate('SSSO|SSZO', [org, user, role, opts]) + user = user.replace(/^@?/, '') + org = org.replace(/^@?/, '') + return fetch.json(`/-/org/${eu(org)}/user`, { + ...opts, + method: 'PUT', + body: { user, role }, + }).then(ret => Object.assign(new MembershipDetail(), ret)) +} + +cmd.rm = (org, user, opts = {}) => { + validate('SSO', [org, user, opts]) + user = user.replace(/^@?/, '') + org = org.replace(/^@?/, '') + return fetch(`/-/org/${eu(org)}/user`, { + ...opts, + method: 'DELETE', + body: { user }, + ignoreBody: true, + }).then(() => null) +} + +class Roster {} +cmd.ls = (org, opts = {}) => { + return cmd.ls.stream(org, opts) + .collect() + .then(data => data.reduce((acc, [key, val]) => { + if (!acc) { + acc = {} + } + acc[key] = val + return acc + }, null)) + .then(ret => Object.assign(new Roster(), ret)) +} + +cmd.ls.stream = (org, opts = {}) => { + validate('SO', [org, opts]) + org = org.replace(/^@?/, '') + return fetch.json.stream(`/-/org/${eu(org)}/user`, '*', { + ...opts, + mapJSON: (value, [key]) => { + return [key, value] + }, + }) +} diff --git a/workspaces/libnpmorg/package.json b/workspaces/libnpmorg/package.json new file mode 100644 index 000000000..021c46815 --- /dev/null +++ b/workspaces/libnpmorg/package.json @@ -0,0 +1,55 @@ +{ + "name": "libnpmorg", + "version": "3.0.0", + "description": "Programmatic api for `npm org` commands", + "author": "GitHub Inc.", + "main": "lib/index.js", + "keywords": [ + "libnpm", + "npm", + "package manager", + "api", + "orgs", + "teams" + ], + "license": "ISC", + "scripts": { + "preversion": "npm test", + "postversion": "npm publish", + "prepublishOnly": "git push origin --follow-tags", + "lint": "eslint '**/*.js'", + "test": "tap", + "posttest": "npm run lint", + "postlint": "npm-template-check", + "lintfix": "npm run lint -- --fix", + "snap": "tap" + }, + "files": [ + "bin", + "lib" + ], + "tap": { + "check-coverage": true + }, + "devDependencies": { + "minipass": "^3.1.1", + "nock": "^12.0.1", + "tap": "^15.0.0" + }, + "repository": { + "type": "git", + "url": "https://github.com/npm/libnpmorg.git" + }, + "bugs": "https://github.com/npm/libnpmorg/issues", + "homepage": "https://npmjs.com/package/libnpmorg", + "dependencies": { + "aproba": "^2.0.0", + "npm-registry-fetch": "^11.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16" + }, + "templateOSS": { + "version": "2.4.1" + } +} diff --git a/workspaces/libnpmorg/test/fixtures/tnock.js b/workspaces/libnpmorg/test/fixtures/tnock.js new file mode 100644 index 000000000..1593224a1 --- /dev/null +++ b/workspaces/libnpmorg/test/fixtures/tnock.js @@ -0,0 +1,14 @@ +'use strict' + +const nock = require('nock') + +nock.disableNetConnect() + +module.exports = tnock +function tnock (t, host) { + const server = nock(host) + t.teardown(function () { + server.done() + }) + return server +} diff --git a/workspaces/libnpmorg/test/index.js b/workspaces/libnpmorg/test/index.js new file mode 100644 index 000000000..ecdda07c0 --- /dev/null +++ b/workspaces/libnpmorg/test/index.js @@ -0,0 +1,129 @@ +'use strict' + +const Minipass = require('minipass') +const test = require('tap').test +const tnock = require('./fixtures/tnock.js') + +const org = require('../lib/index.js') + +const OPTS = { + registry: 'https://mock.reg/', +} +const REG = 'https://registry.npmjs.org/' + +test('set', t => { + const memDeets = { + org: { + name: 'myorg', + size: 15, + }, + user: 'myuser', + role: 'admin', + } + tnock(t, OPTS.registry) + .put('/-/org/myorg/user', { + user: 'myuser', + role: 'admin', + }) + .reply(201, memDeets) + + return org.set('myorg', 'myuser', 'admin', OPTS) + .then(res => { + t.same(res, memDeets, 'got a membership details object back') + }) +}) + +test('optional role for set', t => { + const memDeets = { + org: { + name: 'myorg', + size: 15, + }, + user: 'myuser', + role: 'developer', + } + tnock(t, OPTS.registry).put('/-/org/myorg/user', { + user: 'myuser', + }).reply(201, memDeets) + return org.set('myorg', 'myuser', OPTS).then(res => { + t.same(res, memDeets, 'got a membership details object back') + }) +}) + +test('rm with no options', t => { + tnock(t, REG).delete('/-/org/myorg/user', { + user: 'myuser', + }).reply(204) + return org.rm('myorg', 'myuser').then(() => { + t.ok(true, 'request succeeded') + }) +}) + +test('rm', t => { + tnock(t, OPTS.registry).delete('/-/org/myorg/user', { + user: 'myuser', + }).reply(204) + return org.rm('myorg', 'myuser', OPTS) + .then(ret => { + t.equal(ret, null, 'null return value') + t.ok(true, 'request succeeded') + }) +}) + +test('ls with no options', t => { + const roster = { + zkat: 'developer', + iarna: 'admin', + isaacs: 'owner', + } + tnock(t, REG).get('/-/org/myorg/user').reply(200, roster) + return org.ls('myorg').then(res => { + t.same(res, roster, 'got back a roster') + }) +}) + +test('ls', t => { + const roster = { + zkat: 'developer', + iarna: 'admin', + isaacs: 'owner', + } + tnock(t, OPTS.registry).get('/-/org/myorg/user').reply(200, roster) + return org.ls('myorg', OPTS).then(res => { + t.same(res, roster, 'got back a roster') + }) +}) + +test('ls stream with no options', t => { + t.plan(2) + const roster = { + zkat: 'developer', + iarna: 'admin', + isaacs: 'owner', + } + const rosterArr = Object.keys(roster).map(k => [k, roster[k]]) + tnock(t, REG).get('/-/org/myorg/user').reply(200, roster) + const result = org.ls.stream('myorg') + t.ok(Minipass.isStream(result), 'returns a stream') + return result.collect() + .then(res => { + t.same(res, rosterArr, 'got back a roster, in entries format') + }) +}) + +test('ls stream', t => { + t.plan(2) + const roster = { + zkat: 'developer', + iarna: 'admin', + isaacs: 'owner', + } + const rosterArr = Object.keys(roster).map(k => [k, roster[k]]) + tnock(t, OPTS.registry).get('/-/org/myorg/user').reply(200, roster) + const result = org.ls.stream('myorg', OPTS) + t.ok(Minipass.isStream(result), 'returns a stream') + return result.collect() + .then(res => { + t.same(res, rosterArr, 'got back a roster, in entries format') + }) +}) |