Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
058f6f0
wip
beeman Feb 9, 2025
977f7d5
fix: upgrade @clack/prompts from 0.7.0 to 0.11.0
snyk-bot Sep 5, 2025
148313f
Add .circleci/config.yml
Dargon789 Sep 19, 2025
eb77ed6
Merge branch 'solana-foundation:main' into circleci-project-setup
Dargon789 Sep 19, 2025
53b9543
Merge branch 'solana-foundation:main' into circleci-project-setup
Dargon789 Jan 12, 2026
4d740a3
Potential fix for code scanning alert no. 1: Regular expression injec…
Dargon789 Jan 12, 2026
bfe0f3f
fix: upgrade zod from 4.1.5 to 4.1.8 (#3)
Dargon789 Jan 12, 2026
5a5317d
fix: upgrade commander from 14.0.0 to 14.0.1 (#4)
Dargon789 Jan 12, 2026
73f8030
fix: upgrade semver from 7.7.2 to 7.7.3 (#5)
Dargon789 Jan 12, 2026
c8f6ae7
Version Packages (solana-foundation#206) (#7)
Dargon789 Jan 12, 2026
891a380
Create old-bags-rest.md (#10)
Dargon789 Jan 12, 2026
971b6f4
Merge branch 'solana-foundation:main' into main
Dargon789 Jan 12, 2026
aa4469a
Create config.yml (#13)
Dargon789 Jan 12, 2026
42ac0ba
Merge branch 'main' into circleci-project-setup
Dargon789 Jan 13, 2026
d81c8f7
Add .circleci/config.yml (#14)
Dargon789 Jan 13, 2026
16e4b3d
Merge branch 'main' into circleci-project-setup
Dargon789 Jan 13, 2026
2943928
Merge remote-tracking branch 'upstream/beeman/search-replace'
Dargon789 Jan 13, 2026
3224179
Merge remote-tracking branch 'origin/9-sequence-diagram-for-updated-c…
Dargon789 Jan 13, 2026
107cf1b
feat: support `in` alias for rename entries (#15)
Dargon789 Jan 13, 2026
547c775
Create rude-eyes-check.md (#17)
Dargon789 Jan 13, 2026
dc93052
Update publish-pkg-pr-new.yml (#18)
Dargon789 Jan 13, 2026
43261fe
Create two-bees-trade.md (#19)
Dargon789 Jan 13, 2026
5545ec9
fix: upgrade @beeman/repokit from 0.0.0-canary-20250801172233 to 0.0.…
Dargon789 Jan 14, 2026
6d05942
fix: upgrade @beeman/repokit from 0.0.0-canary-20250801172233 to 0.0.…
Dargon789 Jan 14, 2026
60c71c3
Circleci project setup (#24)
Dargon789 Jan 14, 2026
fa97832
Merge branch 'main' into ci-create-solana-dapp
Dargon789 Jan 14, 2026
41804c2
Update .changeset/two-bees-trade.md
Dargon789 Jan 14, 2026
d7025ec
fix chore: solana-foundation-(solana-foundation#190) (#21) (#26)
Dargon789 Jan 14, 2026
3701969
Merge branch 'main' into ci-create-solana-dapp
Dargon789 Jan 15, 2026
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
7 changes: 7 additions & 0 deletions .changeset/old-bags-rest.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
"create-solana-dapp": patch
---

fix: upgrade @clack/prompts to v0.11.0

This upgrade makes the vendored tasks utility in `src/utils/vendor/clack-tasks.ts` obsolete, as this functionality is now exported directly by `@clack/prompts`.
5 changes: 5 additions & 0 deletions .changeset/rude-eyes-check.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"create-solana-dapp": patch
---

Added CircleCI configuration for continuous integration.
5 changes: 5 additions & 0 deletions .changeset/two-bees-trade.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"create-solana-dapp": patch
---

Added CircleCI configuration for continuous integration.
34 changes: 34 additions & 0 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
version: 2.1

orbs:
node: circleci/node@x.y

jobs:
install-node-example:
docker:
- image: cimg/base:stable
steps:
- checkout
- node/install:
install-yarn: true
node-version: '16.13'
- run: node --version
workflows:
test_my_app:
jobs:
- install-node-example

# Add steps to the job
steps:
# Checkout the code as the first step.
- checkout
- run:
name: "Say hello"
command: "echo Hello, World!"

# Orchestrate jobs using workflows
workflows:
say-hello-workflow: # This is the name of the workflow, feel free to change it to better match your workflow.
# Inside the workflow, you define the jobs you want to run.
jobs:
- say-hello
28 changes: 16 additions & 12 deletions .github/workflows/publish-pkg-pr-new.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,19 +7,23 @@ on:
env:
# See https://consoledonottrack.com/
DO_NOT_TRACK: '1'


version: '2.1'
orbs:
node: circleci/node@x.y
jobs:
build-and-publish-snapshots-to-npm:
runs-on: ubuntu-latest
test:
executor: node/default
steps:
- name: Checkout
uses: actions/checkout@v4

- name: Install Dependencies
uses: ./.github/workflows/actions/install-dependencies
- checkout
- node/install-bun:
version: 1.2.22
- node/install-packages:
pkg-manager: bun
- run: bun run test
workflows:
test_my_app:
jobs:
- test

- name: Run Build Step
run: pnpm build

- name: Publish to pkg.pr.new
run: pnpm pkg-pr-new publish
63 changes: 27 additions & 36 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "create-solana-dapp",
"version": "4.8.2",
"version": "4.6.0",
"description": "The fastest way to create Solana apps",
"repository": {
"name": "solana-foundation/create-solana-dapp",
Expand Down Expand Up @@ -39,52 +39,43 @@
"dev": "vitest dev",
"docker:build": "docker build -t create-solana-dapp:latest .",
"docker:run": "docker run --rm --name create-solana-dapp -v \"${PWD}/dist:/workspace/dist\" -it create-solana-dapp:latest",
"lint": "eslint .",
"lint:fix": "automd && eslint . --fix",
"lint": "eslint . && prettier -c .",
"lint:fix": "automd && eslint . --fix && prettier -w .",
"prepublishOnly": "pnpm pkg delete devDependencies",
"publish-impl": "npm view $npm_package_name@$npm_package_version > /dev/null 2>&1 || pnpm publish --tag ${PUBLISH_TAG:-latest} --access public --no-git-checks",
"publish-impl": "npm view $npm_package_name@$npm_package_version > /dev/null 2>&1 || pnpm publish --tag ${PUBLISH_TAG:-canary} --access public --no-git-checks",
"publish-packages": "pnpm prepublishOnly && pnpm publish-impl",
"test": "pnpm lint && pnpm test:types && vitest run --coverage",
"test:types": "tsc --noEmit --skipLibCheck"
},
"devDependencies": {
"@changesets/changelog-github": "^0.5.1",
"@changesets/cli": "^2.29.7",
"@changesets/changelog-github": "^0.5.0",
"@changesets/cli": "^2.27.10",
"@types/mock-fs": "^4.13.4",
"@types/node": "^24.3.1",
"@types/semver": "^7.7.1",
"@types/node": "^22.13.1",
"@types/semver": "^7.5.8",
"@types/update-notifier": "^6.0.8",
"@vitest/coverage-v8": "^3.2.4",
"automd": "^0.4.0",
"eslint": "^9.35.0",
"eslint-config-prettier": "^10.1.8",
"eslint-config-unjs": "^0.5.0",
"eslint-plugin-prettier": "^5.5.4",
"eslint-plugin-sort": "^4.0.0",
"lefthook": "^1.12.4",
"memfs": "^4.39.0",
"@vitest/coverage-v8": "^3.0.5",
"automd": "^0.3.12",
"eslint": "^9.20.0",
"eslint-config-unjs": "^0.4.2",
"memfs": "^4.17.2",
"mock-fs": "^5.5.0",
"pkg-pr-new": "^0.0.59",
"prettier": "^3.6.2",
"typescript": "^5.9.2",
"unbuild": "^3.6.1",
"vitest": "^3.2.4"
},
"packageManager": "pnpm@10.15.1",
"pnpm": {
"onlyBuiltDependencies": [
"lefthook"
]
"prettier": "^3.4.2",
"typescript": "^5.6.0",
"unbuild": "^3.3.1",
"vitest": "^3.0.5"
},
"packageManager": "pnpm@10.5.2",
"dependencies": {
"@clack/prompts": "0.7.0",
"commander": "14.0.0",
"giget": "2.0.0",
"is-in-ci": "2.0.0",
"picocolors": "1.1.1",
"semver": "7.7.2",
"update-notifier": "7.3.1",
"zod": "4.1.5"
"@beeman/repokit": "0.0.0-canary-20250801172233",
"@clack/prompts": "^0.11.0",
"commander": "^13.1.0",
"giget": "^1.2.4",
"is-in-ci": "^1.0.0",
"picocolors": "^1.1.1",
"semver": "^7.7.1",
"update-notifier": "^7.3.1",
"zod": "^3.24.1"
},
"contributors": [
{
Expand Down
171 changes: 153 additions & 18 deletions src/utils/create-app-task-run-init-script.ts
Original file line number Diff line number Diff line change
@@ -1,41 +1,176 @@
import { log } from '@clack/prompts'
import { join } from 'node:path'
import { bold, yellow } from 'picocolors'
import { ensureTargetPath } from './ensure-target-path'
import { GetArgsResult } from './get-args-result'
import { getPackageJson } from './get-package-json'
import { initScriptDelete } from './init-script-delete'
import { initScriptInstructions } from './init-script-instructions'
import { initScriptRename } from './init-script-rename'
import { initScriptKey } from './init-script-schema'
import { initScriptVersion } from './init-script-version'
import { deleteInitScript, getInitScript, InitScript } from './get-init-script'
import { searchAndReplace } from './search-and-replace'
import { validateAnchorVersion, validateSolanaVersion } from './validate-version'
import { Task, taskFail } from './vendor/clack-tasks'
import { namesValues } from './vendor/names'

export function createAppTaskRunInitScript(args: GetArgsResult): Task {
return {
enabled: !args.skipInit,
title: 'Running init script',
task: async (result) => {
try {
const { contents } = getPackageJson(args.targetDirectory)
const init = contents[initScriptKey]
const init = getInitScript(args.targetDirectory)
if (!init) {
return result({ message: 'Init script not found' })
return result({ message: 'Repository does not have an init script' })
}
if (args.verbose) {
log.warn(`Init script started`)
log.warn(`Running init script`)
}

await initScriptVersion(init.versions, args.verbose)

await initScriptRename(args, init.rename, args.verbose)
await initCheckVersion(init)
if (args.verbose) {
log.warn(`initCheckVersion done`)
}
await initRename(args, init, args.verbose)
if (args.verbose) {
log.warn(`initRename done`)
}

const instructions: string[] = initScriptInstructions(init.instructions, args.verbose)
const instructions: string[] = (initInstructions(init) ?? [])
?.filter(Boolean)
.map((msg) => msg.replace('{pm}', args.packageManager))

initScriptDelete(args)
return result({ instructions, message: 'Init script done' })
if (args.verbose) {
log.warn(`initInstructions done`)
}
deleteInitScript(args.targetDirectory)
if (args.verbose) {
log.warn(`deleteInitScript done`)
}
return result({ message: 'Executed init script', instructions })
} catch (error) {
taskFail(`Error running init script: ${error}`)
taskFail(`init: Error running init script: ${error}`)
}
},
title: 'Running init script',
}
}

async function initRename(args: GetArgsResult, init: InitScript, verbose: boolean) {
const projectContainsTemplateName = args.name.includes(args.template.name)
// Rename template to project name throughout the whole project
await searchAndReplace(
args.targetDirectory,
projectContainsTemplateName ? [] : [`template-${args.template.name}`, args.template.name],
projectContainsTemplateName ? [] : [args.name, args.name],
false,
verbose,
)

// Return early if there are no renames defined in the init script
if (!init?.rename) {
return
}
if (args.verbose) {
log.warn(`initRename: Found renames in init script`)
console.log(init.rename)
}
let renameCount = 0

// Loop through each word in the rename object
for (const from of Object.keys(init.rename)) {
renameCount += 1
if (args.verbose) {
log.warn(`initRename: [${renameCount}] Processing ${from}`)
}
// Get the 'to' property from the rename object
const to = init.rename[from].to.replace('{{name}}', args.name.replace(/-/g, ''))
if (args.verbose) {
log.warn(`initRename: [${renameCount}] from ${from} to ${to}`)
}

// Get the name matrix for the 'from' and the 'to' value
const fromNames = namesValues(from)
const toNames = namesValues(to)

if (args.verbose) {
log.warn(`initRename: [${renameCount}] fromNames: ${fromNames.join(', ')}`)
log.warn(`initRename: [${renameCount}] ..toNames: ${toNames.join(', ')}`)
}

for (const path of init.rename[from].paths) {
if (args.verbose) {
log.warn(`initRename: [${renameCount}] => Processing path ${path}`)
}
const targetPath = join(args.targetDirectory, path)
if (!(await ensureTargetPath(targetPath))) {
console.error(`init-script.rename: target does not exist ${targetPath}`)
continue
}
if (args.verbose) {
log.warn(`initRename: [${renameCount}] => Searching and replacing ${fromNames.join(', ')} in ${targetPath}`)
}
await searchAndReplace(join(args.targetDirectory, path), fromNames, toNames, args.dryRun, args.verbose)
if (args.verbose) {
log.warn(`initRename: [${renameCount}] => Done`)
}
}
if (args.verbose) {
log.warn(`initRename: [${renameCount}] Done`)
}
}
}

async function initCheckVersion(init: InitScript) {
if (init?.versions?.anchor) {
await initCheckVersionAnchor(init.versions.anchor)
}
if (init?.versions?.solana) {
await initCheckVersionSolana(init.versions.solana)
}
}

async function initCheckVersionAnchor(requiredVersion: string) {
try {
const { required, valid, version } = validateAnchorVersion(requiredVersion)
if (!version) {
log.warn(
[
bold(yellow(`Could not find Anchor version. Please install Anchor.`)),
'https://www.anchor-lang.com/docs/installation',
].join(' '),
)
} else if (!valid) {
log.warn(
[
yellow(`Found Anchor version ${version}. Expected Anchor version ${required}.`),
'https://www.anchor-lang.com/release-notes/0.30.1',
].join(' '),
)
}
} catch (error_) {
log.warn(`Error ${error_}`)
}
}

async function initCheckVersionSolana(requiredVersion: string) {
try {
const { required, valid, version } = validateSolanaVersion(requiredVersion)
if (!version) {
log.warn(
[
bold(yellow(`Could not find Solana version. Please install Solana.`)),
'https://docs.solana.com/cli/install-solana-cli-tools',
].join(' '),
)
} else if (!valid) {
log.warn(
[
yellow(`Found Solana version ${version}. Expected Solana version ${required}.`),
'https://docs.solana.com/cli/install-solana-cli-tools',
].join(' '),
)
}
} catch (error_) {
log.warn(`Error ${error_}`)
}
}

function initInstructions(init: InitScript) {
return init?.instructions?.length === 0 ? [] : init?.instructions
}
Loading