Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 6 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,13 @@
"@types/js-yaml": "^4.0.0",
"@types/mocha": "^9",
"@types/node": "^17",
"@typescript-eslint/eslint-plugin": "^5.17.0",
"@typescript-eslint/parser": "^5.17.0",
"chai": "^4",
"eslint": "^7.19.0",
"eslint-config-oclif": "^3.1.0",
"eslint-config-oclif-typescript": "^0.2.0",
"eslint": "^8.12.0",
"eslint-config-oclif": "^4.0.0",
"eslint-config-oclif-typescript": "^1.0.2",
"eslint-plugin-unicorn": "^42.0.0",
"globby": "^11",
"install": "^0.13.0",
"mocha": "^9",
Expand Down
5 changes: 3 additions & 2 deletions src/asserters/badge.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import * as path from 'path'
import * as path from 'node:path'
import * as fs from 'fs-extra'

import AsserterBase from './base'
Expand All @@ -15,7 +15,7 @@ export class ReadmeHasBadgesAsserter extends AsserterBase {
protected async uniqWork() {
const pkgJson = require(path.join(this.workingDir, 'package.json'))
const readmePath = path.join(this.workingDir, 'README.md')
let readme = fs.readFileSync(readmePath, 'utf-8')
let readme = fs.readFileSync(readmePath, 'utf8')

const {name, license} = pkgJson
const BADGES: Record<string, string> = {
Expand All @@ -38,6 +38,7 @@ export class ReadmeHasBadgesAsserter extends AsserterBase {
// if we can't find the header, insert the badges as the first line
readme = `${badges.join(' ')}\n${readme}`
}

fs.writeFileSync(readmePath, readme)
}
}
6 changes: 3 additions & 3 deletions src/asserters/base.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ export default abstract class AsserterBase {
await exec(`git -C ${this.workingDir} checkout ${this.branchName}`)
indentLog(8, `Checking out branch ${this.branchName}...`)
} catch (error: any) {
if (error.toString().match(/did not match/)) {
if (/did not match/.test(error.toString())) {
await exec(`git -C ${this.workingDir} checkout -b ${this.branchName}`)
indentLog(8, `Creating branch ${this.branchName}...`)
} else {
Expand All @@ -55,7 +55,7 @@ export default abstract class AsserterBase {
try {
await exec(`cd ${this.workingDir} && ${this.assertion.if}`)
indentLog(8, 'Passed `if` guard, continuing assertion...')
} catch (error: any) {
} catch {
indentLog(8, 'Did not pass `if` guard, skipping assertion...')
await exec(`git -C ${this.workingDir} checkout ${this.mainBranchName}`)
return
Expand All @@ -80,7 +80,7 @@ export default abstract class AsserterBase {

// 3.
const {stdout} = await exec(`git -C ${this.workingDir} status`)
if (stdout.toString().match(/nothing to commit, working tree clean/)) {
if (/nothing to commit, working tree clean/.test(stdout.toString())) {
// if working dir clean
indentLog(8, 'Working directory clean, no changes to push...')
} else {
Expand Down
2 changes: 1 addition & 1 deletion src/asserters/file.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import * as path from 'path'
import * as path from 'node:path'
import * as fs from 'fs-extra'

import AsserterBase from './base'
Expand Down
2 changes: 2 additions & 0 deletions src/asserters/github.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,11 @@ export class GithubRepoPropertyValueAsserter extends AsserterBase {
if (this.dryRun) {
return `In --dry-run mode: set ${property} to ${value} on ${owner}/${repo}`
}

await GitHubClient.repos.update(payload as any)
return `Set ${property} to ${value} on ${owner}/${repo}`
}

return `The ${property} is already ${value} on ${owner}/${repo}`
}
}
3 changes: 2 additions & 1 deletion src/asserters/json.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import * as path from 'path'
import * as path from 'node:path'
import * as fs from 'fs-extra'
import * as glob from 'fast-glob'

Expand All @@ -17,6 +17,7 @@ export class JsonHasPropertiesAsserter extends AsserterBase {
} else {
throw new Error('Neither target_glob_filepath nor target_relative_filepath are provided')
}

for (const targetJSONPath of jsonPaths) {
const targetJSON = require(targetJSONPath)
const assertedJSON = deepAssign({...targetJSON}, sourceJSON, {arrayBehavior: this.assertion.array_behavior})
Expand Down
11 changes: 4 additions & 7 deletions src/asserters/node.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import * as path from 'path'
import * as path from 'node:path'
import * as fs from 'fs-extra'

import AsserterBase from './base'
Expand Down Expand Up @@ -57,6 +57,7 @@ export class NodeLernaProjectHasDepsAsserter extends NodeProjectHasDepsAsserter
console.log('No lerna.json file found, skipping...')
return
}

const targets: string[] = []
if (this.assertion.target_glob_filepath) {
const fullGlob = path.join(this.workingDir, this.assertion.target_glob_filepath)
Expand All @@ -67,11 +68,7 @@ export class NodeLernaProjectHasDepsAsserter extends NodeProjectHasDepsAsserter
}

for (const target of targets) {
if (target === this.workingDir) {
await this.doWork(target, '-W')
} else {
await this.doWork(target)
}
await (target === this.workingDir ? this.doWork(target, '-W') : this.doWork(target))
}
}
}
Expand All @@ -98,7 +95,7 @@ export class NodeProjectDoesNotHaveDepsAsserter extends AsserterBase {
await exec(`cd ${this.workingDir}; npm uninstall ${depsToUninstall.join(' ')}`)
}
} catch (error: any) {
if (error.toString().match(/This module isn't specified in a/)) {
if (/This module isn't specified in a/.test(error.toString())) {
// carry on
} else {
throw error
Expand Down
6 changes: 3 additions & 3 deletions src/asserters/yaml.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import * as path from 'path'
import * as path from 'node:path'
import * as fs from 'fs-extra'
import * as yaml from 'js-yaml'

Expand All @@ -8,8 +8,8 @@ import {deepAssign} from '../utils'
export class YamlHasPropertiesAsserter extends AsserterBase {
protected async uniqWork() {
const targetYamlPath = path.join(this.workingDir, this.assertion.target_relative_filepath)
const sourceYamlAsJson = yaml.load(await fs.readFile(path.join(this.templateDir, this.assertion.source_relative_filepath), 'utf-8')) as object
const targetYamlAsJson = yaml.load(await fs.readFile(targetYamlPath, 'utf-8')) as object
const sourceYamlAsJson = yaml.load(await fs.readFile(path.join(this.templateDir, this.assertion.source_relative_filepath), 'utf8')) as object
const targetYamlAsJson = yaml.load(await fs.readFile(targetYamlPath, 'utf8')) as object

const assertedJson = deepAssign({...targetYamlAsJson}, sourceYamlAsJson, {arrayBehavior: this.assertion.array_behavior})
const assertedYaml = yaml.dump(assertedJson, {indent: 2})
Expand Down
1 change: 1 addition & 0 deletions src/commands/cleanup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ export default class Cleanup extends Command {
if (!args.org) this.error('Either an org or --all must be passed')
localDir = `${localDir}/${args.org}`
}

this.log(`Removing ${localDir}`)
await fs.ensureDir(localDir)
await fs.rmdir(localDir)
Expand Down
8 changes: 4 additions & 4 deletions src/repos.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,16 +19,16 @@ export default class RepoService {
await exec(`git -C ${localRepoDir} fetch --prune`)
await exec(`git -C ${localRepoDir} pull`)
try {
const branches = (await exec(`git -C ${localRepoDir} branch -vv`)).stdout.split(/[\r\n]+/)
const branches = (await exec(`git -C ${localRepoDir} branch -vv`)).stdout.split(/[\n\r]+/)

// Clean up branches by finding any that match ': gone' or that don't have a remote tracking branch and delete them
branches.forEach(async (branch: string) => {
if (branch.match(/: gone/) || !branch.match(/origin\//)) {
const branchMatch = branch.match(/^(?:[*\s]{2})([\w/-]+)/g) // Gets the branch name from the branch string that `git branch -vv` returns
if (/: gone/.test(branch) || !/origin\//.test(branch)) {
const branchMatch = branch.match(/^[\s*]{2}([\w/-]+)/g) // Gets the branch name from the branch string that `git branch -vv` returns
if (branchMatch) await exec(`git -C ${localRepoDir} branch ${branchMatch[0].trim()} -D`)
}
})
} catch (_) {
} catch {
ux.log(`A error occured cleaning up stale branches in ${localRepoDir}`)
ux.log('You may need to clean up branches manually')
}
Expand Down
1 change: 1 addition & 0 deletions src/sequences.ts
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ export default class SequenceService {
} else {
await exec(`git -C ${workingDir} push origin ${branchName} --no-verify`)
}

indentLog(6, `Pushing branch ${branchName} to GitHub...`)
} else {
skipCreatingPR = true
Expand Down
39 changes: 23 additions & 16 deletions src/utils.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import * as util from 'util'
import * as util from 'node:util'
import * as fs from 'fs-extra'
import * as path from 'path'
import * as path from 'node:path'

import {Leif} from './types'
import WorkflowService from './workflows'
Expand All @@ -14,27 +14,26 @@ export const exec = util.promisify(execz)
export const homedir = require('os').homedir()

export const indentLog = (spaces: number, ...loglines: string[]) => {
loglines.forEach(line => {
for (const line of loglines) {
console.log(`${''.padEnd(spaces)}${line}`)
})
}
}

export const syncProcessArray = async (array: any[], fn: (x: any) => void) => {
for (let i = 0; i < array.length; i++) {
await fn(array[i])
for (const element of array) {
await fn(element)
}
return Promise.resolve()
}

export function masterBranchName(cwd: string): string {
try {
execSync(`git -C ${cwd} show-branch remotes/origin/main`, {stdio: 'ignore'})
return 'main'
} catch (error: any) {
} catch {
try {
execSync(`git -C ${cwd} show-branch remotes/origin/master`, {stdio: 'ignore'})
return 'master'
} catch (error) {
} catch {
return String(execSync(`git -C ${cwd} symbolic-ref --short HEAD`)).replace('\n', '')
}
}
Expand All @@ -48,6 +47,7 @@ export function deepAssign(target: AnyObject, source: AnyObject, opts?: {arrayBe
if (typeof target !== 'object' || typeof source !== 'object') {
return source
}

const behavior = opts?.arrayBehavior

function handleUniqueKeyObjectsArray(target: any, source: any) {
Expand All @@ -72,31 +72,35 @@ export function deepAssign(target: AnyObject, source: AnyObject, opts?: {arrayBe
if (behavior === 'concat') {
return target.concat(source)
}

if (behavior === 'merge') {
return source.map((v: any, i: number) => {
return deepAssign(target[i] || {}, v, {arrayBehavior: 'merge'})
})
}

if (behavior === 'unique-key-objects') {
const isUniqueKeyObjectsArray = target.length > 1 && target.find((t: any) => {
return typeof t === 'object' && Object.keys(t).length === 1
})
if (isUniqueKeyObjectsArray) {
return handleUniqueKeyObjectsArray(target, source)
}

// if not uniq keys, fallback to merge behavior
return source.map((s: any, i: number) => {
return deepAssign(target[i], s, {arrayBehavior: 'merge'})
})
}

// replace target[key] (default behavior)
return source
}

Object.keys(source).forEach(k => {
for (const k of Object.keys(source)) {
if (source[k] && typeof source[k] === 'object') {
// source[key] value is truthy && of type object
// eslint-disable-next-line no-negated-condition

if (!target[k]) {
// key doesn't exist, just assign it
target[k] = source[k]
Expand All @@ -113,7 +117,8 @@ export function deepAssign(target: AnyObject, source: AnyObject, opts?: {arrayBe
// replace key with source
target[k] = source[k]
}
})
}

return target
}

Expand All @@ -130,6 +135,7 @@ export function filterWorkflows(preparedWorkflows: Leif.Workflow[], filters: {wo
pw.sequences = pw.sequences.filter(s => sequences.includes(s.id))
if (pw.sequences.length === 0) throw new Error(`Could not find any matching sequences for ${sequences}`)
}

return shouldInclude
})
if (preparedWorkflows.length === 0) throw new Error(`Could not find any matching workflows for ${workflows}`)
Expand All @@ -149,16 +155,17 @@ export async function prepareWorkflows(args: AnyObject, flags: AnyObject) {
const repos = flags.repo

if (repos) {
preparedWorkflows.forEach(w => {
for (const w of preparedWorkflows) {
w.repos = repos
w.sequences.forEach(s => {
for (const s of w.sequences) {
s.repos = repos
})
})
}
}
}

if (workflows) {
preparedWorkflows = filterWorkflows(preparedWorkflows, {workflows, sequences})
}

return preparedWorkflows
}
Loading