-
Notifications
You must be signed in to change notification settings - Fork 2.4k
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
feat(datasource/azure-pipelines-tasks): Azure DevOps API based datasource #32966
base: main
Are you sure you want to change the base?
feat(datasource/azure-pipelines-tasks): Azure DevOps API based datasource #32966
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are you sure that this can replace the existing functionality in a backwards-compatible way?
How efficient is this approach? e.g. how many API calls and how many MB should it require each run?
Any caching possible?
return { releases }; | ||
if (platform === 'azure' && endpoint) { | ||
const auth = Buffer.from( | ||
`renovate:${process.env.RENOVATE_TOKEN}`, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's not certain that RENOVATE_TOKEN is defined. Instead, use hostRules
to get the token
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have used the GlobalConfig and hostRules based on other data sources but I don't know if I have done it right.
I don't see any API documentation, I've only seen the pages you recommend here: https://github.com/renovatebot/renovate/blob/main/.github/contributing.md#code
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@rarkins can you answer please?
Doesn't the caching already do it with the code that was there? And the backwards-compatible thing is for when these conditions are not met that it at least does what it did before: I've also added more tests to compare function so we have 100% code coverage. |
So it caches once per 24 hours, if the user has persistent datasource caching? (note: most people running Renovate in pipelines do not have such persistence) I don't understand your answer to my backwards-compatibility question. Is it replacing existing logic, or adding to it? If it's replacing it, is it fully backwards compatible? How many API calls and how many MB should it require? |
@rarkins is there any documentation on how to implement persistence? Without documentation or examples I will hardly be able to do it since it is the first time I do a PR. As I said, the persistence there was already implemented, I haven't touched anything in this PR.
If these conditions are met: https://github.com/renovatebot/renovate/pull/32966/files#diff-2ef2acf656366f4dd2036d71f106b4d8d0b41cd546e1349942a4e40efffde808R36 It will use the new logic, otherwise it will do what it did before. The difference is that if you work against Azure DevOps and provide a PAT (personal access token), it will resolve the task versions according to your organization and not to a static file as now (https://github.com/renovatebot/azure-devops-marketplace/blob/main/azure-pipelines-builtin-tasks.json). Not all organizations propagate task updates at the same time and with the current implementation the problem is that it suggests updates that have not yet been propagated in your organization (= do not exist yet) and it is very confusing. In the discussion of where this PR comes from that I mention in my first post of this PR #24820 puts you in context of what I am trying to solve. One of the keys is here: renovatebot/azure-devops-marketplace#42 (comment)
The API (https://dev.azure.com/{org}/_apis/distributedtask/tasks/) resolves which are the latest versions of each task so that this call can be cached and used equally for all subsequent requests. In the tests that I add you can see an example of response. The MB depends on each organization, because in my organization I can have 5 third party extensions and another organization 50. This API lists the latest versions of the official/built-in tasks (same for all organizations) + those of third parties/marketplace (these are the ones that can not be measured, it depends on each organization). Example API result in my organization (built-in + third party installed): 1.93 MB |
const platform = GlobalConfig.get('platform'); | ||
const endpoint = GlobalConfig.get('endpoint'); | ||
const { token } = hostRules.find({ | ||
hostType: AzurePipelinesTasksDatasource.id, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure this is set, you might want to drop this line
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do you mean the line to call "find" with “hostType”? If I remove it I think it won't work, if you see the implementation of that "find" method both the “hostType” and “url” fields have to be defined, unless I'm wrong, as I say, I'm new to TS:
renovate/lib/util/host-rules.ts
Line 133 in 98693e2
if ([search.hostType, search.url].every(is.falsy)) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@rarkins can you answer please?
const releases = versions.map((version) => ({ version })); | ||
return { releases }; | ||
if (platform === 'azure' && endpoint && token) { | ||
const auth = Buffer.from(`renovate:${token}`).toString('base64'); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
username doesn't matter for this endpoint?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In this link it mentions it but if you look at the code example, it doesn't even use it: https://learn.microsoft.com/en-us/rest/api/azure/devops/?view=azure-devops-rest-7.2#assemble-the-request
I personally use that API and I know that the user is not necessary and you can pass any value.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@rarkins can you answer please?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Best to use zod parsing to ensure the structure matches what we expect
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you give an example of that I have to change? I'm new to TS, I don't even know what is "zod parsing". Thanks.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@zharinov could you guide? Or even PR?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@rarkins done! I've figured out what the whole zod thing is about.
ttlMinutes: 24 * 60, | ||
}) | ||
async getFallbackTasks<ResT>(url: string): Promise<ResT> { | ||
const { body } = await this.http.getJson<ResT>(url); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Our http functions accept schema object, so internally it will check against it and return the proper type, so you don't have to specify generic
UPD. I see you use it above, please do here also. As a rule, your code should end up using zero generics, with all the types inferred from schema.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was going to do it but I don't know how to convert Record<string, string[]> to a schema.
That code you mention is not from this PR, we are talking about the fallback that already existed: https://github.com/renovatebot/azure-devops-marketplace/blob/main/azure-pipelines-builtin-tasks.json
I have simply split the methods in 2 so that “the new” uses schemas.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Use z.record(z.string().array())
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done, thanks!
@rarkins @zharinov I think it's all done, I just need you to answer some doubts you had to see if any more changes are needed or not. Besides, I don't understand this workflow, it fails by adding files to the tests? https://github.com/renovatebot/renovate/actions/runs/12457890306/job/34782564100 |
We prefer inline test fixtures instead of dedicated file fixtures, so the test checks for that. It's possible to override and still merge |
I suppose that in this case, as it stands, it is correct and the inline is only for when there is little content. |
Changes
Initially as I do not have much experience of the Renovate API, I tried (looking at other code examples in this repository) that only changes the behavior for the case that you are running it from
platform: azure
because this way there is no need to create any new variable and it can use the values ofRENOVATE_PLATFORM
,RENOVATE_ENDPOINT
andRENOVATE_TOKEN
.This PR does not solve the case that platform is a value different to
azure
(in that case it makes fallback to what it was already doing) because for that case I suppose that new variables will be needed and I consider that this can go in another future PR because it requires more analysis.Context
The need comes from the fact that we currently take as a source of data the static files that are generated from this repository: https://github.com/renovatebot/azure-devops-marketplace
The problem is that task updates are not propagated at the same speed to all Azure Devops organizations so there are times when renovate mistakenly suggests updating to versions of tasks that do not exist in the organization and if you do not know why it happens it is very confusing.
There is an open discussion: #24820
Documentation (please check one with an [x])
How I've tested my work (please select one)
I have verified these changes via: