diff --git a/actions/active-step-workflow/README.md b/actions/active-step-workflow/README.md new file mode 100644 index 0000000..6a247c3 --- /dev/null +++ b/actions/active-step-workflow/README.md @@ -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@ + + - 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 +``` diff --git a/actions/active-step-workflow/action.yml b/actions/active-step-workflow/action.yml new file mode 100644 index 0000000..bcc3057 --- /dev/null +++ b/actions/active-step-workflow/action.yml @@ -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}`);