Skip to content
Open
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
4 changes: 4 additions & 0 deletions .github/actions/setup-ci/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@ runs:
node-version-file: './.nvmrc'
registry-url: 'https://registry.npmjs.org'
cache: 'pnpm'
- uses: actions/setup-go@v6
with:
go-version: '1.26.x'
cache: false

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we are going to add Go as a runtime dependency for our CI we should update our dev env setup instructions to ensure the correct Go version is added as well. https://github.com/NVIDIA/elements#setup

Comment thread
coderabbitai[bot] marked this conversation as resolved.
- name: Install dependencies
shell: bash
run: pnpm install --frozen-lockfile
Expand Down
3 changes: 2 additions & 1 deletion .prettierignore
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ projects/starters/bundles/src/index.html
projects/starters/eleventy/src/_layouts/index.11ty.js
projects/starters/eleventy/src/index.11ty.js
projects/starters/go/src/index.html
projects/starters/go-htmx/src/index.html
projects/starters/hugo/**/*
projects/starters/importmaps/src/index.html
projects/starters/mpa/src/**/*.html
Expand All @@ -39,4 +40,4 @@ projects/starters/solidjs/src/App.tsx
projects/starters/typescript/src/index.html
projects/starters/vue/src/**/*
projects/starters/nuxt/.nuxt/**/*
projects/starters/nuxt/app/**/*
projects/starters/nuxt/app/**/*
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,11 +33,14 @@ Examples of projects include:

To set up repository dependencies and run the full build, run the following commands at the **root** of the repository:

The CI pipeline also builds Go starters. Install [Go 1.26.x](https://go.dev/doc/install) before running the full local CI pipeline.

```shell
# install required dependencies
brew install git-lfs
git lfs install
git lfs pull
go version
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.1/install.sh | bash
. ~/.nvm/nvm.sh
nvm install
Expand Down
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,8 @@
"./projects/starters/bundles:ci",
"./projects/starters/eleventy:ci",
"./projects/starters/eleventy-ssr:ci",
"./projects/starters/go:ci",
"./projects/starters/go-htmx:ci",
"./projects/starters/hugo:ci",
"./projects/starters/importmaps:ci",
"./projects/starters/lit-library:ci",
Expand Down
2 changes: 2 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions pnpm-workspace.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ packages:
- projects/starters/eleventy
- projects/starters/eleventy-ssr
- projects/starters/go
- projects/starters/go-htmx
- projects/starters/hugo
- projects/starters/importmaps
- projects/starters/lit-library
Expand Down
23 changes: 21 additions & 2 deletions projects/internals/tools/src/project/service.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@ vi.mock('./setup-agent.js', () => ({
vi.mock('./starters.js', () => ({
startersData: {
typescript: { cli: true, zip: 'typescript.zip' },
react: { cli: true, zip: 'react.zip' },
importmaps: { cli: false, zip: 'importmaps.zip' }
go: { cli: true, zip: 'go.zip', setupElementsDependencies: false },
lit: { cli: false, zip: null }
},
createStarter: vi.fn(),
startStarter: vi.fn()
Expand Down Expand Up @@ -60,6 +60,25 @@ describe('ProjectService', () => {
expect(updateProject).toHaveBeenCalled();
});

it('should skip dependency setup for starters that opt out of project setup', async () => {
const { createStarter } = await import('./starters.js');
const { setupAgent } = await import('./setup-agent.js');
const { setupProject } = await import('./setup.js');
const { updateProject } = await import('./update.js');
vi.mocked(createStarter).mockResolvedValue({ create: { message: 'created', status: 'success' } });
vi.mocked(setupAgent).mockResolvedValue({ agent: { message: 'configured', status: 'success' } });

const { ProjectService } = await import('./service.js');
const result = await ProjectService.create({ type: 'go', cwd: '/test', start: false });

expect(result).toHaveProperty('create');
expect(result).toHaveProperty('agent');
expect(createStarter).toHaveBeenCalledWith('go', '/test');
expect(setupAgent).toHaveBeenCalled();
expect(setupProject).not.toHaveBeenCalled();
expect(updateProject).not.toHaveBeenCalled();
});

it('should return failed report when a step fails', async () => {
const { createStarter } = await import('./starters.js');
const { setupAgent } = await import('./setup-agent.js');
Expand Down
21 changes: 12 additions & 9 deletions projects/internals/tools/src/project/service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,11 @@ const starters = Object.keys(startersData).filter(
starter => startersData[starter as keyof typeof startersData]?.cli
) as Starter[];

function starterShouldSetupElementsDependencies(type: Starter): boolean {
const starterData = startersData[type];
return !('setupElementsDependencies' in starterData) || starterData.setupElementsDependencies;
}

@service()
export class ProjectService {
@tool({
Expand Down Expand Up @@ -56,9 +61,12 @@ export class ProjectService {

const createReport = await createStarter(type, dir);
const agentReport = await setupAgent(projectDir, 'all');
const setupProjectReport = await setupProject(projectDir);
const updateReport = await updateProject(projectDir);
const reports = [createReport, agentReport, setupProjectReport, updateReport];
const reports = [createReport, agentReport];
if (starterShouldSetupElementsDependencies(type)) {
const setupProjectReport = setupProject(projectDir);
const updateProjectReport = await updateProject(projectDir);
reports.push(setupProjectReport, updateProjectReport);
}
Comment thread
coderabbitai[bot] marked this conversation as resolved.

const failedReport = reports.find(report => Object.values(report).some(value => value.status === 'danger'));
if (failedReport) {
Expand All @@ -69,12 +77,7 @@ export class ProjectService {
await startStarter(projectDir);
}

return {
...createReport,
...agentReport,
...setupProjectReport,
...updateReport
};
return Object.assign({}, ...reports);
}

@tool({
Expand Down
94 changes: 94 additions & 0 deletions projects/internals/tools/src/project/starters.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,13 @@ import type * as childProcess from 'node:child_process';
import { beforeEach, describe, expect, it, vi } from 'vitest';
import {
startersData,
createStarterCDNUrl,
createGitInitProcess,
createStarterPaths,
execPackageManager,
getDependencyInstallFailureMessage,
getRequiredNPMClient,
stampStarterCDNVersions,
removeWireitScripts,
startStarter
} from './starters.js';
Expand Down Expand Up @@ -48,6 +50,7 @@ describe('startersData', () => {
expect(startersData.nextjs.cli).toBe(true);
expect(startersData.solidjs.cli).toBe(true);
expect(startersData.go.cli).toBe(true);
expect(startersData['go-htmx'].cli).toBe(true);
expect(startersData.hugo.cli).toBe(true);
expect(startersData.eleventy.cli).toBe(true);
expect(startersData.bundles.cli).toBe(true);
Expand All @@ -66,6 +69,7 @@ describe('startersData', () => {
expect(startersData.nextjs.zip).toContain('nextjs.zip');
expect(startersData.solidjs.zip).toContain('solidjs.zip');
expect(startersData.go.zip).toContain('go.zip');
expect(startersData['go-htmx'].zip).toContain('go-htmx.zip');
expect(startersData.eleventy.zip).toContain('eleventy.zip');
expect(startersData.importmaps.zip).toContain('importmaps.zip');
expect(startersData.bundles.zip).toContain('bundles.zip');
Expand Down Expand Up @@ -198,6 +202,96 @@ describe('getDependencyInstallFailureMessage', () => {
});
});

describe('starter CDN URLs', () => {
type StarterCDNPackageName = Parameters<typeof createStarterCDNUrl>[0];
type StarterCDNAsset = { packageName: StarterCDNPackageName; filePath: string };

const versions: Record<StarterCDNPackageName, string> = {
'@nvidia-elements/core': '1.2.3',
'@nvidia-elements/styles': '4.5.6',
'@nvidia-elements/themes': '7.8.9'
};

const coreAsset: StarterCDNAsset = { packageName: '@nvidia-elements/core', filePath: 'dist/bundles/index.min.js' };
const stylesAsset: StarterCDNAsset = { packageName: '@nvidia-elements/styles', filePath: 'dist/bundles/index.css' };
const themesAsset: StarterCDNAsset = { packageName: '@nvidia-elements/themes', filePath: 'dist/bundles/index.css' };
const themeFontsAsset: StarterCDNAsset = { packageName: '@nvidia-elements/themes', filePath: 'dist/fonts/inter.css' };
const starterCDNAssets = [stylesAsset, themesAsset, themeFontsAsset, coreAsset];

function createVersionedStarterCDNUrl(asset: StarterCDNAsset, version = versions[asset.packageName]) {
return createStarterCDNUrl(asset.packageName, version, asset.filePath);
}

function createUnversionedStarterCDNUrl(asset: StarterCDNAsset) {
return createVersionedStarterCDNUrl(asset).replace(
`${asset.packageName}@${versions[asset.packageName]}`,
asset.packageName
);
}

it('should create versioned CDN URLs', () => {
const url = createVersionedStarterCDNUrl(coreAsset);

expect(new URL(url).protocol).toBe('https:');
expect(url).toContain(`${coreAsset.packageName}@${versions[coreAsset.packageName]}/${coreAsset.filePath}`);
});

it('should stamp unversioned Elements CDN URLs with package versions', () => {
const content = `
<link rel="stylesheet" href="${createUnversionedStarterCDNUrl(stylesAsset)}" />
<link rel="stylesheet" href="${createUnversionedStarterCDNUrl(themesAsset)}" />
<link rel="stylesheet" href="${createUnversionedStarterCDNUrl(themeFontsAsset)}" />
<script type="module">
import '${createUnversionedStarterCDNUrl(coreAsset)}';
</script>
`;

const result = stampStarterCDNVersions(content, versions);

for (const asset of starterCDNAssets) {
expect(result).toContain(createVersionedStarterCDNUrl(asset));
}
});

it('should replace existing Elements CDN versions', () => {
const content = `
<link rel="stylesheet" href="${createVersionedStarterCDNUrl(stylesAsset, '0.0.1')}" />
<link rel="stylesheet" href="${createVersionedStarterCDNUrl(themesAsset, '0.0.1')}" />
<link rel="stylesheet" href="${createVersionedStarterCDNUrl(themeFontsAsset, '0.0.1')}" />
<script type="module">
import '${createVersionedStarterCDNUrl(coreAsset, '0.0.1')}';
</script>
`;

const result = stampStarterCDNVersions(content, versions);

for (const asset of starterCDNAssets) {
expect(result).toContain(createVersionedStarterCDNUrl(asset));
}
expect(result).not.toContain('@0.0.1/');
});

it('should leave unrelated CDN URLs unchanged', () => {
const unrelatedElementsPackageUrl = createVersionedStarterCDNUrl(coreAsset).replace(
`${coreAsset.packageName}@${versions[coreAsset.packageName]}/${coreAsset.filePath}`,
'@nvidia-elements/monaco/dist/bundles/index.css'
);
const htmxUrl = createVersionedStarterCDNUrl(coreAsset).replace(
`${coreAsset.packageName}@${versions[coreAsset.packageName]}/${coreAsset.filePath}`,
'htmx.org@2.0.10/dist/htmx.min.js'
);
const content = `
<link rel="stylesheet" href="${unrelatedElementsPackageUrl}" />
<script src="${htmxUrl}"></script>
`;

const result = stampStarterCDNVersions(content, versions);

expect(result).toContain(unrelatedElementsPackageUrl);
expect(result).toContain(htmxUrl);
});
});

describe('getNPMClient', () => {
it('should return the npm client', async () => {
expect(await getNPMClient()).toBe('pnpm');
Expand Down
Loading