fix(ci): GitHub Actions:\Usage Examples

Now you can run specific audits directly:

  # Run specific audits
  gh act workflow_dispatch -j cli-3-enterprise
  gh act workflow_dispatch -j cli-3-core
  gh act workflow_dispatch -j api-3-cloud-dedicated

  # Run with custom version
  gh act workflow_dispatch -j cli-3-enterprise --input
  version=3.1.0

  # Run all audits (scheduled behavior)
  gh act workflow_dispatch
pull/6190/head
Jason Stirnaman 2025-07-05 18:31:57 -05:00
parent eb83cc7767
commit fa069a77ea
2 changed files with 477 additions and 126 deletions

View File

@ -3,17 +3,6 @@ name: Audit Documentation
on:
workflow_dispatch:
inputs:
product:
description: 'Product to audit'
required: true
type: choice
options:
- core
- enterprise
- clustered
- cloud-dedicated
- all-monolith
- all-distributed
version:
description: 'Version to audit (use "local" for running containers)'
required: false
@ -25,17 +14,13 @@ on:
default: false
schedule:
# Run weekly on Mondays at 9 AM UTC
# Note: This only runs API audits for distributed products
# CLI audits for core/enterprise run via the release workflow
# Run weekly on Mondays at 9 AM UTC for all audits
- cron: '0 9 * * 1'
jobs:
audit-cli:
name: Audit CLI Documentation
cli-3-core:
name: Audit InfluxDB 3 Core CLI
runs-on: ubuntu-latest
# Only run for manual triggers, not scheduled runs (which are for distributed products)
if: github.event_name == 'workflow_dispatch' && contains(fromJSON('["core", "enterprise", "all-monolith"]'), github.event.inputs.product)
steps:
- uses: actions/checkout@v4
@ -50,89 +35,368 @@ jobs:
run: yarn install --frozen-lockfile
- name: Set up Docker
if: github.event.inputs.version == 'local'
if: github.event.inputs.version == 'local' || github.event_name == 'schedule'
run: |
docker compose up -d influxdb3-core influxdb3-enterprise
docker compose up -d influxdb3-core
sleep 10 # Wait for containers to be ready
- name: Run CLI audit
- name: Run Core CLI audit
run: |
PRODUCT="${{ github.event.inputs.product }}"
VERSION="${{ github.event.inputs.version }}"
if [ "$PRODUCT" == "all-monolith" ]; then
node ./helper-scripts/influxdb3-monolith/audit-cli-documentation.js both $VERSION
else
node ./helper-scripts/influxdb3-monolith/audit-cli-documentation.js $PRODUCT $VERSION
fi
VERSION="${{ github.event.inputs.version || 'local' }}"
node ./helper-scripts/influxdb3-monolith/audit-cli-documentation.js core $VERSION
- name: Upload CLI audit reports
- name: Upload audit reports
uses: actions/upload-artifact@v4
with:
name: cli-audit-${{ github.event.inputs.product }}-${{ github.event.inputs.version }}
name: cli-audit-3-core-${{ github.event.inputs.version || 'local' }}
path: helper-scripts/output/cli-audit/
retention-days: 30
- name: Create CLI audit issue
if: github.event_name == 'schedule' || github.event.inputs.create_issue == 'true'
uses: actions/github-script@v7
with:
script: |
const fs = require('fs');
let product = '${{ github.event.inputs.product }}';
let version = '${{ github.event.inputs.version }}';
// Handle scheduled runs (no inputs)
if (github.event_name === 'schedule') {
product = 'both';
version = 'local';
}
// Read audit report
const reportPath = `helper-scripts/output/cli-audit/documentation-audit-${product}-${version}.md`;
if (!fs.existsSync(reportPath)) {
console.log(`Audit report not found at ${reportPath}`);
return;
}
const report = fs.readFileSync(reportPath, 'utf8');
// Create issue
await github.rest.issues.create({
owner: context.repo.owner,
repo: context.repo.repo,
title: `CLI Documentation Audit - ${product} ${version}`,
body: report,
labels: ['documentation', 'cli-audit', product === 'both' ? 'core-enterprise' : product]
});
audit-api:
name: Audit API Documentation
cli-3-enterprise:
name: Audit InfluxDB 3 Enterprise CLI
runs-on: ubuntu-latest
if: contains(fromJSON('["clustered", "cloud-dedicated", "all-distributed"]'), github.event.inputs.product)
steps:
- uses: actions/checkout@v4
- name: Run API audit
run: |
echo "API audit not yet implemented"
# TODO: Implement API documentation audit
# ./helper-scripts/influxdb3-distributed/audit-api-documentation.sh ${{ github.event.inputs.product }}
- name: Set up Node.js
uses: actions/setup-node@v4
with:
node-version: '18'
cache: 'yarn'
- name: Upload API audit reports
if: false # Enable when API audit is implemented
- name: Install dependencies
run: yarn install --frozen-lockfile
- name: Set up Docker
if: github.event.inputs.version == 'local' || github.event_name == 'schedule'
run: |
docker compose up -d influxdb3-enterprise
sleep 10 # Wait for containers to be ready
- name: Run Enterprise CLI audit
run: |
VERSION="${{ github.event.inputs.version || 'local' }}"
node ./helper-scripts/influxdb3-monolith/audit-cli-documentation.js enterprise $VERSION
- name: Upload audit reports
uses: actions/upload-artifact@v4
with:
name: api-audit-${{ github.event.inputs.product }}
name: cli-audit-3-enterprise-${{ github.event.inputs.version || 'local' }}
path: helper-scripts/output/cli-audit/
retention-days: 30
cli-3-influxctl:
name: Audit InfluxDB 3 influxctl CLI
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Set up Node.js
uses: actions/setup-node@v4
with:
node-version: '18'
cache: 'yarn'
- name: Install dependencies
run: yarn install --frozen-lockfile
- name: Run influxctl CLI audit
run: |
VERSION="${{ github.event.inputs.version || 'local' }}"
echo "influxctl CLI audit not yet implemented"
# TODO: Implement influxctl CLI audit
# node ./helper-scripts/influxdb3-distributed/audit-influxctl-cli.js $VERSION
# Create placeholder report
mkdir -p helper-scripts/output/cli-audit
cat > helper-scripts/output/cli-audit/influxctl-audit-$VERSION.md << 'EOF'
# influxctl CLI Audit Report
**CLI:** influxctl
**Version:** $VERSION
**Date:** $(date)
**Status:** Placeholder - audit not yet implemented
## TODO
- Implement influxctl CLI help extraction
- Compare against clustered and cloud-dedicated documentation
- Generate patches for missing documentation
EOF
- name: Upload audit reports
uses: actions/upload-artifact@v4
with:
name: cli-audit-3-influxctl-${{ github.event.inputs.version || 'local' }}
path: helper-scripts/output/cli-audit/
retention-days: 30
api-3-core:
name: Audit InfluxDB 3 Core API
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Run Core API audit
run: |
VERSION="${{ github.event.inputs.version || 'local' }}"
echo "Core API audit not yet implemented"
# TODO: Implement Core API audit
# node ./helper-scripts/influxdb3-monolith/audit-api-documentation.js core $VERSION
# Create placeholder report
mkdir -p helper-scripts/output/api-audit
cat > helper-scripts/output/api-audit/core-api-audit-$VERSION.md << 'EOF'
# InfluxDB 3 Core API Audit Report
**API:** InfluxDB 3 Core
**Version:** $VERSION
**Date:** $(date)
**Status:** Placeholder - audit not yet implemented
## TODO
- Implement API endpoint discovery
- Compare against OpenAPI specs
- Validate documentation examples
EOF
- name: Upload audit reports
uses: actions/upload-artifact@v4
with:
name: api-audit-3-core-${{ github.event.inputs.version || 'local' }}
path: helper-scripts/output/api-audit/
retention-days: 30
summary:
api-3-enterprise:
name: Audit InfluxDB 3 Enterprise API
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Run Enterprise API audit
run: |
VERSION="${{ github.event.inputs.version || 'local' }}"
echo "Enterprise API audit not yet implemented"
# TODO: Implement Enterprise API audit
# node ./helper-scripts/influxdb3-monolith/audit-api-documentation.js enterprise $VERSION
# Create placeholder report
mkdir -p helper-scripts/output/api-audit
cat > helper-scripts/output/api-audit/enterprise-api-audit-$VERSION.md << 'EOF'
# InfluxDB 3 Enterprise API Audit Report
**API:** InfluxDB 3 Enterprise
**Version:** $VERSION
**Date:** $(date)
**Status:** Placeholder - audit not yet implemented
## TODO
- Implement API endpoint discovery
- Compare against OpenAPI specs
- Validate documentation examples
- Check enterprise-specific endpoints
EOF
- name: Upload audit reports
uses: actions/upload-artifact@v4
with:
name: api-audit-3-enterprise-${{ github.event.inputs.version || 'local' }}
path: helper-scripts/output/api-audit/
retention-days: 30
api-3-cloud-dedicated:
name: Audit InfluxDB 3 Cloud Dedicated API
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Run Cloud Dedicated API audit
run: |
VERSION="${{ github.event.inputs.version || 'local' }}"
echo "Cloud Dedicated API audit not yet implemented"
# TODO: Implement Cloud Dedicated API audit
# node ./helper-scripts/influxdb3-distributed/audit-api-documentation.js cloud-dedicated $VERSION
# Create placeholder report
mkdir -p helper-scripts/output/api-audit
cat > helper-scripts/output/api-audit/cloud-dedicated-api-audit-$VERSION.md << 'EOF'
# InfluxDB 3 Cloud Dedicated API Audit Report
**API:** InfluxDB 3 Cloud Dedicated
**Version:** $VERSION
**Date:** $(date)
**Status:** Placeholder - audit not yet implemented
## TODO
- Implement management API audit
- Implement data API audit
- Compare against OpenAPI specs
- Validate documentation examples
EOF
- name: Upload audit reports
uses: actions/upload-artifact@v4
with:
name: api-audit-3-cloud-dedicated-${{ github.event.inputs.version || 'local' }}
path: helper-scripts/output/api-audit/
retention-days: 30
api-3-clustered:
name: Audit InfluxDB 3 Clustered API
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Run Clustered API audit
run: |
VERSION="${{ github.event.inputs.version || 'local' }}"
echo "Clustered API audit not yet implemented"
# TODO: Implement Clustered API audit
# node ./helper-scripts/influxdb3-distributed/audit-api-documentation.js clustered $VERSION
# Create placeholder report
mkdir -p helper-scripts/output/api-audit
cat > helper-scripts/output/api-audit/clustered-api-audit-$VERSION.md << 'EOF'
# InfluxDB 3 Clustered API Audit Report
**API:** InfluxDB 3 Clustered
**Version:** $VERSION
**Date:** $(date)
**Status:** Placeholder - audit not yet implemented
## TODO
- Implement management API audit
- Implement data API audit
- Compare against OpenAPI specs
- Validate documentation examples
EOF
- name: Upload audit reports
uses: actions/upload-artifact@v4
with:
name: api-audit-3-clustered-${{ github.event.inputs.version || 'local' }}
path: helper-scripts/output/api-audit/
retention-days: 30
api-3-cloud-serverless:
name: Audit InfluxDB 3 Cloud Serverless API
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Run Cloud Serverless API audit
run: |
VERSION="${{ github.event.inputs.version || 'local' }}"
echo "Cloud Serverless API audit not yet implemented"
# TODO: Implement Cloud Serverless API audit
# node ./helper-scripts/influxdb3-distributed/audit-api-documentation.js cloud-serverless $VERSION
# Create placeholder report
mkdir -p helper-scripts/output/api-audit
cat > helper-scripts/output/api-audit/cloud-serverless-api-audit-$VERSION.md << 'EOF'
# InfluxDB 3 Cloud Serverless API Audit Report
**API:** InfluxDB 3 Cloud Serverless
**Version:** $VERSION
**Date:** $(date)
**Status:** Placeholder - audit not yet implemented
## TODO
- Implement management API audit
- Implement data API audit
- Compare against OpenAPI specs
- Validate documentation examples
EOF
- name: Upload audit reports
uses: actions/upload-artifact@v4
with:
name: api-audit-3-cloud-serverless-${{ github.event.inputs.version || 'local' }}
path: helper-scripts/output/api-audit/
retention-days: 30
create-audit-issues:
name: Create Issues from Audit Results
runs-on: ubuntu-latest
needs: [
cli-3-core,
cli-3-enterprise,
cli-3-influxctl,
api-3-core,
api-3-enterprise,
api-3-cloud-dedicated,
api-3-clustered,
api-3-cloud-serverless
]
if: always() && (github.event_name == 'schedule' || github.event.inputs.create_issue == 'true')
steps:
- uses: actions/checkout@v4
- name: Download all audit reports
uses: actions/download-artifact@v4
with:
path: audit-reports/
- name: Create issues from audit results
uses: actions/github-script@v7
with:
script: |
const fs = require('fs');
const path = require('path');
// Find all audit report directories
const reportDirs = fs.readdirSync('audit-reports');
for (const reportDir of reportDirs) {
const reportPath = path.join('audit-reports', reportDir);
const files = fs.readdirSync(reportPath);
for (const file of files) {
if (file.endsWith('.md')) {
const content = fs.readFileSync(path.join(reportPath, file), 'utf8');
// Only create issues if there are actual problems (not placeholders)
const hasIssues = content.includes('⚠️ Missing from docs') ||
content.includes(' Documented but not in CLI') ||
content.includes('API endpoint mismatch');
if (hasIssues) {
const auditType = reportDir.replace(/-(local|\d+\.\d+\.\d+)$/, '');
await github.rest.issues.create({
owner: context.repo.owner,
repo: context.repo.repo,
title: `Documentation Audit Issues - ${auditType}`,
body: `## Audit Results\n\n${content}`,
labels: ['documentation', 'audit', auditType.includes('cli') ? 'cli-audit' : 'api-audit']
});
console.log(`Created issue for ${auditType}`);
}
}
}
}
audit-summary:
name: Generate Summary Report
runs-on: ubuntu-latest
needs: [audit-cli, audit-api]
needs: [
cli-3-core,
cli-3-enterprise,
cli-3-influxctl,
api-3-core,
api-3-enterprise,
api-3-cloud-dedicated,
api-3-clustered,
api-3-cloud-serverless
]
if: always()
steps:
@ -147,21 +411,19 @@ jobs:
run: |
echo "# Documentation Audit Summary" > summary.md
echo "Date: $(date)" >> summary.md
echo "Product: ${{ github.event.inputs.product }}" >> summary.md
echo "Version: ${{ github.event.inputs.version }}" >> summary.md
echo "Version: ${{ github.event.inputs.version || 'local' }}" >> summary.md
echo "" >> summary.md
# Add CLI audit results if available
if [ -d "audit-artifacts/cli-audit-*" ]; then
echo "## CLI Audit Results" >> summary.md
cat audit-artifacts/cli-audit-*/*.md >> summary.md
fi
# Add API audit results if available
if [ -d "audit-artifacts/api-audit-*" ]; then
echo "## API Audit Results" >> summary.md
cat audit-artifacts/api-audit-*/*.md >> summary.md
fi
# Add results from each audit type
for dir in audit-artifacts/*/; do
if [ -d "$dir" ]; then
echo "## $(basename "$dir")" >> summary.md
if [ -f "$dir"/*.md ]; then
cat "$dir"/*.md >> summary.md
fi
echo "" >> summary.md
fi
done
- name: Upload summary
uses: actions/upload-artifact@v4

View File

@ -10,7 +10,9 @@ on:
options:
- core
- enterprise
- both
- clustered
- cloud-dedicated
- cloud-serverless
version:
description: 'Version being released (e.g., 3.0.0)'
required: true
@ -30,7 +32,7 @@ jobs:
name: Generate Release Notes
runs-on: ubuntu-latest
outputs:
release_notes_generated: ${{ steps.generate.outputs.generated }}
generated: ${{ steps.generate.outputs.generated }}
steps:
- uses: actions/checkout@v4
@ -58,7 +60,7 @@ jobs:
# For now, create a placeholder
mkdir -p helper-scripts/output/release-notes
echo "# Release Notes for ${{ github.event.inputs.product }} v${{ github.event.inputs.version }}" > helper-scripts/output/release-notes/release-notes-${{ github.event.inputs.product }}-${{ github.event.inputs.version }}.md
echo "Generated: true" >> $GITHUB_OUTPUT
echo "generated=true" >> $GITHUB_OUTPUT
- name: Upload release notes
uses: actions/upload-artifact@v4
@ -71,7 +73,7 @@ jobs:
name: Audit CLI Documentation
needs: generate-release-notes
runs-on: ubuntu-latest
if: needs.generate-release-notes.outputs.release_notes_generated == 'true'
if: needs.generate-release-notes.outputs.generated == 'true' && contains(fromJSON('["core", "enterprise"]'), github.event.inputs.product)
steps:
- uses: actions/checkout@v4
@ -111,11 +113,70 @@ jobs:
path: helper-scripts/output/cli-audit/
retention-days: 90
audit-distributed-documentation:
name: Audit Distributed Products Documentation
needs: generate-release-notes
runs-on: ubuntu-latest
if: needs.generate-release-notes.outputs.generated == 'true' && contains(fromJSON('["clustered", "cloud-dedicated", "cloud-serverless"]'), github.event.inputs.product)
steps:
- uses: actions/checkout@v4
- name: Set up Node.js
uses: actions/setup-node@v4
with:
node-version: '18'
cache: 'yarn'
- name: Install dependencies
run: yarn install --frozen-lockfile
- name: Run distributed products audit
run: |
PRODUCT="${{ github.event.inputs.product }}"
VERSION="${{ github.event.inputs.version }}"
echo "Auditing distributed product: $PRODUCT v$VERSION"
# TODO: Implement distributed products audit for release
# This would audit API docs, deployment guides, configuration references
# node ./helper-scripts/influxdb3-distributed/audit-documentation.js $PRODUCT $VERSION
# For now, create placeholder report
mkdir -p helper-scripts/output/distributed-audit
cat > helper-scripts/output/distributed-audit/release-audit-$PRODUCT-$VERSION.md << 'EOF'
# Release Audit Report - Distributed Products
**Product:** $PRODUCT
**Version:** $VERSION
**Date:** $(date)
**Status:** Placeholder - audit not yet implemented
## Areas to Audit
- API documentation completeness
- Deployment guide accuracy
- Configuration reference updates
- Integration guide updates
- Version-specific feature documentation
## TODO
- Implement API documentation audit
- Implement deployment guide audit
- Implement configuration reference audit
- Implement integration guide audit
EOF
- name: Upload distributed audit reports
uses: actions/upload-artifact@v4
with:
name: distributed-audit-release-${{ github.event.inputs.product }}-${{ github.event.inputs.version }}
path: helper-scripts/output/distributed-audit/
retention-days: 90
create-documentation-pr:
name: Create Documentation PR
needs: [generate-release-notes, audit-cli-documentation]
needs: [generate-release-notes, audit-cli-documentation, audit-distributed-documentation]
runs-on: ubuntu-latest
if: github.event.inputs.dry_run != 'true'
if: github.event.inputs.dry_run != 'true' && always() && needs.generate-release-notes.result == 'success'
steps:
- uses: actions/checkout@v4
@ -168,57 +229,84 @@ jobs:
draft: true
create-audit-issue:
name: Create CLI Audit Issue
needs: audit-cli-documentation
name: Create Audit Issue
needs: [audit-cli-documentation, audit-distributed-documentation]
runs-on: ubuntu-latest
if: github.event.inputs.dry_run != 'true'
if: github.event.inputs.dry_run != 'true' && always() && (needs.audit-cli-documentation.result == 'success' || needs.audit-distributed-documentation.result == 'success')
steps:
- uses: actions/checkout@v4
- name: Download audit report
- name: Download audit reports
uses: actions/download-artifact@v4
with:
name: cli-audit-release-${{ github.event.inputs.product }}-${{ github.event.inputs.version }}
path: audit-report/
path: audit-reports/
- name: Create issue from audit
uses: actions/github-script@v7
with:
script: |
const fs = require('fs');
const path = require('path');
const product = '${{ github.event.inputs.product }}';
const version = '${{ github.event.inputs.version }}';
// Find and read the audit report
const files = fs.readdirSync('audit-report');
const auditFile = files.find(f => f.includes('documentation-audit'));
let auditReports = [];
let hasIssues = false;
if (!auditFile) {
console.log('No audit report found');
return;
// Check for CLI audit report
const cliAuditPath = `audit-reports/cli-audit-release-${product}-${version}`;
if (fs.existsSync(cliAuditPath)) {
const files = fs.readdirSync(cliAuditPath);
const cliAuditFile = files.find(f => f.includes('documentation-audit'));
if (cliAuditFile) {
const report = fs.readFileSync(path.join(cliAuditPath, cliAuditFile), 'utf8');
const hasMissingOptions = report.includes('⚠️ Missing from docs');
const hasExtraOptions = report.includes(' Documented but not in CLI');
if (hasMissingOptions || hasExtraOptions) {
auditReports.push({
type: 'CLI',
content: report
});
hasIssues = true;
}
}
}
const report = fs.readFileSync(`audit-report/${auditFile}`, 'utf8');
// Check for distributed audit report
const distributedAuditPath = `audit-reports/distributed-audit-release-${product}-${version}`;
if (fs.existsSync(distributedAuditPath)) {
const files = fs.readdirSync(distributedAuditPath);
const distributedAuditFile = files.find(f => f.includes('release-audit'));
if (distributedAuditFile) {
const report = fs.readFileSync(path.join(distributedAuditPath, distributedAuditFile), 'utf8');
// For now, always include distributed audit reports since they're placeholders
auditReports.push({
type: 'Distributed Products',
content: report
});
hasIssues = true;
}
}
// Check if there are any issues to report
const hasMissingOptions = report.includes('⚠️ Missing from docs');
const hasExtraOptions = report.includes(' Documented but not in CLI');
if (hasMissingOptions || hasExtraOptions) {
// Create issue
if (hasIssues && auditReports.length > 0) {
// Create comprehensive issue
const issueBody = [
'## CLI Documentation Audit Results',
'## Release Documentation Audit Results',
'',
`The following documentation issues were found during the release of **${product} v${version}**:`,
'',
report,
'',
...auditReports.map(report => [
`### ${report.type} Audit`,
'',
report.content,
''
]).flat(),
'### Action Items:',
'- [ ] Review and update documentation for commands with missing options',
'- [ ] Remove documentation for deprecated options',
'- [ ] Review and update documentation for missing or outdated content',
'- [ ] Verify all examples work with the new version',
'- [ ] Update any version-specific content',
'- [ ] Remove documentation for deprecated features',
'',
'---',
'*This issue was automatically generated during the release process.*'
@ -227,19 +315,19 @@ jobs:
await github.rest.issues.create({
owner: context.repo.owner,
repo: context.repo.repo,
title: `CLI Documentation Updates Needed - ${product} v${version}`,
title: `Documentation Updates Needed - ${product} v${version}`,
body: issueBody,
labels: ['documentation', 'cli-audit', 'release', product]
labels: ['documentation', 'release', product, 'audit']
});
console.log('Created issue for CLI documentation updates');
console.log('Created issue for documentation updates');
} else {
console.log('No documentation issues found - skipping issue creation');
}
summary:
influxdb3-monolith-release-summary:
name: Release Summary
needs: [generate-release-notes, audit-cli-documentation, create-documentation-pr, create-audit-issue]
needs: [generate-release-notes, audit-cli-documentation, audit-distributed-documentation, create-documentation-pr, create-audit-issue]
runs-on: ubuntu-latest
if: always()
@ -260,6 +348,7 @@ jobs:
echo "|------|--------|" >> $GITHUB_STEP_SUMMARY
echo "| Generate Release Notes | ${{ needs.generate-release-notes.result }} |" >> $GITHUB_STEP_SUMMARY
echo "| CLI Documentation Audit | ${{ needs.audit-cli-documentation.result }} |" >> $GITHUB_STEP_SUMMARY
echo "| Distributed Documentation Audit | ${{ needs.audit-distributed-documentation.result }} |" >> $GITHUB_STEP_SUMMARY
echo "| Create Documentation PR | ${{ needs.create-documentation-pr.result }} |" >> $GITHUB_STEP_SUMMARY
echo "| Create Audit Issue | ${{ needs.create-audit-issue.result }} |" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY