Skip to content

Commit

Permalink
wip(youtrack): wip youtrack issues
Browse files Browse the repository at this point in the history
  • Loading branch information
CanisHelix committed Feb 26, 2024
1 parent e01272d commit 4175b51
Show file tree
Hide file tree
Showing 7 changed files with 189 additions and 0 deletions.
2 changes: 2 additions & 0 deletions core/server/server.js
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,7 @@ const publicConfigSchema = Joi.object({
sonar: defaultService,
teamcity: defaultService,
weblate: defaultService,
youtrack: defaultService,
trace: Joi.boolean().required(),
}).required(),
cacheHeaders: { defaultCacheLengthSeconds: nonNegativeInteger },
Expand Down Expand Up @@ -205,6 +206,7 @@ const privateConfigSchema = Joi.object({
influx_password: Joi.string(),
weblate_api_key: Joi.string(),
youtube_api_key: Joi.string(),
youtrack_token: Joi.string(),
}).required()
const privateMetricsInfluxConfigSchema = privateConfigSchema.append({
influx_username: Joi.string().required(),
Expand Down
9 changes: 9 additions & 0 deletions doc/server-secrets.md
Original file line number Diff line number Diff line change
Expand Up @@ -364,6 +364,15 @@ and create an API key for the YouTube Data API v3.

[youtube credentials]: https://console.developers.google.com/apis/credentials

### YouTrack

- `YOUTRACK_ORIGINS` (yml: `public.services.youtrack.authorizedOrigins`)
- `YOUTRACK_TOKEN` (yml: `private.youtrack_token`)

A Youtrack [Permanent Access Token][youtrack-pat] is required for accessing private content. If you need a Youtrack token for your self-hosted Shields server then we recommend limiting the scopes to the minimal set necessary for the badges you are using.

[youtrack-pat]: https://www.jetbrains.com/help/youtrack/devportal/Manage-Permanent-Token.html

## Error reporting

- `SENTRY_DSN` (yml: `private.sentry_dsn`)
Expand Down
22 changes: 22 additions & 0 deletions services/youtrack/youtrack-base.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { BaseJsonService } from '../index.js'

export default class YoutrackBase extends BaseJsonService {
static auth = {
passKey: 'youtrack_token',
serviceKey: 'youtrack',
}

async fetch({ url, options, schema, httpErrors }) {
console.log(url)
console.log(options)

return this._requestJson(
this.authHelper.withBearerAuthHeader({
schema,
url,
options,
httpErrors: { 500: 'invalid query' },
}),
)
}
}
48 changes: 48 additions & 0 deletions services/youtrack/youtrack-base.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import Joi from 'joi'
import { expect } from 'chai'
import nock from 'nock'
import { cleanUpNockAfterEach, defaultContext } from '../test-helpers.js'
import YoutrackBase from './youtrack-base.js'

class DummyYoutrackService extends YoutrackBase {
static route = { base: 'fake-base' }

async handle() {
const data = await this.fetch({
schema: Joi.any(),
url: 'https://youtrack.jetbrains.com//api/issuesGetter/count?fields=count',
})
return { message: data.message }
}
}

describe('YoutrackBase', function () {
describe('auth', function () {
cleanUpNockAfterEach()

const config = {
public: {
services: {
youtrack: {
authorizedOrigins: ['https://youtrack.jetbrains.com'],
},
},
},
private: {
youtrack_token: 'fake-key',
},
}

it('sends the auth information as configured', async function () {
const scope = nock('https://youtrack.jetbrains.com')
.get('/api/issuesGetter/count?fields=count')
.matchHeader('Authorization', 'Bearer fake-key')
.reply(200, { message: 'fake message' })
expect(
await DummyYoutrackService.invoke(defaultContext, config, {}),
).to.not.have.property('isError')

scope.done()
})
})
})
6 changes: 6 additions & 0 deletions services/youtrack/youtrack-helper.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
const description = `
By default this badge looks for projects on [youtrack.jetbrains.com](https://youtrack.jetbrains.com).
To specify a self-hosted instance, use the \`youtrack_url\` query param.
`

export { description }
93 changes: 93 additions & 0 deletions services/youtrack/youtrack-issues.service.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
import Joi from 'joi'
import { pathParam, queryParam } from '../index.js'
import { optionalUrl } from '../validators.js'
import { metric } from '../text-formatters.js'
import { description } from './youtrack-helper.js'
import YoutrackBase from './youtrack-base.js'

const schema = Joi.array().items(
Joi.object({
count: Joi.number().required(),
type: Joi.string().required(),
}),
)

const queryParamSchema = Joi.object({
query: Joi.string(),
youtrack_url: optionalUrl,
}).required()

export default class YoutrackIssues extends YoutrackBase {
static category = 'issue-tracking'

static route = {
base: 'youtrack/issues',
pattern: ':project+',
queryParamSchema,
}

static openApi = {
'/youtrack/issues/{project}': {
get: {
summary: 'Youtrack Issues',
description,
parameters: [
pathParam({
name: 'project',
example: 'RIDER',
}),
queryParam({
name: 'youtrack_url',
example: 'https://youtrack.jetbrains.com',
}),
queryParam({
name: 'query',
example: 'bug #Unresolved',
description: 'A valid YouTrack search query.',
}),
],
},
},
}

static defaultBadgeData = { label: 'issues', color: 'informational' }

static render({ count }) {
return {
label: 'issues',
message: metric(count),
color: count > 0 ? 'yellow' : 'brightgreen',
}
}

async fetch({ baseUrl, query }) {
// https://www.jetbrains.com.cn/en-us/help/youtrack/devportal/resource-api-issuesGetter-count.html
return super.fetch({
schema,
options: {
method: 'POST',
searchParams: {
query,
},
},
url: `${baseUrl}/api/issuesGetter/count?fields=count`,
})
}

async handle(
{ project },
{ youtrack_url: baseUrl = 'https://youtrack.jetbrains.com', query },
) {
const { res } = await this.fetch({
baseUrl,
query: `project: ${project} ${query}`,
})

console.log(res)

const data = this.constructor._validate(res.headers, schema)

const count = data.count()
return this.constructor.render({ count })
}
}
9 changes: 9 additions & 0 deletions services/youtrack/youtrack-issues.tester.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { createServiceTester } from '../tester.js'
import { isMetric } from '../test-validators.js'

export const t = await createServiceTester()

t.create('Issues (RIDER)').get('/RIDER?query=#Unresolved').expectBadge({
label: 'issues',
message: isMetric,
})

0 comments on commit 4175b51

Please sign in to comment.