一键导入
crete-reusable-action
Create a new reusable composite GitHub Action with well-defined inputs/outputs that can be used by customer workflows.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
菜单
Create a new reusable composite GitHub Action with well-defined inputs/outputs that can be used by customer workflows.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
基于 SOC 职业分类
Map internal corporate author identities (name + email) to public github.com identities using MCP-driven user lookup, then rewrite git history with git-filter-repo + .mailmap. Specific to CNCF OSS migration workflows.
Inject and validate the legal and governance documents required for a CNCF-compliant open-source project: Apache 2.0, DCO, GOVERNANCE, SECURITY, CODE_OF_CONDUCT, and README hygiene. Specific to CNCF OSS migration.
Technically migrate a clean repository from GitHub Enterprise Server (GHES) to a public github.com org using squash-to-milestones or mirror-push, then configure branch protection and least-privilege RBAC. Specific to CNCF OSS migration.
Integrate CNCF CLOMonitor and OpenSSF Scorecard into CI/CD to continuously validate open-source project health after a GHES-to-github.com migration. Specific to CNCF OSS migration post-validation workflows.
Scan and strip hardcoded secrets, internal credentials, corporate hostnames, and proprietary naming from a GitHub Enterprise repo before it goes public. Specific to the Vionix CNCF migration workflow — do not use for general code review.
File a Vionix LookinGlass mirror request for a github.com GitHub Action by filling out the IssueOps form at https://<git-host>/github/vionix-lookinglass/issues/new?template=mirrorrepo.yaml. Use this skill whenever the user asks to mirror a github.com repo/action into <git-host>, to "create a mirror request", "onboard a github action", or mentions vionix-lookinglass mirror issues — even if they only provide the upstream URL. It maps the user's intent to every form field, submits the issue with the gh CLI, and explains the follow-up IssueOps commands (@vionix validate, @vionix lgtm) and the GHAS exposed-secrets resume flow.
| name | crete-reusable-action |
| description | Create a new reusable composite GitHub Action with well-defined inputs/outputs that can be used by customer workflows. |
Use this skill when you need to:
Use when:
Examples in this repo:
actions/build/env-pairs-to-dot-env/action.yaml - Converts env pairs to .env fileactions/build/dotenv-to-ghaction-env/action.yaml - Loads .env into GitHub Actions environmentactions/github/check-runs-create/action.yaml - Creates GitHub check run via curlproducts/lookinglass/manage-records/to-github-actions-matrix/action.yaml - Processes YAML to matrixUse when:
Examples in this repo:
actions/github/ghas-dependabot-metadata/action.yaml - Fetches Dependabot metadata and creates PR commentsactions/github/lint-gha-sha-version/action.yaml - Downloads and runs gha-fix CLI with complex setupactions/build/openssf-dependency-metadata/action.yaml - Fetches deps.dev API and formats resultsactions/messaging/slack-notification/action.yaml - Email-to-Slack mention conversion with API callsIMPORTANT: JavaScript actions MUST use actions/github-script@vX with inline pure JavaScript.
fs, path, os, child_process, crypto, etc.@actions/core, @actions/github, github context, fetch (Node 20+)actions/
├── {category}/ # build, docker, github, messaging, network
│ └── {action-name}/ # descriptive-kebab-case name
│ └── action.yaml # MUST be action.yaml (not action.yml)
Categories:
build/ - Build utilities, configuration, environment managementdocker/ - Docker-specific operations (scanning, SBOM, registry)github/ - GitHub API operations, workflow management, GHASmessaging/ - Notifications (Slack, email, etc.)network/ - Network utilities, runner operationsproducts/
├── {product}/ # lift, lookinglass
│ └── {domain}/ # manage-env, manage-repo, manage-issue, etc.
│ └── {action}/ # specific action name
│ └── action.yaml
Products:
lift/ - Environment management productlookinglass/ - Repository management and issue-ops productname: {Action Name}
description: {Clear description of what this action does}
author: {team-name or vionix}
branding:
icon: anchor
color: blue
inputs:
input-name:
description: "{Clear description of the input}"
required: true
default: "" # Only if optional
outputs:
output-name:
description: "{Clear description of the output}"
value: ${{ steps.step-id.outputs.output-name }}
runs:
using: composite
steps:
- name: {Descriptive step name}
id: step-id
shell: bash
env:
INPUT_VAR: ${{ inputs.input-name }}
run: |
# Shell script implementation
echo "Processing ${INPUT_VAR}"
# Set output
echo "output-name=value" >> $GITHUB_OUTPUT
# Add to job summary
echo "## Summary" >> $GITHUB_STEP_SUMMARY
echo "Processed successfully" >> $GITHUB_STEP_SUMMARY
name: {Action Name}
description: {Clear description of what this action does}
author: {team-name or vionix}
branding:
icon: anchor
color: blue
inputs:
github-token:
description: "GitHub token for API access"
required: true
input-name:
description: "{Clear description}"
required: true
outputs:
output-name:
description: "{Clear description}"
value: ${{ steps.process.outputs.output-name }}
runs:
using: composite
steps:
- name: {Descriptive step name}
id: process
uses: actions/github-script@v8
env:
INPUT_VAR: ${{ inputs.input-name }}
with:
github-token: ${{ inputs.github-token }}
script: |
const core = require('@actions/core');
const github = require('@actions/github');
const fs = require('fs');
const path = require('path');
// Get inputs from environment
const inputVar = process.env.INPUT_VAR || '';
// Process data
const result = processData(inputVar);
// Set outputs
core.setOutput('output-name', result);
// Add to job summary
await core.summary
.addHeading('Summary', 2)
.addRaw(`Processed: ${result}`)
.write();
// Helper functions
function processData(input) {
// Implementation
return input.toUpperCase();
}
name: {Composite Action Name}
description: {Description of the cohesive problem this solves}
inputs:
input-1:
description: "First input"
required: true
input-2:
description: "Second input"
required: false
default: "default-value"
outputs:
final-output:
description: "The final result"
value: ${{ steps.combine.outputs.result }}
runs:
using: composite
steps:
# Step 1: Prepare data
- name: Prepare data
id: prepare
shell: bash
run: |
echo "Preparing ${{ inputs.input-1 }}"
echo "prepared=true" >> $GITHUB_OUTPUT
# Step 2: Use existing action
- name: Process with existing action
id: process
uses: Viasat/vionix/actions/category/action@main
with:
input: ${{ inputs.input-1 }}
# Step 3: Combine results with JavaScript
- name: Combine results
id: combine
uses: actions/github-script@v8
env:
PREPARED: ${{ steps.prepare.outputs.prepared }}
PROCESSED: ${{ steps.process.outputs.result }}
with:
script: |
const prepared = process.env.PREPARED === 'true';
const processed = process.env.PROCESSED || '';
const result = prepared ? `Combined: ${processed}` : 'Failed';
core.setOutput('result', result);
required: true for mandatory inputsShell:
if [ ! -f "required-file.txt" ]; then
echo "ERROR: required-file.txt does not exist!"
exit 1
fi
JavaScript:
try {
const result = await riskyOperation();
core.setOutput('result', result);
} catch (error) {
core.setFailed(`Operation failed: ${error.message}`);
return;
}
core.setSecret() to mask sensitive values in JavaScriptgithub-token input instead of hardcoding secrets.GITHUB_TOKENExample:
const token = process.env.GITHUB_TOKEN || '';
if (token) core.setSecret(token);
Always add meaningful summaries using $GITHUB_STEP_SUMMARY:
Shell:
echo "## Action Results" >> $GITHUB_STEP_SUMMARY
echo "- Status: Success ✅" >> $GITHUB_STEP_SUMMARY
echo "- Files processed: ${COUNT}" >> $GITHUB_STEP_SUMMARY
JavaScript:
await core.summary
.addHeading('Action Results', 2)
.addRaw('- Status: Success ✅\n')
.addRaw(`- Files processed: ${count}\n`)
.write();
Composite actions can call other actions:
- name: Use existing action
uses: Viasat/vionix/actions/build/dotenv-to-ghaction-env@main
with:
dot-file-path: .env
act or in a test workflow.github/workflows/test-*.yamlsteps:
- name: Process files
shell: bash
run: |
for file in *.yaml; do
echo "Processing $file"
yq eval '.field' "$file"
done
async function fetchWithRetry(url, options, retries = 3) {
for (let i = 0; i < retries; i++) {
try {
const response = await fetch(url, options);
if (!response.ok) throw new Error(`HTTP ${response.status}`);
return await response.json();
} catch (error) {
if (i === retries - 1) throw error;
await new Promise(resolve => setTimeout(resolve, 1000 * (i + 1)));
}
}
}
const octokit = github.getOctokit(process.env.GITHUB_TOKEN);
// Create issue comment
await octokit.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.issue.number,
body: 'Comment text'
});
// List files in PR
const { data: files } = await octokit.rest.pulls.listFiles({
owner: context.repo.owner,
repo: context.repo.repo,
pull_number: context.issue.number
});
# Shell - Use EOF delimiters
echo 'multiline-output<<EOF' >> $GITHUB_OUTPUT
echo "Line 1" >> $GITHUB_OUTPUT
echo "Line 2" >> $GITHUB_OUTPUT
echo 'EOF' >> $GITHUB_OUTPUT
// JavaScript
const multilineValue = `
Line 1
Line 2
Line 3
`.trim();
core.setOutput('multiline-output', multilineValue);
steps:
- name: Check condition
id: check
shell: bash
run: |
if [ "${{ inputs.enable-feature }}" == "true" ]; then
echo "enabled=true" >> $GITHUB_OUTPUT
else
echo "enabled=false" >> $GITHUB_OUTPUT
fi
- name: Run if enabled
if: ${{ steps.check.outputs.enabled == 'true' }}
shell: bash
run: echo "Feature is enabled"
Below are inline code patterns found in existing workflows that should be extracted into reusable actions:
Found in: Multiple workflows (docker-compose-devsecops-workflow.yaml, etc.)
Pattern: Extracting git SHA, branch name, committer info
Proposed action: actions/github/extract-git-metadata/action.yaml
# Extract from workflows like:
# gitShortSha: $(git rev-parse --short HEAD)
# committerName: $(git log -1 --pretty=format:'%an')
# committerEmail: $(git log -1 --pretty=format:'%ae')
# Should output: sha, shortSha, branch, committer.name, committer.email, timestamp
Found in: docker-compose-devsecops-workflow.yaml (lines 192-200)
Pattern: Generating Docker image tags from branch names and SHAs
Proposed action: actions/docker/generate-image-tags/action.yaml
# Generate standardized tags:
# - defaultDockerImageVersion
# - defaultDockerImageBranchTag
# - defaultDockerImageBranchShaTag
# - defaultDockerImageBranchTagForVersion
Found in: Multiple workflows (279 shell runs for notifications)
Pattern: Building Slack payloads with job context
Proposed action: actions/messaging/build-slack-payload/action.yaml
# Already partially done in slack-notification/action.yaml
# But many workflows still build payloads inline
# Should standardize: success/failure payloads, link formatting, emoji status
Found in: Multiple workflows
Pattern: Generating job URLs for linking in notifications
Proposed action: actions/github/generate-job-url/action.yaml
# Extract from:
# githubActionJobUrl: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
# Should handle: job URLs, step URLs, PR URLs, commit URLs
Found in: docker-compose-devsecops-workflow.yaml and others
Pattern: Validating YAML/JSON files with exclusion patterns
Proposed action: actions/build/validate-config-files/action.yaml
# Inputs: file-pattern, exclude-regex, allow-multiple-documents
# Should validate syntax, report errors, support both YAML and JSON
Found in: Multiple workflows using github-script inline
Pattern: Fetching PR number, title, author, labels
Proposed action: actions/github/fetch-pr-context/action.yaml
# Get PR metadata in any event (push, pull_request, workflow_dispatch)
# Outputs: pr-number, pr-title, pr-author, pr-labels, is-pr
Found in: Multiple workflows with docker login commands
Pattern: Authenticating to Artifactory registry
Proposed action: actions/docker/artifactory-login/action.yaml
# Inputs: username, password, registry-url
# Handle: docker login, credential masking, logout on failure
Found in: docker-compose workflows
Pattern: Generating ISO timestamps for build metadata
Proposed action: actions/build/generate-timestamp/action.yaml
# Generate: ISO8601, Unix epoch, formatted timestamps
# For: build metadata, cache keys, artifact naming
Found in: terraform-devsecops-workflow.yaml, security scanning workflows
Pattern: Uploading SARIF files to GHAS with error handling
Proposed action: actions/github/upload-sarif-results/action.yaml
# Handle: SARIF validation, upload to GHAS, retry logic, error reporting
Found in: Workflows with dynamic matrix generation
Pattern: Building GitHub Actions matrix from files or API responses
Proposed action: actions/github/build-matrix-strategy/action.yaml
# Partially exists in: products/lookinglass/manage-records/to-github-actions-matrix
# Should generalize: support JSON/YAML input, filtering, transformation
Found in: Multiple workflows with env file handling
Pattern: Loading environment variables from various sources
Proposed action: actions/build/inject-environment-vars/action.yaml
# Combine: env-pairs-to-dot-env + dotenv-to-ghaction-env
# Add: support for JSON, YAML, env files, base64 encoded
Found in: PR workflows checking changed files
Pattern: Getting changed files list, filtering by pattern
Proposed action: actions/github/analyze-git-diff/action.yaml
# Outputs: changed-files (list), has-changes (bool), file-count
# Support: glob patterns, exclude patterns, base branch comparison
Found in: Docker build workflows with sonarqube scanning
Pattern: Submitting scan results to SonarQube
Proposed action: actions/build/sonarqube-reporter/action.yaml
Found in: Multiple workflows with submodule handling
Pattern: Conditional checkout with submodule support
Proposed action: actions/github/checkout-with-options/action.yaml
Found in: Workflows using actions/cache
Pattern: Generating cache keys from file hashes
Proposed action: actions/build/generate-cache-key/action.yaml
actions/{category}/{action-name}/products/{product}/{domain}/{action}/mkdir -p actions/github/my-new-action
cd actions/github/my-new-action
Create a test workflow:
name: Test My Action
on: workflow_dispatch
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Test action
uses: ./actions/github/my-new-action
with:
input-name: test-value
- name: Verify output
run: echo "Output was ${{ steps.test.outputs.output-name }}"
- name: Convert env pairs to .env
uses: Viasat/vionix/actions/build/env-pairs-to-dot-env@v1.2.3
with:
dot-file-content: |
KEY1=value1
KEY2=value2
dot-file-artifact-name: build-env
dot-file-path: .env.build
- name: Get Dependabot metadata
id: metadata
uses: Viasat/vionix/actions/github/ghas-dependabot-metadata@v2.0.0
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
github-enterprise: "true"
- name: Use metadata output
run: echo "Dependency: ${{ steps.metadata.outputs.dependabotMetadata }}"
- name: Authenticate to GitHub
id: auth
uses: Viasat/vionix/products/lookinglass/manage-repo/authenticate@main
with:
authentication: app
application-id: ${{ secrets.APP_ID }}
application-private-key: ${{ secrets.APP_PRIVATE_KEY }}
- name: Use authenticated token
run: |
echo "Token: ${{ steps.auth.outputs.token }}"
Add debug output:
echo "::debug::Variable value is ${VAR}"
core.debug(`Variable value is ${var}`);
# Shell - Use jq
echo '{"key":"value"}' | jq -r '.key'
# Create JSON array
jq -n --arg val "$VALUE" '{"key": $val}'
// JavaScript - Native support
const obj = JSON.parse(jsonString);
const result = JSON.stringify({ key: 'value' });
const fs = require('fs');
const path = require('path');
// Read file
const content = fs.readFileSync('file.txt', 'utf8');
// Write file
fs.writeFileSync('output.txt', content, 'utf8');
// Check if file exists
if (fs.existsSync('file.txt')) {
// File exists
}
// Create directory
fs.mkdirSync('new-dir', { recursive: true });
// Get workspace path
const workspace = process.env.GITHUB_WORKSPACE || process.cwd();
// Get runner temp
const temp = process.env.RUNNER_TEMP || '/tmp';
// Get GitHub context
const eventName = process.env.GITHUB_EVENT_NAME;
// Always use async/await in github-script
const result = await asyncOperation();
// Parallel operations
const [result1, result2] = await Promise.all([
operation1(),
operation2()
]);
Remember: Actions should solve ONE cohesive problem. If your action does too many unrelated things, consider splitting it into multiple actions that can be composed together.