Skip to content

Commit

Permalink
feat: workflow actions (#38)
Browse files Browse the repository at this point in the history
  • Loading branch information
dsanders11 authored Oct 29, 2024
1 parent ac80511 commit 438b25e
Show file tree
Hide file tree
Showing 33 changed files with 48,838 additions and 1 deletion.
40 changes: 40 additions & 0 deletions .github/workflows/integration-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -360,6 +360,46 @@ jobs:
assert.strictEqual('${{ steps.get-project.outputs.description }}', 'New Description');
assert.strictEqual('${{ steps.get-project.outputs.readme }}', 'This is the readme');
- name: Find Workflow
uses: ./find-workflow/
id: find-workflow
with:
owner: ${{ matrix.owner }}
project-number: ${{ steps.copy-project.outputs.number }}
name: 'Item closed'
token: ${{ steps.get-auth-token.outputs.token }}

- name: Check Workflow Values
uses: ./github-script/
with:
script: |
const assert = require('node:assert');
assert.strictEqual('${{ steps.find-workflow.outputs.name }}', 'Item closed');
assert.strictEqual(${{ steps.find-workflow.outputs.enabled }}, true);
assert.strictEqual('${{ steps.find-workflow.outputs.project-id }}', '${{ steps.get-project.outputs.id }}');
- name: Get Workflow
uses: ./get-workflow/
id: get-workflow
with:
owner: ${{ matrix.owner }}
project-number: ${{ steps.copy-project.outputs.number }}
number: ${{ steps.find-workflow.outputs.number }}
token: ${{ steps.get-auth-token.outputs.token }}

- name: Check Workflow Values
uses: ./github-script/
with:
script: |
const assert = require('node:assert');
assert.strictEqual('${{ steps.get-workflow.outputs.id }}', '${{ steps.find-workflow.outputs.id }}');
assert.strictEqual('${{ steps.get-workflow.outputs.name }}', 'Item closed');
assert.strictEqual('${{ steps.get-workflow.outputs.number }}', '${{ steps.find-workflow.outputs.number }}');
assert.strictEqual(${{ steps.get-workflow.outputs.enabled }}, true);
assert.strictEqual('${{ steps.get-workflow.outputs.project-id }}', '${{ steps.get-project.outputs.id }}');
- name: Close Project
uses: ./close-project/
id: close-project
Expand Down
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,10 @@ private repositories the PAT must also have the `repo` scope.
| [`project-actions/edit-item`](edit-item) | Edit an item on a project |
| [`project-actions/edit-project`](edit-project) | Edit a project |
| [`project-actions/find-project`](find-project) | Find a project |
| [`project-actions/find-workflow`](find-workflow) | Find a project workflow |
| [`project-actions/get-item`](get-item) | Get an item on a project |
| [`project-actions/get-project`](get-project) | Get a project |
| [`project-actions/get-workflow`](get-workflow) | Get a project workflow |
| [`project-actions/github-script`](github-script) | Modify projects programmatically |
| [`project-actions/link-project`](link-project) | Link a project to a repository or team |

Expand Down
123 changes: 123 additions & 0 deletions __tests__/find-workflow.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
import { beforeEach, describe, expect, it, vi } from 'vitest';

import * as core from '@actions/core';

import * as index from '../src/find-workflow';
import { findWorkflow } from '../src/lib';
import { mockGetBooleanInput, mockGetInput } from './utils';

vi.mock('@actions/core');
vi.mock('../src/lib');

// Spy the action's entrypoint
const findWorkflowActionSpy = vi.spyOn(index, 'findWorkflowAction');

const owner = 'dsanders11';
const projectNumber = '94';
const name = 'workflow-name';
const projectId = 'project-id';
const workflowId = 'workflow-id';
const workflowNumber = 42;

describe('findWorkflowAction', () => {
beforeEach(() => {
vi.clearAllMocks();
});

it('requires the project-number input', async () => {
mockGetInput({ owner });

await index.findWorkflowAction();
expect(findWorkflowActionSpy).toHaveReturned();

expect(core.setFailed).toHaveBeenCalledTimes(1);
expect(core.setFailed).toHaveBeenLastCalledWith(
'Input required and not supplied: project-number'
);
});

it('requires the name input', async () => {
mockGetInput({ owner, 'project-number': projectNumber });

await index.findWorkflowAction();
expect(findWorkflowActionSpy).toHaveReturned();

expect(core.setFailed).toHaveBeenCalledTimes(1);
expect(core.setFailed).toHaveBeenLastCalledWith(
'Input required and not supplied: name'
);
});

it('handles workflow not found', async () => {
mockGetInput({ owner, 'project-number': projectNumber, name });
mockGetBooleanInput({ 'fail-if-workflow-not-found': true });
vi.mocked(findWorkflow).mockResolvedValue(null);

await index.findWorkflowAction();
expect(findWorkflowActionSpy).toHaveReturned();

expect(core.setFailed).toHaveBeenCalledTimes(1);
expect(core.setFailed).toHaveBeenLastCalledWith(
`Workflow not found: ${name}`
);
});

it('can ignore item not found', async () => {
mockGetInput({ owner, 'project-number': projectNumber, name });
mockGetBooleanInput({ 'fail-if-workflow-not-found': false });
vi.mocked(findWorkflow).mockResolvedValue(null);

await index.findWorkflowAction();
expect(findWorkflowActionSpy).toHaveReturned();

expect(core.setFailed).not.toHaveBeenCalled();
expect(core.setOutput).not.toHaveBeenCalled();
});

it('handles generic errors', async () => {
mockGetInput({ owner, 'project-number': projectNumber, name });
vi.mocked(findWorkflow).mockImplementation(() => {
throw new Error('Server error');
});

await index.findWorkflowAction();
expect(findWorkflowActionSpy).toHaveReturned();

expect(core.setFailed).toHaveBeenCalledTimes(1);
expect(core.setFailed).toHaveBeenLastCalledWith('Server error');
});

it('stringifies non-errors', async () => {
mockGetInput({ owner, 'project-number': projectNumber, name });
vi.mocked(findWorkflow).mockImplementation(() => {
throw 42; // eslint-disable-line no-throw-literal
});

await index.findWorkflowAction();
expect(findWorkflowActionSpy).toHaveReturned();

expect(core.setFailed).toHaveBeenCalledTimes(1);
expect(core.setFailed).toHaveBeenLastCalledWith('42');
});

it('sets output', async () => {
mockGetInput({ owner, 'project-number': projectNumber, name });
vi.mocked(findWorkflow).mockResolvedValue({
id: workflowId,
name,
number: workflowNumber,
enabled: true,
projectId
});

await index.findWorkflowAction();
expect(findWorkflowActionSpy).toHaveReturned();

expect(core.setOutput).toHaveBeenCalledTimes(5);
expect(core.setOutput).toHaveBeenCalledWith('id', workflowId);
expect(core.setOutput).toHaveBeenCalledWith('name', name);
expect(core.setOutput).toHaveBeenCalledWith('number', workflowNumber);
expect(core.setOutput).toHaveBeenCalledWith('enabled', true);
expect(core.setOutput).toHaveBeenCalledWith('project-id', projectId);
});
});
123 changes: 123 additions & 0 deletions __tests__/get-workflow.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
import { beforeEach, describe, expect, it, vi } from 'vitest';

import * as core from '@actions/core';

import * as index from '../src/get-workflow';
import { getWorkflow } from '../src/lib';
import { mockGetBooleanInput, mockGetInput } from './utils';

vi.mock('@actions/core');
vi.mock('../src/lib');

// Spy the action's entrypoint
const getWorkflowActionSpy = vi.spyOn(index, 'getWorkflowAction');

const owner = 'dsanders11';
const projectNumber = '94';
const name = 'workflow-name';
const projectId = 'project-id';
const workflowId = 'workflow-id';
const number = '42';

describe('getWorkflowAction', () => {
beforeEach(() => {
vi.clearAllMocks();
});

it('requires the project-number input', async () => {
mockGetInput({ owner });

await index.getWorkflowAction();
expect(getWorkflowActionSpy).toHaveReturned();

expect(core.setFailed).toHaveBeenCalledTimes(1);
expect(core.setFailed).toHaveBeenLastCalledWith(
'Input required and not supplied: project-number'
);
});

it('requires the number input', async () => {
mockGetInput({ owner, 'project-number': projectNumber });

await index.getWorkflowAction();
expect(getWorkflowActionSpy).toHaveReturned();

expect(core.setFailed).toHaveBeenCalledTimes(1);
expect(core.setFailed).toHaveBeenLastCalledWith(
'Input required and not supplied: number'
);
});

it('handles workflow not found', async () => {
mockGetInput({ owner, 'project-number': projectNumber, number });
mockGetBooleanInput({ 'fail-if-workflow-not-found': true });
vi.mocked(getWorkflow).mockResolvedValue(null);

await index.getWorkflowAction();
expect(getWorkflowActionSpy).toHaveReturned();

expect(core.setFailed).toHaveBeenCalledTimes(1);
expect(core.setFailed).toHaveBeenLastCalledWith(
`Workflow not found: ${number}`
);
});

it('can ignore item not found', async () => {
mockGetInput({ owner, 'project-number': projectNumber, number });
mockGetBooleanInput({ 'fail-if-workflow-not-found': false });
vi.mocked(getWorkflow).mockResolvedValue(null);

await index.getWorkflowAction();
expect(getWorkflowActionSpy).toHaveReturned();

expect(core.setFailed).not.toHaveBeenCalled();
expect(core.setOutput).not.toHaveBeenCalled();
});

it('handles generic errors', async () => {
mockGetInput({ owner, 'project-number': projectNumber, number });
vi.mocked(getWorkflow).mockImplementation(() => {
throw new Error('Server error');
});

await index.getWorkflowAction();
expect(getWorkflowActionSpy).toHaveReturned();

expect(core.setFailed).toHaveBeenCalledTimes(1);
expect(core.setFailed).toHaveBeenLastCalledWith('Server error');
});

it('stringifies non-errors', async () => {
mockGetInput({ owner, 'project-number': projectNumber, number });
vi.mocked(getWorkflow).mockImplementation(() => {
throw 42; // eslint-disable-line no-throw-literal
});

await index.getWorkflowAction();
expect(getWorkflowActionSpy).toHaveReturned();

expect(core.setFailed).toHaveBeenCalledTimes(1);
expect(core.setFailed).toHaveBeenLastCalledWith('42');
});

it('sets output', async () => {
mockGetInput({ owner, 'project-number': projectNumber, number });
vi.mocked(getWorkflow).mockResolvedValue({
id: workflowId,
name,
number: parseInt(number),
enabled: true,
projectId
});

await index.getWorkflowAction();
expect(getWorkflowActionSpy).toHaveReturned();

expect(core.setOutput).toHaveBeenCalledTimes(5);
expect(core.setOutput).toHaveBeenCalledWith('id', workflowId);
expect(core.setOutput).toHaveBeenCalledWith('name', name);
expect(core.setOutput).toHaveBeenCalledWith('number', parseInt(number));
expect(core.setOutput).toHaveBeenCalledWith('enabled', true);
expect(core.setOutput).toHaveBeenCalledWith('project-id', projectId);
});
});
Loading

0 comments on commit 438b25e

Please sign in to comment.