This commit is contained in:
Tingluo Huang
2023-09-18 01:13:38 +00:00
commit 7751908620
45 changed files with 3072 additions and 0 deletions
+183
View File
@@ -0,0 +1,183 @@
const assert = require('assert')
const exec = require('./exec')
const fs = require('fs')
const git = require('./git')
const path = require('path')
const paths = require('./paths')
const Patterns = require('./patterns').Patterns
const defaultPatterns = ['+^master$', '+^v[0-9]+(\\.[0-9]+){0,2}$']
exports.defaultPatterns = defaultPatterns
class ActionConfig {
/**
* Repository owner
*/
owner = ''
/**
* Repository name
*/
repo = ''
/**
* Ref include/exclude regexp patterns
* @type {string[]}
*/
patterns = []
/**
* Branch versions (ref to commit SHA)
* @type {{[ref: string]: string}}
*/
branches = {}
/**
* Default branch to checkout, defaults to master
* @type {string}
*/
defaultBranch = 'master'
/**
* Tag versions
* @type {{[ref: string]: TagVersion}}
*/
tags = {}
}
exports.ActionConfig = ActionConfig
class TagVersion {
/**
* Commit SHA
*/
commit = ''
/**
* SHA of the annotated tag, or undefined for a lightweight tag
* @type {string|undefined}
*/
tag = undefined
}
exports.TagVersion = TagVersion
/**
* Adds a new action config file
* @param {string} owner
* @param {string} repos
* @param {string[]} patternStrings
* @param {string} defaultBranch
* @returns {Promise}
*/
async function add(owner, repo, patternStrings, defaultBranch) {
assert.ok(owner, "Arg 'owner' must not be empty")
assert.ok(repo, "Arg 'repo' must not be empty")
assert.ok(patternStrings, "Arg 'patternStrings' must not be null")
assert.ok(defaultBranch, "Arg 'defaultBranch' must not be empty")
if (patternStrings.length === 0) {
patternStrings = defaultPatterns
}
const patterns = new Patterns(patternStrings)
const file = getFilePath(owner, repo)
const config = new ActionConfig()
config.owner = owner
config.repo = repo
config.patterns = patternStrings
config.defaultBranch = defaultBranch
const tempDir = path.join(paths.temp, `${owner}_${repo}`)
await exec.exec('rm', ['-rf', tempDir])
await exec.exec('mkdir', ['-p', tempDir])
const originalCwd = process.cwd()
try {
process.chdir(tempDir)
await exec.exec('pwd')
// Clone
await git.init()
await git.gcAutoDisable()
await git.remoteAdd(owner, repo)
await git.fetch()
// Snapshot branches
let branches = await git.branchList()
branches = branches.filter(x => patterns.test(x))
for (const branch of branches) {
config.branches[branch] = await git.logCommitSha(`refs/remotes/origin/${branch}`)
}
// Snapshot tags
let tags = await git.tagList()
tags = tags.filter(x => patterns.test(x))
for (const tag of tags) {
const tagVersion = new TagVersion()
tagVersion.commit = await git.logCommitSha(`refs/tags/${tag}`)
tagVersion.tag = await git.revParse(`refs/tags/${tag}`)
if (tagVersion.commit === tagVersion.tag) {
delete tagVersion.tag
}
config.tags[tag] = tagVersion
}
// Write config
await exec.exec('mkdir', ['-p', path.dirname(file)])
await fs.promises.writeFile(file, JSON.stringify(config, null, ' '))
console.log(`Added config file: ${file}`)
}
finally {
process.chdir(originalCwd)
}
}
exports.add = add
/**
* Returns the action config file path
* @param {string} owner
* @param {string} repo
* @returns {string}
*/
function getFilePath(owner, repo) {
assert.ok(owner, "Arg 'owner' must not be empty")
assert.ok(repo, "Arg 'repo' must not be empty")
return path.join(paths.actionsConfig, `${owner}_${repo}.json`)
}
exports.getFilePath = getFilePath
/**
* Returns the action config file paths
* @returns {Promise<string[]>}
*/
async function getFilePaths() {
const names = await fs.promises.readdir(paths.actionsConfig)
return names.filter(x => x.endsWith('.json')).map(x => path.join(paths.actionsConfig, x))
}
exports.getFilePaths = getFilePaths
/**
* Loads an action config file
* @param {string} owner
* @param {string} repo
* @returns {Promise<ActionConfig>}
*/
async function load(owner, repo) {
assert.ok(owner, "Arg 'owner' must not be empty")
assert.ok(repo, "Arg 'repo' must not be empty")
const file = getFilePath(owner, repo)
const buffer = await fs.promises.readFile(file)
return JSON.parse(buffer.toString())
}
exports.load = load
/**
* Loads an action config file from a specific path
* @param {string} file File path
* @returns {Promise<ActionConfig>}
*/
async function loadFromPath(file) {
assert.ok(file, "Arg 'file' must not be empty")
const buffer = await fs.promises.readFile(file)
return JSON.parse(buffer.toString())
}
exports.loadFromPath = loadFromPath
+99
View File
@@ -0,0 +1,99 @@
const actionConfig = require('./action-config')
const argHelper = require('./arg-helper')
const assert = require('assert')
const debugHelper = require('./debug-helper')
const exec = require('./exec')
const fsHelper = require('./fs-helper')
const Patterns = require('./patterns').Patterns
async function main() {
try {
// Command line args
const args = getArgs()
const owner = args.owner
const repo = args.repo
const patterns = args.patterns
const defaultBranch = args.defaultBranch || 'master'
// File exists?
const file = actionConfig.getFilePath(owner, repo)
assert.ok(!(await fsHelper.exists(file)), `File '${file}' already exists. Use 'update-action.sh' instead.`)
// Reinit _temp
await fsHelper.reinitTemp()
// Add the config
await actionConfig.add(owner, repo, patterns, defaultBranch)
}
catch (err) {
// Help
if (err.code === argHelper.helpCode) {
printUsage()
return
}
// Arg error?
if (err.code === argHelper.errorCode) {
printUsage()
console.error('')
}
// Print error
debugHelper.debug(err.stack)
console.error(`ERROR: ${err.message}`)
process.exitCode = 1
}
}
class Args {
owner = ''
repo = ''
patterns = []
defaultBranch = ''
}
/**
* Get the command line args
* @returns {Args}
*/
function getArgs() {
// Parse
const parsedArgs = argHelper.parse([], ['default-branch'])
if (parsedArgs.arguments.length < 1) {
argHelper.throwError('Expected at least one arg')
}
// Validate name with owner
const nwo = parsedArgs.arguments[0]
const splitNwo = nwo.split('/')
if (splitNwo.length !== 2 || !splitNwo[0] || !splitNwo[1]) {
argHelper.throwError(`Invalid nwo '${nwo}'`)
}
// Validate patterns
const patterns = parsedArgs.arguments.slice(1)
if (patterns.length) {
try {
new Patterns(patterns)
}
catch (err) {
argHelper.throwError(err.message)
}
}
return {
owner: splitNwo[0],
repo: splitNwo[1],
patterns: patterns,
defaultBranch: parsedArgs.options['default-branch']
}
}
function printUsage() {
console.error('USAGE: add-action.sh [--default-branch branch] nwo [(+|-)regexp [...]]')
console.error(` --default-branch Default branch name. For example: master`)
console.error(` nwo Name with owner. For example: actions/checkout`)
console.error(` regexp Refs to include or exclude. Default: ${actionConfig.defaultPatterns.join(' ')}`)
}
main()
+93
View File
@@ -0,0 +1,93 @@
const debugHelper = require('./debug-helper')
/**
* Parse command line arguments
*/
class Arguments {
flags = {}
options = {}
arguments = []
}
exports.Arguments = Arguments
const helpCode = 'ARGHELP'
exports.helpCode = helpCode
const errorCode = 'ARGV'
exports.errorCode = errorCode
/**
* Parses the command line arguments
* @param {string[]} flags Allowed flags
* @param {string[]} options Allowed options
* @param {boolean} allowArgs Whether to allow unnamed arguments
* @returns {Arguments}
*/
function parse(flags, options, allowArgs) {
flags = flags || []
options = options || []
allowArgs = typeof(allowArgs) === 'boolean' ? allowArgs : true
const result = new Arguments()
// Check for --help
const argv = process.argv.slice(2)
if (argv.some(x => x === '--help')) {
throwError('Help requested', helpCode)
}
// Parse
for (let i = 0; i < argv.length; i++) {
const arg = argv[i]
const nextArg = i + 1 < argv.length ? argv[i + 1] : null
// Starts with "--"
if (arg.startsWith('--')) {
const name = arg.substr(2)
// Legal flag
if (flags.some(x => x === name)) {
debugHelper.debug(`arg: ${arg} (flag)`)
result.flags[name] = true
continue
}
// Unknown option
if (!options.some(x => x === name)) {
throwError(`Unknown option '${name}'`)
}
// Missing value following option
if (nextArg === null || nextArg.startsWith('--')) {
throwError(`Option '${name}' must have a value`)
}
// Legal option
debugHelper.debug(`arg: ${arg} (option)`)
result.options[name] = nextArg
i++
continue
}
// Unexpected argument
if (!allowArgs) {
throwError(`Unexpected argument '${arg}'`)
}
// Legal argument
debugHelper.debug(`arg: ${arg}`)
result.arguments.push(arg)
}
return result
}
exports.parse = parse
function throwError(message, code) {
const err = new Error(message)
err.code = code || errorCode
throw err
}
exports.throwError = throwError
+40
View File
@@ -0,0 +1,40 @@
#!/bin/sh
# Lowest version tested against :)
expected_major=2
expected_minor=11
if [ -z "$(which git || exit 0)" ]; then
echo "Unable to find 'git' in the PATH"
exit 1
fi
# Get <major>.<minor>
# Note:
# - Use "-o" instead of "--only-matching" for compatibility
# - Use "-E" instead of "--extended-regexp" for compatibility
major_minor=$(git --version | grep -o -E '[0-9]+\.[0-9]+')
if [ -z "$major_minor" ]; then
echo "Unable to determine git version. Expected output of 'git --version' to contain a version, for example '2.1'"
exit 1
fi
major=$(echo "$major_minor" | grep -o -E '^[0-9]+')
minor=$(echo "$major_minor" | grep -o -E '[0-9]+$')
# Higher major version
if [ $major -gt $expected_major ]; then
exit 0
fi
# Lower major version
if [ $major -lt $expected_major ]; then
echo "Git $expected_major.$expected_minor or higher must be in the PATH"
exit 1
fi
# Lower minor version
if [ $minor -lt $expected_minor ]; then
echo "Git $expected_major.$expected_minor or higher must be in the PATH"
exit 1
fi
+17
View File
@@ -0,0 +1,17 @@
#!/bin/bash
if [ -z "$(which node || exit 0)" ]; then
echo "Unable to find 'node' in the PATH"
exit 1
fi
node_version=$(node --version | grep --only-matching --extended-regexp 'v[0-9]+' | tr -d 'v')
if [ -z "$node_version" ]; then
echo "Unable to determine node version. Expected output of 'node --version' to contain a version, for example 'v12.13.1'"
exit 1
fi
if [ $node_version -lt 12 ]; then
echo "Node 12 or higher must be in the PATH"
exit 1
fi
+12
View File
@@ -0,0 +1,12 @@
const isDebug = ['TRUE', '1'].some(x => x === (process.env['GITHUB_ACTIONS_DEBUG'] || '').toUpperCase())
/**
* Log the message if debug mode
* @param {string} message
*/
function debug(message) {
if (isDebug) {
console.log(message)
}
}
exports.debug = debug
+49
View File
@@ -0,0 +1,49 @@
const child_process = require('child_process')
class ExecResult {
stdout = ''
exitCode = 0
}
exports.ExecResult = ExecResult
/**
* Executes a process
* @param {string} command
* @param {string[]} args
* @param {boolea} allowAllExitCodes
* @returns {Promise<ExecResult>}
*/
function exec(
command = '',
args = [],
allowAllExitCodes = false
) {
process.stdout.write(`EXEC: ${command} ${args.join(' ')}\n`)
return new Promise((resolve, reject) =>
{
const execResult = new ExecResult()
const cp = child_process.spawn(command, args, {})
// STDOUT
cp.stdout.on('data', (data) => {
process.stdout.write(data)
execResult.stdout += data.toString()
})
// STDERR
cp.stderr.on('data', (data) => {
process.stderr.write(data)
})
// Close
cp.on('close', (code) => {
execResult.exitCode = code
if (code === 0 || allowAllExitCodes) {
resolve(execResult)
} else {
reject(new Error(`Command exited with code ${code}`))
}
})
})
}
exports.exec = exec
+37
View File
@@ -0,0 +1,37 @@
const assert = require('assert')
const exec = require('./exec')
const fs = require('fs')
const paths = require('./paths')
/**
* Checks whether a path exists
* @param {string} p File or directory path
* @returns {Promise<boolean>}
*/
async function exists(p) {
assert.ok(p, "Arg 'p' must not be empty")
try {
await fs.promises.stat(p)
return true
}
catch (err) {
if (err.code === 'ENOENT') {
return false
}
throw err
}
}
exports.exists = exists
/**
* Recreates the _temp directory
* @returns {Promise}
*/
async function reinitTemp() {
const temp = paths.temp
assert.ok(temp, 'Expected paths.temp to be defined')
await exec.exec('rm', ['-rf', temp])
await exec.exec('mkdir', ['-p', temp])
}
exports.reinitTemp = reinitTemp
+66
View File
@@ -0,0 +1,66 @@
#!/bin/bash
set -e
# Script dir
script_dir="$( cd "$(dirname "$0")" >/dev/null 2>&1 ; pwd -P )"
# Trace
. $script_dir/set-trace.sh
# Recreate script/generated/
target_dir="$script_dir/../generated"
rm -rf "$target_dir"
mkdir -p "$target_dir"
cd "$target_dir"
# Create each script
for json_file in $script_dir/../../config/actions/*.json; do
json="$(cat "$json_file")"
split=( $(echo "$json" | jq --raw-output '.owner + " " + .repo') )
owner="${split[0]}"
repo="${split[1]}"
script_file="${owner}_${repo}.sh"
echo "Generating $PWD/$script_file"
# Append curl download command
curl_download_commands=()
# Get an array of branch info. Each item contains "<branch> <sha>"
branch_info=()
IFS=$'\n' read -r -d '' -a branch_info < <( echo "$json" | jq --raw-output '.branches | to_entries | .[] | .key + " " + .value' && printf '\0' )
for item in "${branch_info[@]}"; do
split=( $(echo $item) )
branch="${split[0]}"
sha="${split[1]}"
# Append curl download command
curl_download_commands+=("curl -s -S -L -o '$sha.tar.gz' 'https://api.github.com/repos/$owner/$repo/tarball/$sha'")
curl_download_commands+=("curl -s -S -L -o '$sha.zip' 'https://api.github.com/repos/$owner/$repo/zipball/$sha'")
done
# Get an array of tag info. Each item contains "<tag> <tag_or_commit_sha> <commit_sha>"
tag_info=()
IFS=$'\n' read -r -d '' -a tag_info < <( echo "$json" | jq --raw-output '.tags | to_entries | .[] | .key + " " + if .value.tag? then .value.tag else .value.commit end + " " + .value.commit' && printf '\0' )
for item in "${tag_info[@]}"; do
split=( $(echo $item) )
tag="${split[0]}"
sha="${split[1]}"
commit="${split[2]}"
# Append curl download command
curl_download_commands+=("curl -s -S -L -o '$sha.tar.gz' 'https://api.github.com/repos/$owner/$repo/tarball/$sha'")
curl_download_commands+=("curl -s -S -L -o '$sha.zip' 'https://api.github.com/repos/$owner/$repo/zipball/$sha'")
done
# Append curl commands
echo "mkdir ${owner}_$repo" >> "$script_file"
echo "pushd ${owner}_$repo" >> "$script_file"
for curl_download_command in "${curl_download_commands[@]}"
do
echo "$curl_download_command" >> "$script_file"
done
echo "popd" >> "$script_file"
done
+116
View File
@@ -0,0 +1,116 @@
const assert = require('assert')
const exec = require('./exec')
/**
* Gets a list of branches from origin. For example: ["master"]
* @returns {Promise<string[]>}
*/
async function branchList() {
const result = []
// Note, this implementation uses "rev-parse --symbolic-full-name" because:
// - The output from "branch --list" is difficult when in a detached HEAD state.
// - There is a bug in Git 2.18 that causes "rev-parse --symbolic" to output symbolic full names.
const execResult = await exec.exec('git', ['rev-parse', '--symbolic-full-name', '--remotes=origin'])
for (let ref of execResult.stdout.trim().split('\n')) {
ref = ref.trim()
if (!ref) {
continue
}
const prefix = 'refs/remotes/origin/'
if (!ref.startsWith(prefix) || ref.length === prefix.length) {
throw new Error(`Unexpected branch format '${ref}'`)
}
ref = ref.substr(prefix.length)
result.push(ref)
}
return result
}
exports.branchList = branchList
/**
* Disable automatic garbage collection
* @returns {Promise}
*/
async function gcAutoDisable() {
await exec.exec('git', ['config', '--local', 'gc.auto', '0'])
}
exports.gcAutoDisable = gcAutoDisable
/**
* Fetches the repo
* @returns {Promise}
*/
async function fetch() {
const args = [
'-c',
'protocol.version=2',
'fetch',
'--tags',
'--no-recurse-submodules',
'origin'
]
await exec.exec('git', args)
}
exports.fetch = fetch
/**
* Initializes a repo
* @returns {Promise}
*/
async function init() {
await exec.exec('git', ['init'])
}
exports.init = init
/**
* Resolves a ref to a commit SHA
* @param {string} ref
* @returns {Promise<string>}
*/
async function logCommitSha(ref) {
assert.ok(ref, "Arg 'ref' must not be empty")
const execResult = await exec.exec('git', ['log', '-1', '--format=format:%H%n', ref])
return execResult.stdout.trim()
}
exports.logCommitSha = logCommitSha
/**
* Adds a remote
* @param {string} owner
* @param {string} repo
* @returns {Promise}
*/
async function remoteAdd(owner, repo) {
assert.ok(owner, "Arg 'owner' must not be empty")
assert.ok(repo, "Arg 'repo' must not be empty")
await exec.exec('git', ['remote', 'add', 'origin', `https://github.com/${owner}/${repo}.git`])
}
exports.remoteAdd = remoteAdd
/**
* Resolves a ref to a SHA. For a branch or lightweight tag, the commit SHA is returned.
* For an annotated tag, the tag SHA is returned.
* @param {string} ref For example: 'refs/heads/master' or '/refs/tags/v1'
* @returns {Promise<string>}
*/
async function revParse(ref) {
assert.ok(ref, "Arg 'ref' must not be empty")
const execResult = await exec.exec('git', ['rev-parse', ref])
return execResult.stdout.trim()
}
exports.revParse = revParse
/**
* Returns a list of tags. For example: ["v1", "v2"]
* @returns {Promise<string[]>}
*/
async function tagList() {
const execResult = await exec.exec('git', ['tag', '--list'])
return execResult.stdout.trim().split('\n').filter(str => str && str.length > 0)
}
exports.tagList = tagList
+39
View File
@@ -0,0 +1,39 @@
const https = require("https");
const fs = require("fs");
const assert = require("assert");
/**
* Performs a get request
* @param {string} url
* @returns {Promise}
*/
async function get(url) {
assert.ok(url, "Arg 'url' must not be empty");
var options = {
method: "GET",
headers: {
"User-Agent": "node/" + process.version,
},
};
var promise = new Promise((resolve, reject) => {
var req = https.request(url, options, function (res) {
var chunks = [];
res.on("data", function (chunk) {
chunks.push(chunk);
});
res.on("end", function (chunk) {
var body = JSON.parse(Buffer.concat(chunks).toString("utf8"));
resolve(body);
});
res.on("error", function (error) {
reject(error);
});
});
req.end();
});
return promise;
}
exports.get = get;
+1
View File
@@ -0,0 +1 @@
github.com ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQCj7ndNxQowgcQnjshcLrqPEiiphnt+VTTvDP6mHBL9j1aNUkY4Ue1gvwnGLVlOhGeYrnZaMgRK6+PKCUXaDbC7qtbW8gIkhL7aGCsOr/C56SJMy/BCZfxd1nWzAOxSDPgVsmerOBYfNqltV9/hWCqBywINIR+5dIg6JTJ72pcEpEjcYgXkE2YEFXV1JHnsKgbLWNlhScqb2UmyRkQyytRLtL+38TGxkxCflmO+5Z8CSSNY7GidjMIZ7Q4zMjA2n1nGrlTDkzwDCsw+wqFPGQA179cnfGWOWRVruj16z6XyvxvjJwbz0wQZ75XK5tKSb7FNyeIEs4TT4jk+S4dhPeAUC5y+bDYirYgM4GC7uEnztnZyaVWQ7B381AK4Qdrwt51ZqExKbQpTUNn+EjqoTwvqNj4kqx5QUCI0ThS/YkOxJCXmPUWZbhjpCg56i+2aB6CmK2JGhn57K5mj0MNdBXA4/WnwH6XoPWJzK5Nyu2zB3nAZp+S5hpQs+p1vN1/wsjk=
+4
View File
@@ -0,0 +1,4 @@
const path = require('path')
exports.actionsConfig = path.join(__dirname, '..', '..', 'config', 'actions')
exports.temp = path.join(__dirname, '..', '..', '_temp')
+66
View File
@@ -0,0 +1,66 @@
const assert = require('assert')
class Patterns {
patterns = []
/**
* @param {string[]} p Array of pattern strings
*/
constructor(p) {
assert.ok(p && p.length, "Arg 'p' must not be empty")
for (const pattern of p) {
this.patterns.push(new Pattern(pattern))
}
}
/**
* Tests whether the ref is a match
* @param {string} str
* @returns {boolean}
*/
test(str) {
assert.ok(str, "Arg 'str' must not be empty")
let result = false
for (const pattern of this.patterns) {
result = pattern.test(str, result)
}
return result
}
}
class Pattern {
include = true
regexp = undefined
/**
* @param {string} pattern
*/
constructor(pattern) {
assert.ok(pattern, "Arg 'pattern' must not be empty")
if (pattern.startsWith('-')) {
this.include = false
}
else {
assert.ok(pattern.startsWith('+'), 'Pattern must start with + or -')
}
pattern = pattern.substr(1)
assert.ok(pattern, 'Pattern must not be empty')
this.regexp = new RegExp(pattern)
}
/**
* @param {string} str String to test
* @param {boolean} status Whether currently included or excluded
*/
test(str, status) {
assert.ok(str, "Arg 'str' must not be empty")
if (this.include) {
return status || this.regexp.test(str)
}
return status && !this.regexp.test(str)
}
}
exports.Patterns = Patterns
+6
View File
@@ -0,0 +1,6 @@
#!/bin/sh
GITHUB_ACTIONS_DEBUG="$(echo "$GITHUB_ACTIONS_DEBUG" | tr a-z A-Z)"
if [ "$GITHUB_ACTIONS_DEBUG" = 'TRUE' -o "$GITHUB_ACTIONS_DEBUG" = '1' ]; then
set -x
fi
+95
View File
@@ -0,0 +1,95 @@
const actionConfig = require('./action-config')
const argHelper = require('./arg-helper')
const assert = require('assert')
const debugHelper = require('./debug-helper')
const fsHelper = require('./fs-helper')
async function main() {
try {
// Command line args
const args = getArgs()
// Reinit _temp
await fsHelper.reinitTemp()
// Get a list of action config files
const files = args.all ? await actionConfig.getFilePaths() : [actionConfig.getFilePath(args.owner, args.repo)]
debugHelper.debug(`files: ${files}`)
for (const file of files) {
// Load the config
const config = await actionConfig.loadFromPath(file)
const owner = config.owner
const repo = config.repo
const patterns = config.patterns
const defaultBranch = config.defaultBranch
assert.ok(patterns && patterns.length, 'Existing patterns must not be empty')
await actionConfig.add(owner, repo, patterns, defaultBranch)
}
}
catch (err) {
// Help
if (err.code === argHelper.helpCode) {
printUsage()
return
}
// Arg error?
if (err.code === argHelper.errorCode) {
printUsage()
console.error('')
}
// Print error
debugHelper.debug(err.stack)
console.error(`ERROR: ${err.message}`)
process.exitCode = 1
}
}
class Args {
all = false
owner = ''
repo = ''
}
/**
* Get the command line args
* @returns {Args}
*/
function getArgs() {
const parsedArgs = argHelper.parse(['all'])
const result = new Args()
result.all = !!parsedArgs.flags['all']
// All
if (result.all) {
// Validate no args
if (parsedArgs.arguments.length) {
argHelper.throwError(`Expected zero args when '--all' is specified`)
}
}
// Not all
else {
// Validate exactly one arg
if (parsedArgs.arguments.length !== 1) {
argHelper.throwError('Expected exactly one arg')
}
const nwo = parsedArgs.arguments[0]
const splitNwo = nwo.split('/')
if (splitNwo.length !== 2 || !splitNwo[0] || !splitNwo[1]) {
argHelper.throwError(`Invalid nwo '${nwo}'`)
}
result.owner = splitNwo[0]
result.repo = splitNwo[1]
}
return result
}
function printUsage() {
console.error('USAGE: update-action.sh nwo')
console.error(` nwo Name with owner. For example: actions/checkout`)
}
main()