Skip to content
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

Feature assign users to cards #24

Merged
merged 3 commits into from
Sep 29, 2022
Merged
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
26 changes: 26 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,32 @@ Create a new card
#### Outputs
* error; error message if failed
-----------
### Assign User
#### Input Params
|name|description|required|
|----|-----------|--------|
|host|LeanKit Url (https://mycompany.leankit.com)|yes|
|apiToken|API token for your LeanKit board|yes|
|cardIds|Comma-separated list of cardIds to update|yes|
|assignUserIds|Comma-separated list of userIds to that will be assigned to the cards||
|unassignUserIds|Comma-separated list of userIds to that will be unassigned from the cards||
|wipOverrideComment|WIP Override reason to provide, in case user is at WIP||

Although they are not technically required, you must specify either `assignUserIds` or `unassignUserIds`. Validation will fail if neither is present.

#### Example workflow step
```
- name: assign users to cards
uses: leankit/github-actions/assignUsers@v1
with:
host: https://YOUR-ACCOUNT.leankit.com/
apiToken: ${{ secrets.MY_API_TOKEN }}
cardIds: 1234,5678
assignUserIds: 1111,2222
```
#### Outputs
* error; error message if failed
-----------
### Validate Custom Fields
Fail if specified custom fields do not have a value on a particular card
#### Input Params
Expand Down
2 changes: 1 addition & 1 deletion addComment/dist/index.js

Large diffs are not rendered by default.

22 changes: 22 additions & 0 deletions assignUsers/action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
name: "Assign users to LeanKit cards"
description: "Assign or unassign users to cards"
inputs:
host:
description: LeanKit Url (https://mycompany.leankit.com)
required: true
apiToken:
description: Api token for your LeanKit board
required: true
cardIds:
description: List of card ids
required: true
assignUserIds:
description: List of user ids to assign to the cards
unassignUserIds:
description: List of user ids to unassign from the cards
outputs:
error:
description: Status message for errors
runs:
using: "node16"
main: "dist/index.js"
1 change: 1 addition & 0 deletions assignUsers/dist/index.js

Large diffs are not rendered by default.

38 changes: 38 additions & 0 deletions assignUsers/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
"use strict";

const leankitApiFactory = require( "../leankit/api" );
const { getInputParams, reportError, validateLeankitUrl } = require( "../leankit/helpers" );

function parseList( list ) {
if ( !list ) {
return [];
}
return list.trim().split( /\s*,\s*/ );
}

( async () => {
const [
host,
apiToken,
cardIds,
assignUserIds,
unassignUserIds,
wipOverrideComment
] = getInputParams( { required: [ "host", "apiToken", "cardIds" ], optional: [ "assignUserIds", "unassignUserIds", "wipOverrideComment" ] } );

validateLeankitUrl( "host", host );

if ( !assignUserIds && !unassignUserIds ) {
throw new Error( "Either assignUserIds or unassignUserIds must be specified" );
}

const cardIdList = parseList( cardIds );
const userIdsToAssign = parseList( assignUserIds );
const userIdsToUnassign = parseList( unassignUserIds );


const { assignUsers } = leankitApiFactory( host, apiToken );
await assignUsers( cardIdList, userIdsToAssign, userIdsToUnassign, wipOverrideComment );
} )().catch( ex => {
reportError( "assignUsers", ex.message );
} );
136 changes: 136 additions & 0 deletions assignUsers/index.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
"use strict";

const { sinon, proxyquire } = testHelpers;

describe( "assignUsers", () => {
let github, apiFactory, assignUsers, getInputParams, validateLeankitUrl, reportError;
function init() {
github = {
context: {
payload: {}
}
};

getInputParams = sinon.stub().returns( [
"HOST",
"API_TOKEN",
" c1,c2, c3",
"USERS_TO_ASSIGN",
"USERS_TO_UNASSIGN",
"WIPOVERRIDE"
] )
reportError = sinon.stub();
validateLeankitUrl = sinon.stub();
assignUsers = sinon.stub();
apiFactory = sinon.stub().returns( {
assignUsers
} );
}

function action() {
return proxyquire( "~/assignUsers", {
"../leankit/api": apiFactory,
"../leankit/helpers": {
getInputParams,
reportError,
validateLeankitUrl
}
} );
}

describe( "validation", () => {
describe( "when validation fails", () => {
beforeEach( async () => {
init();
getInputParams.throws( new Error( "Input required and not supplied: SOME PARAM" ) );
await action();
} );

it( "should validate params", () => {
getInputParams.should.be.calledOnce.and.calledWith({
required: [
"host",
"apiToken",
"cardIds"
],
optional: [
"assignUserIds",
"unassignUserIds",
"wipOverrideComment"
]
} );
} );

it( "should report error", async () => {
reportError.should.be.calledOnce.and.calledWith( "assignUsers", "Input required and not supplied: SOME PARAM" );
} );
} );

describe("when neither assignUserIds nor unassignUserIds is present", () => {
beforeEach( async () => {
init();
getInputParams.returns( [ "HOST" ] );
await action();
} );

it( "should report error", async () => {
reportError.should.be.calledOnce.and.calledWith( "assignUsers", "Either assignUserIds or unassignUserIds must be specified" );
} );
});

describe( "with invalid host", () => {
beforeEach( async () => {
init();
getInputParams.returns( [ "INVALID_HOST" ] );
validateLeankitUrl.throws( new Error( "Expected a leankit url for 'host' action parameter" ))
await action();
} );

it( "should validate host param", () => {
validateLeankitUrl.should.be.calledOnce.and.calledWith( "host", "INVALID_HOST");
} );

it( "should report error", () => {
reportError.should.be.calledOnce.and.calledWith( "assignUsers", "Expected a leankit url for 'host' action parameter" );
} );
} );
} );

describe( "with valid parameters", () => {
beforeEach( async () => {
init();
await action();
} );

it( "should get leankit api", () => {
apiFactory.should.be.calledOnce.and.calledWith( "HOST", "API_TOKEN" );
} );

it( "should assign the users to the cards", () => {
assignUsers.should.be.calledOnce.and.calledWith( ["c1", "c2", "c3"], ["USERS_TO_ASSIGN"], ["USERS_TO_UNASSIGN"], "WIPOVERRIDE" );
} );
} );

describe( "with an empty parameter", () => {
beforeEach( async () => {
init();
getInputParams = sinon.stub().returns( [
"HOST",
"API_TOKEN",
" c1,c2, c3",
"USERS_TO_ASSIGN",
"",
"WIPOVERRIDE"
] )
await action();
} );

it( "should get leankit api", () => {
apiFactory.should.be.calledOnce.and.calledWith( "HOST", "API_TOKEN" );
} );

it( "should assign the users to the cards", () => {
assignUsers.should.be.calledOnce.and.calledWith( ["c1", "c2", "c3"], ["USERS_TO_ASSIGN"], [], "WIPOVERRIDE" );
} );
} );
} );
2 changes: 1 addition & 1 deletion blockCard/dist/index.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion createCard/dist/index.js

Large diffs are not rendered by default.

23 changes: 23 additions & 0 deletions leankit/api.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,29 @@ module.exports = ( _baseUrl, apiToken ) => {
headers: { Authorization }
} ).json();
},
assignUsers: ( cardIds, userIdsToAssign, userIdsToUnassign, wipOverrideComment ) => {
const body = {
cardIds
};

if ( userIdsToAssign && userIdsToAssign.length ) {
body.userIdsToAssign = userIdsToAssign;
}

if ( userIdsToUnassign && userIdsToUnassign.length ) {
body.userIdsToUnassign = userIdsToUnassign;
}

if ( wipOverrideComment ) {
body.wipOverrideComment = wipOverrideComment;
}

return got( `${ baseUrl }/io/card/assign`, {
method: "POST",
json: body,
headers: { Authorization }
} ).json();
},
addComment: ( cardId, comment ) => {
return got( `${ baseUrl }/io/card/${ cardId }/comment`, {
method: "POST",
Expand Down
50 changes: 50 additions & 0 deletions leankit/api.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,56 @@ describe( "leankit/api", () => {
} );
} );

describe( "assignUsers", () => {
describe("when providing all parameters", () => {
beforeEach( async () => {
await api.assignUsers( "CARDIDS", "USERS_TO_ASSIGN", "USERS_TO_UNASSIGN", "OVERRIDE" );
} );

it( "should post /io/card/move with expected params", async () => {
got.should.be.calledOnce.and.calledWith( "BASEURL/io/card/assign", {
method: "POST",
json: {
cardIds: "CARDIDS",
userIdsToAssign: "USERS_TO_ASSIGN",
userIdsToUnassign: "USERS_TO_UNASSIGN",
wipOverrideComment: "OVERRIDE"
},
headers: {
Authorization: "Bearer APITOKEN"
}
})
} );

it( "should use json", () => {
got.json.should.be.calledOnce();
} );
});

describe("when providing minimal parameters", () => {
beforeEach( async () => {
await api.assignUsers( "CARDIDS" );
} );

it( "should post /io/card/move with expected params", async () => {
got.should.be.calledOnce.and.calledWith( "BASEURL/io/card/assign", {
method: "POST",
json: {
cardIds: "CARDIDS"
},
headers: {
Authorization: "Bearer APITOKEN"
}
})
} );

it( "should use json", () => {
got.json.should.be.calledOnce();
} );
});

} );

describe( "addComment", () => {
beforeEach( async () => {
await api.addComment( "CARDID", "COMMENT" );
Expand Down
2 changes: 1 addition & 1 deletion moveCard/dist/index.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
"cover": "nyc -r text-summary -r html -- npm run test:only",
"cover:ci": "nyc -r text-summary -r html -- npm run test:ci",
"cover:show": "open \"file://$PWD/coverage/index.html\"",
"build": "for i in blockCard moveCard createCard addComment validateCustomFields; do ncc build ./${i%%} -m -o ./${i%%}/dist; done",
"build": "for i in blockCard moveCard createCard addComment validateCustomFields assignUsers; do ncc build ./${i%%} -m -o ./${i%%}/dist; done",
"preact": "npm run build",
"act": "act repository_dispatch -e test_payload.json"
},
Expand Down
2 changes: 1 addition & 1 deletion validateCustomFields/dist/index.js

Large diffs are not rendered by default.