-
Notifications
You must be signed in to change notification settings - Fork 108
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Restructure Cookiecutter into simpler per-"type" scripts? #75
Comments
I agree with most of your points😃 But let me try to explain some of the design decisions (that I may did not got enough time to materialize) Examples dir Lets imagine Ihv implemented an The flow here is quite different from generators like But now I clearly see the first issue... calling that dir "examples" is just plain wrong 😄 Its more of a "feature-recipe" dir (or "feature-catalog" or "feature-specs" dir, whatever feels more intuitive). Cookiecutter implementation The reason I'm currently at peace with this is that I know the "feature.yaml" is the real contract between us and the contributors. If today I have Which brings me to the second issue: currently users activate the generator themselve. Different generators for each type (pip/ npm/ apt-get) The motivation to couple those types together were features who needed multiple types together However this is an excellent Idea if I take it one step earlier and use these to generate the the yamls themselves So the chain would be This interactive user input script will make it easy for the user to generate the yaml without having to learn its structure, while still allowing complex manually crafted ones like the mkdocs feature So a crud "roadmap" would be:
Please allow me sometime to stabilize those before doing any generator changes - I really appreciate the effort you made so far, dont want you to waste time on stuff that might change in future |
Btw this is just for the npm/pip etc features . There are many features that I have manually wrote before the generator (haskell/pulumi/D/zig etc) which are not related. I have stopped adding these when I understood I cannot possible keep up with maintaining more of them... |
This is the discussion I want to see! 🥇
Right now there are sort of two copies of certain features in the repo. Take Jest for instance. There's the YAML config file that generates the actual You have a "generated build artifact" in the source control. Ideally, you want some GitHub Action to auto-generate it (like running So, yes, I agree with the summary that eventually the On another note, I think there might be an alternative. Going back to the This is what
Actual file contents
/* No content */
<p>my-component works!</p>
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { MyComponentComponent } from './my-component.component';
describe('MyComponentComponent', () => {
let component: MyComponentComponent;
let fixture: ComponentFixture<MyComponentComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [ MyComponentComponent ]
})
.compileComponents();
fixture = TestBed.createComponent(MyComponentComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});
import { Component } from '@angular/core';
@Component({
selector: 'app-my-component',
templateUrl: './my-component.component.html',
styleUrls: ['./my-component.component.css']
})
export class MyComponentComponent {
}
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import { MyComponentComponent } from './my-component/my-component.component';
@NgModule({
declarations: [
AppComponent,
MyComponentComponent
],
imports: [
BrowserModule
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { } For instance, take Bikeshed. You install it via pip, just like all the other Python dependencies, but it requires a special customization! You can run Anyways, that's one minor example. Over the N number of features, there are bound to be other custom things that need to be added. I think the best way to do it is to import common features (like I think that the end-goal looks more like this: $ scripts/generate-new-feature-npm.js
❓ NPM package name: jest
🟢 CREATE src/jest/devcontainer-feature.json
🟢 CREATE src/jest/install.sh
🟢 CREATE test/jest/test.sh
🔵 UPDATE feature-matrix.json # Or some other index file for the matrix in GitHub Actions Which creates files that look like this:
#!/usr/bin/env bash
set -Eeuo pipefail
# Generated from scripts/generate-new-feature-npm.js with npmpackagename=jest
source ../install-header-npm.sh
npm install -g jest Note how we delegate responsibility to another So, to summarize, I prefer the option of importing common functionality instead of creating a config manifest file. But really, both are better than what is there now (which is source & build artifacts in the same repo). 👍 Once again, thanks for articulating your process and explaining the why these things where done. Good points, and good discussion! Also check out #83 for more discussion on that install.sh header idea |
Here's some of my progress proof-of-concepting my own idea (yeah yeah I need to tidy the commits and stuff): https://github.com/jcbhmr/devcontainers-contrib-features More discussion in #83 |
🟥🟥🟥 More discussion in #83 🟥🟥🟥 I am closing this because it's more of a discussion, not really an issue to be tracked. Continue discussion in #83 and we can open a new issue if/when we get some concrete "what needs to be done?" tasks. |
My honest opinion on the whole Cookiecutter thing:
It's too complicated. There is too much logic concentrated in a template file that belongs in separate scripting files. Cookiecutter and Yeoman (and any project generator really) are great tools, but I don't think they fit the bill the best here.
They work but it's unwieldy to edit them. The files are too big for what they should be. There should be a separate
npm-devcontainer-feature.json
and one forpip-devcontainer-feature.json
if you keep Cookiecutter IMO. They also spread the logic too far apart. You need to reference variables that you declare in JSON and use in Jinja. You need to declare functions separately. You need dependency management. It's a mess.An alternative is to split each "type" (NPM, pip, apt) into its own Cookiecutter package, but I think a better option is to ditch Cookiecutter as too overkill for simple file generation.
Take Angular for instance. They use
ng generate <type>
as a way to create new components, interfaces, app shells, and more. I think this approach of script-based generation should be adopted going forward instead of more complex unweidly (and frankly very intimidating) Cookiecutter template logic. I mean have you seen thatdevcontainer-feature.json
file? It is write-once and never touch again code at its finest.Another argument is that we really need freaking examples of how to do this? Is it really that complicated to just fill out a form in your terminal basically?
Here's an example to really nail home what I am talking about. This is a complete Feature generator script that works! I just wrote it so it might not have proper error handling. It generates an NPM-based feature.
Try it out on Replit! It actually works! https://replit.com/@jcbhmr/SquigglyRepulsiveSolaris#index.js
Then the user experience is so much better! You just run the script and it does it for you. You can even "infer" things from the current Git repo like the remote origin URL for documentation URL generation! And it makes it easier to add new features without coupling them to other features (ie. not as many if-statements). I know you can probably do that in Cookiecutter too, but this is one file instead of like 5 files in 3 directories. It's easier to reason about, follow, and maintain. Especially when compared to that monster of an
install.sh
template.For instance, here are some generator script ideas:
scripts/generate-new-feature-pip.js
scripts/generate-new-feature-apt.py
scripts/generate-new-feature-deno.sh
scripts/generate-new-feature-brew.rb
scripts/generate-new-feature-${yourPackageManager}.${yourFavoriteScriptingLanguage}
Heck, you could even commit a C++ file that compiled and ran itself if you really wanted to!
TL;DR: I want a 👍✅ or a 👎⛔ before I invest more time. If I do all the work and the PR doesn't merge, that's not fun for me 😭.
PS: Yes, you can use Python if you're into Python over TypeScript/JavaScript. I personally like the ability of JavaScript + Deno to be self-contained in a single file even if it includes library stuff using HTTP import URLs.
Originally posted by @jcbhmr in #69 (comment)
The text was updated successfully, but these errors were encountered: