Skip to content
Merged
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
76 changes: 76 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
name: release

on:
push:
tags:
- "v*"

permissions:
contents: write

jobs:
build:
name: Build ${{ matrix.goos }}-${{ matrix.goarch }}
runs-on: ubuntu-latest
strategy:
matrix:
include:
- goos: darwin
goarch: amd64
asset: taco-darwin-amd64
- goos: darwin
goarch: arm64
asset: taco-darwin-arm64
- goos: linux
goarch: amd64
asset: taco-linux-amd64
- goos: linux
goarch: arm64
asset: taco-linux-arm64
- goos: windows
goarch: amd64
asset: taco-windows-amd64.exe

steps:
- uses: actions/checkout@v4

- uses: actions/setup-go@v5
with:
go-version: "1.25"

- name: Build binary
env:
GOOS: ${{ matrix.goos }}
GOARCH: ${{ matrix.goarch }}
CGO_ENABLED: "0"
run: go build -ldflags="-s -w" -o ${{ matrix.asset }} ./cmd/taco

- name: Upload artifact
uses: actions/upload-artifact@v4
with:
name: ${{ matrix.asset }}
path: ${{ matrix.asset }}

release:
name: Create Release
needs: build
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

- name: Download all artifacts
uses: actions/download-artifact@v4
with:
path: dist/
merge-multiple: true

- name: Generate checksums
run: cd dist && sha256sum * > checksums.txt

- name: Create GitHub Release
uses: softprops/action-gh-release@v2
with:
files: dist/*
generate_release_notes: true
draft: false
prerelease: ${{ contains(github.ref_name, '-') }}
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -34,3 +34,7 @@ Thumbs.db
.env.development
.env.production
.env.test

# Downloaded binaries in create-taco-app
packages/create-taco-app/taco
packages/create-taco-app/taco.exe
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ lint-fix:
@hack/lint-fix.sh

build-all:
go build -o npm/bin/taco-windows-amd64.exe ./cmd/taco
GOOS=windows GOARCH=amd64 go build -o npm/bin/taco-windows-amd64.exe ./cmd/taco
GOOS=darwin GOARCH=amd64 go build -o npm/bin/taco-darwin-amd64 ./cmd/taco
GOOS=darwin GOARCH=arm64 go build -o npm/bin/taco-darwin-arm64 ./cmd/taco
GOOS=linux GOARCH=amd64 go build -o npm/bin/taco-linux-amd64 ./cmd/taco
Expand Down
17 changes: 17 additions & 0 deletions packages/create-taco-app/create-taco-app.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
#!/usr/bin/env node
"use strict";

const path = require("path");
const { execFileSync } = require("child_process");
const os = require("os");

const ext = os.platform() === "win32" ? ".exe" : "";
const binaryPath = path.join(__dirname, "taco" + ext);

const userArgs = process.argv.slice(2);

try {
execFileSync(binaryPath, ["init", ...userArgs], { stdio: "inherit" });
} catch (err) {
process.exit(err.status || 1);
}
30 changes: 30 additions & 0 deletions packages/create-taco-app/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
{
"name": "create-taco-app",
"version": "0.1.0",
"description": "Scaffold a full-stack project with Taco CLI",
"bin": {
"create-taco-app": "create-taco-app.js"
},
"scripts": {
"postinstall": "node postinstall.js"
},
"files": [
"create-taco-app.js",
"postinstall.js"
],
"license": "MIT",
"repository": {
"type": "git",
"url": "https://github.com/b-jonathan/taco"
},
"keywords": [
"scaffold",
"fullstack",
"cli",
"create",
"taco"
],
"engines": {
"node": ">=16.0.0"
}
}
147 changes: 147 additions & 0 deletions packages/create-taco-app/postinstall.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
#!/usr/bin/env node
"use strict";

const os = require("os");
const fs = require("fs");
const path = require("path");
const crypto = require("crypto");
const https = require("https");
const http = require("http");

const REPO = "b-jonathan/taco";
const VERSION = require("./package.json").version;
const MAX_REDIRECTS = 5;

const PLATFORM_MAP = {
darwin: "darwin",
linux: "linux",
win32: "windows",
};

const ARCH_MAP = {
x64: "amd64",
arm64: "arm64",
};

const SUPPORTED = [
"darwin-amd64",
"darwin-arm64",
"linux-amd64",
"linux-arm64",
"windows-amd64",
];

function getBinaryName(platform, arch) {
const goOS = PLATFORM_MAP[platform];
const goArch = ARCH_MAP[arch];

if (!goOS || !goArch) return null;

const key = `${goOS}-${goArch}`;
if (!SUPPORTED.includes(key)) return null;

const ext = goOS === "windows" ? ".exe" : "";
return `taco-${key}${ext}`;
}

function downloadFile(url, redirectCount) {
if (redirectCount === undefined) redirectCount = 0;

return new Promise((resolve, reject) => {
if (redirectCount > MAX_REDIRECTS) {
return reject(new Error("Too many redirects"));
}

const client = url.startsWith("https") ? https : http;

client
.get(url, (res) => {
if (
res.statusCode >= 300 &&
res.statusCode < 400 &&
res.headers.location
) {
return downloadFile(res.headers.location, redirectCount + 1).then(
resolve,
reject
);
}

if (res.statusCode !== 200) {
return reject(
new Error(`Download failed: HTTP ${res.statusCode} from ${url}`)
);
}

const chunks = [];
res.on("data", (chunk) => chunks.push(chunk));
res.on("end", () => resolve(Buffer.concat(chunks)));
res.on("error", reject);
})
.on("error", reject);
});
}

async function main() {
const platform = os.platform();
const arch = os.arch();
const binaryName = getBinaryName(platform, arch);

if (!binaryName) {
console.error(
`[create-taco-app] Unsupported platform: ${platform}-${arch}\n` +
`Supported: darwin-x64, darwin-arm64, linux-x64, linux-arm64, win32-x64`
);
process.exit(1);
}

const url = `https://github.com/${REPO}/releases/download/v${VERSION}/${binaryName}`;
const ext = platform === "win32" ? ".exe" : "";
const dest = path.join(__dirname, "taco" + ext);

console.log(
`[create-taco-app] Downloading taco v${VERSION} for ${platform}-${arch}...`
);

try {
const checksumsUrl = `https://github.com/${REPO}/releases/download/v${VERSION}/checksums.txt`;
const [data, checksumsRaw] = await Promise.all([
downloadFile(url),
downloadFile(checksumsUrl),
]);

const actualHash = crypto.createHash("sha256").update(data).digest("hex");
const checksums = checksumsRaw.toString();
const expectedLine = checksums
.split("\n")
.find((line) => line.includes(binaryName));

if (!expectedLine) {
throw new Error(`No checksum found for ${binaryName} in checksums.txt`);
}

const expectedHash = expectedLine.split(/\s+/)[0];
if (actualHash !== expectedHash) {
throw new Error(
`Checksum mismatch for ${binaryName}\n` +
` expected: ${expectedHash}\n` +
` got: ${actualHash}`
);
}

fs.writeFileSync(dest, data);
fs.chmodSync(dest, 0o755);
console.log(`[create-taco-app] Binary installed and verified successfully`);
} catch (err) {
console.error(
`[create-taco-app] Failed to download binary: ${err.message}`
);
console.error(
`[create-taco-app] Ensure that release v${VERSION} exists at:\n` +
` https://github.com/${REPO}/releases/tag/v${VERSION}`
);
process.exit(1);
}
}

main();
Loading