Improve Golang annotation positioning, and improve project structure
This commit is contained in:
parent
16c28ee0b8
commit
ce15a110de
|
@ -1,3 +1,4 @@
|
||||||
|
import { AnnotationSource } from './annotation-source'
|
||||||
import { Dependency } from './dependency'
|
import { Dependency } from './dependency'
|
||||||
|
|
||||||
export class AnnotationResult {
|
export class AnnotationResult {
|
||||||
|
@ -29,3 +30,22 @@ export class AnnotationResult {
|
||||||
this.endLine = endLine
|
this.endLine = endLine
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function createAnnotation(
|
||||||
|
annotationSource: AnnotationSource,
|
||||||
|
annotationLevel: 'notice' | 'warning' | 'failure',
|
||||||
|
title: string,
|
||||||
|
message: string,
|
||||||
|
): AnnotationResult {
|
||||||
|
const { dependency, filename, line } = annotationSource
|
||||||
|
|
||||||
|
return new AnnotationResult(
|
||||||
|
title,
|
||||||
|
message,
|
||||||
|
annotationLevel,
|
||||||
|
dependency,
|
||||||
|
filename,
|
||||||
|
line,
|
||||||
|
line,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,7 @@
|
||||||
|
import { Dependency } from './dependency'
|
||||||
|
|
||||||
|
export interface AnnotationSource {
|
||||||
|
dependency: Dependency
|
||||||
|
filename: string
|
||||||
|
line: number
|
||||||
|
}
|
|
@ -1,10 +1,10 @@
|
||||||
import { Context } from 'probot' // eslint-disable-line no-unused-vars
|
import { Context } from 'probot' // eslint-disable-line no-unused-vars
|
||||||
import toml from 'toml'
|
import toml from 'toml'
|
||||||
|
|
||||||
import { AnalysisResult } from './analysis-result'
|
import { AnalysisResult } from './analysis-result'
|
||||||
|
import { createAnnotation } from './annotation-result'
|
||||||
|
import { AnnotationSource } from './annotation-source'
|
||||||
import { Dependency } from './dependency'
|
import { Dependency } from './dependency'
|
||||||
import { AnnotationSource,
|
|
||||||
createAnnotation,
|
|
||||||
findLineInFileContent } from './dependency-check'
|
|
||||||
|
|
||||||
export async function checkGopkgFileAsync(
|
export async function checkGopkgFileAsync(
|
||||||
analysisResult: AnalysisResult,
|
analysisResult: AnalysisResult,
|
||||||
|
@ -22,45 +22,94 @@ export async function checkGopkgFileAsync(
|
||||||
context.log.debug(`get contents response for ${gopkgLockFilename}: ${gopkgLockContentsResponse.status}`)
|
context.log.debug(`get contents response for ${gopkgLockFilename}: ${gopkgLockContentsResponse.status}`)
|
||||||
|
|
||||||
const gopkgTomlContents = Buffer.from(gopkgTomlContentsResponse.data.content, 'base64').toString('utf8')
|
const gopkgTomlContents = Buffer.from(gopkgTomlContentsResponse.data.content, 'base64').toString('utf8')
|
||||||
const gopkgTomlContentsToml = toml.parse(gopkgTomlContents)
|
|
||||||
const gopkgLockContents = Buffer.from(gopkgLockContentsResponse.data.content, 'base64').toString('utf8')
|
const gopkgLockContents = Buffer.from(gopkgLockContentsResponse.data.content, 'base64').toString('utf8')
|
||||||
const gopkgLockContentsToml = toml.parse(gopkgLockContents)
|
const gopkgLockContentsToml = toml.parse(gopkgLockContents)
|
||||||
|
|
||||||
await checkGoDependenciesAsync(
|
await checkGoDependenciesAsync(
|
||||||
gopkgTomlContents, gopkgLockContents,
|
gopkgTomlContents, gopkgLockContents,
|
||||||
getDependenciesFromGopkg(gopkgTomlContentsToml, gopkgLockContentsToml),
|
getDependenciesFromGopkg(gopkgLockContentsToml),
|
||||||
gopkgTomlFilename, gopkgLockFilename,
|
gopkgTomlFilename, gopkgLockFilename,
|
||||||
analysisResult)
|
analysisResult)
|
||||||
}
|
}
|
||||||
|
|
||||||
function getDependenciesFromGopkg(gopkgTomlContentsToml: any, gopkgLockContentsToml: any): Dependency[] {
|
interface GopkgLockProject {
|
||||||
|
digest: string,
|
||||||
|
name: string,
|
||||||
|
source?: string,
|
||||||
|
packages: string[],
|
||||||
|
pruneopts?: string,
|
||||||
|
|
||||||
|
revision: string,
|
||||||
|
branch?: string,
|
||||||
|
version?: string,
|
||||||
|
}
|
||||||
|
|
||||||
|
function getDependenciesFromGopkg(gopkgLockContentsToml: any): Dependency[] {
|
||||||
const dependencies: Dependency[] = []
|
const dependencies: Dependency[] = []
|
||||||
|
|
||||||
for (const tomlDep of gopkgLockContentsToml.projects) {
|
for (const tomlDep of gopkgLockContentsToml.projects as GopkgLockProject[]) {
|
||||||
|
const rawRefType = getRawRefType(tomlDep)
|
||||||
dependencies.push({
|
dependencies.push({
|
||||||
name: tomlDep.name,
|
name: tomlDep.name,
|
||||||
url: tomlDep.source ? tomlDep.source : tomlDep.name,
|
url: tomlDep.source ? tomlDep.source : tomlDep.name,
|
||||||
|
|
||||||
refType: getRefType(gopkgTomlContentsToml, tomlDep),
|
rawRefType,
|
||||||
|
refName: rawRefType ? (tomlDep as any)[rawRefType] : undefined,
|
||||||
|
refType: getRefType(tomlDep),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
return dependencies
|
return dependencies
|
||||||
}
|
}
|
||||||
|
|
||||||
function getRefType(gopkgTomlContentsToml: any, tomlDep: any): 'commit' | 'tag' | 'branch' | 'unknown' {
|
function getRawRefType(tomlDep: GopkgLockProject): string | undefined {
|
||||||
if (tomlDep.version) {
|
if (tomlDep.version) {
|
||||||
return 'tag'
|
return 'version'
|
||||||
} else if (tomlDep.branch) {
|
} else if (tomlDep.branch) {
|
||||||
return 'branch'
|
return 'branch'
|
||||||
} else {
|
} else if (tomlDep.revision) {
|
||||||
const override: any = gopkgTomlContentsToml.override.find((o: any) => o.name === tomlDep.name)
|
return 'revision'
|
||||||
if (override && override.revision) {
|
}
|
||||||
|
|
||||||
|
return undefined
|
||||||
|
}
|
||||||
|
|
||||||
|
function getRefType(tomlDep: GopkgLockProject): 'commit' | 'tag' | 'branch' | 'unknown' {
|
||||||
|
switch (getRawRefType(tomlDep)) {
|
||||||
|
case 'version':
|
||||||
|
return 'tag'
|
||||||
|
case 'branch':
|
||||||
|
return 'branch'
|
||||||
|
case 'revision':
|
||||||
return 'commit'
|
return 'commit'
|
||||||
|
default:
|
||||||
|
return 'unknown'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return 'unknown'
|
interface SearchArgs {
|
||||||
|
projectName: string,
|
||||||
|
projectLineSubstring: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export function findLineInTomlFileContent(contents: string, searchArgs: SearchArgs): number {
|
||||||
|
const projectNameIndex = contents.indexOf(searchArgs.projectName)
|
||||||
|
if (projectNameIndex < 0) {
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
|
||||||
|
const projectStartIndex = contents.lastIndexOf('[[', projectNameIndex)
|
||||||
|
if (projectStartIndex < 0) {
|
||||||
|
return projectNameIndex
|
||||||
|
}
|
||||||
|
const index = contents.indexOf(searchArgs.projectLineSubstring, projectStartIndex)
|
||||||
|
if (index < 0) {
|
||||||
|
return projectNameIndex
|
||||||
|
}
|
||||||
|
|
||||||
|
const line = contents.substr(0, index).split('\n').length
|
||||||
|
|
||||||
|
return line
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function checkGoDependenciesAsync(
|
export async function checkGoDependenciesAsync(
|
||||||
|
@ -77,40 +126,49 @@ export async function checkGoDependenciesAsync(
|
||||||
result.checkedDependencyCount += dependencies.length
|
result.checkedDependencyCount += dependencies.length
|
||||||
|
|
||||||
for (const dependency of dependencies) {
|
for (const dependency of dependencies) {
|
||||||
const url = dependency.url
|
const name = dependency.name
|
||||||
let line = findLineInFileContent(gopkgTomlContents, `name = "${url}"`)
|
|
||||||
let filename = gopkgTomlFilename
|
|
||||||
if (line < 0) {
|
|
||||||
line = findLineInFileContent(gopkgLockContents, `name = "${url}"`)
|
|
||||||
filename = gopkgLockFilename
|
|
||||||
}
|
|
||||||
const refType = dependency.refType
|
const refType = dependency.refType
|
||||||
if (!refType) {
|
if (!refType) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const searchArgs: SearchArgs = {
|
||||||
|
projectLineSubstring: `${dependency.rawRefType} = "${dependency.refName}"`,
|
||||||
|
projectName: `name = "${name}"`,
|
||||||
|
}
|
||||||
|
let line = findLineInTomlFileContent(gopkgTomlContents, searchArgs)
|
||||||
|
let filename = gopkgTomlFilename
|
||||||
|
if (line < 0) {
|
||||||
|
line = findLineInTomlFileContent(gopkgLockContents, searchArgs)
|
||||||
|
filename = gopkgLockFilename
|
||||||
|
}
|
||||||
|
|
||||||
const annotation: AnnotationSource = {
|
const annotation: AnnotationSource = {
|
||||||
dependency,
|
dependency,
|
||||||
filename,
|
filename,
|
||||||
line,
|
line,
|
||||||
}
|
}
|
||||||
const newAnnotation = (level: 'notice' | 'warning' | 'failure', title: string, message: string) => {
|
const newAnnotation = (level: 'notice' | 'warning' | 'failure', message: string) => {
|
||||||
|
const title = `Dependency '${name}' is locked with ${dependency.rawRefType} '${dependency.refName}'.`
|
||||||
result.annotations.push(createAnnotation(annotation, level, title, message))
|
result.annotations.push(createAnnotation(annotation, level, title, message))
|
||||||
}
|
}
|
||||||
switch (refType) {
|
switch (refType) {
|
||||||
case 'tag':
|
case 'tag':
|
||||||
continue
|
continue
|
||||||
case 'commit':
|
case 'commit':
|
||||||
newAnnotation('notice', `Dependency '${url}' is not locked with a tag/release.`,
|
newAnnotation('notice',
|
||||||
`A commit SHA is not a deterministic dependency locator.
|
`A commit SHA is not a deterministic dependency locator.
|
||||||
If the commit is overwritten by a force-push, it will be impossible to rebuild the same output in the future.`,
|
If the commit is overwritten by a force-push, it will be impossible to rebuild the same output in the future.
|
||||||
|
|
||||||
|
Please lock the dependency with a tag/release.`,
|
||||||
)
|
)
|
||||||
break
|
break
|
||||||
case 'branch':
|
case 'branch':
|
||||||
newAnnotation('notice', // TODO: change this to 'failure' once we've fixed issues in the codebase
|
newAnnotation('notice', // TODO: change this to 'failure' once we've fixed issues in the codebase
|
||||||
`Dependency '${url}' is not locked with a tag/release.`,
|
|
||||||
`A branch is not a deterministic dependency locator.
|
`A branch is not a deterministic dependency locator.
|
||||||
If the branch advances, it will be impossible to rebuild the same output in the future.`,
|
If the branch advances, it will be impossible to rebuild the same output in the future.
|
||||||
|
|
||||||
|
Please lock the dependency with a tag/release.`,
|
||||||
)
|
)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,11 @@
|
||||||
import { Context } from 'probot' // eslint-disable-line no-unused-vars
|
import { Context } from 'probot' // eslint-disable-line no-unused-vars
|
||||||
|
|
||||||
import { AnalysisResult } from './analysis-result'
|
import { AnalysisResult } from './analysis-result'
|
||||||
|
import { createAnnotation } from './annotation-result'
|
||||||
|
import { AnnotationSource } from './annotation-source'
|
||||||
import { Dependency } from './dependency'
|
import { Dependency } from './dependency'
|
||||||
import { AnnotationSource,
|
import { findLineInFileContent,
|
||||||
createAnnotation,
|
slowGetRefTypeAsync } from './utils'
|
||||||
findLineInFileContent,
|
|
||||||
slowGetRefTypeAsync } from './dependency-check'
|
|
||||||
|
|
||||||
export async function checkPackageFileAsync(
|
export async function checkPackageFileAsync(
|
||||||
analysisResult: AnalysisResult,
|
analysisResult: AnalysisResult,
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
export interface Dependency {
|
export interface Dependency {
|
||||||
name: string
|
name: string
|
||||||
url: string
|
url: string
|
||||||
|
rawRefType?: string,
|
||||||
refType?: 'commit' | 'tag' | 'branch' | 'unknown'
|
refType?: 'commit' | 'tag' | 'branch' | 'unknown'
|
||||||
|
refName?: string
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
import Octokit from '@octokit/rest'
|
import Octokit from '@octokit/rest'
|
||||||
import Humanize from 'humanize-plus'
|
import Humanize from 'humanize-plus'
|
||||||
import { Application, Context } from 'probot' // eslint-disable-line no-unused-vars
|
import { Application, Context } from 'probot' // eslint-disable-line no-unused-vars
|
||||||
|
|
||||||
import { AnalysisResult } from './analysis-result'
|
import { AnalysisResult } from './analysis-result'
|
||||||
import { AnnotationResult } from './annotation-result'
|
import { AnnotationResult } from './annotation-result'
|
||||||
import { checkGopkgFileAsync } from './dependency-check-gopkg'
|
import { checkGopkgFileAsync } from './dependency-check-gopkg'
|
||||||
|
|
|
@ -1,13 +1,5 @@
|
||||||
import Octokit from '@octokit/rest'
|
import Octokit from '@octokit/rest'
|
||||||
import { Context } from 'probot'
|
import { Context } from 'probot'
|
||||||
import { AnnotationResult } from './annotation-result'
|
|
||||||
import { Dependency } from './dependency'
|
|
||||||
|
|
||||||
export interface AnnotationSource {
|
|
||||||
dependency: Dependency
|
|
||||||
filename: string
|
|
||||||
line: number
|
|
||||||
}
|
|
||||||
|
|
||||||
export function findLineInFileContent(contents: string, substring: string): number {
|
export function findLineInFileContent(contents: string, substring: string): number {
|
||||||
const index = contents.indexOf(substring)
|
const index = contents.indexOf(substring)
|
||||||
|
@ -15,39 +7,20 @@ export function findLineInFileContent(contents: string, substring: string): numb
|
||||||
return -1
|
return -1
|
||||||
}
|
}
|
||||||
|
|
||||||
const lines = contents.split('\n')
|
|
||||||
const line = contents.substr(0, index).split('\n').length
|
const line = contents.substr(0, index).split('\n').length
|
||||||
|
|
||||||
const startOfLineIndex = (() => {
|
// const lines = contents.split('\n')
|
||||||
const x = lines.slice(0)
|
// const startOfLineIndex = (() => {
|
||||||
x.splice(line - 1)
|
// const x = lines.slice(0)
|
||||||
return x.join('\n').length + (x.length > 0 ? 1 : 0)
|
// x.splice(line - 1)
|
||||||
})()
|
// return x.join('\n').length + (x.length > 0 ? 1 : 0)
|
||||||
|
// })()
|
||||||
|
|
||||||
const col = index - startOfLineIndex
|
// const col = index - startOfLineIndex
|
||||||
|
|
||||||
return line
|
return line
|
||||||
}
|
}
|
||||||
|
|
||||||
export function createAnnotation(
|
|
||||||
annotationSource: AnnotationSource,
|
|
||||||
annotationLevel: 'notice' | 'warning' | 'failure',
|
|
||||||
title: string,
|
|
||||||
message: string,
|
|
||||||
): AnnotationResult {
|
|
||||||
const { dependency, filename, line } = annotationSource
|
|
||||||
|
|
||||||
return new AnnotationResult(
|
|
||||||
title,
|
|
||||||
message,
|
|
||||||
annotationLevel,
|
|
||||||
dependency,
|
|
||||||
filename,
|
|
||||||
line,
|
|
||||||
line,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function slowGetRefTypeAsync(
|
export async function slowGetRefTypeAsync(
|
||||||
context: Context,
|
context: Context,
|
||||||
address: string,
|
address: string,
|
Loading…
Reference in New Issue