yaba-release-cli
Version:
Yaba is a simple CLI tool that helps you manage releases of your Github projects.
108 lines (87 loc) • 3.65 kB
JavaScript
function isNonEmptyString(value) {
return typeof value === 'string' && value.trim().length > 0;
}
function detectTokenKind(tokenValue, env = process.env) {
const token = isNonEmptyString(tokenValue) ? tokenValue.trim() : '';
if (!token) {
return 'missing';
}
const githubActions = env?.GITHUB_ACTIONS === 'true';
const githubToken = isNonEmptyString(env?.GITHUB_TOKEN) ? env.GITHUB_TOKEN.trim() : '';
if ((githubActions && githubToken && token === githubToken) || token.startsWith('ghs_')) {
return 'github-actions-token';
}
if (token.startsWith('github_pat_')) {
return 'fine-grained-pat';
}
if (token.startsWith('ghp_') || token.startsWith('gho_') || token.startsWith('ghu_') || token.startsWith('ghr_')) {
return 'classic-pat';
}
return 'unknown-token';
}
function tokenKindLabel(tokenKind) {
switch (tokenKind) {
case 'github-actions-token':
return 'GitHub Actions token';
case 'fine-grained-pat':
return 'Fine-grained personal access token';
case 'classic-pat':
return 'Classic personal access token';
case 'missing':
return 'Missing token';
default:
return 'Unknown token type';
}
}
function summarizeOAuthScopes(scopesHeader) {
if (!isNonEmptyString(scopesHeader)) {
return 'OAuth scopes header not available (common with fine-grained PATs and GitHub Actions tokens).';
}
const scopes = scopesHeader
.split(',')
.map(scope => scope.trim())
.filter(Boolean);
if (scopes.length === 0) {
return 'OAuth scopes header not available (common with fine-grained PATs and GitHub Actions tokens).';
}
return `OAuth scopes: ${scopes.join(', ')}.`;
}
function resolveErrorStatus(error) {
return error?.status
|| error?.response?.status
|| error?.cause?.status
|| error?.cause?.response?.status
|| null;
}
function buildAuthFailureGuidance({ tokenKind, status }) {
if (tokenKind === 'github-actions-token') {
if (status === 403) {
return 'Token lacks required workflow/repository permissions. Ensure workflow permissions include contents: write.';
}
return 'Use `${{ github.token }}` with workflow permissions (`contents: write`) for same-repo releases. Use a PAT for cross-repo access.';
}
if (tokenKind === 'fine-grained-pat') {
return 'Grant this token access to the target repository and ensure permissions include Contents (read/write) and Metadata (read).';
}
if (tokenKind === 'classic-pat') {
return 'Ensure this PAT has `repo` scope (private repos) and belongs to a user with access to the target repository.';
}
return 'Check token validity, repository visibility, and permissions. Recreate the token if uncertain.';
}
function buildRepoAccessFailureGuidance({ tokenKind, status, owner, repo, apiMessage }) {
const target = isNonEmptyString(owner) && isNonEmptyString(repo)
? `${owner}/${repo}`
: 'target repository';
const statusPart = status ? `status ${status}` : 'unknown status';
const reasonPart = isNonEmptyString(apiMessage) ? ` GitHub API message: ${apiMessage}.` : '';
const guidance = buildAuthFailureGuidance({ tokenKind, status });
return `Repository access check failed (${statusPart}) for ${target}.${reasonPart} ${guidance}`.trim();
}
export {
buildAuthFailureGuidance,
buildRepoAccessFailureGuidance,
detectTokenKind,
resolveErrorStatus,
summarizeOAuthScopes,
tokenKindLabel
};