accent-cli
Advanced tools
Comparing version 0.14.2 to 0.15.0
@@ -1,1 +0,1 @@ | ||
{"version":"0.14.2","commands":{"export":{"id":"export","description":"Export files from Accent and write them to your local filesystem","pluginName":"accent-cli","pluginType":"core","aliases":[],"examples":["$ accent export","$ accent export --order-by=key --version=build.myapp.com:0.12.345"],"flags":{"order-by":{"name":"order-by","type":"option","description":"Order of the keys","options":["index","key"],"default":"index"},"version":{"name":"version","type":"option","description":"Fetch a specific version","default":""},"config":{"name":"config","type":"option","description":"Path to the config file","default":"accent.json"}},"args":[]},"format":{"id":"format","description":"Format local files from server. Exit code is 1 if there are errors.","pluginName":"accent-cli","pluginType":"core","aliases":[],"examples":["$ accent format"],"flags":{"order-by":{"name":"order-by","type":"option","description":"Order of the keys","options":["index","key","-index","-key"],"default":"index"},"config":{"name":"config","type":"option","description":"Path to the config file","default":"accent.json"}},"args":[]},"jipt":{"id":"jipt","description":"Export jipt files from Accent and write them to your local filesystem","pluginName":"accent-cli","pluginType":"core","aliases":[],"examples":["$ accent jipt"],"flags":{"config":{"name":"config","type":"option","description":"Path to the config file","default":"accent.json"}},"args":[{"name":"pseudoLanguageName","description":"The pseudo language for in-place-translation-editing","required":true}]},"lint":{"id":"lint","description":"Lint local files and display errors if any. Exit code is 1 if there are errors.","pluginName":"accent-cli","pluginType":"core","aliases":[],"examples":["$ accent lint"],"flags":{"config":{"name":"config","type":"option","description":"Path to the config file","default":"accent.json"}},"args":[]},"stats":{"id":"stats","description":"Fetch stats from the API and display it beautifully","pluginName":"accent-cli","pluginType":"core","aliases":[],"examples":["$ accent stats"],"flags":{"config":{"name":"config","type":"option","description":"Path to the config file","default":"accent.json"}},"args":[]},"sync":{"id":"sync","description":"Sync files in Accent and write them to your local filesystem","pluginName":"accent-cli","pluginType":"core","aliases":[],"examples":["$ accent sync","$ accent sync --dry-run --sync-type=force","$ accent sync --add-translations --merge-type=smart --order-key=key --version=v0.23"],"flags":{"add-translations":{"name":"add-translations","type":"boolean","description":"Add translations in Accent to help translators if you already have translated strings locally","allowNo":false},"dry-run":{"name":"dry-run","type":"boolean","description":"Do not write the file from the export _after_ the operation","allowNo":false},"merge-type":{"name":"merge-type","type":"option","description":"Algorithm to use on existing strings when adding translation","options":["smart","passive","force"],"default":"passive"},"order-by":{"name":"order-by","type":"option","description":"Will be used in the export call as the order of the keys","options":["index","key"],"default":"index"},"sync-type":{"name":"sync-type","type":"option","description":"Algorithm to use on existing strings when syncing the main language","options":["smart","passive"],"default":"smart"},"version":{"name":"version","type":"option","description":"Sync a specific version, the tag needs to exists in Accent first","default":""},"config":{"name":"config","type":"option","description":"Path to the config file","default":"accent.json"}},"args":[]}}} | ||
{"version":"0.15.0","commands":{"export":{"id":"export","description":"Export files from Accent and write them to your local filesystem","pluginName":"accent-cli","pluginType":"core","aliases":[],"examples":["$ accent export","$ accent export --order-by=key --version=build.myapp.com:0.12.345"],"flags":{"order-by":{"name":"order-by","type":"option","description":"Order of the keys","options":["index","key"],"default":"index"},"version":{"name":"version","type":"option","description":"Fetch a specific version","default":""},"config":{"name":"config","type":"option","description":"Path to the config file","default":"accent.json"}},"args":[]},"format":{"id":"format","description":"Format local files from server. Exit code is 1 if there are errors.","pluginName":"accent-cli","pluginType":"core","aliases":[],"examples":["$ accent format"],"flags":{"order-by":{"name":"order-by","type":"option","description":"Order of the keys","options":["index","key","-index","-key"],"default":"index"},"config":{"name":"config","type":"option","description":"Path to the config file","default":"accent.json"}},"args":[]},"jipt":{"id":"jipt","description":"Export jipt files from Accent and write them to your local filesystem","pluginName":"accent-cli","pluginType":"core","aliases":[],"examples":["$ accent jipt"],"flags":{"config":{"name":"config","type":"option","description":"Path to the config file","default":"accent.json"}},"args":[{"name":"pseudoLanguageName","description":"The pseudo language for in-place-translation-editing","required":true}]},"lint":{"id":"lint","description":"Lint local files and display errors if any. Exit code is 1 if there are errors.","pluginName":"accent-cli","pluginType":"core","aliases":[],"examples":["$ accent lint"],"flags":{"config":{"name":"config","type":"option","description":"Path to the config file","default":"accent.json"}},"args":[]},"stats":{"id":"stats","description":"Fetch stats from the API and display them beautifully","pluginName":"accent-cli","pluginType":"core","aliases":[],"examples":["$ accent stats"],"flags":{"version":{"name":"version","type":"option","description":"View stats for a specific version"},"check-reviewed":{"name":"check-reviewed","type":"boolean","description":"Exit 1 when reviewed percentage is not 100%","allowNo":false},"check-translated":{"name":"check-translated","type":"boolean","description":"Exit 1 when translated percentage is not 100%","allowNo":false},"config":{"name":"config","type":"option","description":"Path to the config file","default":"accent.json"}},"args":[]},"sync":{"id":"sync","description":"Sync files in Accent and write them to your local filesystem","pluginName":"accent-cli","pluginType":"core","aliases":[],"examples":["$ accent sync","$ accent sync --dry-run --sync-type=force","$ accent sync --add-translations --merge-type=smart --order-key=key --version=v0.23"],"flags":{"add-translations":{"name":"add-translations","type":"boolean","description":"Add translations in Accent to help translators if you already have translated strings locally","allowNo":false},"dry-run":{"name":"dry-run","type":"boolean","description":"Do not write the file from the export _after_ the operation","allowNo":false},"merge-type":{"name":"merge-type","type":"option","description":"Algorithm to use on existing strings when adding translation","options":["smart","passive","force"],"default":"passive"},"order-by":{"name":"order-by","type":"option","description":"Will be used in the export call as the order of the keys","options":["index","key"],"default":"index"},"sync-type":{"name":"sync-type","type":"option","description":"Algorithm to use on existing strings when syncing the main language","options":["smart","passive"],"default":"smart"},"version":{"name":"version","type":"option","description":"Sync a specific version, the tag needs to exists in Accent first","default":""},"config":{"name":"config","type":"option","description":"Path to the config file","default":"accent.json"}},"args":[]}}} |
@@ -0,1 +1,2 @@ | ||
import { flags } from '@oclif/command'; | ||
import Command from '../base'; | ||
@@ -6,5 +7,8 @@ export default class Stats extends Command { | ||
static flags: { | ||
config: import("@oclif/command/lib/flags").IOptionFlag<string>; | ||
version: flags.IOptionFlag<string | undefined>; | ||
'check-reviewed': import("@oclif/parser/lib/flags").IBooleanFlag<boolean>; | ||
'check-translated': import("@oclif/parser/lib/flags").IBooleanFlag<boolean>; | ||
config: flags.IOptionFlag<string>; | ||
}; | ||
run(): Promise<void>; | ||
} |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
// Vendor | ||
const chalk = require("chalk"); | ||
// Command | ||
const command_1 = require("@oclif/command"); | ||
const base_1 = require("../base"); | ||
const errors_1 = require("@oclif/errors"); | ||
// Services | ||
const project_stats_1 = require("../services/formatters/project-stats"); | ||
const project_fetcher_1 = require("../services/project-fetcher"); | ||
class Stats extends base_1.default { | ||
/* eslint-disable @typescript-eslint/require-await */ | ||
async run() { | ||
const formatter = new project_stats_1.default(this.project, this.projectConfig.config); | ||
const { flags } = this.parse(Stats); | ||
if (this.projectConfig.config.version?.tag && !flags.version) { | ||
flags.version = this.projectConfig.config.version.tag; | ||
} | ||
if (flags.version) { | ||
const config = this.projectConfig.config; | ||
const fetcher = new project_fetcher_1.default(); | ||
const response = await fetcher.fetch(config, { versionId: flags.version }); | ||
this.project = response.project; | ||
} | ||
const formatter = new project_stats_1.default(this.project, this.projectConfig.config, flags.version); | ||
formatter.log(); | ||
if (flags['check-reviewed']) { | ||
const conflictsCount = this.project.revisions.reduce((memo, revision) => memo + revision.conflictsCount, 0); | ||
if (conflictsCount !== 0) { | ||
const versionFormat = flags.version ? ` ${flags.version}` : ''; | ||
throw new errors_1.CLIError(chalk.red(`Project${versionFormat} has ${conflictsCount} strings to be reviewed`), { exit: 1 }); | ||
} | ||
} | ||
if (flags['check-translated']) { | ||
const translatedCount = this.project.revisions.reduce((memo, revision) => memo + revision.translatedCount, 0); | ||
const translationsCount = this.project.revisions.reduce((memo, revision) => memo + revision.translationsCount, 0); | ||
if (translationsCount - translatedCount !== 0) { | ||
const versionFormat = flags.version ? ` ${flags.version}` : ''; | ||
throw new errors_1.CLIError(chalk.red(`Project${versionFormat} has ${translatedCount} strings to be translated`), { exit: 1 }); | ||
} | ||
} | ||
} | ||
} | ||
exports.default = Stats; | ||
Stats.description = 'Fetch stats from the API and display it beautifully'; | ||
Stats.description = 'Fetch stats from the API and display them beautifully'; | ||
Stats.examples = [`$ accent stats`]; | ||
Stats.flags = { config: base_1.configFlag }; | ||
Stats.flags = { | ||
version: command_1.flags.string({ | ||
default: undefined, | ||
description: 'View stats for a specific version', | ||
}), | ||
'check-reviewed': command_1.flags.boolean({ | ||
description: 'Exit 1 when reviewed percentage is not 100%', | ||
}), | ||
'check-translated': command_1.flags.boolean({ | ||
description: 'Exit 1 when translated percentage is not 100%', | ||
}), | ||
config: base_1.configFlag, | ||
}; |
@@ -24,2 +24,5 @@ "use strict"; | ||
const documents = this.projectConfig.files(); | ||
if (this.projectConfig.config.version?.tag && !flags.version) { | ||
flags.version = this.config.version; | ||
} | ||
// From all the documentConfigs, do the sync or peek operations and log the results. | ||
@@ -26,0 +29,0 @@ const syncFormatter = new project_sync_1.default(); |
@@ -9,2 +9,4 @@ import Document from './document'; | ||
private sourceFolderPath; | ||
private getCurrentBranchName; | ||
private extractVersionFromBranch; | ||
} |
@@ -5,2 +5,3 @@ "use strict"; | ||
const errors_1 = require("@oclif/errors"); | ||
const child_process_1 = require("child_process"); | ||
const fs = require("fs-extra"); | ||
@@ -27,2 +28,6 @@ const path = require("path"); | ||
} | ||
if (this.config.version?.branchVersionPrefix && | ||
this.getCurrentBranchName().startsWith(this.config.version?.branchVersionPrefix)) { | ||
this.config.version.tag = this.extractVersionFromBranch(this.getCurrentBranchName(), this.config.version?.branchVersionPrefix); | ||
} | ||
const sameFolderPathWarning = new Set(); | ||
@@ -48,3 +53,16 @@ this.config.files.forEach((documentConfig) => { | ||
} | ||
getCurrentBranchName() { | ||
try { | ||
return (0, child_process_1.execSync)('git rev-parse --abbrev-ref HEAD') | ||
.toString('utf8') | ||
.replace(/[\n\r\s]+$/, ''); | ||
} | ||
catch { | ||
return ''; | ||
} | ||
} | ||
extractVersionFromBranch(branchName, gitBranchVersionMatch) { | ||
return branchName.replace(gitBranchVersionMatch, ''); | ||
} | ||
} | ||
exports.default = ConfigFetcher; |
@@ -7,4 +7,6 @@ import { Config } from '../../types/config'; | ||
private readonly config; | ||
constructor(project: Project, config: Config); | ||
private readonly version; | ||
constructor(project: Project, config: Config, version?: string); | ||
percentageReviewedString(number: number, translationsCount: number): string; | ||
log(): void; | ||
} |
@@ -8,23 +8,27 @@ "use strict"; | ||
const base_1 = require("./base"); | ||
const TITLE_LENGTH_PADDING = 4; | ||
class ProjectStatsFormatter extends base_1.default { | ||
constructor(project, config) { | ||
constructor(project, config, version) { | ||
super(); | ||
this.project = project; | ||
this.config = config; | ||
this.version = version; | ||
} | ||
log() { | ||
const translationsCount = this.project.revisions.reduce((memo, revision) => memo + revision.translationsCount, 0); | ||
const conflictsCount = this.project.revisions.reduce((memo, revision) => memo + revision.conflictsCount, 0); | ||
const reviewedCount = this.project.revisions.reduce((memo, revision) => memo + revision.reviewedCount, 0); | ||
const percentageReviewed = translationsCount > 0 ? reviewedCount / translationsCount : 0; | ||
const percentageReviewedString = `${percentageReviewed}% reviewed`; | ||
percentageReviewedString(number, translationsCount) { | ||
const prettyFloat = (number) => { | ||
if (number.endsWith('.00')) { | ||
return parseInt(number, 10).toString(); | ||
} | ||
else { | ||
return number; | ||
} | ||
}; | ||
const percentageReviewedString = `${prettyFloat(number.toFixed(2))}% reviewed`; | ||
let percentageReviewedFormat = chalk.green(percentageReviewedString); | ||
if (percentageReviewed === 100) { | ||
if (number === 100) { | ||
percentageReviewedFormat = chalk.green(percentageReviewedString); | ||
} | ||
else if (percentageReviewed > 100 / 2) { | ||
else if (number > 100 / 2) { | ||
percentageReviewedFormat = chalk.yellow(percentageReviewedString); | ||
} | ||
else if (percentageReviewed <= 0 && translationsCount === 0) { | ||
else if (number <= 0 && translationsCount === 0) { | ||
percentageReviewedFormat = chalk.dim('No strings'); | ||
@@ -35,10 +39,13 @@ } | ||
} | ||
console.log(this.project.logo | ||
? this.project.logo | ||
: chalk.bgGreenBright.black.bold(' ^ '), chalk.white.bold(this.project.name), chalk.dim(' • '), percentageReviewedFormat); | ||
const titleLength = (this.project.logo ? this.project.logo.length + 1 : 0) + | ||
this.project.name.length + | ||
percentageReviewedString.length + | ||
TITLE_LENGTH_PADDING; | ||
console.log(chalk.gray.dim('⎯'.repeat(titleLength))); | ||
return percentageReviewedFormat; | ||
} | ||
log() { | ||
const translationsCount = this.project.revisions.reduce((memo, revision) => memo + revision.translationsCount, 0); | ||
const translatedCount = this.project.revisions.reduce((memo, revision) => memo + revision.translatedCount, 0); | ||
const conflictsCount = this.project.revisions.reduce((memo, revision) => memo + revision.conflictsCount, 0); | ||
const reviewedCount = this.project.revisions.reduce((memo, revision) => memo + revision.reviewedCount, 0); | ||
const percentageReviewed = translationsCount > 0 ? (reviewedCount / translationsCount) * 100 : 0; | ||
const percentageReviewedFormat = this.percentageReviewedString(percentageReviewed, translationsCount); | ||
console.log(this.project.logo ? this.project.logo : chalk.bgGreen.black.bold(' ^ '), chalk.whiteBright.bold(this.project.name), chalk.dim(' • '), percentageReviewedFormat); | ||
console.log(chalk.gray.dim('⎯')); | ||
console.log(chalk.magenta('Last synced')); | ||
@@ -59,14 +66,4 @@ if (this.project.lastSyncedAt) { | ||
if (this.project.masterRevision.id !== revision.id) { | ||
const percentageReviewed = revision.reviewedCount / revision.translationsCount; | ||
const percentageReviewedString = `${percentageReviewed}% reviewed`; | ||
let percentageReviewedFormat = chalk.green(percentageReviewedString); | ||
if (percentageReviewed === 100) { | ||
percentageReviewedFormat = chalk.green(percentageReviewedString); | ||
} | ||
else if (percentageReviewed > 100 / 2) { | ||
percentageReviewedFormat = chalk.yellow(percentageReviewedString); | ||
} | ||
else { | ||
percentageReviewedFormat = chalk.red(percentageReviewedString); | ||
} | ||
const percentageReviewed = (revision.reviewedCount / revision.translationsCount) * 100; | ||
const percentageReviewedFormat = this.percentageReviewedString(percentageReviewed, translationsCount); | ||
console.log(`${chalk.white.bold((0, revision_slug_fetcher_1.fetchNameFromRevision)(revision))} – ${(0, revision_slug_fetcher_1.fetchFromRevision)(revision)}`, chalk.dim('•'), percentageReviewedFormat); | ||
@@ -88,10 +85,15 @@ } | ||
this.project.versions.entries.forEach((version) => { | ||
console.log(chalk.bgBlack.white(` ${version.tag} `)); | ||
if (version.tag === this.version) { | ||
console.log(chalk.bgBlack.whiteBright(` ${version.tag} `)); | ||
} | ||
else { | ||
console.log(chalk.white(`${version.tag}`)); | ||
} | ||
}); | ||
console.log(''); | ||
} | ||
console.log(chalk.magenta('Strings')); | ||
console.log(chalk.white('# Strings:'), chalk.white(`${translationsCount}`)); | ||
console.log(chalk.magenta(`Strings (${translationsCount})`)); | ||
console.log(chalk.green('✓ Reviewed:'), chalk.green(`${reviewedCount}`)); | ||
console.log(chalk.red('× In review:'), chalk.red(`${conflictsCount}`)); | ||
console.log(chalk.white('✎ Translated:'), chalk.white(`${translatedCount}`)); | ||
console.log(''); | ||
@@ -98,0 +100,0 @@ const owners = this.project.collaborators.filter(({ role }) => role === 'OWNER'); |
import { Config } from '../types/config'; | ||
import { ProjectViewer } from '../types/project'; | ||
export default class ProjectFetcher { | ||
fetch(config: Config): Promise<ProjectViewer>; | ||
fetch(config: Config, params?: object): Promise<ProjectViewer>; | ||
private graphql; | ||
} |
@@ -8,4 +8,4 @@ "use strict"; | ||
class ProjectFetcher { | ||
async fetch(config) { | ||
const response = await this.graphql(config); | ||
async fetch(config, params) { | ||
const response = await this.graphql(config, params || {}); | ||
try { | ||
@@ -22,4 +22,4 @@ const data = (await response.json()); | ||
} | ||
async graphql(config) { | ||
const query = `query ProjectDetails($project_id: ID!) { | ||
async graphql(config, params) { | ||
const query = `query ProjectDetails($project_id: ID! $versionId: ID) { | ||
viewer { | ||
@@ -80,5 +80,6 @@ user { | ||
revisions { | ||
revisions(versionId: $versionId) { | ||
id | ||
isMaster | ||
translatedCount | ||
translationsCount | ||
@@ -99,3 +100,4 @@ conflictsCount | ||
// eslint-disable-next-line camelcase | ||
const variables = config.project ? { project_id: config.project } : {}; | ||
const configParams = config.project ? { project_id: config.project } : {}; | ||
const variables = { ...configParams, ...params }; | ||
return await (0, node_fetch_1.default)(`${config.apiUrl}/graphql`, { | ||
@@ -102,0 +104,0 @@ body: JSON.stringify({ query, variables }), |
import { DocumentConfig } from './document-config'; | ||
import { VersionConfig } from './version-config'; | ||
export interface Config { | ||
apiUrl: string; | ||
apiKey: string; | ||
project: string | null | undefined; | ||
project?: string | null; | ||
version?: VersionConfig; | ||
files: DocumentConfig[]; | ||
} |
@@ -12,2 +12,3 @@ export interface Language { | ||
isMaster: boolean; | ||
translatedCount: number; | ||
translationsCount: number; | ||
@@ -14,0 +15,0 @@ conflictsCount: number; |
{ | ||
"name": "accent-cli", | ||
"version": "0.14.2", | ||
"version": "0.15.0", | ||
"author": "Simon Prévost", | ||
@@ -5,0 +5,0 @@ "description": "Accent CLI", |
@@ -23,3 +23,3 @@ Accent CLI | ||
$ accent (-v|--version|version) | ||
accent-cli/0.14.2 darwin-arm64 node-v16.15.1 | ||
accent-cli/0.15.0 darwin-arm64 node-v16.19.1 | ||
$ accent --help [COMMAND] | ||
@@ -42,2 +42,5 @@ USAGE | ||
"apiKey": "2nziVSaa8yUJxLkwoZA", | ||
"version": { | ||
"branchVersionPrefix": "release/" | ||
} | ||
"files": [ | ||
@@ -70,2 +73,6 @@ { | ||
Version object configuration | ||
- `branchVersionPrefix`: The Git branch prefix use to extract the file version | ||
Each operation section `sync` and `addTranslations` can contain the following object: | ||
@@ -136,2 +143,14 @@ | ||
## Version | ||
Version can be extracted from the current Git branch name. | ||
``` | ||
"version": { | ||
"branchVersionPrefix": "release/" | ||
} | ||
``` | ||
Naming a branch `release/v1.0.0` will cause the `sync` and `stats` CLI commands to be invoked as if `--version=1.0.0` had been specified. | ||
# Commands | ||
@@ -165,3 +184,3 @@ <!-- commands --> | ||
_See code: [src/commands/export.ts](https://github.com/mirego/accent/blob/v0.14.2/src/commands/export.ts)_ | ||
_See code: [src/commands/export.ts](https://github.com/mirego/accent/blob/v0.15.0/src/commands/export.ts)_ | ||
@@ -184,3 +203,3 @@ ## `accent format` | ||
_See code: [src/commands/format.ts](https://github.com/mirego/accent/blob/v0.14.2/src/commands/format.ts)_ | ||
_See code: [src/commands/format.ts](https://github.com/mirego/accent/blob/v0.15.0/src/commands/format.ts)_ | ||
@@ -222,3 +241,3 @@ ## `accent help [COMMAND]` | ||
_See code: [src/commands/jipt.ts](https://github.com/mirego/accent/blob/v0.14.2/src/commands/jipt.ts)_ | ||
_See code: [src/commands/jipt.ts](https://github.com/mirego/accent/blob/v0.15.0/src/commands/jipt.ts)_ | ||
@@ -240,7 +259,7 @@ ## `accent lint` | ||
_See code: [src/commands/lint.ts](https://github.com/mirego/accent/blob/v0.14.2/src/commands/lint.ts)_ | ||
_See code: [src/commands/lint.ts](https://github.com/mirego/accent/blob/v0.15.0/src/commands/lint.ts)_ | ||
## `accent stats` | ||
Fetch stats from the API and display it beautifully | ||
Fetch stats from the API and display them beautifully | ||
@@ -252,3 +271,6 @@ ``` | ||
OPTIONS | ||
--config=config [default: accent.json] Path to the config file | ||
--check-reviewed Exit 1 when reviewed percentage is not 100% | ||
--check-translated Exit 1 when translated percentage is not 100% | ||
--config=config [default: accent.json] Path to the config file | ||
--version=version View stats for a specific version | ||
@@ -259,3 +281,3 @@ EXAMPLE | ||
_See code: [src/commands/stats.ts](https://github.com/mirego/accent/blob/v0.14.2/src/commands/stats.ts)_ | ||
_See code: [src/commands/stats.ts](https://github.com/mirego/accent/blob/v0.15.0/src/commands/stats.ts)_ | ||
@@ -292,3 +314,3 @@ ## `accent sync` | ||
_See code: [src/commands/sync.ts](https://github.com/mirego/accent/blob/v0.14.2/src/commands/sync.ts)_ | ||
_See code: [src/commands/sync.ts](https://github.com/mirego/accent/blob/v0.15.0/src/commands/sync.ts)_ | ||
<!-- commandsstop --> | ||
@@ -337,3 +359,2 @@ | ||
`accent-cli` is © 2019 [Mirego](http://www.mirego.com) and may be freely distributed under the [New BSD license](http://opensource.org/licenses/BSD-3-Clause). See the [`LICENSE.md`](https://github.com/mirego/accent-cli/blob/master/LICENSE.md) file. | ||
# About Mirego | ||
@@ -340,0 +361,0 @@ |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
84914
74
1712
353
2