Java 프로젝트에서 체계적인 빌드 번호 매기기 및 버전 번호 관리에 대한 현재 모범 사례는 무엇입니까? 구체적으로 특별히:
분산 개발 환경에서 빌드 번호를 체계적으로 관리하는 방법
소스에서 버전 번호를 유지 보수하는 방법 / 런타임 애플리케이션에서 사용 가능한 방법
소스 리포지토리와 올바르게 통합하는 방법
버전 번호와 저장소 태그를보다 자동으로 관리하는 방법
지속적인 빌드 인프라와 통합하는 방법
사용 가능한 많은 도구가 있으며 개미 (우리가 사용하는 빌드 시스템)에는 빌드 번호를 유지 관리하는 작업이 있지만 CVS, svn 또는 이와 유사한 것을 사용하여 여러 명의 동시 개발자와 함께 관리하는 방법은 명확하지 않습니다 .
[편집하다]
몇 가지 좋고 유용한 부분 또는 구체적인 답변이 아래에 나와 있으므로 그 중 일부를 요약하겠습니다. 이것에 대한 강력한 "모범 사례"가 아니라 중복되는 아이디어 모음이있는 것처럼 들립니다. 아래에서 내 요약과 사람들이 후속 조치로 답변을 시도 할 수있는 몇 가지 결과적인 질문을 찾으십시오. [스택 오버플로가 처음입니다 ...이 작업을 잘못하면 의견을 보내주십시오.]
SVN을 사용하는 경우 특정 체크 아웃의 버전 관리가 제공됩니다. 빌드 번호 매기기는이를 이용하여 특정 체크 아웃 / 수정을 식별하는 고유 한 빌드 번호를 만들 수 있습니다. [우리가 레거시 이유로 사용하고있는 CVS는 이러한 수준의 통찰력을 제공하지 않습니다. 태그를 사용하여 수동으로 개입하면 도움이됩니다.]
maven을 빌드 시스템으로 사용하는 경우 SCM에서 버전 번호를 생성하고 릴리스를 자동으로 생성하기위한 릴리스 모듈이 지원됩니다. [우리는 여러 가지 이유로 maven을 사용할 수 없지만 이것은 가능한 사람들에게 도움이됩니다. [ 마르첼로 사기 감사합니다 ]]
당신이 사용하는 경우 개미를 빌드 시스템으로, 다음과 같은 작업 설명 캔 도움은 여러 가지 방법으로 빌드로 접을 수있는 Java .properties의 파일 캡처 빌드 정보를 생산하고 있습니다. [우리는 marty-lamb 덕분에 hudson 파생 정보를 포함하도록이 아이디어를 확장했습니다 ].
Ant 및 Maven (및 hudson 및 cruise 컨트롤)은 빌드 번호를 .properties 파일 또는 .txt / .html 파일로 가져 오는 쉬운 방법을 제공합니다. 이 "안전한"부분이 의도적으로 또는 실수로 변조되지 않도록하기에 충분합니까? 빌드시 "versioning"클래스로 컴파일하는 것이 더 낫습니까?
주장 : 빌드 넘버링은 hudson 과 같은 지속적인 통합 시스템에서 정의 / 제정되어야합니다 . [ marcelo-morales 에게 감사드립니다. ] 우리는이 제안을 받았지만, 릴리즈 엔지니어링 질문을 공개합니다 : 릴리즈는 어떻게 이루어 집니까? 릴리스에 여러 빌드 번호가 있습니까? 다른 릴리스의 빌드 번호 간에는 의미있는 관계가 있습니까?
질문 : 빌드 번호의 목표는 무엇입니까? 품질 관리에 사용됩니까? 어떻게? 개발자가 주로 개발 중에 여러 빌드를 명확하게하거나 QA가 최종 사용자가 얻은 빌드를 결정하기 위해 더 많이 사용합니까? 재현성이 목표라면 이론적으로 이것은 릴리스 버전 번호가 제공해야하는 것입니다. 왜 그렇지 않습니까? (아래 답변의 일부로이 답변에 답하십시오. 선택 / 제안한 사항을 밝히는 데 도움이됩니다 ...)
질문 : 수동 빌드에 빌드 번호를위한 장소가 있습니까? 모두가 CI 솔루션을 사용해야 할 정도로 문제가 있습니까?
질문 : 빌드 번호를 SCM에 체크인해야합니까? 목표가 확실하고 명확하게 특정 빌드를 식별하는 경우 충돌 / 재시작 등의 다양한 연속 또는 수동 빌드 시스템에 대처하는 방법 ...
질문 : 빌드 번호가 짧고 달콤합니다 (즉, 단조 증가하는 정수)하여 보관을 위해 파일 이름을 사용하기 쉽고 통신에서 참조하기 쉽습니다. 날짜, 기계 이름 등?
질문 : 빌드 번호 할당이 대규모 자동 릴리스 프로세스에 어떻게 적용되는지 자세히 설명하십시오. 예, 메이븐 애호가들, 우리는 이것이 완료되었다는 것을 알고 있지만, 우리 모두가 아직 쿨 에이드를 마신 것은 아닙니다 ...
나는 적어도 cvs / ant / hudson 설정의 구체적인 예를 위해 이것을 완전한 대답으로 육체 화하고 싶습니다. 그래서 누군가이 질문에 기초하여 완전한 전략을 세울 수 있습니다. 이 특정 사례 (cvs 태그 지정 체계, 관련 CI 구성 항목 및 빌드 번호를 릴리스로 접는 릴리스 절차를 포함하여 프로그래밍 방식으로 설명)를 제공 할 수있는 사람이라면 누구나 "답변"으로 표시하겠습니다. 다른 특정 구성 (예 : svn / maven / cruise control)에 대해 질문 / 답변을하려면 여기에서 질문에 연결하겠습니다. --JA
[편집 10 10 월 9 일] 나는 그것이 합리적인 해결책이라고 생각하기 때문에 가장 인기있는 답변을 수락했지만 다른 답변들도 좋은 아이디어를 포함하고 있습니다. 누군가가 이들 중 일부를 marty-lamb 과 합성하는 데 어려움 을 겪고 싶다면 다른 것을 받아들이는 것이 좋습니다. marty-lamb과 관련하여 유일하게 걱정하는 것은 직렬화 된 빌드 번호를 안정적으로 생성하지 않는다는 것입니다. 빌드 시스템의 현지 시계에 따라 모호하지 않은 빌드 번호를 제공하므로 좋지 않습니다.
[7 월 10 일 편집]
이제 아래와 같은 클래스가 포함됩니다. 이를 통해 버전 번호를 최종 실행 파일로 컴파일 할 수 있습니다. 다양한 형태의 버전 정보가 로깅 데이터, 장기간 보관 된 출력 제품에서 생성되며 출력 제품에 대한 (때로는 몇 년 후) 분석을 특정 빌드로 추적하는 데 사용됩니다.
public final class AppVersion
{
// SVN should fill this out with the latest tag when it's checked out.
private static final String APP_SVNURL_RAW =
"$HeadURL: svn+ssh://user@host/svnroot/app/trunk/src/AppVersion.java $";
private static final String APP_SVN_REVISION_RAW = "$Revision: 325 $";
private static final Pattern SVNBRANCH_PAT =
Pattern.compile("(branches|trunk|releases)\\/([\\w\\.\\-]+)\\/.*");
private static final String APP_SVNTAIL =
APP_SVNURL_RAW.replaceFirst(".*\\/svnroot\\/app\\/", "");
private static final String APP_BRANCHTAG;
private static final String APP_BRANCHTAG_NAME;
private static final String APP_SVNREVISION =
APP_SVN_REVISION_RAW.replaceAll("\\$Revision:\\s*","").replaceAll("\\s*\\$", "");
static {
Matcher m = SVNBRANCH_PAT.matcher(APP_SVNTAIL);
if (!m.matches()) {
APP_BRANCHTAG = "[Broken SVN Info]";
APP_BRANCHTAG_NAME = "[Broken SVN Info]";
} else {
APP_BRANCHTAG = m.group(1);
if (APP_BRANCHTAG.equals("trunk")) {
// this isn't necessary in this SO example, but it
// is since we don't call it trunk in the real case
APP_BRANCHTAG_NAME = "trunk";
} else {
APP_BRANCHTAG_NAME = m.group(2);
}
}
}
public static String tagOrBranchName()
{ return APP_BRANCHTAG_NAME; }
/** Answers a formatter String descriptor for the app version.
* @return version string */
public static String longStringVersion()
{ return "app "+tagOrBranchName()+" ("+
tagOrBranchName()+", svn revision="+svnRevision()+")"; }
public static String shortStringVersion()
{ return tagOrBranchName(); }
public static String svnVersion()
{ return APP_SVNURL_RAW; }
public static String svnRevision()
{ return APP_SVNREVISION; }
public static String svnBranchId()
{ return APP_BRANCHTAG + "/" + APP_BRANCHTAG_NAME; }
public static final String banner()
{
StringBuilder sb = new StringBuilder();
sb.append("\n----------------------------------------------------------------");
sb.append("\nApplication -- ");
sb.append(longStringVersion());
sb.append("\n----------------------------------------------------------------\n");
return sb.toString();
}
}
위키 토론이 될만한 의견이 있으면 남겨주세요.
gradle
및 / 또는 git
?를 사용할 때 비슷한 접근 방식을 가진 사람이 있는지 궁금합니다 .