Skip to content

makeConfig() fails to parse CLI arguments in GitHub Actions CI environments #14

@konard

Description

@konard

makeConfig() fails to parse CLI arguments in GitHub Actions CI environments

Summary

The makeConfig() function from lino-arguments fails to parse CLI arguments in GitHub Actions CI environments, returning empty default values instead of the actual arguments passed. This causes scripts to fail with "Missing required arguments" errors even when arguments are correctly provided.

Environment

  • Platform: GitHub Actions CI (Ubuntu runners)
  • Loading method: Dynamic loading via use-m from unpkg
  • Node.js version: v20.x (GitHub Actions default)

Reproducible Example

Minimal failing script

#!/usr/bin/env node

// Load use-m dynamically
const { use } = eval(
  await (await fetch('https://unpkg.com/use-m/use.js')).text()
);

const { makeConfig } = await use('lino-arguments');

// Configure CLI arguments using lino-arguments
const config = makeConfig({
  yargs: ({ yargs, getenv }) =>
    yargs
      .option('version', {
        type: 'string',
        description: 'Version to process',
        default: getenv('VERSION') || '',
      })
      .option('repository', {
        type: 'string',
        description: 'Repository name',
        default: getenv('REPOSITORY') || '',
      })
      .help()
      .strict(),
});

const version = config.version;
const repository = config.repository;

if (!version || !repository) {
  console.error('Error: Missing required arguments');
  process.exit(1);
}

console.log('✅ Arguments parsed successfully!');

How to run

# This works locally on most machines
node script.mjs --version "0.8.36" --repository "link-foundation/test-anywhere"

# This fails in GitHub Actions CI with exit code 1
# Even though the command is identical and arguments are passed correctly

Expected Behavior

When run with CLI arguments:

node script.mjs --version "0.8.36" --repository "link-foundation/test-anywhere"

The script should:

  1. Parse --version as "0.8.36"
  2. Parse --repository as "link-foundation/test-anywhere"
  3. Print "✅ Arguments parsed successfully!"
  4. Exit with code 0

Actual Behavior in GitHub Actions CI

When run with the same command in GitHub Actions:

  1. makeConfig() returns empty strings (the getenv() defaults)
  2. Arguments are NOT parsed from CLI
  3. Script exits with code 1 due to missing required arguments
  4. No stdout produced
  5. No clear error message about why parsing failed

Evidence from CI logs

From GitHub Actions run logs:

{
  "finalExitCode": 1,
  "stdoutLength": 0,
  "stderrLength": 4413,
  "stdoutPreview": ""
}

The script produces no output and exits early with code 1, indicating that makeConfig() silently failed to parse arguments.

Real-World Impact

This issue affected production releases in the test-anywhere repository:

  1. Initial occurrence: PR #115 introduced lino-arguments to release scripts
  2. First failure: Release v0.8.33 failed (Issue #116) - workflow was suspected but was actually correct
  3. Continued failures: Multiple releases (v0.8.34, v0.8.35, v0.8.36) had broken release notes
  4. Root cause discovered: Issue #122 identified that format-release-notes.mjs was failing due to lino-arguments

Affected scripts

  • scripts/format-release-notes.mjs (confirmed failing)
  • scripts/create-github-release.mjs (fixed in PR #119)
  • scripts/format-github-release.mjs (fixed in PR #119)
  • scripts/publish-to-npm.mjs (failed silently, optional args masked the issue)

Investigation Timeline

  1. v0.8.36 release (December 11, 2025): Release notes not formatted properly
  2. Issue #122 opened: Reported missing PR links and unformatted markdown in releases
  3. CI logs analysis: Downloaded logs from run 20126234140, found exit code 1 with no output
  4. Local testing: Script worked locally but examination of CI behavior showed parsing failure
  5. PR #119 precedent: Previous fix for same issue in other scripts (replaced lino-arguments with manual parsing)
  6. PR #123 implementation: Replaced lino-arguments in format-release-notes.mjs with manual parsing

Full case study: link-foundation/test-anywhere#123

Workaround

Replace lino-arguments with manual argument parsing:

// Manual argument parser - supports both --arg=value and --arg value formats
function parseArgs(argv) {
  const args = {};
  for (let i = 2; i < argv.length; i++) {
    const arg = argv[i];
    if (arg.startsWith('--')) {
      const key = arg.slice(2);
      if (key.includes('=')) {
        const [k, v] = key.split('=');
        args[k] = v;
      } else if (i + 1 < argv.length && !argv[i + 1].startsWith('--')) {
        args[key] = argv[i + 1];
        i++;
      } else {
        args[key] = true;
      }
    }
  }
  return args;
}

const args = parseArgs(process.argv);
const version = args.version || process.env.VERSION || '';
const repository = args.repository || process.env.REPOSITORY || '';

This workaround:

  • ✅ Works reliably in all environments (local, CI, containers)
  • ✅ Supports both --arg=value and --arg value formats
  • ✅ Falls back to environment variables
  • ✅ Uses only standard Node.js APIs (no external dependencies)
  • ✅ Easy to debug and maintain

Suggested Fix

Possible root causes to investigate:

  1. Shell interaction: The way yargs interacts with process.argv in GitHub Actions' shell environment
  2. Dynamic loading timing: Whether use-m loading affects argument parsing initialization
  3. Environment detection: Whether lino-arguments has environment detection that behaves differently in CI
  4. stdin/stdout/stderr: Whether CI's non-interactive terminal affects parsing
  5. yargs version/config: Whether the yargs configuration used by lino-arguments has CI-specific issues

Suggested investigation steps:

  1. Add debug logging to makeConfig() to show:
    • Raw process.argv at entry point
    • Arguments after yargs parsing
    • Any errors/warnings from yargs
  2. Test specifically in GitHub Actions environment with debug output
  3. Compare behavior between local and CI environments with identical Node.js versions
  4. Check if the issue is specific to use-m dynamic loading or affects npm-installed packages too

Related Issues

  • test-anywhere #116: First release failure attributed to workflow (actual root cause was lino-arguments)
  • test-anywhere #118: Release failure, led to PR #119 fixing some scripts
  • test-anywhere #122: Release notes formatting, led to PR #123 fixing remaining script

Additional Context

From PR #119 investigation:

The lino-arguments library's makeConfig function failed to parse CLI arguments in GitHub Actions environments, returning empty default values instead of the actual arguments. This caused release scripts to fail with "Missing required arguments" errors.

The issue appears to be systematic rather than a one-time occurrence, affecting multiple scripts across multiple releases.


References:

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions