Skip to content

feat: add active-step-workflow action #87

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 4 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 52 additions & 0 deletions actions/active-step-workflow/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
# Active Step Workflow :package:

A GitHub Action that determines the current step of a GitHub Skills exercise by analyzing enabled workflows in the repository.

This action identifies the current step by finding enabled workflows that match the "Step X" naming pattern and extracts the step number.

## Inputs ⚙️

| Name | Description | Required | Default |
| ------------------ | -------------------------------- | -------- | --------------------- |
| `github-token` | GitHub token for API access | No | `${{ github.token }}` |
| `workflow-pattern` | Regex pattern for step workflows | No | `^Step \\d+$` |

## Outputs 📤

| Name | Description |
| --------------- | ------------------------------------------------------------------------------------ |
| `current-step` | The current step number (string) |
| `workflow-name` | Name of the current step workflow file (primary workflow if multiple with same step) |

## Usage 🚀

```yaml
steps:
- name: Get active step workflow
id: step-info
uses: skills/exercise-toolkit/actions/active-step-workflow@<git-tag>

- name: Use the step information
run: |
echo "Currently on step: ${{ steps.step-info.outputs.current-step }}"
echo "Workflow name: ${{ steps.step-info.outputs.workflow-name }}"
```

## Behavior 🔍

- **Detects enabled workflows**: Scans all repository workflows and identifies those in `active` state
- **Matches step pattern**: Filters workflows by the "Step X" naming pattern (e.g., "Step 0", "Step 3")
- **Single enabled step**: Returns that step number
- **Multiple enabled steps with same number**: Returns the shared step number
- **Multiple enabled steps with different numbers**: Fails with descriptive error listing all enabled steps
- **No enabled step workflows**: Fails with descriptive error


## Permissions 🔐

This action requires the following permissions:

```yaml
permissions:
actions: read
```
84 changes: 84 additions & 0 deletions actions/active-step-workflow/action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
name: Active Step Workflow
description: Determines the current step of a GitHub Skills exercise by analyzing enabled workflows

inputs:
github-token:
description: GitHub token for API access
default: ${{ github.token }}
required: false
workflow-pattern:
description: Regex pattern for step workflows
required: false
default: '^Step \\d+$'

outputs:
current-step:
description: The current step number
value: ${{ steps.get-step.outputs.current-step }}
workflow-name:
description: Name of the current step workflow file
value: ${{ steps.get-step.outputs.workflow-name }}

runs:
using: composite
steps:
- name: Get current step from enabled workflows
id: get-step
uses: actions/github-script@v7
with:
github-token: ${{ inputs.github-token }}
script: |
const pattern = new RegExp('${{ inputs.workflow-pattern }}');

// Get all workflows
const { data: workflows } = await github.rest.actions.listRepoWorkflows({
owner: context.repo.owner,
repo: context.repo.repo
});

// Log all workflows found
console.log(`Found ${workflows.workflows.length} total workflows:`);
workflows.workflows.forEach(workflow => {
console.log(` - ${workflow.name} (state: ${workflow.state})`);
});

// Log the first workflow with all fields for debugging
if (workflows.workflows.length > 0) {
console.log('First workflow object with all fields:');
console.log(JSON.stringify(workflows.workflows[0], null, 2));
}

// Find enabled step workflows
const enabledSteps = workflows.workflows
.filter(workflow => workflow.state === 'active' && pattern.test(workflow.name))
.map(workflow => {
// Match "Step X" format
const match = workflow.name.match(/^Step (\d+)$/);
return {
name: workflow.name,
stepNumber: match ? match[1] : null
};
})
.filter(step => step.stepNumber !== null);

if (enabledSteps.length === 0) {
core.setFailed('No enabled step workflows found');
return;
}

// Check if all enabled steps have the same base number
const uniqueStepNumbers = [...new Set(enabledSteps.map(step => step.stepNumber))];

if (uniqueStepNumbers.length > 1) {
core.setFailed(`Multiple different step numbers enabled: ${uniqueStepNumbers.join(', ')}`);
return;
}

const currentStep = uniqueStepNumbers[0];
const primaryWorkflow = enabledSteps.find(step => step.name.startsWith(`${currentStep}-`)) || enabledSteps[0];

core.setOutput('current-step', currentStep);
core.setOutput('workflow-name', primaryWorkflow.name);

console.log(`Current step: ${currentStep}`);
console.log(`Primary workflow: ${primaryWorkflow.name}`);