1.1.2Updated a month ago
import { existsSync } from "jsr:@std/fs/exists";
import { Command } from "jsr:@cliffy/command@1.0.0-rc.7";

import { HOST_URL, TOKEN } from "../config.ts";
import { join } from "jsr:@std/path@1.0.8/join";
import { ScanPublishableFiles } from "../../utils/scan_files.ts";
import { FileSize } from "../../utils/file_size.ts";
import { Zip } from "../../modules/zip.ts";

interface DenoMeta {
  name?: string
  version?: string
  tasks?: { 'viapak:build': string | undefined }
  tags?: string[]
}

export default new Command()
  .name('publish')
  .alias('push')
  .description('Publishes the current code to Viapak under a new version')
  .option('--force', 'If the current version already exists, overwrite it.')
  .action(async (options) => {
    try {
      const __dirname = Deno.cwd();
      const deno_json_path = join(__dirname, 'deno.json');

      if(!existsSync(deno_json_path, { isFile: true })) throw new Error('deno.json not found. Are you running this in a project root directory?');

      let { name, version, tasks, tags } = JSON.parse(Deno.readTextFileSync(join(__dirname, 'deno.json')) ?? "{}") as DenoMeta;
      tags ||= [];

      if(!name) throw new Error('Please add a package name to your deno.json');
      if(!version) throw new Error('Please add a package version to your deno.json');

      console.log(`Publishing %c${name}@${version}%c...`, "color: #ffaa00", "color: inherit");
      if(tags.length > 0) console.log(`  '- tags: %c${tags.map(t => `#${t}`).join(' ')}`, "color: #00AAFF");

      if(tasks?.["viapak:build"]) {
        console.log(`  '- Found a viapak build step. Executing...`)
        const run_viapak_build = new Deno.Command('deno', {
          args: ['task', 'viapak:build']
        });

        const { stdout, stderr } = await run_viapak_build.output();
        if(stderr.length) {
          console.error(`    '-`, new TextDecoder().decode(stderr));
        } else {
          console.log(`    '-`, new TextDecoder().decode(stdout));
        }
      }

      console.log(`  '- Compressing package...`);

      const files = ScanPublishableFiles(__dirname);

      const temp_publish_zip_path = join(__dirname, '_publish.zip');
      if(existsSync(temp_publish_zip_path)) Deno.removeSync(temp_publish_zip_path);

      await Zip.Process(files, { destination_file_path: temp_publish_zip_path }).then(async zip => {
        console.log(`  '- Uploading package... (${FileSize(zip.length)})`);

        const headers = new Headers({
          'Content-Type': 'application/zip',
          'Content-Length': zip.length.toString(),
          'Authorization': `Bearer ${TOKEN}`,
          'X-Tags': JSON.stringify(tags)
        })

        const FORCE = options.force;

        if(FORCE) {
          console.log("  X  You have set the %c--force%c flag to overwrite ${name}@${version} if it exists. Are you sure? This can't be undone!", "color: red", "color: inherit")
          const confirm_force = confirm("Force?");
          if(!confirm_force) {
            console.log();
            Deno.exit(0);
          }

          headers.append('X-Force', 'TRUE');
        }

        const req = new Request(new URL(`publish/${name}@${version}`, HOST_URL), {
          method: 'PUT',
          headers,
          body: zip.stream,
        });

        const response = await fetch(req);

        if(!response.ok) {
          throw new Error(await response.text());
        }

        console.log(`  '- ${name}@${version} ${FORCE ? 'overwritten' : 'published'}!`);

        Deno.exit(0);
      });
      
    } catch(e: any) {
      console.error(`  '- Could not publish!`);
      console.error(`     ${e.message}`);
      Deno.exit(0);
    }

    console.log("");
  });