Compare commits
39 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fff032b1e8 | ||
|
|
4bceac5a4c | ||
|
|
e09cdad6ec | ||
|
|
6384229a53 | ||
|
|
7e419c1fb4 | ||
|
|
bda3f1caf4 | ||
|
|
e76885847c | ||
|
|
32d5084fdc | ||
|
|
f2055a355f | ||
|
|
3d366dd996 | ||
|
|
6fcc5c6dab | ||
|
|
b761a8f4eb | ||
|
|
65a8d1d324 | ||
|
|
57515de719 | ||
|
|
ca78d00f28 | ||
|
|
ea84da989f | ||
|
|
c562645db7 | ||
|
|
eb04533714 | ||
|
|
7bc0fccaca | ||
|
|
84ae9bcfa0 | ||
|
|
fad30adc56 | ||
|
|
f961219dbe | ||
|
|
c02010f2e5 | ||
|
|
d55c680ef9 | ||
|
|
c1eb0978ba | ||
|
|
c6b8aecfd0 | ||
|
|
32e842e882 | ||
|
|
5738d569ea | ||
|
|
9dd2d4bbe4 | ||
|
|
0b35ead2a0 | ||
|
|
a64ebd80f3 | ||
|
|
be8387dfa4 | ||
|
|
d6c4cf5029 | ||
|
|
0ada89b2fc | ||
|
|
7eb209de13 | ||
|
|
5965dbddbc | ||
|
|
e40c5021bb | ||
|
|
65a3df891d | ||
|
|
43d77ee91e |
52
.github/workflows/nodejs.yml
vendored
52
.github/workflows/nodejs.yml
vendored
@@ -5,15 +5,9 @@ name: Node.js CI
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
- master
|
||||
branches: [ master ]
|
||||
pull_request:
|
||||
branches:
|
||||
- main
|
||||
- master
|
||||
schedule:
|
||||
- cron: '0 2 * * *'
|
||||
branches: [ master ]
|
||||
|
||||
jobs:
|
||||
test-mysql57-fs-nfs:
|
||||
@@ -28,28 +22,28 @@ jobs:
|
||||
ports:
|
||||
- 3306:3306
|
||||
options: --health-cmd="mysqladmin ping" --health-interval=10s --health-timeout=5s --health-retries=5
|
||||
redis:
|
||||
# https://docs.github.com/en/actions/using-containerized-services/about-service-containers#example-mapping-redis-ports
|
||||
image: redis
|
||||
ports:
|
||||
# Opens tcp port 6379 on the host and service container
|
||||
- 6379:6379
|
||||
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
node-version: [16, 18, 19]
|
||||
node-version: [16, 18]
|
||||
os: [ubuntu-latest]
|
||||
|
||||
steps:
|
||||
- name: Checkout Git Source
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Use Node.js ${{ matrix.node-version }}
|
||||
uses: actions/setup-node@v1
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: ${{ matrix.node-version }}
|
||||
|
||||
# https://github.com/marketplace/actions/redis-server-in-github-actions#usage
|
||||
- name: Start Redis
|
||||
uses: supercharge/redis-github-action@1.4.0
|
||||
with:
|
||||
redis-version: 6
|
||||
|
||||
- name: Install Dependencies
|
||||
run: npm i
|
||||
|
||||
@@ -57,15 +51,14 @@ jobs:
|
||||
run: npm run ci
|
||||
|
||||
- name: Code Coverage
|
||||
uses: codecov/codecov-action@v1
|
||||
uses: codecov/codecov-action@v3
|
||||
with:
|
||||
token: ${{ secrets.CODECOV_TOKEN }}
|
||||
|
||||
test-mysql57-oss-nfs:
|
||||
runs-on: ${{ matrix.os }}
|
||||
if:
|
||||
if: |
|
||||
contains('
|
||||
refs/heads/main
|
||||
refs/heads/master
|
||||
refs/heads/dev
|
||||
', github.ref)
|
||||
@@ -80,6 +73,13 @@ jobs:
|
||||
- 3306:3306
|
||||
options: --health-cmd="mysqladmin ping" --health-interval=10s --health-timeout=5s --health-retries=5
|
||||
|
||||
redis:
|
||||
# https://docs.github.com/en/actions/using-containerized-services/about-service-containers#example-mapping-redis-ports
|
||||
image: redis
|
||||
ports:
|
||||
# Opens tcp port 6379 on the host and service container
|
||||
- 6379:6379
|
||||
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
@@ -88,19 +88,13 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Checkout Git Source
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Use Node.js ${{ matrix.node-version }}
|
||||
uses: actions/setup-node@v1
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: ${{ matrix.node-version }}
|
||||
|
||||
# https://github.com/marketplace/actions/redis-server-in-github-actions#usage
|
||||
- name: Start Redis
|
||||
uses: supercharge/redis-github-action@1.4.0
|
||||
with:
|
||||
redis-version: 6
|
||||
|
||||
- name: Install Dependencies
|
||||
run: npm i
|
||||
|
||||
@@ -114,6 +108,6 @@ jobs:
|
||||
CNPMCORE_NFS_OSS_SECRET: ${{ secrets.CNPMCORE_NFS_OSS_SECRET }}
|
||||
|
||||
- name: Code Coverage
|
||||
uses: codecov/codecov-action@v1
|
||||
uses: codecov/codecov-action@v3
|
||||
with:
|
||||
token: ${{ secrets.CODECOV_TOKEN }}
|
||||
|
||||
18
.github/workflows/release.yml
vendored
Normal file
18
.github/workflows/release.yml
vendored
Normal file
@@ -0,0 +1,18 @@
|
||||
name: Release
|
||||
on:
|
||||
# 合并后自动发布
|
||||
push:
|
||||
branches: [ master, main ]
|
||||
|
||||
# 手动发布
|
||||
workflow_dispatch: {}
|
||||
|
||||
jobs:
|
||||
release:
|
||||
name: Node.js
|
||||
uses: artusjs/github-actions/.github/workflows/node-release.yml@v1
|
||||
secrets:
|
||||
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
|
||||
GIT_TOKEN: ${{ secrets.GIT_TOKEN }}
|
||||
with:
|
||||
checkTest: false
|
||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -13,6 +13,7 @@ config/config.prod.ts
|
||||
config/**/*.js
|
||||
app/**/*.js
|
||||
test/**/*.js
|
||||
app.js
|
||||
|
||||
.cnpmcore
|
||||
.cnpmcore_unittest
|
||||
|
||||
23
CHANGELOG.md
Normal file
23
CHANGELOG.md
Normal file
@@ -0,0 +1,23 @@
|
||||
# Changelog
|
||||
|
||||
## [2.10.1](https://github.com/cnpm/npmcore/compare/v2.10.0...v2.10.1) (2023-01-08)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* export _cnpmcore_publish_time on abbreviated manifests ([#374](https://github.com/cnpm/npmcore/issues/374)) ([4bceac5](https://github.com/cnpm/npmcore/commit/4bceac5a4c94f8e8624ae1113ad1c5e69a5a2ae1))
|
||||
|
||||
## [2.10.0](https://github.com/cnpm/npmcore/compare/v2.9.1...v2.10.0) (2023-01-05)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* unpublish pkg when upstream block ([#372](https://github.com/cnpm/npmcore/issues/372)) ([7e419c1](https://github.com/cnpm/npmcore/commit/7e419c1fb4fe297adea86cb5d9eae4c8e77e2aec))
|
||||
|
||||
## [2.9.1](https://github.com/cnpm/npmcore/compare/v2.9.0...v2.9.1) (2022-12-17)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* Auto enable npm publish on github action ([3d366dd](https://github.com/cnpm/npmcore/commit/3d366dd996161f8f08ae43bde29b7768f5a5241c))
|
||||
* fix tsc:prod ([ca78d00](https://github.com/cnpm/npmcore/commit/ca78d00f28930180a9374c01d2a9b3b47d6e9db3))
|
||||
70
History.md
70
History.md
@@ -1,4 +1,74 @@
|
||||
|
||||
2.9.0 / 2022-12-15
|
||||
==================
|
||||
|
||||
**features**
|
||||
* [[`c562645`](http://github.com/cnpm/cnpmcore/commit/c562645db7c88f9c3c5787fd450b457574d1cce6)] - feat: suspend task before app close (#365) (elrrrrrrr <<elrrrrrrr@gmail.com>>)
|
||||
|
||||
2.8.1 / 2022-12-05
|
||||
==================
|
||||
|
||||
**features**
|
||||
* [[`fad30ad`](http://github.com/cnpm/cnpmcore/commit/fad30adc564c931c0bf63828d83bab84105aaef0)] - feat: npm command support npm v6 (#356) (laibao101 <<369632567@qq.com>>)
|
||||
|
||||
**fixes**
|
||||
* [[`f961219`](http://github.com/cnpm/cnpmcore/commit/f961219dbe4676156e1766db82379ee40087bcd8)] - fix: Sync save ignore ER_DUP_ENTRY error (#364) (elrrrrrrr <<elrrrrrrr@gmail.com>>)
|
||||
|
||||
**others**
|
||||
* [[`7bc0fcc`](http://github.com/cnpm/cnpmcore/commit/7bc0fccaca880efe08228b4109953bd3974d2eb9)] - 🤖 TEST: Fix async function mock (fengmk2 <<fengmk2@gmail.com>>)
|
||||
* [[`84ae9bc`](http://github.com/cnpm/cnpmcore/commit/84ae9bcfa06124255703b926f83fb5e6a6bf9d6b)] - 📖 DOC: Update contributors (fengmk2 <<fengmk2@gmail.com>>)
|
||||
|
||||
2.8.0 / 2022-11-29
|
||||
==================
|
||||
|
||||
**others**
|
||||
* [[`d55c680`](http://github.com/cnpm/cnpmcore/commit/d55c680ef906ecb27f7967782ad7d25987cef7d4)] - Event cork (#361) (elrrrrrrr <<elrrrrrrr@gmail.com>>)
|
||||
|
||||
2.7.1 / 2022-11-25
|
||||
==================
|
||||
|
||||
**fixes**
|
||||
* [[`c6b8aec`](http://github.com/cnpm/cnpmcore/commit/c6b8aecfd0c2b0d454389e931747c431dac5742b)] - fix: request binary error (#360) (Ke Wu <<gemwuu@163.com>>)
|
||||
|
||||
2.7.0 / 2022-11-25
|
||||
==================
|
||||
|
||||
**others**
|
||||
* [[`5738d56`](http://github.com/cnpm/cnpmcore/commit/5738d569ea691c05c3f3b0b74a454a33fefb8fc7)] - refactor: binary sync task use binaryName by default (#358) (Ke Wu <<gemwuu@163.com>>)
|
||||
|
||||
2.6.1 / 2022-11-23
|
||||
==================
|
||||
|
||||
**fixes**
|
||||
* [[`0b35ead`](http://github.com/cnpm/cnpmcore/commit/0b35ead2a0cd73b89d2d961bafec13d7250fe805)] - 🐛 FIX: typo for canvas (fengmk2 <<fengmk2@gmail.com>>)
|
||||
|
||||
2.6.0 / 2022-11-23
|
||||
==================
|
||||
|
||||
**features**
|
||||
* [[`be8387d`](http://github.com/cnpm/cnpmcore/commit/be8387dfa48b9487156542000a93081fa823694a)] - feat: Support canvas sync from different binary (#357) (Ke Wu <<gemwuu@163.com>>)
|
||||
|
||||
**fixes**
|
||||
* [[`d6c4cf5`](http://github.com/cnpm/cnpmcore/commit/d6c4cf5029ca6450064fc05696a8624b6c36f0b2)] - fix: duplicate binary task (#354) (elrrrrrrr <<elrrrrrrr@gmail.com>>)
|
||||
|
||||
2.5.2 / 2022-11-11
|
||||
==================
|
||||
|
||||
**fixes**
|
||||
* [[`7eb209d`](http://github.com/cnpm/cnpmcore/commit/7eb209de1332417db2070846891d78f5afa0cd10)] - fix: create task when waiting (#352) (elrrrrrrr <<elrrrrrrr@gmail.com>>)
|
||||
|
||||
2.5.1 / 2022-11-07
|
||||
==================
|
||||
|
||||
**others**
|
||||
* [[`e40c502`](http://github.com/cnpm/cnpmcore/commit/e40c5021bb2ba78f8879d19bc477883168560b85)] - 🐛 FIX: Mirror cypress arm64 binary (#351) (fengmk2 <<fengmk2@gmail.com>>)
|
||||
|
||||
2.5.0 / 2022-11-04
|
||||
==================
|
||||
|
||||
**features**
|
||||
* [[`43d77ee`](http://github.com/cnpm/cnpmcore/commit/43d77ee91e52bd74594d9d569b839c1a4b7fbac6)] - feat: long description (#349) (elrrrrrrr <<elrrrrrrr@gmail.com>>)
|
||||
|
||||
2.4.1 / 2022-10-28
|
||||
==================
|
||||
|
||||
|
||||
@@ -24,12 +24,12 @@ See [DEVELOPER.md](DEVELOPER.md)
|
||||
|
||||
## Contributors
|
||||
|
||||
|[<img src="https://avatars.githubusercontent.com/u/156269?v=4" width="100px;"/><br/><sub><b>fengmk2</b></sub>](https://github.com/fengmk2)<br/>|[<img src="https://avatars.githubusercontent.com/u/6897780?v=4" width="100px;"/><br/><sub><b>killagu</b></sub>](https://github.com/killagu)<br/>|[<img src="https://avatars.githubusercontent.com/u/5574625?v=4" width="100px;"/><br/><sub><b>elrrrrrrr</b></sub>](https://github.com/elrrrrrrr)<br/>|[<img src="https://avatars.githubusercontent.com/u/26033663?v=4" width="100px;"/><br/><sub><b>Zian502</b></sub>](https://github.com/Zian502)<br/>|[<img src="https://avatars.githubusercontent.com/u/13284978?v=4" width="100px;"/><br/><sub><b>Beace</b></sub>](https://github.com/Beace)<br/>|[<img src="https://avatars.githubusercontent.com/u/227713?v=4" width="100px;"/><br/><sub><b>atian25</b></sub>](https://github.com/atian25)<br/>|
|
||||
|[<img src="https://avatars.githubusercontent.com/u/156269?v=4" width="100px;"/><br/><sub><b>fengmk2</b></sub>](https://github.com/fengmk2)<br/>|[<img src="https://avatars.githubusercontent.com/u/6897780?v=4" width="100px;"/><br/><sub><b>killagu</b></sub>](https://github.com/killagu)<br/>|[<img src="https://avatars.githubusercontent.com/u/5574625?v=4" width="100px;"/><br/><sub><b>elrrrrrrr</b></sub>](https://github.com/elrrrrrrr)<br/>|[<img src="https://avatars.githubusercontent.com/u/26033663?v=4" width="100px;"/><br/><sub><b>Zian502</b></sub>](https://github.com/Zian502)<br/>|[<img src="https://avatars.githubusercontent.com/u/4635838?v=4" width="100px;"/><br/><sub><b>gemwuu</b></sub>](https://github.com/gemwuu)<br/>|[<img src="https://avatars.githubusercontent.com/u/17879221?v=4" width="100px;"/><br/><sub><b>laibao101</b></sub>](https://github.com/laibao101)<br/>|
|
||||
| :---: | :---: | :---: | :---: | :---: | :---: |
|
||||
|[<img src="https://avatars.githubusercontent.com/u/17879221?v=4" width="100px;"/><br/><sub><b>laibao101</b></sub>](https://github.com/laibao101)<br/>|[<img src="https://avatars.githubusercontent.com/u/8198408?v=4" width="100px;"/><br/><sub><b>BlackHole1</b></sub>](https://github.com/BlackHole1)<br/>|[<img src="https://avatars.githubusercontent.com/u/1814071?v=4" width="100px;"/><br/><sub><b>xiekw2010</b></sub>](https://github.com/xiekw2010)<br/>|[<img src="https://avatars.githubusercontent.com/u/13471233?v=4" width="100px;"/><br/><sub><b>OpportunityLiu</b></sub>](https://github.com/OpportunityLiu)<br/>|[<img src="https://avatars.githubusercontent.com/u/958063?v=4" width="100px;"/><br/><sub><b>thonatos</b></sub>](https://github.com/thonatos)<br/>|[<img src="https://avatars.githubusercontent.com/u/11039003?v=4" width="100px;"/><br/><sub><b>chenpx976</b></sub>](https://github.com/chenpx976)<br/>|
|
||||
[<img src="https://avatars.githubusercontent.com/u/29791463?v=4" width="100px;"/><br/><sub><b>fossabot</b></sub>](https://github.com/fossabot)<br/>|[<img src="https://avatars.githubusercontent.com/u/1119126?v=4" width="100px;"/><br/><sub><b>looksgood</b></sub>](https://github.com/looksgood)<br/>|[<img src="https://avatars.githubusercontent.com/u/3478550?v=4" width="100px;"/><br/><sub><b>coolyuantao</b></sub>](https://github.com/coolyuantao)<br/>
|
||||
|[<img src="https://avatars.githubusercontent.com/u/13284978?v=4" width="100px;"/><br/><sub><b>Beace</b></sub>](https://github.com/Beace)<br/>|[<img src="https://avatars.githubusercontent.com/u/227713?v=4" width="100px;"/><br/><sub><b>atian25</b></sub>](https://github.com/atian25)<br/>|[<img src="https://avatars.githubusercontent.com/u/3478550?v=4" width="100px;"/><br/><sub><b>coolyuantao</b></sub>](https://github.com/coolyuantao)<br/>|[<img src="https://avatars.githubusercontent.com/u/8198408?v=4" width="100px;"/><br/><sub><b>BlackHole1</b></sub>](https://github.com/BlackHole1)<br/>|[<img src="https://avatars.githubusercontent.com/u/1814071?v=4" width="100px;"/><br/><sub><b>xiekw2010</b></sub>](https://github.com/xiekw2010)<br/>|[<img src="https://avatars.githubusercontent.com/u/13471233?v=4" width="100px;"/><br/><sub><b>OpportunityLiu</b></sub>](https://github.com/OpportunityLiu)<br/>|
|
||||
[<img src="https://avatars.githubusercontent.com/u/958063?v=4" width="100px;"/><br/><sub><b>thonatos</b></sub>](https://github.com/thonatos)<br/>|[<img src="https://avatars.githubusercontent.com/u/11039003?v=4" width="100px;"/><br/><sub><b>chenpx976</b></sub>](https://github.com/chenpx976)<br/>|[<img src="https://avatars.githubusercontent.com/u/29791463?v=4" width="100px;"/><br/><sub><b>fossabot</b></sub>](https://github.com/fossabot)<br/>|[<img src="https://avatars.githubusercontent.com/u/1119126?v=4" width="100px;"/><br/><sub><b>looksgood</b></sub>](https://github.com/looksgood)<br/>
|
||||
|
||||
This project follows the git-contributor [spec](https://github.com/xudafeng/git-contributor), auto updated at `Sun Aug 28 2022 19:00:22 GMT+0800`.
|
||||
This project follows the git-contributor [spec](https://github.com/xudafeng/git-contributor), auto updated at `Sat Dec 03 2022 14:59:50 GMT+0800`.
|
||||
|
||||
<!-- GITCONTRIBUTOR_END -->
|
||||
|
||||
|
||||
11
app.ts
11
app.ts
@@ -1,7 +1,6 @@
|
||||
import path from 'path';
|
||||
import { readFile } from 'fs/promises';
|
||||
import { Application } from 'egg';
|
||||
|
||||
declare module 'egg' {
|
||||
interface Application {
|
||||
binaryHTML: string;
|
||||
@@ -23,4 +22,14 @@ export default class CnpmcoreAppHook {
|
||||
const text = await readFile(filepath, 'utf-8');
|
||||
this.app.binaryHTML = text.replace('{{registry}}', this.app.config.cnpmcore.registry);
|
||||
}
|
||||
|
||||
// 应用退出时执行
|
||||
// 需要暂停当前执行的 changesStream task
|
||||
async beforeClose() {
|
||||
await this.app.runInAnonymousContextScope(async ctx => {
|
||||
await ctx.beginModuleScope(async () => {
|
||||
await ctx.module.cnpmcoreCore.changesStreamService.suspendTaskWhenExit();
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,11 +19,13 @@ export abstract class AbstractBinary {
|
||||
protected httpclient: EggContextHttpClient;
|
||||
protected logger: EggLogger;
|
||||
protected binaryConfig: BinaryTaskConfig;
|
||||
protected binaryName: string;
|
||||
|
||||
constructor(httpclient: EggContextHttpClient, logger: EggLogger, binaryConfig: BinaryTaskConfig) {
|
||||
constructor(httpclient: EggContextHttpClient, logger: EggLogger, binaryConfig: BinaryTaskConfig, binaryName: string) {
|
||||
this.httpclient = httpclient;
|
||||
this.logger = logger;
|
||||
this.binaryConfig = binaryConfig;
|
||||
this.binaryName = binaryName;
|
||||
}
|
||||
|
||||
abstract fetch(dir: string, params?: any): Promise<FetchResult | undefined>;
|
||||
|
||||
@@ -4,13 +4,13 @@ import { BinaryTaskConfig } from '../../../../config/binaries';
|
||||
|
||||
export class ApiBinary extends AbstractBinary {
|
||||
private apiUrl: string;
|
||||
constructor(httpclient: EggContextHttpClient, logger: EggLogger, binaryConfig: BinaryTaskConfig, apiUrl: string) {
|
||||
super(httpclient, logger, binaryConfig);
|
||||
constructor(httpclient: EggContextHttpClient, logger: EggLogger, binaryConfig: BinaryTaskConfig, apiUrl: string, binaryName: string) {
|
||||
super(httpclient, logger, binaryConfig, binaryName);
|
||||
this.apiUrl = apiUrl;
|
||||
}
|
||||
|
||||
async fetch(dir: string): Promise<FetchResult | undefined> {
|
||||
const url = `${this.apiUrl}/${this.binaryConfig.category}${dir}`;
|
||||
const url = `${this.apiUrl}/${this.binaryName}${dir}`;
|
||||
const data = await this.requestJSON(url);
|
||||
if (!Array.isArray(data)) {
|
||||
this.logger.warn('[ApiBinary.fetch:response-data-not-array] data: %j', data);
|
||||
|
||||
@@ -31,10 +31,11 @@ export class CypressBinary extends AbstractBinary {
|
||||
// "https://cdn.cypress.io/desktop/4.0.0/darwin-x64/cypress.zip"
|
||||
// "https://cdn.cypress.io/desktop/4.0.0/linux-x64/cypress.zip"
|
||||
// "https://cdn.cypress.io/desktop/4.0.0/win32-x64/cypress.zip"
|
||||
// "https://cdn.cypress.io/desktop/9.2.0/darwin-arm64/cypress.zip"
|
||||
// "https://cdn.cypress.io/desktop/9.2.0/darwin-x64/cypress.zip"
|
||||
// "https://cdn.cypress.io/desktop/9.2.0/linux-x64/cypress.zip"
|
||||
// "https://cdn.cypress.io/desktop/9.2.0/win32-x64/cypress.zip"
|
||||
const platforms = [ 'darwin-x64', 'linux-x64', 'win32-x64' ];
|
||||
const platforms = [ 'darwin-x64', 'darwin-arm64', 'linux-x64', 'win32-x64' ];
|
||||
for (const platform of platforms) {
|
||||
this.dirItems[subDir].push({
|
||||
name: `${platform}/`,
|
||||
|
||||
@@ -8,7 +8,7 @@ export class ImageminBinary extends AbstractBinary {
|
||||
async fetch(dir: string): Promise<FetchResult | undefined> {
|
||||
if (!this.dirItems) {
|
||||
this.dirItems = {};
|
||||
const npmPackageName = this.binaryConfig.options?.npmPackageName ?? this.binaryConfig.category;
|
||||
const npmPackageName = this.binaryConfig.options?.npmPackageName ?? this.binaryName;
|
||||
const pkgUrl = `https://registry.npmjs.com/${npmPackageName}`;
|
||||
const data = await this.requestJSON(pkgUrl);
|
||||
this.dirItems = {};
|
||||
|
||||
@@ -10,7 +10,7 @@ export class NodePreGypBinary extends AbstractBinary {
|
||||
async fetch(dir: string): Promise<FetchResult | undefined> {
|
||||
if (!this.dirItems) {
|
||||
this.dirItems = {};
|
||||
const pkgUrl = `https://registry.npmjs.com/${this.binaryConfig.category}`;
|
||||
const pkgUrl = `https://registry.npmjs.com/${this.binaryName}`;
|
||||
const data = await this.requestJSON(pkgUrl);
|
||||
this.dirItems = {};
|
||||
this.dirItems['/'] = [];
|
||||
@@ -77,7 +77,7 @@ export class NodePreGypBinary extends AbstractBinary {
|
||||
date,
|
||||
size: '-',
|
||||
isDir: false,
|
||||
url: `${this.binaryConfig.distUrl}/${this.binaryConfig.category}${versionPrefix}/${name}`,
|
||||
url: `${this.binaryConfig.distUrl}/${this.binaryName}${versionPrefix}/${name}`,
|
||||
ignoreDownloadStatuses: [ 404 ],
|
||||
});
|
||||
}
|
||||
@@ -99,7 +99,7 @@ export class NodePreGypBinary extends AbstractBinary {
|
||||
date,
|
||||
size: '-',
|
||||
isDir: false,
|
||||
url: `${this.binaryConfig.distUrl}/${this.binaryConfig.category}${versionPrefix}/${name}`,
|
||||
url: `${this.binaryConfig.distUrl}/${this.binaryName}${versionPrefix}/${name}`,
|
||||
ignoreDownloadStatuses: [ 404 ],
|
||||
});
|
||||
}
|
||||
@@ -163,7 +163,7 @@ export class NodePreGypBinary extends AbstractBinary {
|
||||
const binaryFileName = binaryFile.replace('{platform}', platform)
|
||||
.replace('{arch}', arch);
|
||||
remotePath = remotePath.replace('{module_name}', moduleName)
|
||||
.replace('{name}', this.binaryConfig.category)
|
||||
.replace('{name}', this.binaryName)
|
||||
.replace('{version}', version)
|
||||
.replace('{configuration}', 'Release');
|
||||
const binaryFilePath = join('/', remotePath, binaryFileName);
|
||||
|
||||
@@ -216,6 +216,7 @@ export class Task<T extends TaskBaseData = TaskBaseData> extends Entity {
|
||||
targetName,
|
||||
authorId: `pid_${PID}`,
|
||||
authorIp: HOST_NAME,
|
||||
bizId: `SyncBinary:${targetName}`,
|
||||
data: {
|
||||
// task execute worker
|
||||
taskWorker: '',
|
||||
|
||||
@@ -30,6 +30,7 @@ import { ElectronBinary } from '../../common/adapter/binary/ElectronBinary';
|
||||
import { NodePreGypBinary } from '../../common/adapter/binary/NodePreGypBinary';
|
||||
import { ImageminBinary } from '../../common/adapter/binary/ImageminBinary';
|
||||
import { PlaywrightBinary } from '../../common/adapter/binary/PlaywrightBinary';
|
||||
import { TaskRepository } from 'app/repository/TaskRepository';
|
||||
|
||||
const BinaryClasses = {
|
||||
[SyncerClass.NodeBinary]: NodeBinary,
|
||||
@@ -58,6 +59,8 @@ export class BinarySyncerService extends AbstractService {
|
||||
@Inject()
|
||||
private readonly taskService: TaskService;
|
||||
@Inject()
|
||||
private readonly taskRepository: TaskRepository;
|
||||
@Inject()
|
||||
private readonly httpclient: EggContextHttpClient;
|
||||
@Inject()
|
||||
private readonly nfsAdapter: NFSAdapter;
|
||||
@@ -71,15 +74,51 @@ export class BinarySyncerService extends AbstractService {
|
||||
}
|
||||
|
||||
public async listRootBinaries(binaryName: string) {
|
||||
return await this.binaryRepository.listBinaries(binaryName, '/');
|
||||
// 通常 binaryName 和 category 是一样的,但是有些特殊的 binaryName 会有多个 category,比如 canvas
|
||||
// 所以查询 canvas 的时候,需要将 binaryName 和 category 的数据都查出来
|
||||
const {
|
||||
category,
|
||||
} = binaries[binaryName];
|
||||
const reqs = [
|
||||
this.binaryRepository.listBinaries(binaryName, '/'),
|
||||
];
|
||||
if (category && category !== binaryName) {
|
||||
reqs.push(this.binaryRepository.listBinaries(category, '/'));
|
||||
}
|
||||
|
||||
const [
|
||||
rootBinary,
|
||||
categoryBinary,
|
||||
] = await Promise.all(reqs);
|
||||
|
||||
const versions = rootBinary.map(b => b.name);
|
||||
categoryBinary?.forEach(b => {
|
||||
const version = b.name;
|
||||
// 只将没有的版本添加进去
|
||||
if (!versions.includes(version)) {
|
||||
rootBinary.push(b);
|
||||
}
|
||||
});
|
||||
|
||||
return rootBinary;
|
||||
}
|
||||
|
||||
public async downloadBinary(binary: Binary) {
|
||||
return await this.nfsAdapter.getDownloadUrlOrStream(binary.storePath);
|
||||
}
|
||||
|
||||
// SyncBinary 由定时任务每台单机定时触发,手动去重
|
||||
// 添加 bizId 在 db 防止重复,记录 id 错误
|
||||
public async createTask(binaryName: string, lastData?: any) {
|
||||
return await this.taskService.createTask(Task.createSyncBinary(binaryName, lastData), false);
|
||||
const existsTask = await this.taskRepository.findTaskByTargetName(binaryName, TaskType.SyncBinary);
|
||||
if (existsTask) {
|
||||
return existsTask;
|
||||
}
|
||||
try {
|
||||
return await this.taskService.createTask(Task.createSyncBinary(binaryName, lastData), false);
|
||||
} catch (e) {
|
||||
this.logger.error('[BinarySyncerService.createTask] binaryName: %s, error: %s', binaryName, e);
|
||||
}
|
||||
}
|
||||
|
||||
public async findTask(taskId: string) {
|
||||
@@ -250,15 +289,13 @@ export class BinarySyncerService extends AbstractService {
|
||||
|
||||
private createBinaryInstance(binaryName: string): AbstractBinary | undefined {
|
||||
const config = this.config.cnpmcore;
|
||||
const binaryConfig = binaries[binaryName];
|
||||
|
||||
if (config.sourceRegistryIsCNpm) {
|
||||
const binaryConfig = binaries[binaryName];
|
||||
const syncBinaryFromAPISource = config.syncBinaryFromAPISource || `${config.sourceRegistry}/-/binary`;
|
||||
return new ApiBinary(this.httpclient, this.logger, binaryConfig, syncBinaryFromAPISource);
|
||||
}
|
||||
for (const binaryConfig of Object.values(binaries)) {
|
||||
if (binaryConfig.category === binaryName) {
|
||||
return new BinaryClasses[binaryConfig.syncer](this.httpclient, this.logger, binaryConfig);
|
||||
}
|
||||
return new ApiBinary(this.httpclient, this.logger, binaryConfig, syncBinaryFromAPISource, binaryName);
|
||||
}
|
||||
|
||||
return new BinaryClasses[binaryConfig.syncer](this.httpclient, this.logger, binaryConfig, binaryName);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ import {
|
||||
EggObjectFactory,
|
||||
Inject,
|
||||
} from '@eggjs/tegg';
|
||||
import { TaskType } from '../../common/enum/Task';
|
||||
import { TaskState, TaskType } from '../../common/enum/Task';
|
||||
import { AbstractService } from '../../common/AbstractService';
|
||||
import { TaskRepository } from '../../repository/TaskRepository';
|
||||
import { HOST_NAME, ChangesStreamTask, Task } from '../entity/Task';
|
||||
@@ -55,6 +55,26 @@ export class ChangesStreamService extends AbstractService {
|
||||
return await this.taskService.findExecuteTask(TaskType.ChangesStream) as ChangesStreamTask;
|
||||
}
|
||||
|
||||
public async suspendTaskWhenExit() {
|
||||
this.logger.info('[ChangesStreamService.suspendTaskWhenExit:start]');
|
||||
if (this.config.cnpmcore.enableChangesStream) {
|
||||
// 防止继续获取新的任务
|
||||
this.config.cnpmcore.enableChangesStream = false;
|
||||
const authorIp = os.hostname();
|
||||
// 暂停当前机器所有的 changesStream 任务
|
||||
const tasks = await this.taskRepository.findTaskByAuthorIpAndType(authorIp, TaskType.ChangesStream);
|
||||
for (const task of tasks) {
|
||||
if (task.state === TaskState.Processing) {
|
||||
this.logger.info('[ChangesStreamService.suspendTaskWhenExit:suspend] taskId: %s', task.taskId);
|
||||
// 1. 更新任务状态为 waiting
|
||||
// 2. 重新推入任务队列供其他机器执行
|
||||
await this.taskService.retryTask(task);
|
||||
}
|
||||
}
|
||||
}
|
||||
this.logger.info('[ChangesStreamService.suspendTaskWhenExit:finish]');
|
||||
}
|
||||
|
||||
public async executeTask(task: ChangesStreamTask) {
|
||||
task.authorIp = os.hostname();
|
||||
task.authorId = `pid_${process.pid}`;
|
||||
|
||||
16
app/core/service/EventCorkerAdvice.ts
Normal file
16
app/core/service/EventCorkerAdvice.ts
Normal file
@@ -0,0 +1,16 @@
|
||||
import { ContextEventBus, Inject } from '@eggjs/tegg';
|
||||
import { Advice, IAdvice } from '@eggjs/tegg/aop';
|
||||
|
||||
@Advice()
|
||||
export class EventCorkAdvice implements IAdvice {
|
||||
@Inject()
|
||||
private eventBus: ContextEventBus;
|
||||
|
||||
async beforeCall() {
|
||||
this.eventBus.cork();
|
||||
}
|
||||
|
||||
async afterFinally() {
|
||||
this.eventBus.uncork();
|
||||
}
|
||||
}
|
||||
@@ -65,6 +65,7 @@ export interface PublishPackageCmd {
|
||||
|
||||
const TOTAL = '@@TOTAL@@';
|
||||
const SCOPE_TOTAL_PREFIX = '@@SCOPE@@:';
|
||||
const DESCRIPTION_LIMIT = 1024 * 10;
|
||||
|
||||
@ContextProto({
|
||||
accessLevel: AccessLevel.PUBLIC,
|
||||
@@ -109,6 +110,11 @@ export class PackageManagerService extends AbstractService {
|
||||
pkg.registryId = cmd.registryId;
|
||||
}
|
||||
}
|
||||
|
||||
// 防止 description 长度超过 db 限制
|
||||
if (pkg.description?.length > DESCRIPTION_LIMIT) {
|
||||
pkg.description = pkg.description.substring(0, DESCRIPTION_LIMIT);
|
||||
}
|
||||
await this.packageRepository.savePackage(pkg);
|
||||
// create maintainer
|
||||
await this.packageRepository.savePackageMaintainer(pkg.packageId, publisher.userId);
|
||||
@@ -123,9 +129,14 @@ export class PackageManagerService extends AbstractService {
|
||||
delete cmd.packageJson.readme;
|
||||
}
|
||||
|
||||
const publishTime = cmd.publishTime || new Date();
|
||||
|
||||
// add _cnpmcore_publish_time field to cmd.packageJson
|
||||
if (!cmd.packageJson._cnpmcore_publish_time) {
|
||||
cmd.packageJson._cnpmcore_publish_time = new Date();
|
||||
cmd.packageJson._cnpmcore_publish_time = publishTime;
|
||||
}
|
||||
if (!cmd.packageJson.publish_time) {
|
||||
cmd.packageJson.publish_time = publishTime.getTime();
|
||||
}
|
||||
|
||||
// https://github.com/npm/registry/blob/master/docs/responses/package-metadata.md#abbreviated-version-object
|
||||
@@ -181,6 +192,9 @@ export class PackageManagerService extends AbstractService {
|
||||
engines: cmd.packageJson.engines,
|
||||
_hasShrinkwrap: cmd.packageJson._hasShrinkwrap,
|
||||
hasInstallScript,
|
||||
// https://github.com/cnpm/npminstall/blob/13efc7eec21a61e509226e3772bfb75cd5605612/lib/install_package.js#L176
|
||||
// npminstall require publish time to show the recently update versions
|
||||
publish_time: cmd.packageJson.publish_time,
|
||||
});
|
||||
const abbreviatedDistBytes = Buffer.from(abbreviated);
|
||||
const abbreviatedDistIntegrity = await calculateIntegrity(abbreviatedDistBytes);
|
||||
@@ -192,7 +206,7 @@ export class PackageManagerService extends AbstractService {
|
||||
pkgVersion = PackageVersion.create({
|
||||
packageId: pkg.packageId,
|
||||
version: cmd.version,
|
||||
publishTime: cmd.publishTime || new Date(),
|
||||
publishTime,
|
||||
manifestDist: pkg.createManifest(cmd.version, {
|
||||
size: manifestDistBytes.length,
|
||||
shasum: manifestDistIntegrity.shasum,
|
||||
@@ -215,7 +229,14 @@ export class PackageManagerService extends AbstractService {
|
||||
this.distRepository.saveDist(pkgVersion.manifestDist, manifestDistBytes),
|
||||
this.distRepository.saveDist(pkgVersion.readmeDist, readmeDistBytes),
|
||||
]);
|
||||
await this.packageRepository.createPackageVersion(pkgVersion);
|
||||
try {
|
||||
await this.packageRepository.createPackageVersion(pkgVersion);
|
||||
} catch (e) {
|
||||
if (e.code === 'ER_DUP_ENTRY') {
|
||||
throw new ForbiddenError(`Can't modify pre-existing version: ${pkg.fullname}@${cmd.version}`);
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
if (cmd.skipRefreshPackageManifests !== true) {
|
||||
await this.refreshPackageChangeVersionsToDists(pkg, [ pkgVersion.version ]);
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ import {
|
||||
ContextProto,
|
||||
Inject,
|
||||
} from '@eggjs/tegg';
|
||||
import { Pointcut } from '@eggjs/tegg/aop';
|
||||
import {
|
||||
EggContextHttpClient,
|
||||
} from 'egg';
|
||||
@@ -18,7 +19,6 @@ import { TaskRepository } from '../../repository/TaskRepository';
|
||||
import { PackageRepository } from '../../repository/PackageRepository';
|
||||
import { PackageVersionDownloadRepository } from '../../repository/PackageVersionDownloadRepository';
|
||||
import { UserRepository } from '../../repository/UserRepository';
|
||||
import { DistRepository } from '../../repository/DistRepository';
|
||||
import { Task, SyncPackageTaskOptions, CreateSyncPackageTask } from '../entity/Task';
|
||||
import { Package } from '../entity/Package';
|
||||
import { UserService } from './UserService';
|
||||
@@ -30,6 +30,7 @@ import { RegistryManagerService } from './RegistryManagerService';
|
||||
import { Registry } from '../entity/Registry';
|
||||
import { BadRequestError } from 'egg-errors';
|
||||
import { ScopeManagerService } from './ScopeManagerService';
|
||||
import { EventCorkAdvice } from './EventCorkerAdvice';
|
||||
|
||||
function isoNow() {
|
||||
return new Date().toISOString();
|
||||
@@ -63,8 +64,6 @@ export class PackageSyncerService extends AbstractService {
|
||||
@Inject()
|
||||
private readonly httpclient: EggContextHttpClient;
|
||||
@Inject()
|
||||
private readonly distRepository: DistRepository;
|
||||
@Inject()
|
||||
private readonly registryManagerService: RegistryManagerService;
|
||||
@Inject()
|
||||
private readonly scopeManagerService: ScopeManagerService;
|
||||
@@ -245,6 +244,12 @@ export class PackageSyncerService extends AbstractService {
|
||||
return registry;
|
||||
}
|
||||
|
||||
// 由于 cnpmcore 将 version 和 tag 作为两个独立的 changes 事件分发
|
||||
// 普通版本发布时,短时间内会有两条相同 task 进行同步
|
||||
// 尽量保证读取和写入都需保证任务幂等,需要确保 changes 在同步任务完成后再触发
|
||||
// 通过 DB 唯一索引来保证任务幂等,插入失败不影响 pkg.manifests 更新
|
||||
// 通过 eventBus.cork/uncork 来暂缓事件触发
|
||||
@Pointcut(EventCorkAdvice)
|
||||
public async executeTask(task: Task) {
|
||||
const fullname = task.targetName;
|
||||
const [ scope, name ] = getScopeAndName(fullname);
|
||||
@@ -337,10 +342,13 @@ export class PackageSyncerService extends AbstractService {
|
||||
const contentLength = headers['content-length'] || '-';
|
||||
logs.push(`[${isoNow()}] HTTP [${status}] content-length: ${contentLength}, timing: ${JSON.stringify(res.timing)}`);
|
||||
|
||||
if (status === 404) {
|
||||
// 404 unpublished
|
||||
// 451 blocked
|
||||
const shouldRemovePkg = status === 404 || status === 451;
|
||||
if (shouldRemovePkg) {
|
||||
if (pkg) {
|
||||
await this.packageManagerService.unpublishPackage(pkg);
|
||||
logs.push(`[${isoNow()}] 🟢 Package "${fullname}" was unpublished caused by 404 response: ${JSON.stringify(data)}`);
|
||||
logs.push(`[${isoNow()}] 🟢 Package "${fullname}" was unpublished caused by ${status} response: ${JSON.stringify(data)}`);
|
||||
logs.push(`[${isoNow()}] 🟢 log: ${logUrl}`);
|
||||
logs.push(`[${isoNow()}] 🟢🟢🟢🟢🟢 ${url} 🟢🟢🟢🟢🟢`);
|
||||
await this.taskService.finishTask(task, TaskState.Success, logs.join('\n'));
|
||||
@@ -470,17 +478,6 @@ export class PackageSyncerService extends AbstractService {
|
||||
updateVersions.push(version);
|
||||
logs.push(`[${isoNow()}] 🐛 Remote version ${version} not exists on local abbreviated manifests, need to refresh`);
|
||||
}
|
||||
} else {
|
||||
// try to read from db detect if last sync interrupt before refreshPackageManifestsToDists() be called
|
||||
existsItem = await this.distRepository.findPackageVersionManifest(pkg.packageId, version);
|
||||
// only allow existsItem on db to force refresh, to avoid big versions fresh
|
||||
// see https://r.cnpmjs.org/-/package/@npm-torg/public-scoped-free-org-test-package-2/syncs/61fcc7e8c1646e26a845b674/log
|
||||
if (existsItem) {
|
||||
// version not exists on manifests, need to refresh
|
||||
// bugfix: https://github.com/cnpm/cnpmcore/issues/115
|
||||
updateVersions.push(version);
|
||||
logs.push(`[${isoNow()}] 🐛 Remote version ${version} not exists on local manifests, need to refresh`);
|
||||
}
|
||||
}
|
||||
|
||||
if (existsItem && forceSyncHistory === true) {
|
||||
@@ -568,17 +565,6 @@ export class PackageSyncerService extends AbstractService {
|
||||
if (!pkg) {
|
||||
pkg = await this.packageRepository.findPackage(scope, name);
|
||||
}
|
||||
if (pkg) {
|
||||
// check again, make sure prefix version not exists
|
||||
const existsPkgVersion = await this.packageRepository.findPackageVersion(pkg.packageId, version);
|
||||
if (existsPkgVersion) {
|
||||
await rm(localFile, { force: true });
|
||||
logs.push(`[${isoNow()}] 🐛 [${syncIndex}] Synced version ${version} already exists, skip publish it`);
|
||||
await this.taskService.appendTaskLog(task, logs.join('\n'));
|
||||
logs = [];
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
const publishCmd = {
|
||||
scope,
|
||||
@@ -596,12 +582,15 @@ export class PackageSyncerService extends AbstractService {
|
||||
skipRefreshPackageManifests: true,
|
||||
};
|
||||
try {
|
||||
// 当 version 记录已经存在时,还需要校验一下 pkg.manifests 是否存在
|
||||
const pkgVersion = await this.packageManagerService.publish(publishCmd, users[0]);
|
||||
updateVersions.push(pkgVersion.version);
|
||||
logs.push(`[${isoNow()}] 🟢 [${syncIndex}] Synced version ${version} success, packageVersionId: ${pkgVersion.packageVersionId}, db id: ${pkgVersion.id}`);
|
||||
} catch (err: any) {
|
||||
if (err.name === 'ForbiddenError') {
|
||||
logs.push(`[${isoNow()}] 🐛 [${syncIndex}] Synced version ${version} already exists, skip publish error`);
|
||||
logs.push(`[${isoNow()}] 🐛 [${syncIndex}] Synced version ${version} already exists, skip publish, try to set in local manifest`);
|
||||
// 如果 pkg.manifests 不存在,需要补充一下
|
||||
updateVersions.push(version);
|
||||
} else {
|
||||
err.taskId = task.taskId;
|
||||
this.logger.error(err);
|
||||
@@ -680,6 +669,12 @@ export class PackageSyncerService extends AbstractService {
|
||||
let shouldRefreshDistTags = false;
|
||||
for (const tag in distTags) {
|
||||
const version = distTags[tag];
|
||||
// 新 tag 指向的版本既不在存量数据里,也不在本次同步版本列表里
|
||||
// 例如 latest 对应的 version 写入失败跳过
|
||||
if (!existsVersionMap[version] && !updateVersions.includes(version)) {
|
||||
logs.push(`[${isoNow()}] 🚧 invalid tag(${tag}: ${version}), version is not exists, skip`);
|
||||
continue;
|
||||
}
|
||||
const changed = await this.packageManagerService.savePackageTag(pkg, tag, version);
|
||||
if (changed) {
|
||||
changedTags.push({ action: 'change', tag, version });
|
||||
|
||||
@@ -28,16 +28,21 @@ export class TaskService extends AbstractService {
|
||||
public async createTask(task: Task, addTaskQueueOnExists: boolean) {
|
||||
const existsTask = await this.taskRepository.findTaskByTargetName(task.targetName, task.type);
|
||||
if (existsTask) {
|
||||
if (addTaskQueueOnExists && existsTask.state === TaskState.Waiting) {
|
||||
const queueLength = await this.getTaskQueueLength(task.type);
|
||||
if (queueLength < this.config.cnpmcore.taskQueueHighWaterSize) {
|
||||
// make sure waiting task in queue
|
||||
await this.queueAdapter.push<string>(task.type, existsTask.taskId);
|
||||
this.logger.info('[TaskService.createTask:exists-to-queue] taskType: %s, targetName: %s, taskId: %s, queue size: %s',
|
||||
task.type, task.targetName, task.taskId, queueLength);
|
||||
// 如果任务还未被触发,就不继续重复创建
|
||||
// 如果任务正在执行,可能任务状态已更新,这种情况需要继续创建
|
||||
if (existsTask.state === TaskState.Waiting) {
|
||||
// 提高任务的优先级
|
||||
if (addTaskQueueOnExists) {
|
||||
const queueLength = await this.getTaskQueueLength(task.type);
|
||||
if (queueLength < this.config.cnpmcore.taskQueueHighWaterSize) {
|
||||
// make sure waiting task in queue
|
||||
await this.queueAdapter.push<string>(task.type, existsTask.taskId);
|
||||
this.logger.info('[TaskService.createTask:exists-to-queue] taskType: %s, targetName: %s, taskId: %s, queue size: %s',
|
||||
task.type, task.targetName, task.taskId, queueLength);
|
||||
}
|
||||
}
|
||||
return existsTask;
|
||||
}
|
||||
return existsTask;
|
||||
}
|
||||
await this.taskRepository.saveTask(task);
|
||||
await this.queueAdapter.push<string>(task.type, task.taskId);
|
||||
|
||||
5
app/core/typing.ts
Normal file
5
app/core/typing.ts
Normal file
@@ -0,0 +1,5 @@
|
||||
import { ChangesStreamService } from './service/ChangesStreamService';
|
||||
|
||||
export interface ContextCnpmcore {
|
||||
changesStreamService: ChangesStreamService;
|
||||
}
|
||||
@@ -33,9 +33,10 @@ export class BinarySyncController extends AbstractController {
|
||||
method: HTTPMethodEnum.GET,
|
||||
})
|
||||
async listBinaries() {
|
||||
return Object.values(binaries).map(binaryConfig => {
|
||||
return Object.entries(binaries).map(([ binaryName, binaryConfig ]) => {
|
||||
return {
|
||||
name: `${binaryConfig.category}/`,
|
||||
name: `${binaryName}/`,
|
||||
category: `${binaryConfig.category}/`,
|
||||
description: binaryConfig.description,
|
||||
distUrl: binaryConfig.distUrl,
|
||||
repoUrl: /^https?:\/\//.test(binaryConfig.repo) ? binaryConfig.repo : `https://github.com/${binaryConfig.repo}`,
|
||||
@@ -59,7 +60,18 @@ export class BinarySyncController extends AbstractController {
|
||||
const parsed = path.parse(subpath);
|
||||
const parent = parsed.dir === '/' ? '/' : `${parsed.dir}/`;
|
||||
const name = subpath.endsWith('/') ? `${parsed.base}/` : parsed.base;
|
||||
const binary = await this.binarySyncerService.findBinary(binaryName, parent, name);
|
||||
// 首先查询 binary === category 的情况
|
||||
let binary = await this.binarySyncerService.findBinary(binaryName, parent, name);
|
||||
if (!binary) {
|
||||
// 查询不到再去查询 mergeCategory 的情况
|
||||
const category = binaries?.[binaryName]?.category;
|
||||
if (category) {
|
||||
// canvas/v2.6.1/canvas-v2.6.1-node-v57-linux-glibc-x64.tar.gz
|
||||
// -> node-canvas-prebuilt/v2.6.1/node-canvas-prebuilt-v2.6.1-node-v57-linux-glibc-x64.tar.gz
|
||||
binary = await this.binarySyncerService.findBinary(category, parent, name.replace(new RegExp(`^${binaryName}-`), `${category}-`));
|
||||
}
|
||||
}
|
||||
|
||||
if (!binary) {
|
||||
throw new NotFoundError(`Binary "${binaryName}${subpath}" not found`);
|
||||
}
|
||||
|
||||
@@ -38,13 +38,13 @@ export class UpdatePackageController extends AbstractController {
|
||||
method: HTTPMethodEnum.PUT,
|
||||
})
|
||||
async update(@Context() ctx: EggContext, @HTTPParam() fullname: string, @HTTPBody() data: Maintainer) {
|
||||
const npmCommand = ctx.get('npm-command');
|
||||
if (npmCommand === 'unpublish') {
|
||||
if (this.isNpmCommandValid(ctx, 'unpublish')) {
|
||||
// ignore it
|
||||
return { ok: false };
|
||||
}
|
||||
// only support update maintainer
|
||||
if (npmCommand !== 'owner') {
|
||||
if (!this.isNpmCommandValid(ctx, 'owner')) {
|
||||
const npmCommand = this.getNpmCommand(ctx);
|
||||
throw new BadRequestError(`header: npm-command expected "owner", but got "${npmCommand}"`);
|
||||
}
|
||||
ctx.tValidate(MaintainerDataRule, data);
|
||||
@@ -61,4 +61,21 @@ export class UpdatePackageController extends AbstractController {
|
||||
await this.packageManagerService.replacePackageMaintainers(pkg, users);
|
||||
return { ok: true };
|
||||
}
|
||||
|
||||
private getNpmCommand(ctx: EggContext) {
|
||||
// npm@6: referer: 'xxx [REDACTED]'
|
||||
// npm@>=7: 'npm-command': 'xxx'
|
||||
let npmCommand = ctx.get('npm-command');
|
||||
if (!npmCommand) {
|
||||
npmCommand = ctx.get('referer').split(' ', 1)[0];
|
||||
}
|
||||
|
||||
return npmCommand;
|
||||
}
|
||||
|
||||
private isNpmCommandValid(ctx: EggContext, expectCommand: string) {
|
||||
const npmCommand = this.getNpmCommand(ctx);
|
||||
|
||||
return npmCommand === expectCommand;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,10 +21,14 @@ export class CreateSyncBinaryTask {
|
||||
async subscribe() {
|
||||
if (!this.config.cnpmcore.enableSyncBinary) return;
|
||||
|
||||
for (const binary of Object.values(binaries)) {
|
||||
if (this.config.env === 'unittest' && binary.category !== 'node') continue;
|
||||
for (const [ binaryName, binary ] of Object.entries(binaries)) {
|
||||
if (this.config.env === 'unittest' && binaryName !== 'node') continue;
|
||||
if (binary.disable) continue;
|
||||
await this.binarySyncerService.createTask(binary.category);
|
||||
|
||||
// 默认只同步 binaryName 的二进制,即使有不一致的 category,会在同名的 binaryName 任务中同步
|
||||
// 例如 canvas 只同步 binaryName 为 canvas 的二进制,不同步 category 为 node-canvas-prebuilt 的二进制
|
||||
// node-canvas-prebuilt 的二进制会在 node-canvas-prebuilt 的任务中同步
|
||||
await this.binarySyncerService.createTask(binaryName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -116,4 +116,12 @@ export class TaskRepository extends AbstractRepository {
|
||||
}).limit(1000);
|
||||
return models.map(model => ModelConvertor.convertModelToEntity(model, TaskEntity));
|
||||
}
|
||||
|
||||
async findTaskByAuthorIpAndType(authorIp: string, type: TaskType) {
|
||||
const models = await this.Task.find({
|
||||
type,
|
||||
authorIp,
|
||||
}).limit(1000);
|
||||
return models.map(model => ModelConvertor.convertModelToEntity(model, TaskEntity));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@ export enum SyncerClass {
|
||||
}
|
||||
|
||||
export type BinaryTaskConfig = {
|
||||
category: string;
|
||||
category: string; // 默认 category 为 binaryName,但是有些 binary 会有不同的 category,比如 canvas,包含 canvas 和 node-canvas-prebuilt 两个
|
||||
description: string;
|
||||
syncer: SyncerClass;
|
||||
repo: string;
|
||||
@@ -637,13 +637,6 @@ const binaries: {
|
||||
repo: 'eugeneware/ffmpeg-static',
|
||||
distUrl: 'https://github.com/eugeneware/ffmpeg-static/releases',
|
||||
},
|
||||
canvas: {
|
||||
category: 'canvas',
|
||||
description: 'Node canvas is a Cairo backed Canvas implementation for NodeJS.',
|
||||
syncer: SyncerClass.GithubBinary,
|
||||
repo: 'Automattic/node-canvas',
|
||||
distUrl: 'https://github.com/Automattic/node-canvas/releases',
|
||||
},
|
||||
nodejieba: {
|
||||
category: 'nodejieba',
|
||||
description: '"结巴"中文分词的Node.js版本',
|
||||
@@ -862,6 +855,42 @@ const binaries: {
|
||||
repo: 'dragonflyoss/image-service',
|
||||
distUrl: 'https://github.com/dragonflyoss/image-service/releases',
|
||||
},
|
||||
canvas: {
|
||||
// canvas@<=2.6.1 二进制需要从 node-canvas-prebuilt 下载
|
||||
category: 'node-canvas-prebuilt',
|
||||
description: 'Node canvas is a Cairo backed Canvas implementation for NodeJS.',
|
||||
syncer: SyncerClass.GithubBinary,
|
||||
repo: 'Automattic/node-canvas',
|
||||
distUrl: 'https://github.com/Automattic/node-canvas/releases',
|
||||
},
|
||||
'canvas-prebuilt': {
|
||||
category: 'canvas-prebuilt',
|
||||
distUrl: 'https://github.com/node-gfx/node-canvas-prebuilt/releases',
|
||||
repo: 'chearon/node-canvas-prebuilt',
|
||||
description: 'Prebuilt versions of node-canvas as a drop-in replacement',
|
||||
syncer: SyncerClass.GithubBinary,
|
||||
options: {
|
||||
nodeArchs: {
|
||||
linux: [ 'x64' ],
|
||||
darwin: [ 'x64' ],
|
||||
win32: [ 'x64' ],
|
||||
},
|
||||
},
|
||||
},
|
||||
'node-canvas-prebuilt': {
|
||||
category: 'node-canvas-prebuilt',
|
||||
distUrl: 'https://github.com/node-gfx/node-canvas-prebuilt/releases',
|
||||
repo: 'node-gfx/node-canvas-prebuilt',
|
||||
description: 'Repo used to build binaries for node-canvas on CI',
|
||||
syncer: SyncerClass.GithubBinary,
|
||||
options: {
|
||||
nodeArchs: {
|
||||
linux: [ 'x64' ],
|
||||
darwin: [ 'x64' ],
|
||||
win32: [ 'x64' ],
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export default binaries;
|
||||
|
||||
7
module.d.ts
vendored
Normal file
7
module.d.ts
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
import { ContextCnpmcore } from "./app/core/typing";
|
||||
|
||||
declare module "egg" {
|
||||
export interface EggContextModule {
|
||||
cnpmcoreCore: ContextCnpmcore;
|
||||
}
|
||||
}
|
||||
28
package.json
28
package.json
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "cnpmcore",
|
||||
"version": "2.4.1",
|
||||
"version": "2.10.1",
|
||||
"description": "npm core",
|
||||
"files": [
|
||||
"dist/**/*"
|
||||
@@ -42,13 +42,13 @@
|
||||
"lint:fix": "eslint . --ext .ts --fix",
|
||||
"test": "npm run lint:fix && npm run test-local",
|
||||
"prepare-database": "rm -rf dist && ts-node test/prepare.ts",
|
||||
"test-local": "npm run prepare-database && egg-bin test -r tsconfig-paths/register --full-trace",
|
||||
"t": "npm run lint:fix && npm run prepare-database && egg-bin test --changed -r tsconfig-paths/register --full-trace",
|
||||
"cov": "npm run prepare-database && egg-bin cov -r tsconfig-paths/register --full-trace",
|
||||
"ci": "npm run lint && npm run cov",
|
||||
"test-local": "npm run prepare-database && egg-bin test --full-trace",
|
||||
"t": "npm run lint:fix && npm run prepare-database && egg-bin test --changed --full-trace",
|
||||
"cov": "npm run prepare-database && egg-bin cov --full-trace",
|
||||
"ci": "npm run lint && npm run cov && npm run tsc:prod",
|
||||
"clean": "tsc -b --clean && rm -rf dist",
|
||||
"tsc": "npm run clean && ets && tsc -p ./tsconfig.json",
|
||||
"tsc:prod": "rm -rf dist && ets && tsc -p ./tsconfig.prod.json",
|
||||
"tsc": "npm run clean && tsc -p ./tsconfig.json",
|
||||
"tsc:prod": "npm run clean && tsc -p ./tsconfig.prod.json",
|
||||
"prepublishOnly": "npm run tsc:prod",
|
||||
"start": "eggctl start --daemon",
|
||||
"stop": "eggctl stop"
|
||||
@@ -80,7 +80,7 @@
|
||||
"base-x": "^3.0.9",
|
||||
"bson-objectid": "^2.0.1",
|
||||
"dayjs": "^1.10.7",
|
||||
"egg": "^3.1.0",
|
||||
"egg": "^3.9.0",
|
||||
"egg-cors": "^2.2.3",
|
||||
"egg-errors": "^2.3.0",
|
||||
"egg-redis": "^2.4.0",
|
||||
@@ -102,18 +102,18 @@
|
||||
"validate-npm-package-name": "^3.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/mocha": "^9.0.0",
|
||||
"@types/mocha": "^10.0.1",
|
||||
"@types/mysql": "^2.15.21",
|
||||
"@types/semver": "^7.3.12",
|
||||
"coffee": "^5.4.0",
|
||||
"egg-bin": "^4.16.4",
|
||||
"egg-bin": "^5.9.0",
|
||||
"egg-mock": "^5.0.1",
|
||||
"eslint": "^7.32.0",
|
||||
"eslint-config-egg": "^9.0.0",
|
||||
"eslint": "^8.29.0",
|
||||
"eslint-config-egg": "^12.1.0",
|
||||
"git-contributor": "^1.0.10",
|
||||
"npm-cli-login": "^1.0.0",
|
||||
"ts-node": "^10.4.0",
|
||||
"typescript": "~4.7.0"
|
||||
"ts-node": "^10.9.1",
|
||||
"typescript": "^4.9.4"
|
||||
},
|
||||
"author": "killagu",
|
||||
"license": "MIT",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
-- fix https://github.com/cnpm/cnpmcore/issues/343
|
||||
UPDATE
|
||||
`cnpmcore`.`registries`
|
||||
`registries`
|
||||
SET
|
||||
`host` = 'https://registry.npmjs.org'
|
||||
WHERE
|
||||
|
||||
@@ -323,4 +323,17 @@ export class TestUtil {
|
||||
}
|
||||
return Buffer.concat(chunks).toString();
|
||||
}
|
||||
|
||||
static pickKeys(obj, keys) {
|
||||
const d: Record<string, any> = [];
|
||||
obj.forEach(item => {
|
||||
const newItem = {};
|
||||
for (const key of keys) {
|
||||
newItem[key] = item[key];
|
||||
}
|
||||
|
||||
d.push(newItem);
|
||||
});
|
||||
return d;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,7 +22,7 @@ describe('test/common/adapter/binary/ApiBinary.test.ts', () => {
|
||||
data: await TestUtil.readFixturesFile('cnpmjs.org/mirrors/apis/node.json'),
|
||||
persist: false,
|
||||
});
|
||||
const binary = new ApiBinary(ctx.httpclient, ctx.logger, binaries.node, 'https://cnpmjs.org/mirrors/apis');
|
||||
const binary = new ApiBinary(ctx.httpclient, ctx.logger, binaries.node, 'https://cnpmjs.org/mirrors/apis', 'node');
|
||||
const result = await binary.fetch('/');
|
||||
assert(result);
|
||||
assert(result.items.length > 0);
|
||||
@@ -56,7 +56,7 @@ describe('test/common/adapter/binary/ApiBinary.test.ts', () => {
|
||||
data: await TestUtil.readFixturesFile('r.cnpmjs.org/-/binary/node/v16.13.1.json'),
|
||||
persist: false,
|
||||
});
|
||||
const binary = new ApiBinary(ctx.httpclient, ctx.logger, binaries.node, 'https://r.cnpmjs.org/-/binary');
|
||||
const binary = new ApiBinary(ctx.httpclient, ctx.logger, binaries.node, 'https://r.cnpmjs.org/-/binary', 'node');
|
||||
const result = await binary.fetch('/v16.13.1/');
|
||||
assert(result);
|
||||
assert(result.items.length > 0);
|
||||
|
||||
@@ -22,7 +22,7 @@ describe('test/common/adapter/binary/BucketBinary.test.ts', () => {
|
||||
data: await TestUtil.readFixturesFile('chromedriver.storage.googleapis.com/index.xml'),
|
||||
persist: false,
|
||||
});
|
||||
const binary = new BucketBinary(ctx.httpclient, ctx.logger, binaries.chromedriver);
|
||||
const binary = new BucketBinary(ctx.httpclient, ctx.logger, binaries.chromedriver, 'chromedriver');
|
||||
const result = await binary.fetch('/');
|
||||
assert(result);
|
||||
assert(result.items.length > 0);
|
||||
@@ -51,7 +51,7 @@ describe('test/common/adapter/binary/BucketBinary.test.ts', () => {
|
||||
data: await TestUtil.readFixturesFile('chromedriver.storage.googleapis.com/97.0.4692.71.xml'),
|
||||
persist: false,
|
||||
});
|
||||
const binary = new BucketBinary(ctx.httpclient, ctx.logger, binaries.chromedriver);
|
||||
const binary = new BucketBinary(ctx.httpclient, ctx.logger, binaries.chromedriver, 'chromedriver');
|
||||
const result = await binary.fetch('/97.0.4692.71/');
|
||||
assert(result);
|
||||
assert(result.items.length > 0);
|
||||
@@ -77,7 +77,7 @@ describe('test/common/adapter/binary/BucketBinary.test.ts', () => {
|
||||
persist: false,
|
||||
});
|
||||
// https://selenium-release.storage.googleapis.com/?delimiter=/&prefix=2.43/
|
||||
const binary = new BucketBinary(ctx.httpclient, ctx.logger, binaries.selenium);
|
||||
const binary = new BucketBinary(ctx.httpclient, ctx.logger, binaries.selenium, 'selenium');
|
||||
const result = await binary.fetch('/2.43/');
|
||||
assert(result);
|
||||
assert(result.items.length > 0);
|
||||
@@ -91,7 +91,7 @@ describe('test/common/adapter/binary/BucketBinary.test.ts', () => {
|
||||
data: await TestUtil.readFixturesFile('node-inspector.s3.amazonaws.com/index.xml'),
|
||||
persist: false,
|
||||
});
|
||||
const binary = new BucketBinary(ctx.httpclient, ctx.logger, binaries['node-inspector']);
|
||||
const binary = new BucketBinary(ctx.httpclient, ctx.logger, binaries['node-inspector'], 'node-inspector');
|
||||
const result = await binary.fetch('/');
|
||||
assert(result);
|
||||
assert(result.items.length > 0);
|
||||
@@ -105,7 +105,7 @@ describe('test/common/adapter/binary/BucketBinary.test.ts', () => {
|
||||
data: await TestUtil.readFixturesFile('prisma-builds.s3-eu-west-1.amazonaws.com/index.xml'),
|
||||
persist: false,
|
||||
});
|
||||
const binary = new BucketBinary(ctx.httpclient, ctx.logger, binaries.prisma);
|
||||
const binary = new BucketBinary(ctx.httpclient, ctx.logger, binaries.prisma, 'prisma');
|
||||
const result = await binary.fetch('/');
|
||||
assert(result);
|
||||
assert(result.items.length > 0);
|
||||
|
||||
@@ -22,7 +22,7 @@ describe('test/common/adapter/binary/CypressBinary.test.ts', () => {
|
||||
data: await TestUtil.readFixturesFile('registry.npmjs.com/cypress.json'),
|
||||
persist: false,
|
||||
});
|
||||
const binary = new CypressBinary(ctx.httpclient, ctx.logger, binaries.cypress);
|
||||
const binary = new CypressBinary(ctx.httpclient, ctx.logger, binaries.cypress, 'cypress');
|
||||
const result = await binary.fetch('/');
|
||||
assert(result);
|
||||
assert(result.items.length > 0);
|
||||
@@ -51,13 +51,14 @@ describe('test/common/adapter/binary/CypressBinary.test.ts', () => {
|
||||
data: await TestUtil.readFixturesFile('registry.npmjs.com/cypress.json'),
|
||||
persist: false,
|
||||
});
|
||||
const binary = new CypressBinary(ctx.httpclient, ctx.logger, binaries.cypress);
|
||||
const binary = new CypressBinary(ctx.httpclient, ctx.logger, binaries.cypress, 'cypress');
|
||||
let result = await binary.fetch('/4.0.0/');
|
||||
assert(result);
|
||||
assert(result.items.length === 3);
|
||||
assert(result.items.length === 4);
|
||||
assert(result.items[0].name === 'darwin-x64/');
|
||||
assert(result.items[1].name === 'linux-x64/');
|
||||
assert(result.items[2].name === 'win32-x64/');
|
||||
assert(result.items[1].name === 'darwin-arm64/');
|
||||
assert(result.items[2].name === 'linux-x64/');
|
||||
assert(result.items[3].name === 'win32-x64/');
|
||||
assert(result.items[0].isDir);
|
||||
|
||||
result = await binary.fetch('/4.0.0/darwin-x64/');
|
||||
@@ -67,6 +68,13 @@ describe('test/common/adapter/binary/CypressBinary.test.ts', () => {
|
||||
assert(result.items[0].url === 'https://cdn.cypress.io/desktop/4.0.0/darwin-x64/cypress.zip');
|
||||
assert(!result.items[0].isDir);
|
||||
|
||||
result = await binary.fetch('/4.0.0/darwin-arm64/');
|
||||
assert(result);
|
||||
assert(result.items.length === 1);
|
||||
assert(result.items[0].name === 'cypress.zip');
|
||||
assert(result.items[0].url === 'https://cdn.cypress.io/desktop/4.0.0/darwin-arm64/cypress.zip');
|
||||
assert(!result.items[0].isDir);
|
||||
|
||||
result = await binary.fetch('/4.0.0/linux-x64/');
|
||||
assert(result);
|
||||
assert(result.items.length === 1);
|
||||
|
||||
@@ -23,7 +23,7 @@ describe('test/common/adapter/binary/ElectronBinary.test.ts', () => {
|
||||
data: response,
|
||||
status: 200,
|
||||
});
|
||||
const binary = new ElectronBinary(ctx.httpclient, ctx.logger, binaries.electron);
|
||||
const binary = new ElectronBinary(ctx.httpclient, ctx.logger, binaries.electron, 'electron');
|
||||
let result = await binary.fetch('/');
|
||||
assert(result);
|
||||
assert(result.items.length > 0);
|
||||
|
||||
@@ -23,7 +23,7 @@ describe('test/common/adapter/binary/GithubBinary.test.ts', () => {
|
||||
data: response,
|
||||
status: 200,
|
||||
});
|
||||
const binary = new GithubBinary(ctx.httpclient, ctx.logger, binaries.electron);
|
||||
const binary = new GithubBinary(ctx.httpclient, ctx.logger, binaries.electron, 'electron');
|
||||
let result = await binary.fetch('/');
|
||||
assert(result);
|
||||
assert(result.items.length > 0);
|
||||
|
||||
@@ -20,7 +20,7 @@ describe('test/common/adapter/binary/ImageminBinary.test.ts', () => {
|
||||
app.mockHttpclient('https://registry.npmjs.com/jpegtran-bin', 'GET', {
|
||||
data: await TestUtil.readFixturesFile('registry.npmjs.com/jpegtran-bin.json'),
|
||||
});
|
||||
const binary = new ImageminBinary(ctx.httpclient, ctx.logger, binaries['jpegtran-bin']);
|
||||
const binary = new ImageminBinary(ctx.httpclient, ctx.logger, binaries['jpegtran-bin'], 'jpegtran-bin');
|
||||
let result = await binary.fetch('/');
|
||||
assert(result);
|
||||
assert(result.items.length > 0);
|
||||
@@ -88,7 +88,7 @@ describe('test/common/adapter/binary/ImageminBinary.test.ts', () => {
|
||||
app.mockHttpclient('https://registry.npmjs.com/advpng-bin', 'GET', {
|
||||
data: await TestUtil.readFixturesFile('registry.npmjs.com/advpng-bin.json'),
|
||||
});
|
||||
const binary = new ImageminBinary(ctx.httpclient, ctx.logger, binaries['advpng-bin']);
|
||||
const binary = new ImageminBinary(ctx.httpclient, ctx.logger, binaries['advpng-bin'], 'advpng-bin');
|
||||
let result = await binary.fetch('/');
|
||||
assert(result);
|
||||
assert(result.items.length > 0);
|
||||
@@ -141,7 +141,7 @@ describe('test/common/adapter/binary/ImageminBinary.test.ts', () => {
|
||||
app.mockHttpclient('https://registry.npmjs.com/mozjpeg', 'GET', {
|
||||
data: await TestUtil.readFixturesFile('registry.npmjs.com/mozjpeg.json'),
|
||||
});
|
||||
const binary = new ImageminBinary(ctx.httpclient, ctx.logger, binaries['mozjpeg-bin']);
|
||||
const binary = new ImageminBinary(ctx.httpclient, ctx.logger, binaries['mozjpeg-bin'], 'mozjpeg-bin');
|
||||
let result = await binary.fetch('/');
|
||||
assert(result);
|
||||
// console.log(result.items);
|
||||
@@ -205,7 +205,7 @@ describe('test/common/adapter/binary/ImageminBinary.test.ts', () => {
|
||||
app.mockHttpclient('https://registry.npmjs.com/gifsicle', 'GET', {
|
||||
data: await TestUtil.readFixturesFile('registry.npmjs.com/gifsicle.json'),
|
||||
});
|
||||
const binary = new ImageminBinary(ctx.httpclient, ctx.logger, binaries['gifsicle-bin']);
|
||||
const binary = new ImageminBinary(ctx.httpclient, ctx.logger, binaries['gifsicle-bin'], 'gifsicle-bin');
|
||||
const result = await binary.fetch('/');
|
||||
assert(result);
|
||||
// console.log(result.items);
|
||||
@@ -234,7 +234,7 @@ describe('test/common/adapter/binary/ImageminBinary.test.ts', () => {
|
||||
app.mockHttpclient('https://registry.npmjs.com/optipng-bin', 'GET', {
|
||||
data: await TestUtil.readFixturesFile('registry.npmjs.com/optipng-bin.json'),
|
||||
});
|
||||
const binary = new ImageminBinary(ctx.httpclient, ctx.logger, binaries['optipng-bin']);
|
||||
const binary = new ImageminBinary(ctx.httpclient, ctx.logger, binaries['optipng-bin'], 'optipng-bin');
|
||||
const result = await binary.fetch('/');
|
||||
assert(result);
|
||||
// console.log(result.items);
|
||||
@@ -263,7 +263,7 @@ describe('test/common/adapter/binary/ImageminBinary.test.ts', () => {
|
||||
app.mockHttpclient('https://registry.npmjs.com/zopflipng-bin', 'GET', {
|
||||
data: await TestUtil.readFixturesFile('registry.npmjs.com/zopflipng-bin.json'),
|
||||
});
|
||||
const binary = new ImageminBinary(ctx.httpclient, ctx.logger, binaries['zopflipng-bin']);
|
||||
const binary = new ImageminBinary(ctx.httpclient, ctx.logger, binaries['zopflipng-bin'], 'zopflipng-bin');
|
||||
const result = await binary.fetch('/');
|
||||
assert(result);
|
||||
// console.log(result.items);
|
||||
@@ -292,7 +292,7 @@ describe('test/common/adapter/binary/ImageminBinary.test.ts', () => {
|
||||
app.mockHttpclient('https://registry.npmjs.com/jpegoptim-bin', 'GET', {
|
||||
data: await TestUtil.readFixturesFile('registry.npmjs.com/jpegoptim-bin.json'),
|
||||
});
|
||||
const binary = new ImageminBinary(ctx.httpclient, ctx.logger, binaries['jpegoptim-bin']);
|
||||
const binary = new ImageminBinary(ctx.httpclient, ctx.logger, binaries['jpegoptim-bin'], 'jpegoptim-bin');
|
||||
const result = await binary.fetch('/');
|
||||
assert(result);
|
||||
// console.log(result.items);
|
||||
@@ -321,7 +321,7 @@ describe('test/common/adapter/binary/ImageminBinary.test.ts', () => {
|
||||
app.mockHttpclient('https://registry.npmjs.com/guetzli', 'GET', {
|
||||
data: await TestUtil.readFixturesFile('registry.npmjs.com/guetzli.json'),
|
||||
});
|
||||
const binary = new ImageminBinary(ctx.httpclient, ctx.logger, binaries['guetzli-bin']);
|
||||
const binary = new ImageminBinary(ctx.httpclient, ctx.logger, binaries['guetzli-bin'], 'guetzli-bin');
|
||||
const result = await binary.fetch('/');
|
||||
assert(result);
|
||||
// console.log(result.items);
|
||||
|
||||
@@ -21,7 +21,7 @@ describe('test/common/adapter/binary/NodeBinary.test.ts', () => {
|
||||
app.mockHttpclient('https://nodejs.org/dist/', 'GET', {
|
||||
data: await TestUtil.readFixturesFile('nodejs.org/site/index.html'),
|
||||
});
|
||||
const binary = new NodeBinary(ctx.httpclient, ctx.logger, binaries.node);
|
||||
const binary = new NodeBinary(ctx.httpclient, ctx.logger, binaries.node, 'node');
|
||||
const result = await binary.fetch('/');
|
||||
assert(result);
|
||||
assert(result.items.length > 0);
|
||||
@@ -54,7 +54,7 @@ describe('test/common/adapter/binary/NodeBinary.test.ts', () => {
|
||||
app.mockHttpclient('https://nodejs.org/dist/v16.13.1/', 'GET', {
|
||||
data: await TestUtil.readFixturesFile('nodejs.org/site/v16.13.1/index.html'),
|
||||
});
|
||||
const binary = new NodeBinary(ctx.httpclient, ctx.logger, binaries.node);
|
||||
const binary = new NodeBinary(ctx.httpclient, ctx.logger, binaries.node, 'node');
|
||||
const result = await binary.fetch('/v16.13.1/');
|
||||
assert(result);
|
||||
assert(result.items.length > 0);
|
||||
@@ -87,7 +87,7 @@ describe('test/common/adapter/binary/NodeBinary.test.ts', () => {
|
||||
app.mockHttpclient('https://nodejs.org/download/nightly/v14.0.0-nightly20200119b318926634/', 'GET', {
|
||||
data: await TestUtil.readFixturesFile('nodejs.org/download/nightly/v14.0.0-nightly20200119b318926634/index.html'),
|
||||
});
|
||||
const binary = new NodeBinary(ctx.httpclient, ctx.logger, binaries['node-nightly']);
|
||||
const binary = new NodeBinary(ctx.httpclient, ctx.logger, binaries['node-nightly'], 'node-nightly');
|
||||
const result = await binary.fetch('/v14.0.0-nightly20200119b318926634/');
|
||||
assert(result);
|
||||
assert(result.items.length > 0);
|
||||
@@ -129,7 +129,7 @@ describe('test/common/adapter/binary/NodeBinary.test.ts', () => {
|
||||
app.mockHttpclient('https://nodejs.org/download/nightly/v14.0.0-nightly20200204ee9e689df2/', 'GET', {
|
||||
data: await TestUtil.readFixturesFile('nodejs.org/download/nightly/v14.0.0-nightly20200204ee9e689df2/index.html'),
|
||||
});
|
||||
const binary = new NodeBinary(ctx.httpclient, ctx.logger, binaries['node-nightly']);
|
||||
const binary = new NodeBinary(ctx.httpclient, ctx.logger, binaries['node-nightly'], 'node-nightly');
|
||||
const result = await binary.fetch('/v14.0.0-nightly20200204ee9e689df2/');
|
||||
assert(result);
|
||||
assert(result.items.length > 0);
|
||||
@@ -184,7 +184,7 @@ describe('test/common/adapter/binary/NodeBinary.test.ts', () => {
|
||||
persist: false,
|
||||
});
|
||||
|
||||
const binary = new NodeBinary(ctx.httpclient, ctx.logger, binaries.python);
|
||||
const binary = new NodeBinary(ctx.httpclient, ctx.logger, binaries.python, 'python');
|
||||
let result = await binary.fetch('/');
|
||||
assert(result);
|
||||
assert(result.items.length > 0);
|
||||
|
||||
@@ -24,7 +24,7 @@ describe('test/common/adapter/binary/NodePreGypBinary.test.ts', () => {
|
||||
app.mockHttpclient('https://nodejs.org/dist/index.json', 'GET', {
|
||||
data: await TestUtil.readFixturesFile('nodejs.org/site/index.json'),
|
||||
});
|
||||
const binary = new NodePreGypBinary(ctx.httpclient, ctx.logger, binaries.grpc);
|
||||
const binary = new NodePreGypBinary(ctx.httpclient, ctx.logger, binaries.grpc, 'grpc');
|
||||
let result = await binary.fetch('/');
|
||||
assert(result);
|
||||
assert(result.items.length > 0);
|
||||
@@ -67,7 +67,7 @@ describe('test/common/adapter/binary/NodePreGypBinary.test.ts', () => {
|
||||
app.mockHttpclient('https://nodejs.org/dist/index.json', 'GET', {
|
||||
data: await TestUtil.readFixturesFile('nodejs.org/site/index.json'),
|
||||
});
|
||||
const binary = new NodePreGypBinary(ctx.httpclient, ctx.logger, binaries['grpc-tools']);
|
||||
const binary = new NodePreGypBinary(ctx.httpclient, ctx.logger, binaries['grpc-tools'], 'grpc-tools');
|
||||
let result = await binary.fetch('/');
|
||||
assert(result);
|
||||
assert(result.items.length > 0);
|
||||
@@ -111,7 +111,7 @@ describe('test/common/adapter/binary/NodePreGypBinary.test.ts', () => {
|
||||
app.mockHttpclient('https://nodejs.org/dist/index.json', 'GET', {
|
||||
data: await TestUtil.readFixturesFile('nodejs.org/site/index.json'),
|
||||
});
|
||||
const binary = new NodePreGypBinary(ctx.httpclient, ctx.logger, binaries.nodegit);
|
||||
const binary = new NodePreGypBinary(ctx.httpclient, ctx.logger, binaries.nodegit, 'nodegit');
|
||||
const result = await binary.fetch('/');
|
||||
assert(result);
|
||||
assert(result.items.length > 0);
|
||||
@@ -155,7 +155,7 @@ describe('test/common/adapter/binary/NodePreGypBinary.test.ts', () => {
|
||||
app.mockHttpclient('https://nodejs.org/dist/index.json', 'GET', {
|
||||
data: await TestUtil.readFixturesFile('nodejs.org/site/index.json'),
|
||||
});
|
||||
const binary = new NodePreGypBinary(ctx.httpclient, ctx.logger, binaries['skia-canvas']);
|
||||
const binary = new NodePreGypBinary(ctx.httpclient, ctx.logger, binaries['skia-canvas'], 'skia-canvas');
|
||||
let result = await binary.fetch('/');
|
||||
assert(result);
|
||||
assert(result.items.length > 0);
|
||||
@@ -210,7 +210,7 @@ describe('test/common/adapter/binary/NodePreGypBinary.test.ts', () => {
|
||||
app.mockHttpclient('https://nodejs.org/dist/index.json', 'GET', {
|
||||
data: await TestUtil.readFixturesFile('nodejs.org/site/index.json'),
|
||||
});
|
||||
const binary = new NodePreGypBinary(ctx.httpclient, ctx.logger, binaries.wrtc);
|
||||
const binary = new NodePreGypBinary(ctx.httpclient, ctx.logger, binaries.wrtc, 'wrtc');
|
||||
let result = await binary.fetch('/');
|
||||
assert(result);
|
||||
assert(result.items.length > 0);
|
||||
|
||||
@@ -22,7 +22,7 @@ describe('test/common/adapter/binary/NwjsBinary.test.ts', () => {
|
||||
data: await TestUtil.readFixturesFile('dl.nwjs.io/index.html'),
|
||||
persist: false,
|
||||
});
|
||||
const binary = new NwjsBinary(ctx.httpclient, ctx.logger, binaries.nwjs);
|
||||
const binary = new NwjsBinary(ctx.httpclient, ctx.logger, binaries.nwjs, 'nwjs');
|
||||
const result = await binary.fetch('/');
|
||||
assert(result);
|
||||
assert(result.items.length > 0);
|
||||
@@ -44,7 +44,7 @@ describe('test/common/adapter/binary/NwjsBinary.test.ts', () => {
|
||||
data: await TestUtil.readFixturesFile('nwjs2.s3.amazonaws.com/v0.59.0.xml'),
|
||||
persist: false,
|
||||
});
|
||||
const binary = new NwjsBinary(ctx.httpclient, ctx.logger, binaries.nwjs);
|
||||
const binary = new NwjsBinary(ctx.httpclient, ctx.logger, binaries.nwjs, 'nwjs');
|
||||
let result = await binary.fetch('/v0.59.0/');
|
||||
assert(result);
|
||||
assert(result.items.length > 0);
|
||||
|
||||
@@ -29,7 +29,7 @@ describe('test/common/adapter/binary/PlaywrightBinary.test.ts', () => {
|
||||
})
|
||||
.reply(200, await TestUtil.readFixturesFile('unpkg.com/playwright-core-browsers.json'))
|
||||
.persist();
|
||||
const binary = new PlaywrightBinary(ctx.httpclient, ctx.logger, binaries.playwright);
|
||||
const binary = new PlaywrightBinary(ctx.httpclient, ctx.logger, binaries.playwright, 'playwright');
|
||||
const result = await binary.fetch('/');
|
||||
assert(result);
|
||||
assert(result.items.length > 0);
|
||||
@@ -57,7 +57,7 @@ describe('test/common/adapter/binary/PlaywrightBinary.test.ts', () => {
|
||||
})
|
||||
.reply(200, await TestUtil.readFixturesFile('unpkg.com/playwright-core-browsers.json'))
|
||||
.persist();
|
||||
const binary = new PlaywrightBinary(ctx.httpclient, ctx.logger, binaries.playwright);
|
||||
const binary = new PlaywrightBinary(ctx.httpclient, ctx.logger, binaries.playwright, 'playwright');
|
||||
let result = await binary.fetch('/builds/');
|
||||
assert(result);
|
||||
// console.log(result.items);
|
||||
|
||||
@@ -30,7 +30,7 @@ describe('test/common/adapter/binary/PuppeteerBinary.test.ts', () => {
|
||||
data: '1055816',
|
||||
persist: false,
|
||||
});
|
||||
const binary = new PuppeteerBinary(ctx.httpclient, ctx.logger, binaries['chromium-browser-snapshots']);
|
||||
const binary = new PuppeteerBinary(ctx.httpclient, ctx.logger, binaries['chromium-browser-snapshots'], 'chromium-browser-snapshots');
|
||||
let result = await binary.fetch('/');
|
||||
assert(result);
|
||||
assert(result.items.length === 5);
|
||||
|
||||
@@ -22,7 +22,7 @@ describe('test/common/adapter/binary/SqlcipherBinary.test.ts', () => {
|
||||
data: await TestUtil.readFixturesFile('registry.npmjs.com/@journeyapps/sqlcipher.json'),
|
||||
persist: false,
|
||||
});
|
||||
const binary = new SqlcipherBinary(ctx.httpclient, ctx.logger, binaries['@journeyapps/sqlcipher']);
|
||||
const binary = new SqlcipherBinary(ctx.httpclient, ctx.logger, binaries['@journeyapps/sqlcipher'], '@journeyapps/sqlcipher');
|
||||
const result = await binary.fetch('/');
|
||||
assert(result);
|
||||
assert(result.items.length > 0);
|
||||
@@ -52,7 +52,7 @@ describe('test/common/adapter/binary/SqlcipherBinary.test.ts', () => {
|
||||
data: await TestUtil.readFixturesFile('registry.npmjs.com/@journeyapps/sqlcipher.json'),
|
||||
persist: false,
|
||||
});
|
||||
const binary = new SqlcipherBinary(ctx.httpclient, ctx.logger, binaries['@journeyapps/sqlcipher']);
|
||||
const binary = new SqlcipherBinary(ctx.httpclient, ctx.logger, binaries['@journeyapps/sqlcipher'], '@journeyapps/sqlcipher');
|
||||
const result = await binary.fetch('/v5.3.1/');
|
||||
assert(result);
|
||||
assert(result.items.length > 0);
|
||||
|
||||
@@ -5,7 +5,7 @@ import { Registry } from 'app/core/entity/Registry';
|
||||
import { RegistryManagerService } from 'app/core/service/RegistryManagerService';
|
||||
import assert = require('assert');
|
||||
import { Context } from 'egg';
|
||||
import { app, mock } from 'egg-mock/bootstrap';
|
||||
import { app } from 'egg-mock/bootstrap';
|
||||
|
||||
describe('test/common/adapter/changesStream/CnpmjsorgChangesStream.test.ts', () => {
|
||||
let ctx: Context;
|
||||
@@ -83,7 +83,7 @@ describe('test/common/adapter/changesStream/CnpmjsorgChangesStream.test.ts', ()
|
||||
],
|
||||
},
|
||||
});
|
||||
const stream = await cnpmjsorgChangesStream.fetchChanges(registry, '1');
|
||||
const stream = cnpmjsorgChangesStream.fetchChanges(registry, '1');
|
||||
const changes:ChangesStreamChange[] = [];
|
||||
for await (const change of stream) {
|
||||
changes.push(change);
|
||||
@@ -92,7 +92,7 @@ describe('test/common/adapter/changesStream/CnpmjsorgChangesStream.test.ts', ()
|
||||
});
|
||||
|
||||
it('should reject max limit', async () => {
|
||||
mock(ctx.httpclient, 'request', async (url: string) => {
|
||||
app.mockHttpclient('https://r2.cnpmjs.org/_changes?since=1&limit=', 'GET', (url = '') => {
|
||||
const limit = (new URL(url)).searchParams.get('limit');
|
||||
return {
|
||||
data: {
|
||||
@@ -105,7 +105,7 @@ describe('test/common/adapter/changesStream/CnpmjsorgChangesStream.test.ts', ()
|
||||
},
|
||||
};
|
||||
});
|
||||
const stream = await cnpmjsorgChangesStream.fetchChanges(registry, '1');
|
||||
const stream = cnpmjsorgChangesStream.fetchChanges(registry, '1');
|
||||
await assert.rejects(async () => {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
for await (const _ of stream) {
|
||||
|
||||
27
test/core/service/BinarySyncerService/createTask.test.ts
Normal file
27
test/core/service/BinarySyncerService/createTask.test.ts
Normal file
@@ -0,0 +1,27 @@
|
||||
import assert = require('assert');
|
||||
import { app } from 'egg-mock/bootstrap';
|
||||
import { Context } from 'egg';
|
||||
import { BinarySyncerService } from 'app/core/service/BinarySyncerService';
|
||||
|
||||
describe('test/core/service/BinarySyncerService/createTask.test.ts', () => {
|
||||
let ctx: Context;
|
||||
let binarySyncerService: BinarySyncerService;
|
||||
|
||||
beforeEach(async () => {
|
||||
ctx = await app.mockModuleContext();
|
||||
binarySyncerService = await ctx.getEggObject(BinarySyncerService);
|
||||
});
|
||||
|
||||
afterEach(async () => {
|
||||
await app.destroyModuleContext(ctx);
|
||||
});
|
||||
|
||||
describe('createTask()', () => {
|
||||
it('should ignore duplicate binary task', async () => {
|
||||
const task = await binarySyncerService.createTask('banana', {});
|
||||
const newTask = await binarySyncerService.createTask('banana', {});
|
||||
assert(task?.taskId === newTask?.taskId);
|
||||
assert(task?.bizId === 'SyncBinary:banana');
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,4 +1,4 @@
|
||||
import assert = require('assert/strict');
|
||||
import assert = require('assert');
|
||||
import { Readable } from 'node:stream';
|
||||
import { app, mock } from 'egg-mock/bootstrap';
|
||||
import { Context } from 'egg';
|
||||
@@ -10,6 +10,7 @@ import { RegistryType } from 'app/common/enum/Registry';
|
||||
import { ScopeManagerService } from 'app/core/service/ScopeManagerService';
|
||||
import { Registry } from 'app/core/entity/Registry';
|
||||
import { TestUtil } from 'test/TestUtil';
|
||||
import { RedisQueueAdapter } from 'app/infra/QueueAdapter';
|
||||
|
||||
describe('test/core/service/ChangesStreamService.test.ts', () => {
|
||||
let ctx: Context;
|
||||
@@ -20,12 +21,14 @@ describe('test/core/service/ChangesStreamService.test.ts', () => {
|
||||
let task: ChangesStreamTask;
|
||||
let npmRegistry: Registry;
|
||||
let cnpmRegistry: Registry;
|
||||
let queueAdapter: RedisQueueAdapter;
|
||||
beforeEach(async () => {
|
||||
ctx = await app.mockModuleContext();
|
||||
changesStreamService = await ctx.getEggObject(ChangesStreamService);
|
||||
taskService = await ctx.getEggObject(TaskService);
|
||||
registryManagerService = await ctx.getEggObject(RegistryManagerService);
|
||||
scopeManagerService = await ctx.getEggObject(ScopeManagerService);
|
||||
queueAdapter = await ctx.getEggObject(RedisQueueAdapter);
|
||||
assert(changesStreamService);
|
||||
task = Task.createChangesStream('GLOBAL_WORKER', '', '9527');
|
||||
taskService.createTask(task, false);
|
||||
@@ -194,4 +197,44 @@ describe('test/core/service/ChangesStreamService.test.ts', () => {
|
||||
assert(task.data.since === '3');
|
||||
});
|
||||
});
|
||||
|
||||
describe('suspendTaskWhenExit()', () => {
|
||||
it('should work', async () => {
|
||||
app.mockLog();
|
||||
mock(app.config.cnpmcore, 'enableChangesStream', true);
|
||||
app.mockHttpclient('https://replicate.npmjs.com/_changes?since=9527', 'GET', () => {
|
||||
return {
|
||||
data: {
|
||||
res: Readable.from(''),
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
const task = await changesStreamService.findExecuteTask();
|
||||
assert(task);
|
||||
await changesStreamService.executeTask(task);
|
||||
assert(task.state === 'processing');
|
||||
|
||||
let len = await queueAdapter.length('changes_stream');
|
||||
assert(len === 0);
|
||||
await changesStreamService.suspendTaskWhenExit();
|
||||
const newTask = await taskService.findTask(task.taskId);
|
||||
assert(newTask);
|
||||
assert(newTask.taskId === task.taskId);
|
||||
assert(newTask.state === 'waiting');
|
||||
len = await queueAdapter.length('changes_stream');
|
||||
assert(len === 1);
|
||||
|
||||
app.expectLog('[ChangesStreamService.suspendTaskWhenExit:suspend] taskId');
|
||||
|
||||
});
|
||||
|
||||
it('should ignore when changesStream disable', async () => {
|
||||
app.mockLog();
|
||||
mock(app.config.cnpmcore, 'enableChangesStream', true);
|
||||
await changesStreamService.suspendTaskWhenExit();
|
||||
app.expectLog('[ChangesStreamService.suspendTaskWhenExit:finish]');
|
||||
});
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
@@ -75,6 +75,28 @@ describe('test/core/service/PackageManagerService/publish.test.ts', () => {
|
||||
app.expectLog(/\[\d+\.\d+\] \[NFSAdapter:uploadBytes|T\]/);
|
||||
});
|
||||
|
||||
it('should work slice long description', async () => {
|
||||
app.mockLog();
|
||||
const { packageId } = await packageManagerService.publish({
|
||||
dist: {
|
||||
content: Buffer.alloc(0),
|
||||
},
|
||||
tag: '',
|
||||
scope: '',
|
||||
name: 'foo',
|
||||
description: '~'.repeat(1100 * 100),
|
||||
packageJson: {},
|
||||
readme: '',
|
||||
version: '1.0.0',
|
||||
isPrivate: true,
|
||||
}, publisher);
|
||||
const pkgVersion = await packageRepository.findPackageVersion(packageId, '1.0.0');
|
||||
assert(pkgVersion);
|
||||
assert.equal(pkgVersion.version, '1.0.0');
|
||||
const pkg = await packageRepository.findPackage('', 'foo');
|
||||
assert(pkg?.description === '~'.repeat(1024 * 10));
|
||||
});
|
||||
|
||||
it('should work with dist.localFile', async () => {
|
||||
const { packageId } = await packageManagerService.publish({
|
||||
dist: {
|
||||
|
||||
@@ -1,18 +1,27 @@
|
||||
import assert = require('assert');
|
||||
import { app, mock } from 'egg-mock/bootstrap';
|
||||
import { Context } from 'egg';
|
||||
import { setTimeout } from 'timers/promises';
|
||||
import { PackageSyncerService } from '../../../../app/core/service/PackageSyncerService';
|
||||
import { TestUtil } from '../../../TestUtil';
|
||||
import { Task } from 'app/core/entity/Task';
|
||||
import { TaskState } from '../../../../app/common/enum/Task';
|
||||
import { TaskRepository } from '../../../../app/repository/TaskRepository';
|
||||
import { TaskService } from '../../../../app/core/service/TaskService';
|
||||
|
||||
describe('test/core/service/PackageSyncerService/createTask.test.ts', () => {
|
||||
let ctx: Context;
|
||||
const pkgName = '@cnpmcore/foo';
|
||||
const username = 'mock_username';
|
||||
let packageSyncerService: PackageSyncerService;
|
||||
let taskRepository: TaskRepository;
|
||||
let taskService: TaskService;
|
||||
|
||||
beforeEach(async () => {
|
||||
ctx = await app.mockModuleContext();
|
||||
packageSyncerService = await ctx.getEggObject(PackageSyncerService);
|
||||
taskRepository = await ctx.getEggObject(TaskRepository);
|
||||
taskService = await ctx.getEggObject(TaskService);
|
||||
|
||||
await TestUtil.createPackage({
|
||||
name: pkgName,
|
||||
@@ -56,4 +65,25 @@ describe('test/core/service/PackageSyncerService/createTask.test.ts', () => {
|
||||
});
|
||||
assert(task);
|
||||
});
|
||||
|
||||
it('should create task when processing', async () => {
|
||||
mock(packageSyncerService, 'executeTask', async (task: Task) => {
|
||||
task.state = TaskState.Processing;
|
||||
await taskRepository.saveTask(task);
|
||||
await setTimeout(2);
|
||||
await taskService.finishTask(task, TaskState.Success);
|
||||
});
|
||||
const task = await packageSyncerService.createTask(pkgName);
|
||||
const res = await Promise.all([ packageSyncerService.executeTask(task), (async () => {
|
||||
await setTimeout(1);
|
||||
return await packageSyncerService.createTask(pkgName);
|
||||
})() ]);
|
||||
assert(res[1].taskId !== task.taskId);
|
||||
});
|
||||
|
||||
it('should not duplicate task when waiting', async () => {
|
||||
const task = await packageSyncerService.createTask(pkgName);
|
||||
const newTask = await packageSyncerService.createTask(pkgName);
|
||||
assert(newTask.taskId === task.taskId);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -17,6 +17,8 @@ import { Registry } from 'app/core/entity/Registry';
|
||||
import { RegistryType } from 'app/common/enum/Registry';
|
||||
import { TaskService } from 'app/core/service/TaskService';
|
||||
import { ScopeManagerService } from 'app/core/service/ScopeManagerService';
|
||||
import { UserService } from 'app/core/service/UserService';
|
||||
import { ChangeRepository } from 'app/repository/ChangeRepository';
|
||||
|
||||
describe('test/core/service/PackageSyncerService/executeTask.test.ts', () => {
|
||||
let ctx: Context;
|
||||
@@ -27,6 +29,8 @@ describe('test/core/service/PackageSyncerService/executeTask.test.ts', () => {
|
||||
let registryManagerService: RegistryManagerService;
|
||||
let taskService: TaskService;
|
||||
let scopeManagerService: ScopeManagerService;
|
||||
let userService: UserService;
|
||||
let changeRepository: ChangeRepository;
|
||||
|
||||
beforeEach(async () => {
|
||||
ctx = await app.mockModuleContext();
|
||||
@@ -37,6 +41,8 @@ describe('test/core/service/PackageSyncerService/executeTask.test.ts', () => {
|
||||
taskService = await ctx.getEggObject(TaskService);
|
||||
registryManagerService = await ctx.getEggObject(RegistryManagerService);
|
||||
scopeManagerService = await ctx.getEggObject(ScopeManagerService);
|
||||
userService = await ctx.getEggObject(UserService);
|
||||
changeRepository = await ctx.getEggObject(ChangeRepository);
|
||||
});
|
||||
|
||||
afterEach(async () => {
|
||||
@@ -389,7 +395,6 @@ describe('test/core/service/PackageSyncerService/executeTask.test.ts', () => {
|
||||
persist: false,
|
||||
});
|
||||
name = 'cnpmcore-test-sync-dependencies';
|
||||
// don't add cnpmcore-test-sync-deprecated task if cnpmcore-test-sync-deprecated already exists
|
||||
const task = await packageSyncerService.createTask(name);
|
||||
assert(task);
|
||||
assert.equal(task.targetName, name);
|
||||
@@ -433,7 +438,7 @@ describe('test/core/service/PackageSyncerService/executeTask.test.ts', () => {
|
||||
app.mockAgent().assertNoPendingInterceptors();
|
||||
});
|
||||
|
||||
it('should ignore publish ForbiddenError on sync task', async () => {
|
||||
it('should ignore when all version publish ForbiddenError', async () => {
|
||||
app.mockHttpclient('https://registry.npmjs.org/cnpmcore-test-sync-deprecated', 'GET', {
|
||||
data: await TestUtil.readFixturesFile('registry.npmjs.org/cnpmcore-test-sync-deprecated.json'),
|
||||
persist: false,
|
||||
@@ -453,8 +458,7 @@ describe('test/core/service/PackageSyncerService/executeTask.test.ts', () => {
|
||||
const stream = await packageSyncerService.findTaskLog(task);
|
||||
assert(stream);
|
||||
const log = await TestUtil.readStreamToLog(stream);
|
||||
// console.log(log);
|
||||
assert(log.includes('🐛 [1] Synced version 0.0.0 already exists, skip publish error'));
|
||||
assert(log.includes('🐛 [1] Synced version 0.0.0 already exists, skip publish, try to set in local manifest'));
|
||||
app.mockAgent().assertNoPendingInterceptors();
|
||||
});
|
||||
|
||||
@@ -483,102 +487,312 @@ describe('test/core/service/PackageSyncerService/executeTask.test.ts', () => {
|
||||
assert(log.includes('❌ All versions sync fail, package not exists'));
|
||||
});
|
||||
|
||||
it('should sync 2 versions package: @cnpmcore/test-sync-package-has-two-versions', async () => {
|
||||
app.mockHttpclient('https://registry.npmjs.org/%40cnpmcore%2Ftest-sync-package-has-two-versions', 'GET', {
|
||||
data: '{"_id":"@cnpmcore/test-sync-package-has-two-versions","_rev":"4-541287ae0a14039fea89ac08fa5ec53d","name":"@cnpmcore/test-sync-package-has-two-versions","dist-tags":{"latest":"2.0.0","next":"2.0.0"},"versions":{"1.0.0":{"name":"@cnpmcore/test-sync-package-has-two-versions","version":"1.0.0","description":"cnpmcore local test package","main":"index.js","scripts":{"test":"echo \\"hello\\""},"author":"","license":"MIT","gitHead":"60cfb1cf401f87a60a1b0dfd7ee739f98ffd7847","_id":"@cnpmcore/test-sync-package-has-two-versions@1.0.0","_nodeVersion":"16.13.1","_npmVersion":"8.1.2","dist":{"integrity":"sha512-WR0T96H8t7ss1FK8GWPPblx+usbjU4bNGRjMHS9t/oVA5DgJDxitydPSFPeIUtXciyekI7R47do9Lc3GgC4P5A==","shasum":"2ddc6ee93b92be6d64139fb1a631d2610f43e946","tarball":"https://registry.npmjs.org/@cnpmcore/test-sync-package-has-two-versions/-/test-sync-package-has-two-versions-1.0.0.tgz","fileCount":2,"unpackedSize":238,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQDj5Ui2GU8nVmHFk0hCt/i3gPW9eQdOCZgKzpAlkvERwQIhAPZ0NCefLoEfOpnbdKAUr7Ng9Sy6FMnTsDxDaM2dQHNw"}]},"_npmUser":{"name":"fengmk2","email":"fengmk2@gmail.com"},"directories":{},"maintainers":[{"name":"fengmk2","email":"fengmk2@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/test-sync-package-has-two-versions_1.0.0_1639442699824_0.6948988437963031"},"_hasShrinkwrap":false},"2.0.0":{"name":"@cnpmcore/test-sync-package-has-two-versions","version":"2.0.0","description":"cnpmcore local test package","main":"index.js","scripts":{"test":"echo \\"hello\\""},"author":"","license":"MIT","gitHead":"60cfb1cf401f87a60a1b0dfd7ee739f98ffd7847","_id":"@cnpmcore/test-sync-package-has-two-versions@2.0.0","_nodeVersion":"16.13.1","_npmVersion":"8.1.2","dist":{"integrity":"sha512-qgHLQzXq+VN7q0JWibeBYrqb3Iajl4lpVuxlQstclRz4ejujfDFswBGSXmCv9FyIIdmSAe5bZo0oHQLsod3pAA==","shasum":"891eb8e08ceadbd86e75b6d66f31f7e5a28a8d68","tarball":"https://registry.npmjs.org/@cnpmcore/test-sync-package-has-two-versions/-/test-sync-package-has-two-versions-2.0.0.tgz","fileCount":2,"unpackedSize":238,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIAWVz7mIHF23Gq4a+Swsj2ZSdn87991HcE1+fQm8shNCAiByOIuhaZAbo9hct24qYf7FWqx6Lyluo+Rpnrn91//Ibg=="}]},"_npmUser":{"name":"fengmk2","email":"fengmk2@gmail.com"},"directories":{},"maintainers":[{"name":"fengmk2","email":"fengmk2@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/test-sync-package-has-two-versions_2.0.0_1639442732240_0.33204392278137207"},"_hasShrinkwrap":false}},"time":{"created":"2021-12-14T00:44:59.775Z","1.0.0":"2021-12-14T00:44:59.940Z","modified":"2022-05-23T02:33:52.613Z","2.0.0":"2021-12-14T00:45:32.457Z"},"maintainers":[{"email":"killa07071201@gmail.com","name":"killagu"},{"email":"fengmk2@gmail.com","name":"fengmk2"}],"description":"cnpmcore local test package","license":"MIT","readme":"ERROR: No README data found!","readmeFilename":""}',
|
||||
persist: false,
|
||||
repeats: 2,
|
||||
});
|
||||
app.mockHttpclient('https://registry.npmjs.org/@cnpmcore/test-sync-package-has-two-versions/-/test-sync-package-has-two-versions-1.0.0.tgz', 'GET', {
|
||||
data: await TestUtil.readFixturesFile('registry.npmjs.org/foobar/-/foobar-1.0.0.tgz'),
|
||||
persist: false,
|
||||
});
|
||||
app.mockHttpclient('https://registry.npmjs.org/@cnpmcore/test-sync-package-has-two-versions/-/test-sync-package-has-two-versions-2.0.0.tgz', 'GET', {
|
||||
data: await TestUtil.readFixturesFile('registry.npmjs.org/foobar/-/foobar-1.0.0.tgz'),
|
||||
persist: false,
|
||||
describe('sync version idempotence', async () => {
|
||||
beforeEach(async () => {
|
||||
app.mockHttpclient('https://registry.npmjs.org/%40cnpmcore%2Ftest-sync-package-has-two-versions', 'GET', {
|
||||
data: '{"_id":"@cnpmcore/test-sync-package-has-two-versions","_rev":"4-541287ae0a14039fea89ac08fa5ec53d","name":"@cnpmcore/test-sync-package-has-two-versions","dist-tags":{"latest":"2.0.0","next":"2.0.0"},"versions":{"1.0.0":{"name":"@cnpmcore/test-sync-package-has-two-versions","version":"1.0.0","description":"cnpmcore local test package","main":"index.js","scripts":{"test":"echo \\"hello\\""},"author":"","license":"MIT","gitHead":"60cfb1cf401f87a60a1b0dfd7ee739f98ffd7847","_id":"@cnpmcore/test-sync-package-has-two-versions@1.0.0","_nodeVersion":"16.13.1","_npmVersion":"8.1.2","dist":{"integrity":"sha512-WR0T96H8t7ss1FK8GWPPblx+usbjU4bNGRjMHS9t/oVA5DgJDxitydPSFPeIUtXciyekI7R47do9Lc3GgC4P5A==","shasum":"2ddc6ee93b92be6d64139fb1a631d2610f43e946","tarball":"https://registry.npmjs.org/@cnpmcore/test-sync-package-has-two-versions/-/test-sync-package-has-two-versions-1.0.0.tgz","fileCount":2,"unpackedSize":238,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQDj5Ui2GU8nVmHFk0hCt/i3gPW9eQdOCZgKzpAlkvERwQIhAPZ0NCefLoEfOpnbdKAUr7Ng9Sy6FMnTsDxDaM2dQHNw"}]},"_npmUser":{"name":"fengmk2","email":"fengmk2@gmail.com"},"directories":{},"maintainers":[{"name":"fengmk2","email":"fengmk2@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/test-sync-package-has-two-versions_1.0.0_1639442699824_0.6948988437963031"},"_hasShrinkwrap":false},"2.0.0":{"name":"@cnpmcore/test-sync-package-has-two-versions","version":"2.0.0","description":"cnpmcore local test package","main":"index.js","scripts":{"test":"echo \\"hello\\""},"author":"","license":"MIT","gitHead":"60cfb1cf401f87a60a1b0dfd7ee739f98ffd7847","_id":"@cnpmcore/test-sync-package-has-two-versions@2.0.0","_nodeVersion":"16.13.1","_npmVersion":"8.1.2","dist":{"integrity":"sha512-qgHLQzXq+VN7q0JWibeBYrqb3Iajl4lpVuxlQstclRz4ejujfDFswBGSXmCv9FyIIdmSAe5bZo0oHQLsod3pAA==","shasum":"891eb8e08ceadbd86e75b6d66f31f7e5a28a8d68","tarball":"https://registry.npmjs.org/@cnpmcore/test-sync-package-has-two-versions/-/test-sync-package-has-two-versions-2.0.0.tgz","fileCount":2,"unpackedSize":238,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIAWVz7mIHF23Gq4a+Swsj2ZSdn87991HcE1+fQm8shNCAiByOIuhaZAbo9hct24qYf7FWqx6Lyluo+Rpnrn91//Ibg=="}]},"_npmUser":{"name":"fengmk2","email":"fengmk2@gmail.com"},"directories":{},"maintainers":[{"name":"fengmk2","email":"fengmk2@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/test-sync-package-has-two-versions_2.0.0_1639442732240_0.33204392278137207"},"_hasShrinkwrap":false}},"time":{"created":"2021-12-14T00:44:59.775Z","1.0.0":"2021-12-14T00:44:59.940Z","modified":"2022-05-23T02:33:52.613Z","2.0.0":"2021-12-14T00:45:32.457Z"},"maintainers":[{"email":"killa07071201@gmail.com","name":"killagu"},{"email":"fengmk2@gmail.com","name":"fengmk2"}],"description":"cnpmcore local test package","license":"MIT","readme":"ERROR: No README data found!","readmeFilename":""}',
|
||||
persist: false,
|
||||
repeats: 2,
|
||||
});
|
||||
app.mockHttpclient('https://registry.npmjs.org/@cnpmcore/test-sync-package-has-two-versions/-/test-sync-package-has-two-versions-1.0.0.tgz', 'GET', {
|
||||
data: await TestUtil.readFixturesFile('registry.npmjs.org/foobar/-/foobar-1.0.0.tgz'),
|
||||
persist: false,
|
||||
});
|
||||
app.mockHttpclient('https://registry.npmjs.org/@cnpmcore/test-sync-package-has-two-versions/-/test-sync-package-has-two-versions-2.0.0.tgz', 'GET', {
|
||||
data: await TestUtil.readFixturesFile('registry.npmjs.org/foobar/-/foobar-1.0.0.tgz'),
|
||||
persist: false,
|
||||
});
|
||||
});
|
||||
|
||||
// https://www.npmjs.com/package/@cnpmcore/test-sync-package-has-two-versions
|
||||
const name = '@cnpmcore/test-sync-package-has-two-versions';
|
||||
await packageSyncerService.createTask(name);
|
||||
let task = await packageSyncerService.findExecuteTask();
|
||||
assert(task);
|
||||
assert.equal(task.targetName, name);
|
||||
await packageSyncerService.executeTask(task);
|
||||
let stream = await packageSyncerService.findTaskLog(task);
|
||||
assert(stream);
|
||||
let log = await TestUtil.readStreamToLog(stream);
|
||||
// console.log(log);
|
||||
assert(log.includes('] 🟢 Synced updated 2 versions, removed 0 versions'));
|
||||
assert(log.includes('] 🚧 Syncing versions 0 => 2'));
|
||||
it('should sync 2 versions package: @cnpmcore/test-sync-package-has-two-versions', async () => {
|
||||
// https://www.npmjs.com/package/@cnpmcore/test-sync-package-has-two-versions
|
||||
const name = '@cnpmcore/test-sync-package-has-two-versions';
|
||||
await packageSyncerService.createTask(name);
|
||||
let task = await packageSyncerService.findExecuteTask();
|
||||
assert(task);
|
||||
assert.equal(task.targetName, name);
|
||||
await packageSyncerService.executeTask(task);
|
||||
let stream = await packageSyncerService.findTaskLog(task);
|
||||
assert(stream);
|
||||
let log = await TestUtil.readStreamToLog(stream);
|
||||
// console.log(log);
|
||||
assert(log.includes('] 🟢 Synced updated 2 versions, removed 0 versions'));
|
||||
assert(log.includes('] 🚧 Syncing versions 0 => 2'));
|
||||
|
||||
// mock listPackageFullManifests return only one version
|
||||
// 如果 version publish 同步中断了,没有刷新 manifests,会导致下一次同步重新 version publish,然后报错
|
||||
// Avoid: Can't modify pre-existing version: 1.0.0
|
||||
const scopedAndName = getScopeAndName(name);
|
||||
const manifests = await packageManagerService.listPackageFullManifests(scopedAndName[0], scopedAndName[1]);
|
||||
delete manifests.data.versions['1.0.0'];
|
||||
mock.data(PackageManagerService.prototype, 'listPackageFullManifests', manifests);
|
||||
// mock listPackageFullManifests return only one version
|
||||
// 如果 version publish 同步中断了,没有刷新 manifests,会导致下一次同步重新 version publish,然后报错
|
||||
// Avoid: Can't modify pre-existing version: 1.0.0
|
||||
const scopedAndName = getScopeAndName(name);
|
||||
const manifests = await packageManagerService.listPackageFullManifests(scopedAndName[0], scopedAndName[1]);
|
||||
delete manifests.data.versions['1.0.0'];
|
||||
mock.data(PackageManagerService.prototype, 'listPackageFullManifests', manifests);
|
||||
|
||||
await packageSyncerService.createTask(name);
|
||||
task = await packageSyncerService.findExecuteTask();
|
||||
assert(task);
|
||||
assert.equal(task.targetName, name);
|
||||
await packageSyncerService.executeTask(task);
|
||||
stream = await packageSyncerService.findTaskLog(task);
|
||||
assert(stream);
|
||||
log = await TestUtil.readStreamToLog(stream);
|
||||
// console.log(log);
|
||||
assert(log.includes('] 🐛 Remote version 1.0.0 not exists on local manifests, need to refresh'));
|
||||
assert(log.includes('] 🟢 Synced updated 1 versions'));
|
||||
assert(log.includes('] 🚧 Syncing versions 1 => 2'));
|
||||
app.mockAgent().assertNoPendingInterceptors();
|
||||
await mock.restore();
|
||||
await packageSyncerService.createTask(name);
|
||||
task = await packageSyncerService.findExecuteTask();
|
||||
assert(task);
|
||||
assert.equal(task.targetName, name);
|
||||
await packageSyncerService.executeTask(task);
|
||||
stream = await packageSyncerService.findTaskLog(task);
|
||||
assert(stream);
|
||||
log = await TestUtil.readStreamToLog(stream);
|
||||
// console.log(log);
|
||||
assert(log.includes('Synced version 1.0.0 already exists, skip publish, try to set in local manifest'));
|
||||
assert(log.includes('] 🟢 Synced updated 1 versions'));
|
||||
assert(log.includes('] 🚧 Syncing versions 1 => 2'));
|
||||
app.mockAgent().assertNoPendingInterceptors();
|
||||
await mock.restore();
|
||||
|
||||
app.mockHttpclient('https://registry.npmjs.org/%40cnpmcore%2Ftest-sync-package-has-two-versions', 'GET', {
|
||||
data: '{"_id":"@cnpmcore/test-sync-package-has-two-versions","_rev":"4-541287ae0a14039fea89ac08fa5ec53d","name":"@cnpmcore/test-sync-package-has-two-versions","dist-tags":{"latest":"2.0.0","next":"2.0.0"},"versions":{"1.0.0":{"name":"@cnpmcore/test-sync-package-has-two-versions","version":"1.0.0","description":"cnpmcore local test package","main":"index.js","scripts":{"test":"echo \\"hello\\""},"author":"","license":"MIT","gitHead":"60cfb1cf401f87a60a1b0dfd7ee739f98ffd7847","_id":"@cnpmcore/test-sync-package-has-two-versions@1.0.0","_nodeVersion":"16.13.1","_npmVersion":"8.1.2","dist":{"integrity":"sha512-WR0T96H8t7ss1FK8GWPPblx+usbjU4bNGRjMHS9t/oVA5DgJDxitydPSFPeIUtXciyekI7R47do9Lc3GgC4P5A==","shasum":"2ddc6ee93b92be6d64139fb1a631d2610f43e946","tarball":"https://registry.npmjs.org/@cnpmcore/test-sync-package-has-two-versions/-/test-sync-package-has-two-versions-1.0.0.tgz","fileCount":2,"unpackedSize":238,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQDj5Ui2GU8nVmHFk0hCt/i3gPW9eQdOCZgKzpAlkvERwQIhAPZ0NCefLoEfOpnbdKAUr7Ng9Sy6FMnTsDxDaM2dQHNw"}]},"_npmUser":{"name":"fengmk2","email":"fengmk2@gmail.com"},"directories":{},"maintainers":[{"name":"fengmk2","email":"fengmk2@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/test-sync-package-has-two-versions_1.0.0_1639442699824_0.6948988437963031"},"_hasShrinkwrap":false},"2.0.0":{"name":"@cnpmcore/test-sync-package-has-two-versions","version":"2.0.0","description":"cnpmcore local test package","main":"index.js","scripts":{"test":"echo \\"hello\\""},"author":"","license":"MIT","gitHead":"60cfb1cf401f87a60a1b0dfd7ee739f98ffd7847","_id":"@cnpmcore/test-sync-package-has-two-versions@2.0.0","_nodeVersion":"16.13.1","_npmVersion":"8.1.2","dist":{"integrity":"sha512-qgHLQzXq+VN7q0JWibeBYrqb3Iajl4lpVuxlQstclRz4ejujfDFswBGSXmCv9FyIIdmSAe5bZo0oHQLsod3pAA==","shasum":"891eb8e08ceadbd86e75b6d66f31f7e5a28a8d68","tarball":"https://registry.npmjs.org/@cnpmcore/test-sync-package-has-two-versions/-/test-sync-package-has-two-versions-2.0.0.tgz","fileCount":2,"unpackedSize":238,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIAWVz7mIHF23Gq4a+Swsj2ZSdn87991HcE1+fQm8shNCAiByOIuhaZAbo9hct24qYf7FWqx6Lyluo+Rpnrn91//Ibg=="}]},"_npmUser":{"name":"fengmk2","email":"fengmk2@gmail.com"},"directories":{},"maintainers":[{"name":"fengmk2","email":"fengmk2@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/test-sync-package-has-two-versions_2.0.0_1639442732240_0.33204392278137207"},"_hasShrinkwrap":false}},"time":{"created":"2021-12-14T00:44:59.775Z","1.0.0":"2021-12-14T00:44:59.940Z","modified":"2022-05-23T02:33:52.613Z","2.0.0":"2021-12-14T00:45:32.457Z"},"maintainers":[{"email":"killa07071201@gmail.com","name":"killagu"},{"email":"fengmk2@gmail.com","name":"fengmk2"}],"description":"cnpmcore local test package","license":"MIT","readme":"ERROR: No README data found!","readmeFilename":""}',
|
||||
persist: false,
|
||||
app.mockHttpclient('https://registry.npmjs.org/%40cnpmcore%2Ftest-sync-package-has-two-versions', 'GET', {
|
||||
data: '{"_id":"@cnpmcore/test-sync-package-has-two-versions","_rev":"4-541287ae0a14039fea89ac08fa5ec53d","name":"@cnpmcore/test-sync-package-has-two-versions","dist-tags":{"latest":"2.0.0","next":"2.0.0"},"versions":{"1.0.0":{"name":"@cnpmcore/test-sync-package-has-two-versions","version":"1.0.0","description":"cnpmcore local test package","main":"index.js","scripts":{"test":"echo \\"hello\\""},"author":"","license":"MIT","gitHead":"60cfb1cf401f87a60a1b0dfd7ee739f98ffd7847","_id":"@cnpmcore/test-sync-package-has-two-versions@1.0.0","_nodeVersion":"16.13.1","_npmVersion":"8.1.2","dist":{"integrity":"sha512-WR0T96H8t7ss1FK8GWPPblx+usbjU4bNGRjMHS9t/oVA5DgJDxitydPSFPeIUtXciyekI7R47do9Lc3GgC4P5A==","shasum":"2ddc6ee93b92be6d64139fb1a631d2610f43e946","tarball":"https://registry.npmjs.org/@cnpmcore/test-sync-package-has-two-versions/-/test-sync-package-has-two-versions-1.0.0.tgz","fileCount":2,"unpackedSize":238,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQDj5Ui2GU8nVmHFk0hCt/i3gPW9eQdOCZgKzpAlkvERwQIhAPZ0NCefLoEfOpnbdKAUr7Ng9Sy6FMnTsDxDaM2dQHNw"}]},"_npmUser":{"name":"fengmk2","email":"fengmk2@gmail.com"},"directories":{},"maintainers":[{"name":"fengmk2","email":"fengmk2@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/test-sync-package-has-two-versions_1.0.0_1639442699824_0.6948988437963031"},"_hasShrinkwrap":false},"2.0.0":{"name":"@cnpmcore/test-sync-package-has-two-versions","version":"2.0.0","description":"cnpmcore local test package","main":"index.js","scripts":{"test":"echo \\"hello\\""},"author":"","license":"MIT","gitHead":"60cfb1cf401f87a60a1b0dfd7ee739f98ffd7847","_id":"@cnpmcore/test-sync-package-has-two-versions@2.0.0","_nodeVersion":"16.13.1","_npmVersion":"8.1.2","dist":{"integrity":"sha512-qgHLQzXq+VN7q0JWibeBYrqb3Iajl4lpVuxlQstclRz4ejujfDFswBGSXmCv9FyIIdmSAe5bZo0oHQLsod3pAA==","shasum":"891eb8e08ceadbd86e75b6d66f31f7e5a28a8d68","tarball":"https://registry.npmjs.org/@cnpmcore/test-sync-package-has-two-versions/-/test-sync-package-has-two-versions-2.0.0.tgz","fileCount":2,"unpackedSize":238,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIAWVz7mIHF23Gq4a+Swsj2ZSdn87991HcE1+fQm8shNCAiByOIuhaZAbo9hct24qYf7FWqx6Lyluo+Rpnrn91//Ibg=="}]},"_npmUser":{"name":"fengmk2","email":"fengmk2@gmail.com"},"directories":{},"maintainers":[{"name":"fengmk2","email":"fengmk2@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/test-sync-package-has-two-versions_2.0.0_1639442732240_0.33204392278137207"},"_hasShrinkwrap":false}},"time":{"created":"2021-12-14T00:44:59.775Z","1.0.0":"2021-12-14T00:44:59.940Z","modified":"2022-05-23T02:33:52.613Z","2.0.0":"2021-12-14T00:45:32.457Z"},"maintainers":[{"email":"killa07071201@gmail.com","name":"killagu"},{"email":"fengmk2@gmail.com","name":"fengmk2"}],"description":"cnpmcore local test package","license":"MIT","readme":"ERROR: No README data found!","readmeFilename":""}',
|
||||
persist: false,
|
||||
});
|
||||
const abbrs = await packageManagerService.listPackageAbbreviatedManifests(scopedAndName[0], scopedAndName[1]);
|
||||
delete abbrs.data.versions['1.0.0'];
|
||||
mock.data(PackageManagerService.prototype, 'listPackageAbbreviatedManifests', abbrs);
|
||||
|
||||
await packageSyncerService.createTask(name);
|
||||
task = await packageSyncerService.findExecuteTask();
|
||||
assert(task);
|
||||
assert.equal(task.targetName, name);
|
||||
await packageSyncerService.executeTask(task);
|
||||
stream = await packageSyncerService.findTaskLog(task);
|
||||
assert(stream);
|
||||
log = await TestUtil.readStreamToLog(stream);
|
||||
// console.log(log);
|
||||
assert(log.includes('] 🐛 Remote version 1.0.0 not exists on local abbreviated manifests, need to refresh'));
|
||||
assert(log.includes('] 🟢 Synced updated 1 versions'));
|
||||
assert(log.includes('] 🚧 Syncing versions 2 => 2'));
|
||||
app.mockAgent().assertNoPendingInterceptors();
|
||||
await mock.restore();
|
||||
|
||||
// mock tag on database but not on manifest dist
|
||||
// https://github.com/cnpm/cnpmcore/issues/97
|
||||
app.mockHttpclient('https://registry.npmjs.org/%40cnpmcore%2Ftest-sync-package-has-two-versions', 'GET', {
|
||||
data: '{"_id":"@cnpmcore/test-sync-package-has-two-versions","_rev":"4-541287ae0a14039fea89ac08fa5ec53d","name":"@cnpmcore/test-sync-package-has-two-versions","dist-tags":{"latest":"2.0.0","next":"2.0.0"},"versions":{"1.0.0":{"name":"@cnpmcore/test-sync-package-has-two-versions","version":"1.0.0","description":"cnpmcore local test package","main":"index.js","scripts":{"test":"echo \\"hello\\""},"author":"","license":"MIT","gitHead":"60cfb1cf401f87a60a1b0dfd7ee739f98ffd7847","_id":"@cnpmcore/test-sync-package-has-two-versions@1.0.0","_nodeVersion":"16.13.1","_npmVersion":"8.1.2","dist":{"integrity":"sha512-WR0T96H8t7ss1FK8GWPPblx+usbjU4bNGRjMHS9t/oVA5DgJDxitydPSFPeIUtXciyekI7R47do9Lc3GgC4P5A==","shasum":"2ddc6ee93b92be6d64139fb1a631d2610f43e946","tarball":"https://registry.npmjs.org/@cnpmcore/test-sync-package-has-two-versions/-/test-sync-package-has-two-versions-1.0.0.tgz","fileCount":2,"unpackedSize":238,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQDj5Ui2GU8nVmHFk0hCt/i3gPW9eQdOCZgKzpAlkvERwQIhAPZ0NCefLoEfOpnbdKAUr7Ng9Sy6FMnTsDxDaM2dQHNw"}]},"_npmUser":{"name":"fengmk2","email":"fengmk2@gmail.com"},"directories":{},"maintainers":[{"name":"fengmk2","email":"fengmk2@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/test-sync-package-has-two-versions_1.0.0_1639442699824_0.6948988437963031"},"_hasShrinkwrap":false},"2.0.0":{"name":"@cnpmcore/test-sync-package-has-two-versions","version":"2.0.0","description":"cnpmcore local test package","main":"index.js","scripts":{"test":"echo \\"hello\\""},"author":"","license":"MIT","gitHead":"60cfb1cf401f87a60a1b0dfd7ee739f98ffd7847","_id":"@cnpmcore/test-sync-package-has-two-versions@2.0.0","_nodeVersion":"16.13.1","_npmVersion":"8.1.2","dist":{"integrity":"sha512-qgHLQzXq+VN7q0JWibeBYrqb3Iajl4lpVuxlQstclRz4ejujfDFswBGSXmCv9FyIIdmSAe5bZo0oHQLsod3pAA==","shasum":"891eb8e08ceadbd86e75b6d66f31f7e5a28a8d68","tarball":"https://registry.npmjs.org/@cnpmcore/test-sync-package-has-two-versions/-/test-sync-package-has-two-versions-2.0.0.tgz","fileCount":2,"unpackedSize":238,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIAWVz7mIHF23Gq4a+Swsj2ZSdn87991HcE1+fQm8shNCAiByOIuhaZAbo9hct24qYf7FWqx6Lyluo+Rpnrn91//Ibg=="}]},"_npmUser":{"name":"fengmk2","email":"fengmk2@gmail.com"},"directories":{},"maintainers":[{"name":"fengmk2","email":"fengmk2@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/test-sync-package-has-two-versions_2.0.0_1639442732240_0.33204392278137207"},"_hasShrinkwrap":false}},"time":{"created":"2021-12-14T00:44:59.775Z","1.0.0":"2021-12-14T00:44:59.940Z","modified":"2022-05-23T02:33:52.613Z","2.0.0":"2021-12-14T00:45:32.457Z"},"maintainers":[{"email":"killa07071201@gmail.com","name":"killagu"},{"email":"fengmk2@gmail.com","name":"fengmk2"}],"description":"cnpmcore local test package","license":"MIT","readme":"ERROR: No README data found!","readmeFilename":""}',
|
||||
persist: false,
|
||||
});
|
||||
const result = await npmRegistry.getFullManifests(name);
|
||||
result.data['dist-tags'].foo = '2.0.0';
|
||||
mock.data(NPMRegistry.prototype, 'getFullManifests', result);
|
||||
mock.data(PackageManagerService.prototype, 'savePackageTag', null);
|
||||
await packageSyncerService.createTask(name);
|
||||
task = await packageSyncerService.findExecuteTask();
|
||||
assert(task);
|
||||
await packageSyncerService.executeTask(task);
|
||||
stream = await packageSyncerService.findTaskLog(task);
|
||||
assert(stream);
|
||||
log = await TestUtil.readStreamToLog(stream);
|
||||
// console.log(log);
|
||||
assert(log.includes('] 🚧 Remote tag(foo: 2.0.0) not exists in local dist-tags'));
|
||||
assert(!log.includes('] 🚧 Refreshing manifests to dists ......'));
|
||||
app.mockAgent().assertNoPendingInterceptors();
|
||||
});
|
||||
const abbrs = await packageManagerService.listPackageAbbreviatedManifests(scopedAndName[0], scopedAndName[1]);
|
||||
delete abbrs.data.versions['1.0.0'];
|
||||
mock.data(PackageManagerService.prototype, 'listPackageAbbreviatedManifests', abbrs);
|
||||
|
||||
await packageSyncerService.createTask(name);
|
||||
task = await packageSyncerService.findExecuteTask();
|
||||
assert(task);
|
||||
assert.equal(task.targetName, name);
|
||||
await packageSyncerService.executeTask(task);
|
||||
stream = await packageSyncerService.findTaskLog(task);
|
||||
assert(stream);
|
||||
log = await TestUtil.readStreamToLog(stream);
|
||||
// console.log(log);
|
||||
assert(log.includes('] 🐛 Remote version 1.0.0 not exists on local abbreviated manifests, need to refresh'));
|
||||
assert(log.includes('] 🟢 Synced updated 1 versions'));
|
||||
assert(log.includes('] 🚧 Syncing versions 2 => 2'));
|
||||
app.mockAgent().assertNoPendingInterceptors();
|
||||
await mock.restore();
|
||||
it('should updated package manifests when version already published', async () => {
|
||||
// https://www.npmjs.com/package/@cnpmcore/test-sync-package-has-two-versions
|
||||
const name = '@cnpmcore/test-sync-package-has-two-versions';
|
||||
await packageSyncerService.createTask(name);
|
||||
const task = await packageSyncerService.findExecuteTask();
|
||||
assert(task);
|
||||
assert.equal(task.targetName, name);
|
||||
|
||||
const { user } = await userService.create({
|
||||
name: 'test-user',
|
||||
password: 'this-is-password',
|
||||
email: 'hello@example.com',
|
||||
ip: '127.0.0.1',
|
||||
});
|
||||
|
||||
const publishCmd = {
|
||||
scope: '@cnpmcore',
|
||||
name: 'test-sync-package-has-two-versions',
|
||||
version: '1.0.0',
|
||||
description: '1.0.0',
|
||||
readme: '',
|
||||
registryId: undefined,
|
||||
packageJson: { name, test: 'test', version: '1.0.0' },
|
||||
dist: {
|
||||
content: Buffer.alloc(0),
|
||||
},
|
||||
isPrivate: false,
|
||||
publishTime: new Date(),
|
||||
skipRefreshPackageManifests: false,
|
||||
};
|
||||
const pkgVersion = await packageManagerService.publish(publishCmd, user);
|
||||
assert(pkgVersion.version === '1.0.0');
|
||||
|
||||
const publishCmd2 = {
|
||||
scope: '@cnpmcore',
|
||||
name: 'test-sync-package-has-two-versions',
|
||||
version: '2.0.0',
|
||||
description: '2.0.0',
|
||||
readme: '',
|
||||
registryId: undefined,
|
||||
packageJson: { name, test: 'test', version: '2.0.0' },
|
||||
dist: {
|
||||
content: Buffer.alloc(0),
|
||||
},
|
||||
isPrivate: false,
|
||||
publishTime: new Date(),
|
||||
skipRefreshPackageManifests: true,
|
||||
};
|
||||
const pkgVersion2 = await packageManagerService.publish(publishCmd2, user);
|
||||
assert(pkgVersion2.version === '2.0.0');
|
||||
|
||||
await packageSyncerService.executeTask(task);
|
||||
|
||||
const stream = await packageSyncerService.findTaskLog(task);
|
||||
assert(stream);
|
||||
const log = await TestUtil.readStreamToLog(stream);
|
||||
// console.log(log);
|
||||
assert(log.includes('Synced version 2.0.0 already exists, skip publish, try to set in local manifest'));
|
||||
assert(log.includes('] 🚧 Syncing versions 1 => 2'));
|
||||
|
||||
const fullManifests = await packageManagerService.listPackageFullManifests('@cnpmcore', 'test-sync-package-has-two-versions');
|
||||
assert(fullManifests.data.versions['2.0.0']);
|
||||
|
||||
// mock tag on database but not on manifest dist
|
||||
// https://github.com/cnpm/cnpmcore/issues/97
|
||||
app.mockHttpclient('https://registry.npmjs.org/%40cnpmcore%2Ftest-sync-package-has-two-versions', 'GET', {
|
||||
data: '{"_id":"@cnpmcore/test-sync-package-has-two-versions","_rev":"4-541287ae0a14039fea89ac08fa5ec53d","name":"@cnpmcore/test-sync-package-has-two-versions","dist-tags":{"latest":"2.0.0","next":"2.0.0"},"versions":{"1.0.0":{"name":"@cnpmcore/test-sync-package-has-two-versions","version":"1.0.0","description":"cnpmcore local test package","main":"index.js","scripts":{"test":"echo \\"hello\\""},"author":"","license":"MIT","gitHead":"60cfb1cf401f87a60a1b0dfd7ee739f98ffd7847","_id":"@cnpmcore/test-sync-package-has-two-versions@1.0.0","_nodeVersion":"16.13.1","_npmVersion":"8.1.2","dist":{"integrity":"sha512-WR0T96H8t7ss1FK8GWPPblx+usbjU4bNGRjMHS9t/oVA5DgJDxitydPSFPeIUtXciyekI7R47do9Lc3GgC4P5A==","shasum":"2ddc6ee93b92be6d64139fb1a631d2610f43e946","tarball":"https://registry.npmjs.org/@cnpmcore/test-sync-package-has-two-versions/-/test-sync-package-has-two-versions-1.0.0.tgz","fileCount":2,"unpackedSize":238,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQDj5Ui2GU8nVmHFk0hCt/i3gPW9eQdOCZgKzpAlkvERwQIhAPZ0NCefLoEfOpnbdKAUr7Ng9Sy6FMnTsDxDaM2dQHNw"}]},"_npmUser":{"name":"fengmk2","email":"fengmk2@gmail.com"},"directories":{},"maintainers":[{"name":"fengmk2","email":"fengmk2@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/test-sync-package-has-two-versions_1.0.0_1639442699824_0.6948988437963031"},"_hasShrinkwrap":false},"2.0.0":{"name":"@cnpmcore/test-sync-package-has-two-versions","version":"2.0.0","description":"cnpmcore local test package","main":"index.js","scripts":{"test":"echo \\"hello\\""},"author":"","license":"MIT","gitHead":"60cfb1cf401f87a60a1b0dfd7ee739f98ffd7847","_id":"@cnpmcore/test-sync-package-has-two-versions@2.0.0","_nodeVersion":"16.13.1","_npmVersion":"8.1.2","dist":{"integrity":"sha512-qgHLQzXq+VN7q0JWibeBYrqb3Iajl4lpVuxlQstclRz4ejujfDFswBGSXmCv9FyIIdmSAe5bZo0oHQLsod3pAA==","shasum":"891eb8e08ceadbd86e75b6d66f31f7e5a28a8d68","tarball":"https://registry.npmjs.org/@cnpmcore/test-sync-package-has-two-versions/-/test-sync-package-has-two-versions-2.0.0.tgz","fileCount":2,"unpackedSize":238,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIAWVz7mIHF23Gq4a+Swsj2ZSdn87991HcE1+fQm8shNCAiByOIuhaZAbo9hct24qYf7FWqx6Lyluo+Rpnrn91//Ibg=="}]},"_npmUser":{"name":"fengmk2","email":"fengmk2@gmail.com"},"directories":{},"maintainers":[{"name":"fengmk2","email":"fengmk2@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/test-sync-package-has-two-versions_2.0.0_1639442732240_0.33204392278137207"},"_hasShrinkwrap":false}},"time":{"created":"2021-12-14T00:44:59.775Z","1.0.0":"2021-12-14T00:44:59.940Z","modified":"2022-05-23T02:33:52.613Z","2.0.0":"2021-12-14T00:45:32.457Z"},"maintainers":[{"email":"killa07071201@gmail.com","name":"killagu"},{"email":"fengmk2@gmail.com","name":"fengmk2"}],"description":"cnpmcore local test package","license":"MIT","readme":"ERROR: No README data found!","readmeFilename":""}',
|
||||
persist: false,
|
||||
});
|
||||
const result = await npmRegistry.getFullManifests(name);
|
||||
result.data['dist-tags'].foo = '2.0.0';
|
||||
mock.data(NPMRegistry.prototype, 'getFullManifests', result);
|
||||
mock.data(PackageManagerService.prototype, 'savePackageTag', null);
|
||||
await packageSyncerService.createTask(name);
|
||||
task = await packageSyncerService.findExecuteTask();
|
||||
assert(task);
|
||||
await packageSyncerService.executeTask(task);
|
||||
stream = await packageSyncerService.findTaskLog(task);
|
||||
assert(stream);
|
||||
log = await TestUtil.readStreamToLog(stream);
|
||||
// console.log(log);
|
||||
assert(log.includes('] 🚧 Remote tag(foo: 2.0.0) not exists in local dist-tags'));
|
||||
assert(!log.includes('] 🚧 Refreshing manifests to dists ......'));
|
||||
app.mockAgent().assertNoPendingInterceptors();
|
||||
|
||||
it('should updated package manifests when version insert duplicated', async () => {
|
||||
// https://www.npmjs.com/package/@cnpmcore/test-sync-package-has-two-versions
|
||||
const name = '@cnpmcore/test-sync-package-has-two-versions';
|
||||
await packageSyncerService.createTask(name);
|
||||
const task = await packageSyncerService.findExecuteTask();
|
||||
assert(task);
|
||||
assert.equal(task.targetName, name);
|
||||
|
||||
const { user } = await userService.create({
|
||||
name: 'test-user',
|
||||
password: 'this-is-password',
|
||||
email: 'hello@example.com',
|
||||
ip: '127.0.0.1',
|
||||
});
|
||||
|
||||
const publishCmd = {
|
||||
scope: '@cnpmcore',
|
||||
name: 'test-sync-package-has-two-versions',
|
||||
version: '1.0.0',
|
||||
description: '1.0.0',
|
||||
readme: '',
|
||||
registryId: undefined,
|
||||
packageJson: { name, test: 'test', version: '1.0.0' },
|
||||
dist: {
|
||||
content: Buffer.alloc(0),
|
||||
},
|
||||
isPrivate: false,
|
||||
publishTime: new Date(),
|
||||
skipRefreshPackageManifests: false,
|
||||
};
|
||||
const pkgVersion = await packageManagerService.publish(publishCmd, user);
|
||||
assert(pkgVersion.version === '1.0.0');
|
||||
|
||||
const publishCmd2 = {
|
||||
scope: '@cnpmcore',
|
||||
name: 'test-sync-package-has-two-versions',
|
||||
version: '2.0.0',
|
||||
description: '2.0.0',
|
||||
readme: '',
|
||||
registryId: undefined,
|
||||
packageJson: { name, test: 'test', version: '2.0.0' },
|
||||
dist: {
|
||||
content: Buffer.alloc(0),
|
||||
},
|
||||
isPrivate: false,
|
||||
publishTime: new Date(),
|
||||
skipRefreshPackageManifests: true,
|
||||
};
|
||||
const pkgVersion2 = await packageManagerService.publish(publishCmd2, user);
|
||||
assert(pkgVersion2.version === '2.0.0');
|
||||
|
||||
// 模拟查询未发现版本重复,写入时异常
|
||||
mock(packageRepository, 'findPackageVersion', async () => {
|
||||
return null;
|
||||
});
|
||||
await packageSyncerService.executeTask(task);
|
||||
|
||||
const stream = await packageSyncerService.findTaskLog(task);
|
||||
assert(stream);
|
||||
const log = await TestUtil.readStreamToLog(stream);
|
||||
// console.log(log);
|
||||
assert(log.includes('Synced version 2.0.0 already exists, skip publish, try to set in local manifest'));
|
||||
assert(log.includes('] 🚧 Syncing versions 1 => 2'));
|
||||
|
||||
});
|
||||
|
||||
it('should skip version when insert error', async () => {
|
||||
// https://www.npmjs.com/package/@cnpmcore/test-sync-package-has-two-versions
|
||||
const name = '@cnpmcore/test-sync-package-has-two-versions';
|
||||
await packageSyncerService.createTask(name);
|
||||
const task = await packageSyncerService.findExecuteTask();
|
||||
assert(task);
|
||||
assert.equal(task.targetName, name);
|
||||
const { user } = await userService.create({
|
||||
name: 'test-user',
|
||||
password: 'this-is-password',
|
||||
email: 'hello@example.com',
|
||||
ip: '127.0.0.1',
|
||||
});
|
||||
|
||||
const publishCmd = {
|
||||
scope: '@cnpmcore',
|
||||
name: 'test-sync-package-has-two-versions',
|
||||
version: '1.0.0',
|
||||
description: '1.0.0',
|
||||
readme: '',
|
||||
registryId: undefined,
|
||||
packageJson: { name, test: 'test', version: '1.0.0' },
|
||||
dist: {
|
||||
content: Buffer.alloc(0),
|
||||
},
|
||||
isPrivate: false,
|
||||
publishTime: new Date(),
|
||||
skipRefreshPackageManifests: false,
|
||||
};
|
||||
const pkgVersion = await packageManagerService.publish(publishCmd, user);
|
||||
assert(pkgVersion.version === '1.0.0');
|
||||
|
||||
// 模拟查询未发现版本重复,写入时异常
|
||||
mock(packageRepository, 'findPackageVersion', async () => {
|
||||
return null;
|
||||
});
|
||||
|
||||
mock(packageRepository, 'createPackageVersion', async () => {
|
||||
throw new Error('mock error');
|
||||
});
|
||||
await packageSyncerService.executeTask(task);
|
||||
|
||||
const stream = await packageSyncerService.findTaskLog(task);
|
||||
assert(stream);
|
||||
const log = await TestUtil.readStreamToLog(stream);
|
||||
assert(log.includes(' Synced updated 0 versions, removed 0 versions'));
|
||||
|
||||
});
|
||||
|
||||
it('event cork should work', async () => {
|
||||
// https://www.npmjs.com/package/@cnpmcore/test-sync-package-has-two-versions
|
||||
const name = '@cnpmcore/test-sync-package-has-two-versions';
|
||||
await packageSyncerService.createTask(name);
|
||||
const task = await packageSyncerService.findExecuteTask();
|
||||
assert(task);
|
||||
assert.equal(task.targetName, name);
|
||||
|
||||
|
||||
await packageSyncerService.executeTask(task);
|
||||
const stream = await packageSyncerService.findTaskLog(task);
|
||||
assert(stream);
|
||||
|
||||
const finishedTask = await taskService.findTask(task.taskId) as TaskEntity;
|
||||
|
||||
const changes = await changeRepository.query(0, 100);
|
||||
const [ firstChange ] = changes;
|
||||
const firstChangeDate = new Date(firstChange.createdAt);
|
||||
const taskFinishedDate = new Date(finishedTask!.updatedAt);
|
||||
|
||||
// 任务结束后一起触发
|
||||
assert(firstChangeDate.getTime() - taskFinishedDate.getTime() > 0);
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
it.skip('should sync missing versions in database', async () => {
|
||||
@@ -1298,6 +1512,45 @@ describe('test/core/service/PackageSyncerService/executeTask.test.ts', () => {
|
||||
app.mockAgent().assertNoPendingInterceptors();
|
||||
});
|
||||
|
||||
it('should stop sync when upstream blocked', async () => {
|
||||
// sync first
|
||||
const name = 'cnpmcore-test-block-from-upstream';
|
||||
app.mockHttpclient(`https://registry.npmjs.org/${name}`, 'GET', {
|
||||
data: '{"_id":"cnpmcore-test-block-from-upstream","_rev":"2-bc8b9a2f6532d1bb3f94eaa4e82dbfe0","name":"cnpmcore-test-block-from-upstream","dist-tags":{"latest":"0.0.0"},"versions":{"0.0.0":{"name":"cnpmcore-test-block-from-upstream","readme":"foo readme","version":"0.0.0","description":"","main":"index.js","scripts":{},"author":"","license":"ISC","dependencies":{},"_id":"cnpmcore-test-block-from-upstream@0.0.0","_nodeVersion":"16.13.1","_npmVersion":"8.1.2","dist":{"integrity":"sha512-ptVWDP7Z39wOBk5EBwi2x8/SKZblEsVcdL0jjIsaI2KdLwVpRRRnezJSKpUsXr982nGf0j7nh6RcHSg4Wlu3AA==","shasum":"c73398ff6db39d138a56c04c7a90f35b70d7b78f","tarball":"https://registry.npmjs.org/cnpmcore-test-block-from-upstream/-/cnpmcore-test-block-from-upstream-0.0.0.tgz","fileCount":1,"unpackedSize":250},"_npmUser":{"name":"fengmk2","email":"fengmk2@gmail.com"},"directories":{},"maintainers":[{"name":"fengmk2","email":"fengmk2@gmail.com"}],"_hasShrinkwrap":false,"deprecated":"only test for cnpmcore"}},"time":{"created":"2021-12-11T18:09:24.624Z","0.0.0":"2021-12-11T18:09:24.768Z","modified":"2022-04-12T06:56:55.617Z"},"maintainers":[],"license":"ISC","readme":{"foo":"mock readme is object"},"readmeFilename":""}',
|
||||
persist: false,
|
||||
});
|
||||
app.mockHttpclient('https://registry.npmjs.org/cnpmcore-test-block-from-upstream/-/cnpmcore-test-block-from-upstream-0.0.0.tgz', 'GET', {
|
||||
data: await TestUtil.readFixturesFile('registry.npmjs.org/foobar/-/foobar-1.0.0.tgz'),
|
||||
persist: false,
|
||||
});
|
||||
await packageSyncerService.createTask(name);
|
||||
let task = await packageSyncerService.findExecuteTask();
|
||||
await packageSyncerService.executeTask(task);
|
||||
|
||||
const pkg = await packageRepository.findPackage('', name);
|
||||
const pkgVersion = await packageRepository.findPackageVersion(pkg!.packageId, '0.0.0');
|
||||
assert(pkg?.name === name);
|
||||
assert(pkgVersion);
|
||||
|
||||
// mock unpublish
|
||||
app.mockHttpclient(`https://registry.npmjs.org/${name}`, 'GET', {
|
||||
data: `{"error":"[UNAVAILABLE_FOR_LEGAL_REASONS] ${name} was blocked, reason: foo (operator: cnpmcore_admin/61f154594ce7cf8f5827edf8)"}`,
|
||||
persist: false,
|
||||
status: 451,
|
||||
});
|
||||
|
||||
await packageSyncerService.createTask(name);
|
||||
task = await packageSyncerService.findExecuteTask();
|
||||
await packageSyncerService.executeTask(task);
|
||||
|
||||
const stream = await packageSyncerService.findTaskLog(task);
|
||||
assert(stream);
|
||||
const log = await TestUtil.readStreamToLog(stream);
|
||||
// console.log(log);
|
||||
|
||||
assert(log.includes(`🟢 Package "${name}" was unpublished caused by 451 response`));
|
||||
});
|
||||
|
||||
it('should stop sync by block list', async () => {
|
||||
const name = 'cnpmcore-test-sync-blocklist';
|
||||
mock(app.config.cnpmcore, 'syncPackageBlockList', [ name, 'foo' ]);
|
||||
|
||||
@@ -4,15 +4,22 @@ import { app, mock } from 'egg-mock/bootstrap';
|
||||
import { BinarySyncerService } from 'app/core/service/BinarySyncerService';
|
||||
import { NodeBinary } from 'app/common/adapter/binary/NodeBinary';
|
||||
import { SqlcipherBinary } from 'app/common/adapter/binary/SqlcipherBinary';
|
||||
import { BinaryRepository } from 'app/repository/BinaryRepository';
|
||||
import { Binary } from 'app/core/entity/Binary';
|
||||
import { NFSClientAdapter } from 'app/infra/NFSClientAdapter';
|
||||
import { TestUtil } from 'test/TestUtil';
|
||||
|
||||
describe('test/port/controller/BinarySyncController/showBinary.test.ts', () => {
|
||||
let ctx: Context;
|
||||
let binarySyncerService: BinarySyncerService;
|
||||
let binaryRepository: BinaryRepository;
|
||||
let nfsClientAdapter: NFSClientAdapter;
|
||||
|
||||
beforeEach(async () => {
|
||||
ctx = await app.mockModuleContext();
|
||||
binarySyncerService = await ctx.getEggObject(BinarySyncerService);
|
||||
binaryRepository = await ctx.getEggObject(BinaryRepository);
|
||||
nfsClientAdapter = await app.getEggObject(NFSClientAdapter);
|
||||
});
|
||||
|
||||
afterEach(async () => {
|
||||
@@ -47,6 +54,99 @@ describe('test/port/controller/BinarySyncController/showBinary.test.ts', () => {
|
||||
}
|
||||
});
|
||||
|
||||
it('should show valid root dirs', async () => {
|
||||
await binaryRepository.saveBinary(Binary.create({
|
||||
category: 'node-canvas-prebuilt',
|
||||
parent: '/',
|
||||
name: 'v2.6.1/',
|
||||
isDir: true,
|
||||
size: 0,
|
||||
date: '2021-12-14T13:12:31.587Z',
|
||||
}));
|
||||
const res = await app.httpRequest()
|
||||
.get('/-/binary/');
|
||||
assert(res.status === 200);
|
||||
assert(res.headers['content-type'] === 'application/json; charset=utf-8');
|
||||
const items = res.body;
|
||||
assert(items.length > 0);
|
||||
for (const item of items) {
|
||||
assert(item.type === 'dir');
|
||||
assert(item.name);
|
||||
assert(item.url);
|
||||
assert(item.repoUrl);
|
||||
assert(item.distUrl);
|
||||
assert(item.description);
|
||||
}
|
||||
|
||||
const item = items.filter((item: any) => item.name === 'nwjs/');
|
||||
assert.deepStrictEqual(item, [{
|
||||
name: 'nwjs/',
|
||||
category: 'nwjs/',
|
||||
description: 'NW.js (previously known as node-webkit) lets you call all Node.js modules directly from DOM and enables a new way of writing applications with all Web technologies.',
|
||||
distUrl: 'https://dl.nwjs.io/',
|
||||
repoUrl: 'https://github.com/nwjs/nw.js',
|
||||
type: 'dir',
|
||||
url: 'http://localhost:7001/-/binary/nwjs/',
|
||||
}]);
|
||||
});
|
||||
it('should show valid sub dirs', async () => {
|
||||
await binaryRepository.saveBinary(Binary.create({
|
||||
category: 'node-canvas-prebuilt',
|
||||
parent: '/',
|
||||
name: 'v2.6.1/',
|
||||
isDir: true,
|
||||
size: 0,
|
||||
date: '2021-12-14T13:12:31.587Z',
|
||||
}));
|
||||
const res = await app.httpRequest()
|
||||
.get('/-/binary/node-canvas-prebuilt/');
|
||||
assert(res.status === 200);
|
||||
assert(res.headers['content-type'] === 'application/json; charset=utf-8');
|
||||
const items = TestUtil.pickKeys(res.body, [ 'category', 'name', 'date', 'type', 'url' ]);
|
||||
assert.deepStrictEqual(items, [{
|
||||
category: 'node-canvas-prebuilt',
|
||||
name: 'v2.6.1/',
|
||||
date: '2021-12-14T13:12:31.587Z',
|
||||
type: 'dir',
|
||||
url: 'http://localhost:7001/-/binary/node-canvas-prebuilt/v2.6.1/',
|
||||
}]);
|
||||
|
||||
});
|
||||
it('should show valid files', async () => {
|
||||
await binaryRepository.saveBinary(Binary.create({
|
||||
category: 'node-canvas-prebuilt',
|
||||
parent: '/',
|
||||
name: 'v2.6.1/',
|
||||
isDir: true,
|
||||
size: 0,
|
||||
date: '2021-12-14T13:12:31.587Z',
|
||||
}));
|
||||
await binaryRepository.saveBinary(Binary.create({
|
||||
category: 'node-canvas-prebuilt',
|
||||
parent: '/v2.6.1/',
|
||||
name: 'node-canvas-prebuilt-v2.6.1-node-v57-linux-glibc-x64.tar.gz',
|
||||
isDir: false,
|
||||
size: 10,
|
||||
date: '2021-12-14T13:12:31.587Z',
|
||||
}));
|
||||
const res = await app.httpRequest()
|
||||
.get('/-/binary/node-canvas-prebuilt/v2.6.1/');
|
||||
assert(res.status === 200);
|
||||
assert(res.headers['content-type'] === 'application/json; charset=utf-8');
|
||||
const items = TestUtil.pickKeys(res.body, [ 'category', 'name', 'date', 'type', 'url' ]);
|
||||
assert(items.length > 0);
|
||||
|
||||
assert.deepStrictEqual(items, [
|
||||
{
|
||||
category: 'node-canvas-prebuilt',
|
||||
name: 'node-canvas-prebuilt-v2.6.1-node-v57-linux-glibc-x64.tar.gz',
|
||||
date: '2021-12-14T13:12:31.587Z',
|
||||
type: 'file',
|
||||
url: 'http://localhost:7001/-/binary/node-canvas-prebuilt/v2.6.1/node-canvas-prebuilt-v2.6.1-node-v57-linux-glibc-x64.tar.gz',
|
||||
},
|
||||
]);
|
||||
});
|
||||
|
||||
it('should show node binaries', async () => {
|
||||
app.mockHttpclient('https://nodejs.org/dist/index.json', 'GET', {
|
||||
data: await TestUtil.readFixturesFile('nodejs.org/site/index.json'),
|
||||
@@ -247,5 +347,210 @@ describe('test/port/controller/BinarySyncController/showBinary.test.ts', () => {
|
||||
}
|
||||
app.mockAgent().assertNoPendingInterceptors();
|
||||
});
|
||||
|
||||
it('should merge category binaries when binaryName and category not equal', async () => {
|
||||
await binaryRepository.saveBinary(Binary.create({
|
||||
category: 'node-canvas-prebuilt',
|
||||
parent: '/',
|
||||
name: 'v2.6.1/',
|
||||
isDir: true,
|
||||
size: 0,
|
||||
date: '2021-12-14T13:12:31.587Z',
|
||||
}));
|
||||
await binaryRepository.saveBinary(Binary.create({
|
||||
category: 'node-canvas-prebuilt',
|
||||
parent: '/',
|
||||
name: 'v2.7.0/',
|
||||
isDir: true,
|
||||
size: 0,
|
||||
date: '2021-12-14T13:12:31.587Z',
|
||||
}));
|
||||
await binaryRepository.saveBinary(Binary.create({
|
||||
category: 'node-canvas-prebuilt',
|
||||
parent: '/v2.6.1/',
|
||||
name: 'node-canvas-prebuilt-v2.6.1-node-v57-linux-glibc-x64.tar.gz',
|
||||
isDir: false,
|
||||
size: 10,
|
||||
date: '2021-12-14T13:12:31.587Z',
|
||||
}));
|
||||
|
||||
await binaryRepository.saveBinary(Binary.create({
|
||||
category: 'canvas',
|
||||
parent: '/v2.7.0/',
|
||||
name: 'canvas-v2.7.0-node-v57-linux-glibc-x64.tar.gz',
|
||||
isDir: false,
|
||||
size: 10,
|
||||
date: '2021-12-14T13:12:31.587Z',
|
||||
}));
|
||||
|
||||
await binaryRepository.saveBinary(Binary.create({
|
||||
category: 'canvas',
|
||||
parent: '/',
|
||||
name: 'v2.7.0/',
|
||||
isDir: true,
|
||||
size: 0,
|
||||
date: '2021-12-14T13:12:31.587Z',
|
||||
}));
|
||||
|
||||
let res = await app.httpRequest()
|
||||
.get('/-/binary/canvas');
|
||||
|
||||
assert.strictEqual(res.status, 200);
|
||||
assert(res.body);
|
||||
let stableData = TestUtil.pickKeys(res.body, [ 'category', 'name', 'date', 'type', 'url' ]);
|
||||
assert.deepStrictEqual(stableData, [
|
||||
{
|
||||
category: 'canvas',
|
||||
name: 'v2.7.0/',
|
||||
date: '2021-12-14T13:12:31.587Z',
|
||||
type: 'dir',
|
||||
url: 'http://localhost:7001/-/binary/canvas/v2.7.0/',
|
||||
},
|
||||
{
|
||||
category: 'node-canvas-prebuilt',
|
||||
name: 'v2.6.1/',
|
||||
date: '2021-12-14T13:12:31.587Z',
|
||||
type: 'dir',
|
||||
url: 'http://localhost:7001/-/binary/node-canvas-prebuilt/v2.6.1/',
|
||||
},
|
||||
]);
|
||||
|
||||
res = await app.httpRequest()
|
||||
.get('/-/binary/node-canvas-prebuilt');
|
||||
|
||||
assert.strictEqual(res.status, 200);
|
||||
assert(res.body);
|
||||
stableData = TestUtil.pickKeys(res.body, [ 'category', 'name', 'date', 'type', 'url' ]);
|
||||
assert.deepStrictEqual(stableData, [
|
||||
{
|
||||
category: 'node-canvas-prebuilt',
|
||||
name: 'v2.6.1/',
|
||||
date: '2021-12-14T13:12:31.587Z',
|
||||
type: 'dir',
|
||||
url: 'http://localhost:7001/-/binary/node-canvas-prebuilt/v2.6.1/',
|
||||
},
|
||||
{
|
||||
category: 'node-canvas-prebuilt',
|
||||
name: 'v2.7.0/',
|
||||
date: '2021-12-14T13:12:31.587Z',
|
||||
type: 'dir',
|
||||
url: 'http://localhost:7001/-/binary/node-canvas-prebuilt/v2.7.0/',
|
||||
},
|
||||
]);
|
||||
|
||||
res = await app.httpRequest()
|
||||
.get('/-/binary/canvas/v2.7.0/');
|
||||
|
||||
assert.strictEqual(res.status, 200);
|
||||
assert(res.body);
|
||||
stableData = TestUtil.pickKeys(res.body, [ 'category', 'name', 'date', 'type', 'url' ]);
|
||||
|
||||
assert.deepStrictEqual(stableData, [
|
||||
{
|
||||
name: 'canvas-v2.7.0-node-v57-linux-glibc-x64.tar.gz',
|
||||
type: 'file',
|
||||
category: 'canvas',
|
||||
date: '2021-12-14T13:12:31.587Z',
|
||||
url: 'http://localhost:7001/-/binary/canvas/v2.7.0/canvas-v2.7.0-node-v57-linux-glibc-x64.tar.gz',
|
||||
},
|
||||
]);
|
||||
|
||||
res = await app.httpRequest()
|
||||
.get('/-/binary/canvas/v2.6.1/');
|
||||
|
||||
assert.strictEqual(res.status, 200);
|
||||
assert(res.body);
|
||||
stableData = TestUtil.pickKeys(res.body, [ 'category', 'name', 'date', 'type', 'url' ]);
|
||||
|
||||
assert.deepStrictEqual(stableData, [
|
||||
{
|
||||
name: 'node-canvas-prebuilt-v2.6.1-node-v57-linux-glibc-x64.tar.gz',
|
||||
type: 'file',
|
||||
category: 'node-canvas-prebuilt',
|
||||
date: '2021-12-14T13:12:31.587Z',
|
||||
url: 'http://localhost:7001/-/binary/node-canvas-prebuilt/v2.6.1/node-canvas-prebuilt-v2.6.1-node-v57-linux-glibc-x64.tar.gz',
|
||||
},
|
||||
]);
|
||||
|
||||
res = await app.httpRequest()
|
||||
.get('/-/binary/node-canvas-prebuilt/v2.6.1/');
|
||||
|
||||
assert.strictEqual(res.status, 200);
|
||||
assert(res.body);
|
||||
stableData = TestUtil.pickKeys(res.body, [ 'category', 'name', 'date', 'type', 'url' ]);
|
||||
|
||||
assert.deepStrictEqual(stableData, [
|
||||
{
|
||||
name: 'node-canvas-prebuilt-v2.6.1-node-v57-linux-glibc-x64.tar.gz',
|
||||
type: 'file',
|
||||
category: 'node-canvas-prebuilt',
|
||||
date: '2021-12-14T13:12:31.587Z',
|
||||
url: 'http://localhost:7001/-/binary/node-canvas-prebuilt/v2.6.1/node-canvas-prebuilt-v2.6.1-node-v57-linux-glibc-x64.tar.gz',
|
||||
},
|
||||
]);
|
||||
|
||||
res = await app.httpRequest()
|
||||
.get('/-/binary/canvas/v2.7.1/');
|
||||
assert.strictEqual(res.status, 404);
|
||||
|
||||
res = await app.httpRequest()
|
||||
.get('/-/binary/node-canvas-prebuilt/v2.7.1/');
|
||||
|
||||
assert.strictEqual(res.status, 404);
|
||||
});
|
||||
|
||||
it('should get binary file success', async () => {
|
||||
await binaryRepository.saveBinary(Binary.create({
|
||||
category: 'node-canvas-prebuilt',
|
||||
parent: '/',
|
||||
name: 'v2.6.1/',
|
||||
isDir: true,
|
||||
size: 0,
|
||||
date: '2021-12-14T13:12:31.587Z',
|
||||
}));
|
||||
await binaryRepository.saveBinary(Binary.create({
|
||||
category: 'node-canvas-prebuilt',
|
||||
parent: '/',
|
||||
name: 'v2.7.0/',
|
||||
isDir: true,
|
||||
size: 0,
|
||||
date: '2021-12-14T13:12:31.587Z',
|
||||
}));
|
||||
await binaryRepository.saveBinary(Binary.create({
|
||||
category: 'node-canvas-prebuilt',
|
||||
parent: '/v2.6.1/',
|
||||
name: 'node-canvas-prebuilt-v2.6.1-node-v57-linux-glibc-x64.tar.gz',
|
||||
isDir: false,
|
||||
size: 10,
|
||||
date: '2021-12-14T13:12:31.587Z',
|
||||
}));
|
||||
|
||||
await binaryRepository.saveBinary(Binary.create({
|
||||
category: 'canvas',
|
||||
parent: '/v2.7.0/',
|
||||
name: 'canvas-v2.7.0-node-v57-linux-glibc-x64.tar.gz',
|
||||
isDir: false,
|
||||
size: 10,
|
||||
date: '2021-12-14T13:12:31.587Z',
|
||||
}));
|
||||
|
||||
await binaryRepository.saveBinary(Binary.create({
|
||||
category: 'canvas',
|
||||
parent: '/',
|
||||
name: 'v2.7.0/',
|
||||
isDir: true,
|
||||
size: 0,
|
||||
date: '2021-12-14T13:12:31.587Z',
|
||||
}));
|
||||
|
||||
mock(nfsClientAdapter, 'url', async (storeKey: string) => {
|
||||
return `https://cdn.mock.com${storeKey}`;
|
||||
});
|
||||
const res = await app.httpRequest()
|
||||
.get('/-/binary/canvas/v2.6.1/canvas-v2.6.1-node-v57-linux-glibc-x64.tar.gz');
|
||||
|
||||
assert.strictEqual(res.status, 302);
|
||||
assert.strictEqual(res.headers.location, 'https://cdn.mock.com/binaries/node-canvas-prebuilt/v2.6.1/node-canvas-prebuilt-v2.6.1-node-v57-linux-glibc-x64.tar.gz');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -5,7 +5,6 @@ import { app, mock } from 'egg-mock/bootstrap';
|
||||
import { TestUtil } from 'test/TestUtil';
|
||||
import { Task as TaskModel } from 'app/repository/model/Task';
|
||||
import { PackageSyncerService } from 'app/core/service/PackageSyncerService';
|
||||
import { TaskState } from 'app/common/enum/Task';
|
||||
|
||||
describe('test/port/controller/PackageSyncController/createSyncTask.test.ts', () => {
|
||||
let publisher: any;
|
||||
@@ -286,7 +285,7 @@ describe('test/port/controller/PackageSyncController/createSyncTask.test.ts', ()
|
||||
assert(res.body.id === firstTaskId);
|
||||
});
|
||||
|
||||
it('should dont create exists processing task update less than 1 min', async () => {
|
||||
it('should dont create exists waiting task', async () => {
|
||||
let res = await app.httpRequest()
|
||||
.put('/-/package/koa/syncs')
|
||||
.expect(201);
|
||||
@@ -295,13 +294,12 @@ describe('test/port/controller/PackageSyncController/createSyncTask.test.ts', ()
|
||||
assert(res.body.id);
|
||||
const firstTaskId = res.body.id;
|
||||
|
||||
await TaskModel.update({ taskId: firstTaskId }, { state: TaskState.Processing });
|
||||
// again dont create
|
||||
res = await app.httpRequest()
|
||||
.put('/-/package/koa/syncs')
|
||||
.expect(201);
|
||||
assert(res.body.ok === true);
|
||||
assert(res.body.state === 'processing');
|
||||
assert(res.body.state === 'waiting');
|
||||
assert(res.body.id === firstTaskId);
|
||||
|
||||
// update bigger than 1 min, same task return
|
||||
@@ -310,7 +308,7 @@ describe('test/port/controller/PackageSyncController/createSyncTask.test.ts', ()
|
||||
.put('/-/package/koa/syncs')
|
||||
.expect(201);
|
||||
assert(res.body.ok === true);
|
||||
assert(res.body.state === 'processing');
|
||||
assert(res.body.state === 'waiting');
|
||||
assert(res.body.id === firstTaskId);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -83,6 +83,7 @@ describe('test/port/controller/package/ShowPackageController.test.ts', () => {
|
||||
const versionOne = pkg.versions['1.0.0'];
|
||||
assert.equal(versionOne.dist.unpackedSize, 6497043);
|
||||
assert(versionOne._cnpmcore_publish_time);
|
||||
assert(versionOne.publish_time);
|
||||
assert.equal(pkg._id, name);
|
||||
assert(pkg._rev);
|
||||
assert(versionOne._id);
|
||||
@@ -214,6 +215,9 @@ describe('test/port/controller/package/ShowPackageController.test.ts', () => {
|
||||
const versionOne = pkg.versions['1.0.0'];
|
||||
assert(versionOne.dist.unpackedSize === 6497043);
|
||||
assert(versionOne._cnpmcore_publish_time);
|
||||
assert.equal(typeof versionOne._cnpmcore_publish_time, 'string');
|
||||
assert(versionOne.publish_time);
|
||||
assert.equal(typeof versionOne.publish_time, 'number');
|
||||
assert(pkg._id === scopedName);
|
||||
assert(pkg._rev);
|
||||
assert(versionOne._id);
|
||||
@@ -258,6 +262,8 @@ describe('test/port/controller/package/ShowPackageController.test.ts', () => {
|
||||
const versionOne = pkg.versions['2.0.0'];
|
||||
assert.equal(versionOne.dist.unpackedSize, 6497043);
|
||||
assert(!versionOne._cnpmcore_publish_time);
|
||||
assert(versionOne.publish_time);
|
||||
assert.equal(typeof versionOne.publish_time, 'number');
|
||||
assert(!pkg._rev);
|
||||
assert(!pkg._id);
|
||||
assert(!versionOne._id);
|
||||
@@ -325,6 +331,8 @@ describe('test/port/controller/package/ShowPackageController.test.ts', () => {
|
||||
const versionOne = pkg.versions['2.0.0'];
|
||||
assert.equal(versionOne.dist.unpackedSize, 6497043);
|
||||
assert(!versionOne._cnpmcore_publish_time);
|
||||
assert(versionOne.publish_time);
|
||||
assert.equal(typeof versionOne.publish_time, 'number');
|
||||
assert(!pkg._rev);
|
||||
assert(!pkg._id);
|
||||
assert(!versionOne._id);
|
||||
@@ -347,6 +355,8 @@ describe('test/port/controller/package/ShowPackageController.test.ts', () => {
|
||||
const versionOne = pkg.versions['2.0.0'];
|
||||
assert(versionOne.dist.unpackedSize === 6497043);
|
||||
assert(!versionOne._cnpmcore_publish_time);
|
||||
assert(versionOne.publish_time);
|
||||
assert.equal(typeof versionOne.publish_time, 'number');
|
||||
assert(!pkg._rev);
|
||||
assert(!pkg._id);
|
||||
assert(!versionOne._id);
|
||||
|
||||
@@ -134,6 +134,66 @@ describe('test/port/controller/package/UpdatePackageController.test.ts', () => {
|
||||
})
|
||||
.expect(400);
|
||||
assert.equal(res.body.error, '[BAD_REQUEST] header: npm-command expected "owner", but got "adduser"');
|
||||
|
||||
// npm@6: referer: 'xxx [REDACTED]'
|
||||
// npm@>=7: 'npm-command': 'xxx'
|
||||
// when npm version < 7, npm command can get from referer
|
||||
res = await app.httpRequest()
|
||||
.put(`/${scopedName}/-rev/${rev}`)
|
||||
.set('authorization', user.authorization)
|
||||
.set('user-agent', 'npm/6.3.1')
|
||||
.set('referer', 'addUser add someone [REDACTED]')
|
||||
.send({
|
||||
_id: rev,
|
||||
_rev: rev,
|
||||
maintainers: [
|
||||
{ name: user.name, email: user.email },
|
||||
],
|
||||
})
|
||||
.expect(400);
|
||||
assert.equal(res.body.error, '[BAD_REQUEST] header: npm-command expected "owner", but got "addUser"');
|
||||
});
|
||||
|
||||
it('should 200 when npm command is npm owner add', async () => {
|
||||
mock(app.config.cnpmcore, 'enableNpmClientAndVersionCheck', false);
|
||||
// npm@6: referer: 'xxx [REDACTED]'
|
||||
// npm@>=7: 'npm-command': 'xxx'
|
||||
|
||||
// npm version < 7
|
||||
const user = await TestUtil.createUser();
|
||||
let res = await app.httpRequest()
|
||||
.put(`/${scopedName}/-rev/${rev}`)
|
||||
.set('authorization', publisher.authorization)
|
||||
.set('user-agent', 'npm/6.3.1')
|
||||
.set('referer', 'owner add someone [REDACTED]')
|
||||
.send({
|
||||
_id: rev,
|
||||
_rev: rev,
|
||||
maintainers: [
|
||||
{ name: user.name, email: user.email },
|
||||
],
|
||||
})
|
||||
.expect(200);
|
||||
assert.equal(res.statusCode, 200);
|
||||
assert.deepEqual(res.body, { ok: true });
|
||||
|
||||
// npm version >= 7
|
||||
res = await app.httpRequest()
|
||||
.put(`/${scopedName}/-rev/${rev}`)
|
||||
.set('authorization', user.authorization)
|
||||
.set('user-agent', 'npm/7.3.1')
|
||||
.set('referer', '')
|
||||
.set('npm-command', 'owner')
|
||||
.send({
|
||||
_id: rev,
|
||||
_rev: rev,
|
||||
maintainers: [
|
||||
{ name: user.name, email: user.email },
|
||||
],
|
||||
})
|
||||
.expect(200);
|
||||
assert.equal(res.statusCode, 200);
|
||||
assert.deepEqual(res.body, { ok: true });
|
||||
});
|
||||
|
||||
it('should 403 when npm client invalid', async () => {
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
"app/**/*.json",
|
||||
"config/**/*.ts",
|
||||
"typings/**/*.ts",
|
||||
"app.ts"
|
||||
"app.ts",
|
||||
"module.d.ts"
|
||||
]
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user